diff --git a/.github/workflows/release-tasks.yml b/.github/workflows/release-tasks.yml index 0d250a6e94d5c..ef1d57dc92c80 100644 --- a/.github/workflows/release-tasks.yml +++ b/.github/workflows/release-tasks.yml @@ -26,7 +26,7 @@ jobs: - name: Install Dependencies run: | - sudo apt-get update \ + sudo apt-get update sudo apt-get install -y \ doxygen \ graphviz \ diff --git a/.github/workflows/repo-lockdown.yml b/.github/workflows/repo-lockdown.yml index 91e062fa8cf30..69e4d7de57de6 100644 --- a/.github/workflows/repo-lockdown.yml +++ b/.github/workflows/repo-lockdown.yml @@ -2,6 +2,11 @@ name: 'Repo Lockdown' on: pull_request_target: types: opened + paths-ignore: + - 'libcxx/**' + - 'libcxxabi/**' + - 'libunwind/**' + - 'runtimes/**' permissions: pull-requests: write diff --git a/bolt/include/bolt/Core/Relocation.h b/bolt/include/bolt/Core/Relocation.h index 51dd769387565..1296c001db57c 100644 --- a/bolt/include/bolt/Core/Relocation.h +++ b/bolt/include/bolt/Core/Relocation.h @@ -64,8 +64,7 @@ struct Relocation { static bool skipRelocationProcess(uint64_t &Type, uint64_t Contents); // Adjust value depending on relocation type (make it PC relative or not) - static uint64_t adjustValue(uint64_t Type, uint64_t Value, - uint64_t PC); + static uint64_t encodeValue(uint64_t Type, uint64_t Value, uint64_t PC); /// Extract current relocated value from binary contents. This is used for /// RISC architectures where values are encoded in specific bits depending diff --git a/bolt/lib/Core/BinarySection.cpp b/bolt/lib/Core/BinarySection.cpp index 846515c3ed131..e0e7b15d04a57 100644 --- a/bolt/lib/Core/BinarySection.cpp +++ b/bolt/lib/Core/BinarySection.cpp @@ -146,7 +146,7 @@ void BinarySection::flushPendingRelocations(raw_pwrite_stream &OS, if (Reloc.Symbol) Value += Resolver(Reloc.Symbol); - Value = Relocation::adjustValue(Reloc.Type, Value, + Value = Relocation::encodeValue(Reloc.Type, Value, SectionAddress + Reloc.Offset); OS.pwrite(reinterpret_cast(&Value), diff --git a/bolt/lib/Core/HashUtilities.cpp b/bolt/lib/Core/HashUtilities.cpp index 1c980e003f884..0752eaeabef85 100644 --- a/bolt/lib/Core/HashUtilities.cpp +++ b/bolt/lib/Core/HashUtilities.cpp @@ -13,6 +13,7 @@ #include "bolt/Core/HashUtilities.h" #include "bolt/Core/BinaryContext.h" #include "bolt/Core/BinaryFunction.h" +#include "llvm/MC/MCInstPrinter.h" namespace llvm { namespace bolt { @@ -116,13 +117,11 @@ std::string hashBlock(BinaryContext &BC, const BinaryBasicBlock &BB, if (IsX86 && BC.MIB->isConditionalBranch(Inst)) Opcode = BC.MIB->getShortBranchOpcode(Opcode); - if (Opcode == 0) + if (Opcode == 0) { HashString.push_back(0); - - while (Opcode) { - uint8_t LSB = Opcode & 0xff; - HashString.push_back(LSB); - Opcode = Opcode >> 8; + } else { + StringRef OpcodeName = BC.InstPrinter->getOpcodeName(Opcode); + HashString.append(OpcodeName.str()); } for (const MCOperand &Op : MCPlus::primeOperands(Inst)) diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp index b36e321f4e342..d3e7fccc23100 100644 --- a/bolt/lib/Core/Relocation.cpp +++ b/bolt/lib/Core/Relocation.cpp @@ -262,10 +262,11 @@ static bool skipRelocationProcessAArch64(uint64_t &Type, uint64_t Contents) { return false; } -static uint64_t adjustValueX86(uint64_t Type, uint64_t Value, uint64_t PC) { +static uint64_t encodeValueX86(uint64_t Type, uint64_t Value, uint64_t PC) { switch (Type) { default: - llvm_unreachable("not supported relocation"); + llvm_unreachable("unsupported relocation"); + case ELF::R_X86_64_64: case ELF::R_X86_64_32: break; case ELF::R_X86_64_PC32: @@ -275,10 +276,10 @@ static uint64_t adjustValueX86(uint64_t Type, uint64_t Value, uint64_t PC) { return Value; } -static uint64_t adjustValueAArch64(uint64_t Type, uint64_t Value, uint64_t PC) { +static uint64_t encodeValueAArch64(uint64_t Type, uint64_t Value, uint64_t PC) { switch (Type) { default: - llvm_unreachable("not supported relocation"); + llvm_unreachable("unsupported relocation"); case ELF::R_AARCH64_ABS32: break; case ELF::R_AARCH64_PREL16: @@ -566,11 +567,10 @@ bool Relocation::skipRelocationProcess(uint64_t &Type, uint64_t Contents) { return skipRelocationProcessX86(Type, Contents); } -uint64_t Relocation::adjustValue(uint64_t Type, uint64_t Value, - uint64_t PC) { +uint64_t Relocation::encodeValue(uint64_t Type, uint64_t Value, uint64_t PC) { if (Arch == Triple::aarch64) - return adjustValueAArch64(Type, Value, PC); - return adjustValueX86(Type, Value, PC); + return encodeValueAArch64(Type, Value, PC); + return encodeValueX86(Type, Value, PC); } uint64_t Relocation::extractValue(uint64_t Type, uint64_t Contents, diff --git a/bolt/lib/Passes/RetpolineInsertion.cpp b/bolt/lib/Passes/RetpolineInsertion.cpp index 4d83fb3903a70..c8a42725c9745 100644 --- a/bolt/lib/Passes/RetpolineInsertion.cpp +++ b/bolt/lib/Passes/RetpolineInsertion.cpp @@ -22,6 +22,7 @@ //===----------------------------------------------------------------------===// #include "bolt/Passes/RetpolineInsertion.h" +#include "llvm/MC/MCInstPrinter.h" #include "llvm/Support/raw_ostream.h" #define DEBUG_TYPE "bolt-retpoline" @@ -173,39 +174,45 @@ BinaryFunction *createNewRetpoline(BinaryContext &BC, std::string createRetpolineFunctionTag(BinaryContext &BC, const IndirectBranchInfo &BrInfo, bool R11Available) { - if (BrInfo.isReg()) - return "__retpoline_r" + to_string(BrInfo.BranchReg) + "_"; + std::string Tag; + llvm::raw_string_ostream TagOS(Tag); + TagOS << "__retpoline_"; + + if (BrInfo.isReg()) { + BC.InstPrinter->printRegName(TagOS, BrInfo.BranchReg); + TagOS << "_"; + TagOS.flush(); + return Tag; + } // Memory Branch if (R11Available) return "__retpoline_r11"; - std::string Tag = "__retpoline_mem_"; - const IndirectBranchInfo::MemOpInfo &MemRef = BrInfo.Memory; - std::string DispExprStr; - if (MemRef.DispExpr) { - llvm::raw_string_ostream Ostream(DispExprStr); - MemRef.DispExpr->print(Ostream, BC.AsmInfo.get()); - Ostream.flush(); - } + TagOS << "mem_"; - Tag += MemRef.BaseRegNum != BC.MIB->getNoRegister() - ? "r" + to_string(MemRef.BaseRegNum) - : ""; + if (MemRef.BaseRegNum != BC.MIB->getNoRegister()) + BC.InstPrinter->printRegName(TagOS, MemRef.BaseRegNum); - Tag += MemRef.DispExpr ? "+" + DispExprStr : "+" + to_string(MemRef.DispImm); + TagOS << "+"; + if (MemRef.DispExpr) + MemRef.DispExpr->print(TagOS, BC.AsmInfo.get()); + else + TagOS << MemRef.DispImm; - Tag += MemRef.IndexRegNum != BC.MIB->getNoRegister() - ? "+" + to_string(MemRef.ScaleImm) + "*" + - to_string(MemRef.IndexRegNum) - : ""; + if (MemRef.IndexRegNum != BC.MIB->getNoRegister()) { + TagOS << "+" << MemRef.ScaleImm << "*"; + BC.InstPrinter->printRegName(TagOS, MemRef.IndexRegNum); + } - Tag += MemRef.SegRegNum != BC.MIB->getNoRegister() - ? "_seg_" + to_string(MemRef.SegRegNum) - : ""; + if (MemRef.SegRegNum != BC.MIB->getNoRegister()) { + TagOS << "_seg_"; + BC.InstPrinter->printRegName(TagOS, MemRef.SegRegNum); + } + TagOS.flush(); return Tag; } diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp index cffcde8213791..749d907627315 100644 --- a/bolt/lib/Rewrite/DWARFRewriter.cpp +++ b/bolt/lib/Rewrite/DWARFRewriter.cpp @@ -199,7 +199,7 @@ void DWARFRewriter::updateDebugInfo() { std::make_unique(*CU.get(), DwarfVersion, false); if (std::optional DWOId = CU->getDWOId()) { - assert(LocListWritersByCU.count(*DWOId) == 0 && + assert(RangeListsWritersByCU.count(*DWOId) == 0 && "RangeLists writer for DWO unit already exists."); auto RangeListsSectionWriter = std::make_unique(); diff --git a/bolt/runtime/CMakeLists.txt b/bolt/runtime/CMakeLists.txt index 7d177f7c598b1..37a894702206a 100644 --- a/bolt/runtime/CMakeLists.txt +++ b/bolt/runtime/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.13.4) +cmake_minimum_required(VERSION 3.20.0) include(CheckIncludeFiles) include(GNUInstallDirs) diff --git a/bolt/test/CMakeLists.txt b/bolt/test/CMakeLists.txt index 1c7814155bdae..216a785b7d69f 100644 --- a/bolt/test/CMakeLists.txt +++ b/bolt/test/CMakeLists.txt @@ -47,6 +47,7 @@ list(APPEND BOLT_TEST_DEPS llvm-objdump llvm-readelf llvm-readobj + llvm-strings llvm-strip llvm-objcopy merge-fdata diff --git a/bolt/test/X86/Inputs/dwarf5-loc-base-no-loc-accesshelper.s b/bolt/test/X86/Inputs/dwarf5-loc-base-no-loc-accesshelper.s index dcf9f6a23a07b..8705755062efd 100644 --- a/bolt/test/X86/Inputs/dwarf5-loc-base-no-loc-accesshelper.s +++ b/bolt/test/X86/Inputs/dwarf5-loc-base-no-loc-accesshelper.s @@ -286,11 +286,10 @@ fooVar: .long .Lloclists_table_base0 # DW_AT_loclists_base .byte 2 # Abbrev [2] 0x27:0xb DW_TAG_variable .byte 3 # DW_AT_name - .long 50 # DW_AT_type + .long 39 # DW_AT_type # DW_AT_external .byte 0 # DW_AT_decl_file .byte 1 # DW_AT_decl_line - .byte 0 .byte 3 # Abbrev [3] 0x32:0x4 DW_TAG_base_type .byte 4 # DW_AT_name .byte 5 # DW_AT_encoding @@ -319,7 +318,7 @@ fooVar: .long 88 # DW_AT_type .byte 0 # End Of Children Mark .byte 8 # Abbrev [8] 0x58:0x5 DW_TAG_pointer_type - .long 50 # DW_AT_type + .long 39 # DW_AT_type .byte 9 # Abbrev [9] 0x5d:0x31 DW_TAG_subprogram .byte 2 # DW_AT_low_pc .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc @@ -330,18 +329,18 @@ fooVar: .byte 9 # DW_AT_name .byte 0 # DW_AT_decl_file .byte 6 # DW_AT_decl_line - .long 50 # DW_AT_type + .long 39 # DW_AT_type # DW_AT_external .byte 10 # Abbrev [10] 0x6d:0xa DW_TAG_formal_parameter .byte 10 # DW_AT_name .byte 0 # DW_AT_decl_file .byte 6 # DW_AT_decl_line - .long 50 # DW_AT_type + .long 39 # DW_AT_type .byte 11 # Abbrev [11] 0x77:0x9 DW_TAG_variable .byte 7 # DW_AT_name .byte 0 # DW_AT_decl_file .byte 7 # DW_AT_decl_line - .long 50 # DW_AT_type + .long 39 # DW_AT_type .byte 12 # Abbrev [12] 0x80:0xd DW_TAG_inlined_subroutine .long 74 # DW_AT_abstract_origin .byte 2 # DW_AT_low_pc diff --git a/bolt/test/X86/cfi-expr-rewrite.s b/bolt/test/X86/cfi-expr-rewrite.s index 27628190c6601..0d20654178543 100644 --- a/bolt/test/X86/cfi-expr-rewrite.s +++ b/bolt/test/X86/cfi-expr-rewrite.s @@ -11,7 +11,7 @@ # CHECK-NEXT: DW_CFA_expression: RBP DW_OP_breg6 RBP+0 # CHECK-NEXT: DW_CFA_advance_loc: 5 # CHECK-NEXT: DW_CFA_def_cfa_expression: DW_OP_breg6 RBP-8, DW_OP_deref -# CHECK-NEXT: DW_CFA_advance_loc2: 3174 +# CHECK-NEXT: DW_CFA_advance_loc2: 3130 # CHECK-NEXT: DW_CFA_def_cfa: R10 +0 # CHECK-NEXT: DW_CFA_advance_loc: 5 # CHECK-NEXT: DW_CFA_def_cfa: RSP +8 diff --git a/bolt/test/lit.cfg.py b/bolt/test/lit.cfg.py index 5838699157db7..f28afd5912279 100644 --- a/bolt/test/lit.cfg.py +++ b/bolt/test/lit.cfg.py @@ -87,6 +87,7 @@ ToolSubst('llvm-nm', unresolved='fatal'), ToolSubst('llvm-objdump', unresolved='fatal'), ToolSubst('llvm-objcopy', unresolved='fatal'), + ToolSubst('llvm-strings', unresolved='fatal'), ToolSubst('llvm-strip', unresolved='fatal'), ToolSubst('llvm-readelf', unresolved='fatal'), ToolSubst('link_fdata', command=sys.executable, unresolved='fatal', extra_args=[link_fdata_cmd]), diff --git a/bolt/test/runtime/X86/retpoline-synthetic.test b/bolt/test/runtime/X86/retpoline-synthetic.test index 6cae6a85fbe78..394d0189207fb 100644 --- a/bolt/test/runtime/X86/retpoline-synthetic.test +++ b/bolt/test/runtime/X86/retpoline-synthetic.test @@ -20,5 +20,11 @@ CHECK-CALL-NOT: callq * RUN: llvm-objdump -d -j ".text" %t | FileCheck %s -check-prefix=CHECK-JUMP CHECK-JUMP-NOT: jmpq * +# Check generated retpoline stub names +RUN: llvm-strings %t | FileCheck %s -check-prefix=CHECK-STRINGS +CHECK-STRINGS-DAG: __retpoline_%rax_ +CHECK-STRINGS-DAG: __retpoline_mem_%rip+DATAat0x[[#]] +CHECK-STRINGS-DAG: __retpoline_mem_%rax+0 + RUN: %t 1000 3 | FileCheck %s CHECK: 30000000 diff --git a/clang-tools-extra/clang-tidy/ClangTidyCheck.h b/clang-tools-extra/clang-tidy/ClangTidyCheck.h index 9381b6e8becb2..17e9df96c39be 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyCheck.h +++ b/clang-tools-extra/clang-tidy/ClangTidyCheck.h @@ -407,7 +407,6 @@ class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback { private: void run(const ast_matchers::MatchFinder::MatchResult &Result) override; - StringRef getID() const override { return CheckName; } std::string CheckName; ClangTidyContext *Context; @@ -422,6 +421,7 @@ class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback { bool areDiagsSelfContained() const { return Context->areDiagsSelfContained(); } + StringRef getID() const override { return CheckName; } }; /// Read a named option from the ``Context`` and parse it as a bool. diff --git a/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp index 600a923b211cf..07a987359d4d8 100644 --- a/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp @@ -117,13 +117,13 @@ void AssertSideEffectCheck::check(const MatchFinder::MatchResult &Result) { StringRef AssertMacroName; while (Loc.isValid() && Loc.isMacroID()) { StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, LangOpts); + Loc = SM.getImmediateMacroCallerLoc(Loc); // Check if this macro is an assert. if (llvm::is_contained(AssertMacros, MacroName)) { AssertMacroName = MacroName; break; } - Loc = SM.getImmediateMacroCallerLoc(Loc); } if (AssertMacroName.empty()) return; diff --git a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp index f02eeceabe96a..eae955e8d4761 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp @@ -40,7 +40,7 @@ analyzeFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx, using llvm::Expected; Expected Context = - ControlFlowContext::build(&FuncDecl, *FuncDecl.getBody(), ASTCtx); + ControlFlowContext::build(FuncDecl, *FuncDecl.getBody(), ASTCtx); if (!Context) return std::nullopt; diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp index fe9412f8d068c..87504e93ca240 100644 --- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp @@ -453,10 +453,6 @@ static bool containerIsConst(const Expr *ContainerExpr, bool Dereference) { return false; } -LoopConvertCheck::RangeDescriptor::RangeDescriptor() - : ContainerNeedsDereference(false), DerefByConstRef(false), - DerefByValue(false), NeedsReverseCall(false) {} - LoopConvertCheck::LoopConvertCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), TUInfo(new TUTrackingInfo), MaxCopySize(Options.get("MaxCopySize", 16ULL)), diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h index 4e57b22662da7..b4f729d3ac538 100644 --- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h +++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h @@ -29,13 +29,13 @@ class LoopConvertCheck : public ClangTidyCheck { private: struct RangeDescriptor { - RangeDescriptor(); - bool ContainerNeedsDereference; - bool DerefByConstRef; - bool DerefByValue; + RangeDescriptor() = default; + bool ContainerNeedsDereference = false; + bool DerefByConstRef = false; + bool DerefByValue = false; std::string ContainerString; QualType ElemType; - bool NeedsReverseCall; + bool NeedsReverseCall = false; }; void getAliasRange(SourceManager &SM, SourceRange &DeclRange); diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp index 9561b2b00904f..0e16edc10a953 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp @@ -14,6 +14,7 @@ #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" #include "llvm/Support/FormatVariadic.h" @@ -396,7 +397,7 @@ std::string IdentifierNamingCheck::HungarianNotation::getDeclTypeName( IdentifierNamingCheck::IdentifierNamingCheck(StringRef Name, ClangTidyContext *Context) - : RenamerClangTidyCheck(Name, Context), Context(Context), CheckName(Name), + : RenamerClangTidyCheck(Name, Context), Context(Context), GetConfigPerFile(Options.get("GetConfigPerFile", true)), IgnoreFailedSplit(Options.get("IgnoreFailedSplit", false)) { @@ -1461,6 +1462,7 @@ IdentifierNamingCheck::getStyleForFile(StringRef FileName) const { if (Iter != NamingStylesCache.end()) return Iter->getValue(); + llvm::StringRef CheckName = getID(); ClangTidyOptions Options = Context->getOptionsForFile(FileName); if (Options.Checks && GlobList(*Options.Checks).contains(CheckName)) { auto It = NamingStylesCache.try_emplace( diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h index 3df15ad780180..2e3d4ea8c39c8 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h @@ -11,6 +11,7 @@ #include "../utils/RenamerClangTidyCheck.h" #include +#include namespace clang::tidy { namespace readability { @@ -202,7 +203,6 @@ class IdentifierNamingCheck final : public RenamerClangTidyCheck { mutable llvm::StringMap NamingStylesCache; FileStyle *MainFileStyle; ClangTidyContext *Context; - const StringRef CheckName; const bool GetConfigPerFile; const bool IgnoreFailedSplit; HungarianNotation HungarianNotation; diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp index 5347dadf18ac5..ee400d88a3a74 100644 --- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp @@ -448,14 +448,18 @@ void RenamerClangTidyCheck::addUsage( void RenamerClangTidyCheck::addUsage(const NamedDecl *Decl, SourceRange Range, const SourceManager *SourceMgr) { + // Don't keep track for non-identifier names. + auto *II = Decl->getIdentifier(); + if (!II) + return; if (const auto *Method = dyn_cast(Decl)) { if (const CXXMethodDecl *Overridden = getOverrideMethod(Method)) Decl = Overridden; } Decl = cast(Decl->getCanonicalDecl()); - return addUsage(RenamerClangTidyCheck::NamingCheckId(Decl->getLocation(), - Decl->getName()), - Range, SourceMgr); + return addUsage( + RenamerClangTidyCheck::NamingCheckId(Decl->getLocation(), II->getName()), + Range, SourceMgr); } void RenamerClangTidyCheck::checkNamedDecl(const NamedDecl *Decl, diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index 558769f209860..de589e70f4afa 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -463,8 +463,23 @@ std::optional printExprValue(const Expr *E, return Constant.Val.getAsString(Ctx, T); } -std::optional printExprValue(const SelectionTree::Node *N, - const ASTContext &Ctx) { +struct PrintExprResult { + /// The evaluation result on expression `Expr`. + std::optional PrintedValue; + /// The Expr object that represents the closest evaluable + /// expression. + const clang::Expr *TheExpr; + /// The node of selection tree where the traversal stops. + const SelectionTree::Node *TheNode; +}; + +// Seek the closest evaluable expression along the ancestors of node N +// in a selection tree. If a node in the path can be converted to an evaluable +// Expr, a possible evaluation would happen and the associated context +// is returned. +// If evaluation couldn't be done, return the node where the traversal ends. +PrintExprResult printExprValue(const SelectionTree::Node *N, + const ASTContext &Ctx) { for (; N; N = N->Parent) { // Try to evaluate the first evaluatable enclosing expression. if (const Expr *E = N->ASTNode.get()) { @@ -473,14 +488,16 @@ std::optional printExprValue(const SelectionTree::Node *N, if (!E->getType().isNull() && E->getType()->isVoidType()) break; if (auto Val = printExprValue(E, Ctx)) - return Val; + return PrintExprResult{/*PrintedValue=*/std::move(Val), /*Expr=*/E, + /*Node=*/N}; } else if (N->ASTNode.get() || N->ASTNode.get()) { // Refuse to cross certain non-exprs. (TypeLoc are OK as part of Exprs). // This tries to ensure we're showing a value related to the cursor. break; } } - return std::nullopt; + return PrintExprResult{/*PrintedValue=*/std::nullopt, /*Expr=*/nullptr, + /*Node=*/N}; } std::optional fieldName(const Expr *E) { @@ -677,6 +694,54 @@ getPredefinedExprHoverContents(const PredefinedExpr &PE, ASTContext &Ctx, return HI; } +HoverInfo evaluateMacroExpansion(unsigned int SpellingBeginOffset, + unsigned int SpellingEndOffset, + llvm::ArrayRef Expanded, + ParsedAST &AST) { + auto &Context = AST.getASTContext(); + auto &Tokens = AST.getTokens(); + auto PP = getPrintingPolicy(Context.getPrintingPolicy()); + auto Tree = SelectionTree::createRight(Context, Tokens, SpellingBeginOffset, + SpellingEndOffset); + + // If macro expands to one single token, rule out punctuator or digraph. + // E.g., for the case `array L_BRACKET 42 R_BRACKET;` where L_BRACKET and + // R_BRACKET expand to + // '[' and ']' respectively, we don't want the type of + // 'array[42]' when user hovers on L_BRACKET. + if (Expanded.size() == 1) + if (tok::getPunctuatorSpelling(Expanded[0].kind())) + return {}; + + auto *StartNode = Tree.commonAncestor(); + if (!StartNode) + return {}; + // If the common ancestor is partially selected, do evaluate if it has no + // children, thus we can disallow evaluation on incomplete expression. + // For example, + // #define PLUS_2 +2 + // 40 PL^US_2 + // In this case we don't want to present 'value: 2' as PLUS_2 actually expands + // to a non-value rather than a binary operand. + if (StartNode->Selected == SelectionTree::Selection::Partial) + if (!StartNode->Children.empty()) + return {}; + + HoverInfo HI; + // Attempt to evaluate it from Expr first. + auto ExprResult = printExprValue(StartNode, Context); + HI.Value = std::move(ExprResult.PrintedValue); + if (auto *E = ExprResult.TheExpr) + HI.Type = printType(E->getType(), Context, PP); + + // If failed, extract the type from Decl if possible. + if (!HI.Value && !HI.Type && ExprResult.TheNode) + if (auto *VD = ExprResult.TheNode->ASTNode.get()) + HI.Type = printType(VD->getType(), Context, PP); + + return HI; +} + /// Generate a \p Hover object given the macro \p MacroDecl. HoverInfo getHoverContents(const DefinedMacro &Macro, const syntax::Token &Tok, ParsedAST &AST) { @@ -732,6 +797,13 @@ HoverInfo getHoverContents(const DefinedMacro &Macro, const syntax::Token &Tok, HI.Definition += "// Expands to\n"; HI.Definition += ExpansionText; } + + auto Evaluated = evaluateMacroExpansion( + /*SpellingBeginOffset=*/SM.getFileOffset(Tok.location()), + /*SpellingEndOffset=*/SM.getFileOffset(Tok.endLocation()), + /*Expanded=*/Expansion->Expanded, AST); + HI.Value = std::move(Evaluated.Value); + HI.Type = std::move(Evaluated.Type); } return HI; } @@ -1293,7 +1365,7 @@ std::optional getHover(ParsedAST &AST, Position Pos, addLayoutInfo(*DeclToUse, *HI); // Look for a close enclosing expression to show the value of. if (!HI->Value) - HI->Value = printExprValue(N, AST.getASTContext()); + HI->Value = printExprValue(N, AST.getASTContext()).PrintedValue; maybeAddCalleeArgInfo(N, *HI, PP); maybeAddSymbolProviders(AST, *HI, include_cleaner::Symbol{*DeclToUse}); } else if (const Expr *E = N->ASTNode.get()) { diff --git a/clang-tools-extra/clangd/IncludeCleaner.cpp b/clang-tools-extra/clangd/IncludeCleaner.cpp index 3b913d851abe2..22d0808235f7f 100644 --- a/clang-tools-extra/clangd/IncludeCleaner.cpp +++ b/clang-tools-extra/clangd/IncludeCleaner.cpp @@ -440,8 +440,9 @@ IncludeCleanerFindings computeIncludeCleanerFindings(ParsedAST &AST) { return {std::move(UnusedIncludes), std::move(MissingIncludes)}; } -Fix removeAllUnusedIncludes(llvm::ArrayRef UnusedIncludes) { - assert(!UnusedIncludes.empty()); +std::optional removeAllUnusedIncludes(llvm::ArrayRef UnusedIncludes) { + if (UnusedIncludes.empty()) + return std::nullopt; Fix RemoveAll; RemoveAll.Message = "remove all unused includes"; @@ -465,8 +466,10 @@ Fix removeAllUnusedIncludes(llvm::ArrayRef UnusedIncludes) { } return RemoveAll; } -Fix addAllMissingIncludes(llvm::ArrayRef MissingIncludeDiags) { - assert(!MissingIncludeDiags.empty()); +std::optional +addAllMissingIncludes(llvm::ArrayRef MissingIncludeDiags) { + if (MissingIncludeDiags.empty()) + return std::nullopt; Fix AddAllMissing; AddAllMissing.Message = "add all missing includes"; @@ -516,15 +519,11 @@ std::vector generateIncludeCleanerDiagnostic( llvm::StringRef Code) { std::vector UnusedIncludes = generateUnusedIncludeDiagnostics( AST.tuPath(), Findings.UnusedIncludes, Code); - std::optional RemoveAllUnused;; - if (UnusedIncludes.size() > 1) - RemoveAllUnused = removeAllUnusedIncludes(UnusedIncludes); + std::optional RemoveAllUnused = removeAllUnusedIncludes(UnusedIncludes); std::vector MissingIncludeDiags = generateMissingIncludeDiagnostics( AST, Findings.MissingIncludes, Code); - std::optional AddAllMissing; - if (MissingIncludeDiags.size() > 1) - AddAllMissing = addAllMissingIncludes(MissingIncludeDiags); + std::optional AddAllMissing = addAllMissingIncludes(MissingIncludeDiags); std::optional FixAll; if (RemoveAllUnused && AddAllMissing) @@ -535,11 +534,16 @@ std::vector generateIncludeCleanerDiagnostic( Out->Fixes.push_back(*F); }; for (auto &Diag : MissingIncludeDiags) { - AddBatchFix(AddAllMissing, &Diag); + AddBatchFix(MissingIncludeDiags.size() > 1 + ? AddAllMissing + : std::nullopt, + &Diag); AddBatchFix(FixAll, &Diag); } for (auto &Diag : UnusedIncludes) { - AddBatchFix(RemoveAllUnused, &Diag); + AddBatchFix(UnusedIncludes.size() > 1 ? RemoveAllUnused + : std::nullopt, + &Diag); AddBatchFix(FixAll, &Diag); } diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp index 1501a5c5f3c3b..e5a391a775389 100644 --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -9,6 +9,7 @@ #include "ParsedAST.h" #include "../clang-tidy/ClangTidyCheck.h" #include "../clang-tidy/ClangTidyDiagnosticConsumer.h" +#include "../clang-tidy/ClangTidyModule.h" #include "../clang-tidy/ClangTidyModuleRegistry.h" #include "AST.h" #include "Compiler.h" @@ -25,7 +26,6 @@ #include "TidyProvider.h" #include "clang-include-cleaner/Record.h" #include "index/CanonicalIncludes.h" -#include "index/Index.h" #include "index/Symbol.h" #include "support/Logger.h" #include "support/Trace.h" @@ -50,7 +50,6 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include #include #include #include @@ -476,16 +475,19 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs, // diagnostics. if (PreserveDiags) { trace::Span Tracer("ClangTidyInit"); - tidy::ClangTidyCheckFactories CTFactories; - for (const auto &E : tidy::ClangTidyModuleRegistry::entries()) - E.instantiate()->addCheckFactories(CTFactories); + static const auto *CTFactories = [] { + auto *CTFactories = new tidy::ClangTidyCheckFactories; + for (const auto &E : tidy::ClangTidyModuleRegistry::entries()) + E.instantiate()->addCheckFactories(*CTFactories); + return CTFactories; + }(); CTContext.emplace(std::make_unique( tidy::ClangTidyGlobalOptions(), ClangTidyOpts)); CTContext->setDiagnosticsEngine(&Clang->getDiagnostics()); CTContext->setASTContext(&Clang->getASTContext()); CTContext->setCurrentFile(Filename); CTContext->setSelfContainedDiags(true); - CTChecks = CTFactories.createChecksForLanguage(&*CTContext); + CTChecks = CTFactories->createChecksForLanguage(&*CTContext); Preprocessor *PP = &Clang->getPreprocessor(); for (const auto &Check : CTChecks) { Check->registerPPCallbacks(Clang->getSourceManager(), PP, PP); @@ -610,10 +612,8 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs, Macros = Patch->mainFileMacros(); Marks = Patch->marks(); } - auto& PP = Clang->getPreprocessor(); - PP.addPPCallbacks( - std::make_unique( - PP, Macros)); + auto &PP = Clang->getPreprocessor(); + PP.addPPCallbacks(std::make_unique(PP, Macros)); PP.addPPCallbacks( collectPragmaMarksCallback(Clang->getSourceManager(), Marks)); diff --git a/clang-tools-extra/clangd/TidyProvider.cpp b/clang-tools-extra/clangd/TidyProvider.cpp index f3ed6f08a9acb..e3a6d5af20ae2 100644 --- a/clang-tools-extra/clangd/TidyProvider.cpp +++ b/clang-tools-extra/clangd/TidyProvider.cpp @@ -8,6 +8,7 @@ #include "TidyProvider.h" #include "../clang-tidy/ClangTidyModuleRegistry.h" +#include "../clang-tidy/ClangTidyOptions.h" #include "Config.h" #include "support/FileCache.h" #include "support/Logger.h" @@ -283,8 +284,15 @@ TidyProvider combine(std::vector Providers) { tidy::ClangTidyOptions getTidyOptionsForFile(TidyProviderRef Provider, llvm::StringRef Filename) { - tidy::ClangTidyOptions Opts = tidy::ClangTidyOptions::getDefaults(); - Opts.Checks->clear(); + // getDefaults instantiates all check factories, which are registered at link + // time. So cache the results once. + static const auto *DefaultOpts = [] { + auto *Opts = new tidy::ClangTidyOptions; + *Opts = tidy::ClangTidyOptions::getDefaults(); + Opts->Checks->clear(); + return Opts; + }(); + auto Opts = *DefaultOpts; if (Provider) Provider(Opts, Filename); return Opts; diff --git a/clang-tools-extra/clangd/unittests/CMakeLists.txt b/clang-tools-extra/clangd/unittests/CMakeLists.txt index 6d7bb59be3ab1..8d02b91fdd716 100644 --- a/clang-tools-extra/clangd/unittests/CMakeLists.txt +++ b/clang-tools-extra/clangd/unittests/CMakeLists.txt @@ -79,8 +79,9 @@ add_unittest(ClangdUnitTests ClangdTests PrintASTTests.cpp ProjectAwareIndexTests.cpp QualityTests.cpp - RenameTests.cpp RIFFTests.cpp + RenameTests.cpp + ReplayPeambleTests.cpp SelectionTests.cpp SemanticHighlightingTests.cpp SemanticSelectionTests.cpp diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 25d6a7b189ed5..1975488fd035a 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -4002,6 +4002,19 @@ TEST(SignatureHelp, TemplateArguments) { EXPECT_EQ(Second.activeParameter, 1); } +TEST(CompletionTest, DoNotCrash) { + llvm::StringLiteral Cases[] = { + R"cpp( + template struct Foo {}; + auto a = [x(3)](Foo<^>){}; + )cpp", + }; + for (auto Case : Cases) { + SCOPED_TRACE(Case); + auto Completions = completions(Case); + } +} + } // namespace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index ce546f54dd75f..f95c947559936 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -18,6 +18,7 @@ #include "clang/Format/Format.h" #include "clang/Index/IndexSymbol.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" #include "gtest/gtest.h" #include @@ -529,6 +530,8 @@ class Foo final {})cpp"; [](HoverInfo &HI) { HI.Name = "MACRO"; HI.Kind = index::SymbolKind::Macro; + HI.Value = "41 (0x29)"; + HI.Type = "int"; HI.Definition = "#define MACRO 41\n\n" "// Expands to\n" "41"; @@ -560,6 +563,7 @@ class Foo final {})cpp"; [](HoverInfo &HI) { HI.Name = "DECL_STR"; HI.Kind = index::SymbolKind::Macro; + HI.Type = HoverInfo::PrintedType("const char *"); HI.Definition = "#define DECL_STR(NAME, VALUE) const char *v_##NAME = " "STRINGIFY(VALUE)\n\n" "// Expands to\n" @@ -1850,6 +1854,8 @@ TEST(Hover, All) { )cpp", [](HoverInfo &HI) { HI.Name = "MACRO"; + HI.Value = "0"; + HI.Type = "int"; HI.Kind = index::SymbolKind::Macro; HI.Definition = "#define MACRO 0\n\n" "// Expands to\n" @@ -3769,6 +3775,233 @@ TEST(Hover, Typedefs) { EXPECT_EQ(H->Type->Type, "int"); EXPECT_EQ(H->Definition, "using foo = type"); } + +TEST(Hover, EvaluateMacros) { + llvm::StringRef PredefinedCXX = R"cpp( +#define X 42 +#define SizeOf sizeof +#define AlignOf alignof +#define PLUS_TWO +2 +#define TWO 2 + +using u64 = unsigned long long; +// calculate (a ** b) % p +constexpr u64 pow_with_mod(u64 a, u64 b, u64 p) { + u64 ret = 1; + while (b) { + if (b & 1) + ret = (ret * a) % p; + a = (a * a) % p; + b >>= 1; + } + return ret; +} +#define last_n_digit(x, y, n) \ + pow_with_mod(x, y, pow_with_mod(10, n, 2147483647)) +#define declare_struct(X, name, value) \ + struct X { \ + constexpr auto name() { return value; } \ + } +#define gnu_statement_expression(value) \ + ({ \ + declare_struct(Widget, getter, value); \ + Widget().getter(); \ + }) +#define define_lambda_begin(lambda, ...) \ + [&](__VA_ARGS__) { +#define define_lambda_end() } + +#define left_bracket [ +#define right_bracket ] +#define dg_left_bracket <: +#define dg_right_bracket :> +#define array_decl(type, name, size) type name left_bracket size right_bracket + )cpp"; + + struct { + llvm::StringRef Code; + const std::function, size_t /*Id*/)> + Validator; + } Cases[] = { + { + /*Code=*/R"cpp( + X^; + )cpp", + /*Validator=*/ + [](std::optional HI, size_t) { + EXPECT_EQ(HI->Value, "42 (0x2a)"); + EXPECT_EQ(HI->Type, HoverInfo::PrintedType("int")); + }, + }, + { + /*Code=*/R"cpp( + Size^Of(int); + )cpp", + /*Validator=*/ + [](std::optional HI, size_t) { + EXPECT_TRUE(HI->Value); + EXPECT_TRUE(HI->Type); + // Don't validate type or value of `sizeof` and `alignof` as we're + // getting different values or desugared types on different + // platforms. Same as below. + }, + }, + { + /*Code=*/R"cpp( + struct Y { + int y; + double z; + }; + Alig^nOf(Y); + )cpp", + /*Validator=*/ + [](std::optional HI, size_t) { + EXPECT_TRUE(HI->Value); + EXPECT_TRUE(HI->Type); + }, + }, + { + /*Code=*/R"cpp( + // 2**32 == 4294967296 + last_n_di^git(2, 32, 6); + )cpp", + /*Validator=*/ + [](std::optional HI, size_t) { + EXPECT_EQ(HI->Value, "967296 (0xec280)"); + EXPECT_EQ(HI->Type, "u64"); + }, + }, + { + /*Code=*/R"cpp( + gnu_statement_exp^ression(42); + )cpp", + /*Validator=*/ + [](std::optional HI, size_t) { + EXPECT_EQ(HI->Value, "42 (0x2a)"); + EXPECT_EQ(HI->Type, "int"); + }, + }, + { + /*Code=*/R"cpp( + 40 + PLU^S_TWO; + )cpp", + /*Validator=*/ + [](std::optional HI, size_t) { + EXPECT_EQ(HI->Value, "2"); + EXPECT_EQ(HI->Type, "int"); + }, + }, + { + /*Code=*/R"cpp( + 40 PLU^S_TWO; + )cpp", + /*Validator=*/ + [](std::optional HI, size_t) { + EXPECT_FALSE(HI->Value) << HI->Value; + EXPECT_FALSE(HI->Type) << HI->Type; + }, + }, + { + /*Code=*/R"cpp( + 40 + TW^O; + )cpp", + /*Validator=*/ + [](std::optional HI, size_t) { + EXPECT_EQ(HI->Value, "2"); + EXPECT_EQ(HI->Type, "int"); + }, + }, + { + /*Code=*/R"cpp( + arra^y_decl(int, vector, 10); + vector left_b^racket 3 right_b^racket; + vector dg_le^ft_bracket 3 dg_righ^t_bracket; + )cpp", + /*Validator=*/ + [](std::optional HI, size_t Id) { + switch (Id) { + case 0: + EXPECT_EQ(HI->Type, HoverInfo::PrintedType("int[10]")); + break; + case 1: + case 2: + case 3: + case 4: + EXPECT_FALSE(HI->Type) << HI->Type; + EXPECT_FALSE(HI->Value) << HI->Value; + break; + default: + ASSERT_TRUE(false) << "Unhandled id: " << Id; + } + }, + }, + { + /*Code=*/R"cpp( + constexpr auto value = define_lamb^da_begin(lambda, int, char) + // Check if the expansion range is right. + return ^last_n_digit(10, 3, 3)^; + define_lam^bda_end(); + )cpp", + /*Validator=*/ + [](std::optional HI, size_t Id) { + switch (Id) { + case 0: + EXPECT_FALSE(HI->Value); + EXPECT_EQ(HI->Type, HoverInfo::PrintedType("const (lambda)")); + break; + case 1: + EXPECT_EQ(HI->Value, "0"); + EXPECT_EQ(HI->Type, HoverInfo::PrintedType("u64")); + break; + case 2: + EXPECT_FALSE(HI); + break; + case 3: + EXPECT_FALSE(HI->Type) << HI->Type; + EXPECT_FALSE(HI->Value) << HI->Value; + break; + default: + ASSERT_TRUE(false) << "Unhandled id: " << Id; + } + }, + }, + }; + + Config Cfg; + Cfg.Hover.ShowAKA = false; + WithContextValue WithCfg(Config::Key, std::move(Cfg)); + for (const auto &C : Cases) { + Annotations Code( + (PredefinedCXX + "void function() {\n" + C.Code + "}\n").str()); + auto TU = TestTU::withCode(Code.code()); + TU.ExtraArgs.push_back("-std=c++17"); + auto AST = TU.build(); + for (auto [Index, Position] : llvm::enumerate(Code.points())) { + C.Validator(getHover(AST, Position, format::getLLVMStyle(), nullptr), + Index); + } + } + + Annotations C(R"c( + #define alignof _Alignof + void foo() { + al^ignof(struct { int x; char y[10]; }); + } + )c"); + + auto TU = TestTU::withCode(C.code()); + TU.Filename = "TestTU.c"; + TU.ExtraArgs = { + "-std=c17", + }; + auto AST = TU.build(); + auto H = getHover(AST, C.point(), format::getLLVMStyle(), nullptr); + + ASSERT_TRUE(H); + EXPECT_TRUE(H->Value); + EXPECT_TRUE(H->Type); +} + } // namespace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp index a38c01b43270f..c0831c2693c97 100644 --- a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp +++ b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp @@ -197,10 +197,10 @@ TEST(IncludeCleaner, GenerateMissingHeaderDiags) { ns::$bar[[Bar]] bar; bar.d(); - $f[[f]](); + $f[[f]](); // this should not be diagnosed, because it's ignored in the config - buzz(); + buzz(); $foobar[[foobar]](); @@ -244,7 +244,7 @@ TEST(IncludeCleaner, GenerateMissingHeaderDiags) { TU.AdditionalFiles["foo.h"] = guard(R"cpp( #define BAR(x) Foo *x #define FOO 1 - struct Foo{}; + struct Foo{}; )cpp"); TU.Code = MainFile.code(); @@ -510,6 +510,71 @@ TEST(IncludeCleaner, FirstMatchedProvider) { } } +TEST(IncludeCleaner, BatchFix) { + Config Cfg; + Cfg.Diagnostics.MissingIncludes = Config::IncludesPolicy::Strict; + Cfg.Diagnostics.UnusedIncludes = Config::IncludesPolicy::Strict; + WithContextValue Ctx(Config::Key, std::move(Cfg)); + + TestTU TU; + TU.Filename = "main.cpp"; + TU.AdditionalFiles["foo.h"] = guard("class Foo;"); + TU.AdditionalFiles["bar.h"] = guard("class Bar;"); + TU.AdditionalFiles["all.h"] = guard(R"cpp( + #include "foo.h" + #include "bar.h" + )cpp"); + + TU.Code = R"cpp( + #include "all.h" + + Foo* foo; + )cpp"; + auto AST = TU.build(); + EXPECT_THAT( + issueIncludeCleanerDiagnostics(AST, TU.Code), + UnorderedElementsAre(withFix({FixMessage("#include \"foo.h\""), + FixMessage("fix all includes")}), + withFix({FixMessage("remove #include directive"), + FixMessage("fix all includes")}))); + + TU.Code = R"cpp( + #include "all.h" + #include "bar.h" + + Foo* foo; + )cpp"; + AST = TU.build(); + EXPECT_THAT( + issueIncludeCleanerDiagnostics(AST, TU.Code), + UnorderedElementsAre(withFix({FixMessage("#include \"foo.h\""), + FixMessage("fix all includes")}), + withFix({FixMessage("remove #include directive"), + FixMessage("remove all unused includes"), + FixMessage("fix all includes")}), + withFix({FixMessage("remove #include directive"), + FixMessage("remove all unused includes"), + FixMessage("fix all includes")}))); + + TU.Code = R"cpp( + #include "all.h" + + Foo* foo; + Bar* bar; + )cpp"; + AST = TU.build(); + EXPECT_THAT( + issueIncludeCleanerDiagnostics(AST, TU.Code), + UnorderedElementsAre(withFix({FixMessage("#include \"foo.h\""), + FixMessage("add all missing includes"), + FixMessage("fix all includes")}), + withFix({FixMessage("#include \"bar.h\""), + FixMessage("add all missing includes"), + FixMessage("fix all includes")}), + withFix({FixMessage("remove #include directive"), + FixMessage("fix all includes")}))); +} + } // namespace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp b/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp index 5792359e3c785..8d5d0630de165 100644 --- a/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp +++ b/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp @@ -12,8 +12,6 @@ //===----------------------------------------------------------------------===// #include "../../clang-tidy/ClangTidyCheck.h" -#include "../../clang-tidy/ClangTidyModule.h" -#include "../../clang-tidy/ClangTidyModuleRegistry.h" #include "AST.h" #include "Annotations.h" #include "Compiler.h" @@ -29,8 +27,6 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.h" -#include "clang/Lex/PPCallbacks.h" -#include "clang/Lex/Token.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/StringRef.h" #include "llvm/Testing/Support/Error.h" @@ -96,10 +92,6 @@ MATCHER_P(withTemplateArgs, ArgName, "") { return false; } -MATCHER_P(rangeIs, R, "") { - return arg.beginOffset() == R.Begin && arg.endOffset() == R.End; -} - MATCHER_P(pragmaTrivia, P, "") { return arg.Trivia == P; } MATCHER(eqInc, "") { @@ -352,123 +344,6 @@ TEST(ParsedASTTest, CollectsMainFileMacroExpansions) { MATCHER_P(withFileName, Inc, "") { return arg.FileName == Inc; } -TEST(ParsedASTTest, ReplayPreambleForTidyCheckers) { - struct Inclusion { - Inclusion(const SourceManager &SM, SourceLocation HashLoc, - const Token &IncludeTok, llvm::StringRef FileName, bool IsAngled, - CharSourceRange FilenameRange) - : HashOffset(SM.getDecomposedLoc(HashLoc).second), IncTok(IncludeTok), - IncDirective(IncludeTok.getIdentifierInfo()->getName()), - FileNameOffset(SM.getDecomposedLoc(FilenameRange.getBegin()).second), - FileName(FileName), IsAngled(IsAngled) { - EXPECT_EQ( - toSourceCode(SM, FilenameRange.getAsRange()).drop_back().drop_front(), - FileName); - } - size_t HashOffset; - syntax::Token IncTok; - llvm::StringRef IncDirective; - size_t FileNameOffset; - llvm::StringRef FileName; - bool IsAngled; - }; - static std::vector Includes; - static std::vector SkippedFiles; - struct ReplayPreamblePPCallback : public PPCallbacks { - const SourceManager &SM; - explicit ReplayPreamblePPCallback(const SourceManager &SM) : SM(SM) {} - - void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, - StringRef FileName, bool IsAngled, - CharSourceRange FilenameRange, OptionalFileEntryRef, - StringRef, StringRef, const clang::Module *, - SrcMgr::CharacteristicKind) override { - Includes.emplace_back(SM, HashLoc, IncludeTok, FileName, IsAngled, - FilenameRange); - } - - void FileSkipped(const FileEntryRef &, const Token &FilenameTok, - SrcMgr::CharacteristicKind) override { - SkippedFiles.emplace_back(FilenameTok); - } - }; - struct ReplayPreambleCheck : public tidy::ClangTidyCheck { - ReplayPreambleCheck(StringRef Name, tidy::ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, - Preprocessor *ModuleExpanderPP) override { - PP->addPPCallbacks(::std::make_unique(SM)); - } - }; - struct ReplayPreambleModule : public tidy::ClangTidyModule { - void - addCheckFactories(tidy::ClangTidyCheckFactories &CheckFactories) override { - CheckFactories.registerCheck( - "replay-preamble-check"); - } - }; - - static tidy::ClangTidyModuleRegistry::Add X( - "replay-preamble-module", ""); - TestTU TU; - // This check records inclusion directives replayed by clangd. - TU.ClangTidyProvider = addTidyChecks("replay-preamble-check"); - llvm::Annotations Test(R"cpp( - $hash^#$include[[import]] $filebegin^"$filerange[[bar.h]]" - $hash^#$include[[include_next]] $filebegin^"$filerange[[baz.h]]" - $hash^#$include[[include]] $filebegin^<$filerange[[a.h]]>)cpp"); - llvm::StringRef Code = Test.code(); - TU.Code = Code.str(); - TU.AdditionalFiles["bar.h"] = ""; - TU.AdditionalFiles["baz.h"] = ""; - TU.AdditionalFiles["a.h"] = ""; - // Since we are also testing #import directives, and they don't make much - // sense in c++ (also they actually break on windows), just set language to - // obj-c. - TU.ExtraArgs = {"-isystem.", "-xobjective-c"}; - - const auto &AST = TU.build(); - const auto &SM = AST.getSourceManager(); - - auto HashLocs = Test.points("hash"); - ASSERT_EQ(HashLocs.size(), Includes.size()); - auto IncludeRanges = Test.ranges("include"); - ASSERT_EQ(IncludeRanges.size(), Includes.size()); - auto FileBeginLocs = Test.points("filebegin"); - ASSERT_EQ(FileBeginLocs.size(), Includes.size()); - auto FileRanges = Test.ranges("filerange"); - ASSERT_EQ(FileRanges.size(), Includes.size()); - - ASSERT_EQ(SkippedFiles.size(), Includes.size()); - for (size_t I = 0; I < Includes.size(); ++I) { - const auto &Inc = Includes[I]; - - EXPECT_EQ(Inc.HashOffset, HashLocs[I]); - - auto IncRange = IncludeRanges[I]; - EXPECT_THAT(Inc.IncTok.range(SM), rangeIs(IncRange)); - EXPECT_EQ(Inc.IncTok.kind(), tok::identifier); - EXPECT_EQ(Inc.IncDirective, - Code.substr(IncRange.Begin, IncRange.End - IncRange.Begin)); - - EXPECT_EQ(Inc.FileNameOffset, FileBeginLocs[I]); - EXPECT_EQ(Inc.IsAngled, Code[FileBeginLocs[I]] == '<'); - - auto FileRange = FileRanges[I]; - EXPECT_EQ(Inc.FileName, - Code.substr(FileRange.Begin, FileRange.End - FileRange.Begin)); - - EXPECT_EQ(SM.getDecomposedLoc(SkippedFiles[I].location()).second, - Inc.FileNameOffset); - // This also contains quotes/angles so increment the range by one from both - // sides. - EXPECT_EQ( - SkippedFiles[I].text(SM), - Code.substr(FileRange.Begin - 1, FileRange.End - FileRange.Begin + 2)); - EXPECT_EQ(SkippedFiles[I].kind(), tok::header_name); - } -} - TEST(ParsedASTTest, PatchesAdditionalIncludes) { llvm::StringLiteral ModifiedContents = R"cpp( #include "baz.h" diff --git a/clang-tools-extra/clangd/unittests/ReplayPeambleTests.cpp b/clang-tools-extra/clangd/unittests/ReplayPeambleTests.cpp new file mode 100644 index 0000000000000..459a8f4c36a4c --- /dev/null +++ b/clang-tools-extra/clangd/unittests/ReplayPeambleTests.cpp @@ -0,0 +1,166 @@ +//===-- ReplayPreambleTests.cpp -------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// These tests cover clangd's logic to replay PP events from preamble to +// clang-tidy checks. +// +//===----------------------------------------------------------------------===// + +#include "../../clang-tidy/ClangTidyCheck.h" +#include "../../clang-tidy/ClangTidyModule.h" +#include "../../clang-tidy/ClangTidyModuleRegistry.h" +#include "AST.h" +#include "Diagnostics.h" +#include "ParsedAST.h" +#include "SourceCode.h" +#include "TestTU.h" +#include "TidyProvider.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/Basic/FileEntry.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TokenKinds.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Token.h" +#include "clang/Tooling/Syntax/Tokens.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Registry.h" +#include "llvm/Testing/Annotations/Annotations.h" +#include "gmock/gmock-matchers.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include +#include +#include + +namespace clang::clangd { +namespace { +struct Inclusion { + Inclusion(const SourceManager &SM, SourceLocation HashLoc, + const Token &IncludeTok, llvm::StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange) + : HashOffset(SM.getDecomposedLoc(HashLoc).second), IncTok(IncludeTok), + IncDirective(IncludeTok.getIdentifierInfo()->getName()), + FileNameOffset(SM.getDecomposedLoc(FilenameRange.getBegin()).second), + FileName(FileName), IsAngled(IsAngled) { + EXPECT_EQ( + toSourceCode(SM, FilenameRange.getAsRange()).drop_back().drop_front(), + FileName); + } + size_t HashOffset; + syntax::Token IncTok; + llvm::StringRef IncDirective; + size_t FileNameOffset; + llvm::StringRef FileName; + bool IsAngled; +}; +static std::vector Includes; +static std::vector SkippedFiles; +struct ReplayPreamblePPCallback : public PPCallbacks { + const SourceManager &SM; + explicit ReplayPreamblePPCallback(const SourceManager &SM) : SM(SM) {} + + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, + StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, OptionalFileEntryRef, + StringRef, StringRef, const clang::Module *, + SrcMgr::CharacteristicKind) override { + Includes.emplace_back(SM, HashLoc, IncludeTok, FileName, IsAngled, + FilenameRange); + } + + void FileSkipped(const FileEntryRef &, const Token &FilenameTok, + SrcMgr::CharacteristicKind) override { + SkippedFiles.emplace_back(FilenameTok); + } +}; +struct ReplayPreambleCheck : public tidy::ClangTidyCheck { + ReplayPreambleCheck(StringRef Name, tidy::ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override { + PP->addPPCallbacks(::std::make_unique(SM)); + } +}; +llvm::StringLiteral CheckName = "replay-preamble-check"; +struct ReplayPreambleModule : public tidy::ClangTidyModule { + void + addCheckFactories(tidy::ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck(CheckName); + } +}; +static tidy::ClangTidyModuleRegistry::Add + X("replay-preamble-module", ""); + +MATCHER_P(rangeIs, R, "") { + return arg.beginOffset() == R.Begin && arg.endOffset() == R.End; +} + +TEST(ReplayPreambleTest, IncludesAndSkippedFiles) { + TestTU TU; + // This check records inclusion directives replayed by clangd. + TU.ClangTidyProvider = addTidyChecks(CheckName); + llvm::Annotations Test(R"cpp( + $hash^#$include[[import]] $filebegin^"$filerange[[bar.h]]" + $hash^#$include[[include_next]] $filebegin^"$filerange[[baz.h]]" + $hash^#$include[[include]] $filebegin^<$filerange[[a.h]]>)cpp"); + llvm::StringRef Code = Test.code(); + TU.Code = Code.str(); + TU.AdditionalFiles["bar.h"] = ""; + TU.AdditionalFiles["baz.h"] = ""; + TU.AdditionalFiles["a.h"] = ""; + // Since we are also testing #import directives, and they don't make much + // sense in c++ (also they actually break on windows), just set language to + // obj-c. + TU.ExtraArgs = {"-isystem.", "-xobjective-c"}; + + const auto &AST = TU.build(); + const auto &SM = AST.getSourceManager(); + + auto HashLocs = Test.points("hash"); + ASSERT_EQ(HashLocs.size(), Includes.size()); + auto IncludeRanges = Test.ranges("include"); + ASSERT_EQ(IncludeRanges.size(), Includes.size()); + auto FileBeginLocs = Test.points("filebegin"); + ASSERT_EQ(FileBeginLocs.size(), Includes.size()); + auto FileRanges = Test.ranges("filerange"); + ASSERT_EQ(FileRanges.size(), Includes.size()); + + ASSERT_EQ(SkippedFiles.size(), Includes.size()); + for (size_t I = 0; I < Includes.size(); ++I) { + const auto &Inc = Includes[I]; + + EXPECT_EQ(Inc.HashOffset, HashLocs[I]); + + auto IncRange = IncludeRanges[I]; + EXPECT_THAT(Inc.IncTok.range(SM), rangeIs(IncRange)); + EXPECT_EQ(Inc.IncTok.kind(), tok::identifier); + EXPECT_EQ(Inc.IncDirective, + Code.substr(IncRange.Begin, IncRange.End - IncRange.Begin)); + + EXPECT_EQ(Inc.FileNameOffset, FileBeginLocs[I]); + EXPECT_EQ(Inc.IsAngled, Code[FileBeginLocs[I]] == '<'); + + auto FileRange = FileRanges[I]; + EXPECT_EQ(Inc.FileName, + Code.substr(FileRange.Begin, FileRange.End - FileRange.Begin)); + + EXPECT_EQ(SM.getDecomposedLoc(SkippedFiles[I].location()).second, + Inc.FileNameOffset); + // This also contains quotes/angles so increment the range by one from both + // sides. + EXPECT_EQ( + SkippedFiles[I].text(SM), + Code.substr(FileRange.Begin - 1, FileRange.End - FileRange.Begin + 2)); + EXPECT_EQ(SkippedFiles[I].kind(), tok::header_name); + } +} +} // namespace +} // namespace clang::clangd diff --git a/clang-tools-extra/pseudo/include/clang-pseudo/DirectiveTree.h b/clang-tools-extra/pseudo/include/clang-pseudo/DirectiveTree.h index aeca616414c24..2b6cb63297915 100644 --- a/clang-tools-extra/pseudo/include/clang-pseudo/DirectiveTree.h +++ b/clang-tools-extra/pseudo/include/clang-pseudo/DirectiveTree.h @@ -80,7 +80,7 @@ struct DirectiveTree { /// The directive terminating the conditional, should be #endif. Directive End; /// The index of the conditional branch we chose as active. - /// None indicates no branch was taken (e.g. #if 0 ... #endif). + /// std::nullopt indicates no branch was taken (e.g. #if 0 ... #endif). /// The initial tree from `parse()` has no branches marked as taken. /// See `chooseConditionalBranches()`. std::optional Taken; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/assert-side-effect/assert.h b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/assert-side-effect/assert.h new file mode 100644 index 0000000000000..904597ff2184e --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/assert-side-effect/assert.h @@ -0,0 +1,40 @@ +#pragma clang system_header + +int abort(); + +#ifdef NDEBUG +#define assert(x) 1 +#else +#define assert(x) \ + if (!(x)) \ + (void)abort() +#endif + +void print(...); +#define assert2(e) (__builtin_expect(!(e), 0) ? \ + print (#e, __FILE__, __LINE__) : (void)0) + +#ifdef NDEBUG +#define my_assert(x) 1 +#else +#define my_assert(x) \ + ((void)((x) ? 1 : abort())) +#endif + +#ifdef NDEBUG +#define not_my_assert(x) 1 +#else +#define not_my_assert(x) \ + if (!(x)) \ + (void)abort() +#endif + +#define real_assert(x) ((void)((x) ? 1 : abort())) +#define wrap1(x) real_assert(x) +#define wrap2(x) wrap1(x) +#define convoluted_assert(x) wrap2(x) + +#define msvc_assert(expression) (void)( \ + (!!(expression)) || \ + (abort(), 0) \ + ) diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/assert-side-effect.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/assert-side-effect.cpp index c327007651d4c..ccafeb4b7f3b1 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/assert-side-effect.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/assert-side-effect.cpp @@ -1,47 +1,5 @@ -// RUN: %check_clang_tidy %s bugprone-assert-side-effect %t -- -config="{CheckOptions: [{key: bugprone-assert-side-effect.CheckFunctionCalls, value: true}, {key: bugprone-assert-side-effect.AssertMacros, value: 'assert,assert2,my_assert,convoluted_assert,msvc_assert'}, {key: bugprone-assert-side-effect.IgnoredFunctions, value: 'MyClass::badButIgnoredFunc'}]}" -- -fexceptions - -//===--- assert definition block ------------------------------------------===// -int abort() { return 0; } - -#ifdef NDEBUG -#define assert(x) 1 -#else -#define assert(x) \ - if (!(x)) \ - (void)abort() -#endif - -void print(...); -#define assert2(e) (__builtin_expect(!(e), 0) ? \ - print (#e, __FILE__, __LINE__) : (void)0) - -#ifdef NDEBUG -#define my_assert(x) 1 -#else -#define my_assert(x) \ - ((void)((x) ? 1 : abort())) -#endif - -#ifdef NDEBUG -#define not_my_assert(x) 1 -#else -#define not_my_assert(x) \ - if (!(x)) \ - (void)abort() -#endif - -#define real_assert(x) ((void)((x) ? 1 : abort())) -#define wrap1(x) real_assert(x) -#define wrap2(x) wrap1(x) -#define convoluted_assert(x) wrap2(x) - -#define msvc_assert(expression) (void)( \ - (!!(expression)) || \ - (abort(), 0) \ - ) - - -//===----------------------------------------------------------------------===// +// RUN: %check_clang_tidy %s bugprone-assert-side-effect %t -- -config="{CheckOptions: [{key: bugprone-assert-side-effect.CheckFunctionCalls, value: true}, {key: bugprone-assert-side-effect.AssertMacros, value: 'assert,assert2,my_assert,convoluted_assert,msvc_assert'}, {key: bugprone-assert-side-effect.IgnoredFunctions, value: 'MyClass::badButIgnoredFunc'}]}" -- -fexceptions -I %S/Inputs/assert-side-effect +#include bool badButIgnoredFunc(int a, int b) { return a * b > 0; } diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/trivially-destructible.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/trivially-destructible.cpp index 927a0905ee424..2ff3eda559a52 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance/trivially-destructible.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/trivially-destructible.cpp @@ -1,7 +1,7 @@ // RUN: %check_clang_tidy %s performance-trivially-destructible %t // RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-tidy %t.cpp -checks='-*,performance-trivially-destructible' -fix -// RUN: clang-tidy %t.cpp -checks='-*,performance-trivially-destructible' -warnings-as-errors='-*,performance-trivially-destructible' +// RUN: clang-tidy %t.cpp -checks='-*,performance-trivially-destructible' -fix -- +// RUN: clang-tidy %t.cpp -checks='-*,performance-trivially-destructible' -warnings-as-errors='-*,performance-trivially-destructible' -- struct TriviallyDestructible1 { int a; diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-bugfix.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-bugfix.cpp index 9f892ebceccf2..25f2c71a316d7 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-bugfix.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-bugfix.cpp @@ -3,3 +3,14 @@ // This used to cause a null pointer dereference. auto [left] = right; // CHECK-MESSAGES: :[[@LINE-1]]:15: error: use of undeclared identifier 'right' + +namespace crash_on_nonidentifiers { +struct Foo { + operator bool(); +}; +void foo() { + // Make sure we don't crash on non-identifier names (e.g. conversion + // operators). + if (Foo()) {} +} +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-standard-types.h b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-standard-types.h index edec8d7380200..e1036483ee8f6 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-standard-types.h +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-standard-types.h @@ -9,7 +9,7 @@ typedef unsigned char uint8_t; // NOLINT typedef unsigned short uint16_t; // NOLINT typedef unsigned long uint32_t; // NOLINT typedef unsigned long long uint64_t; // NOLINT -#ifndef _WIN32 +#ifndef _MSC_VER typedef unsigned long long size_t; // NOLINT #endif typedef long intptr_t; // NOLINT diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index b17794044a17a..4297b48b0653e 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.13.4) +cmake_minimum_required(VERSION 3.20.0) if(NOT DEFINED LLVM_COMMON_CMAKE_UTILS) set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) @@ -11,13 +11,6 @@ include(${LLVM_COMMON_CMAKE_UTILS}/Modules/CMakePolicy.cmake if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) project(Clang) set(CLANG_BUILT_STANDALONE TRUE) - if ("${CMAKE_VERSION}" VERSION_LESS "3.20.0") - message(WARNING - "Your CMake version is ${CMAKE_VERSION}. Starting with LLVM 17.0.0, the " - "minimum version of CMake required to build LLVM will become 3.20.0, and " - "using an older CMake will become an error. Please upgrade your CMake to " - "at least 3.20.0 now to avoid issues in the future!") - endif() endif() # Must go below project(..) @@ -878,9 +871,8 @@ endif() if (CLANG_BOLT_INSTRUMENT AND NOT LLVM_BUILD_INSTRUMENTED) set(CLANG_PATH ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang) - set(CLANGXX_PATH ${CLANG_PATH}++) set(CLANG_INSTRUMENTED ${CLANG_PATH}-bolt.inst) - set(CLANGXX_INSTRUMENTED ${CLANGXX_PATH}-bolt.inst) + set(BOLT_FDATA ${CMAKE_CURRENT_BINARY_DIR}/utils/perf-training/prof.fdata) # Instrument clang with BOLT add_custom_target(clang-instrumented @@ -890,73 +882,11 @@ if (CLANG_BOLT_INSTRUMENT AND NOT LLVM_BUILD_INSTRUMENTED) DEPENDS clang llvm-bolt COMMAND llvm-bolt ${CLANG_PATH} -o ${CLANG_INSTRUMENTED} -instrument --instrumentation-file-append-pid - --instrumentation-file=${CMAKE_CURRENT_BINARY_DIR}/prof.fdata + --instrumentation-file=${BOLT_FDATA} COMMENT "Instrumenting clang binary with BOLT" VERBATIM ) - # Make a symlink from clang-bolt.inst to clang++-bolt.inst - add_custom_target(clang++-instrumented - DEPENDS ${CLANGXX_INSTRUMENTED} - ) - add_custom_command(OUTPUT ${CLANGXX_INSTRUMENTED} - DEPENDS clang-instrumented - COMMAND ${CMAKE_COMMAND} -E create_symlink - ${CLANG_INSTRUMENTED} - ${CLANGXX_INSTRUMENTED} - COMMENT "Creating symlink from BOLT instrumented clang to clang++" - VERBATIM - ) - - # Build specified targets with instrumented Clang to collect the profile - set(STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/bolt-instrumented-clang-stamps/) - set(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/bolt-instrumented-clang-bins/) - set(build_configuration "$") - include(ExternalProject) - ExternalProject_Add(bolt-instrumentation-profile - DEPENDS clang++-instrumented - PREFIX bolt-instrumentation-profile - SOURCE_DIR ${CMAKE_SOURCE_DIR} - STAMP_DIR ${STAMP_DIR} - BINARY_DIR ${BINARY_DIR} - EXCLUDE_FROM_ALL 1 - CMAKE_ARGS - ${CLANG_BOLT_INSTRUMENT_EXTRA_CMAKE_FLAGS} - # We shouldn't need to set this here, but INSTALL_DIR doesn't - # seem to work, so instead I'm passing this through - -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} - -DCMAKE_C_COMPILER=${CLANG_INSTRUMENTED} - -DCMAKE_CXX_COMPILER=${CLANGXX_INSTRUMENTED} - -DCMAKE_ASM_COMPILER=${CLANG_INSTRUMENTED} - -DCMAKE_ASM_COMPILER_ID=Clang - -DCMAKE_BUILD_TYPE=Release - -DLLVM_ENABLE_PROJECTS=${CLANG_BOLT_INSTRUMENT_PROJECTS} - -DLLVM_TARGETS_TO_BUILD=${LLVM_TARGETS_TO_BUILD} - BUILD_COMMAND ${CMAKE_COMMAND} --build ${BINARY_DIR} - --config ${build_configuration} - --target ${CLANG_BOLT_INSTRUMENT_TARGETS} - INSTALL_COMMAND "" - STEP_TARGETS configure build - USES_TERMINAL_CONFIGURE 1 - USES_TERMINAL_BUILD 1 - USES_TERMINAL_INSTALL 1 - ) - - # Merge profiles into one using merge-fdata - add_custom_target(clang-bolt-profile - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/prof.fdata - ) - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/prof.fdata - DEPENDS merge-fdata bolt-instrumentation-profile-build - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${Python3_EXECUTABLE} - ${CMAKE_CURRENT_SOURCE_DIR}/utils/perf-training/perf-helper.py merge-fdata - $ ${CMAKE_CURRENT_BINARY_DIR}/prof.fdata - ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Preparing BOLT profile" - VERBATIM - ) - # Optimize original (pre-bolt) Clang using the collected profile set(CLANG_OPTIMIZED ${CMAKE_CURRENT_BINARY_DIR}/clang.bolt) add_custom_target(clang-bolt @@ -966,7 +896,7 @@ if (CLANG_BOLT_INSTRUMENT AND NOT LLVM_BUILD_INSTRUMENTED) DEPENDS clang-bolt-profile COMMAND llvm-bolt ${CLANG_PATH} -o ${CLANG_OPTIMIZED} - -data ${CMAKE_CURRENT_BINARY_DIR}/prof.fdata + -data ${BOLT_FDATA} -reorder-blocks=ext-tsp -reorder-functions=hfsort+ -split-functions -split-all-cold -split-eh -dyno-stats -icf=1 -use-gnu-stack COMMAND ${CMAKE_COMMAND} -E rename ${CLANG_OPTIMIZED} $ diff --git a/clang/cmake/caches/BOLT.cmake b/clang/cmake/caches/BOLT.cmake index 78ab3b64386a4..7c75d60320f7e 100644 --- a/clang/cmake/caches/BOLT.cmake +++ b/clang/cmake/caches/BOLT.cmake @@ -1,9 +1,6 @@ set(CMAKE_BUILD_TYPE Release CACHE STRING "") set(CLANG_BOLT_INSTRUMENT ON CACHE BOOL "") -set(CLANG_BOLT_INSTRUMENT_PROJECTS "llvm" CACHE STRING "") -set(CLANG_BOLT_INSTRUMENT_TARGETS "count" CACHE STRING "") set(CMAKE_EXE_LINKER_FLAGS "-Wl,--emit-relocs,-znow" CACHE STRING "") -set(CLANG_BOLT_INSTRUMENT_EXTRA_CMAKE_FLAGS "" CACHE STRING "") set(LLVM_ENABLE_PROJECTS "bolt;clang" CACHE STRING "") set(LLVM_TARGETS_TO_BUILD Native CACHE STRING "") diff --git a/clang/docs/AutomaticReferenceCounting.rst b/clang/docs/AutomaticReferenceCounting.rst index 640f3f7dec390..820ad3978d5f2 100644 --- a/clang/docs/AutomaticReferenceCounting.rst +++ b/clang/docs/AutomaticReferenceCounting.rst @@ -1306,7 +1306,7 @@ or between ARC and non-ARC modes) under the following conditions: - The types must be compatible ignoring ownership qualifiers according to the baseline, non-ARC rules (e.g. C struct compatibility or C++'s - ODR). This condition implies a pairwise correspondance between + ODR). This condition implies a pairwise correspondence between fields. Note that an Objective-C++ class with base classes, a user-provided @@ -1351,7 +1351,7 @@ automatically by the compiler. .. admonition:: Rationale In earlier releases, when non-trivial ownership was only permitted - on fields in Objective-C++, the ABI used for such classees was the + on fields in Objective-C++, the ABI used for such classes was the ordinary ABI for non-trivial C++ classes, which passes arguments and returns indirectly and does not transfer responsibility for arguments. When support for Objective-C structs was added, it was decided to diff --git a/clang/docs/CMakeLists.txt b/clang/docs/CMakeLists.txt index 532907385df4b..4163dd2d90ad5 100644 --- a/clang/docs/CMakeLists.txt +++ b/clang/docs/CMakeLists.txt @@ -90,50 +90,60 @@ if (LLVM_ENABLE_DOXYGEN) endif() endif() -function (gen_rst_file_from_td output_file td_option source docs_target) +function (gen_rst_file_from_td output_file td_option source docs_targets) if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${source}") message(FATAL_ERROR "Cannot find source file: ${source} in ${CMAKE_CURRENT_SOURCE_DIR}") endif() get_filename_component(TABLEGEN_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${source}" DIRECTORY) list(APPEND LLVM_TABLEGEN_FLAGS "-I${TABLEGEN_INCLUDE_DIR}") clang_tablegen(${output_file} ${td_option} SOURCE ${source} TARGET "gen-${output_file}") - add_dependencies(${docs_target} "gen-${output_file}") + foreach(target ${docs_targets}) + add_dependencies(${target} gen-${output_file}) + endforeach() endfunction() if (LLVM_ENABLE_SPHINX) include(AddSphinxTarget) - if (SPHINX_FOUND) + if (SPHINX_FOUND AND (${SPHINX_OUTPUT_HTML} OR ${SPHINX_OUTPUT_MAN})) + # Copy rst files to build directory before generating the html + # documentation. Some of the rst files are generated, so they + # only exist in the build directory. Sphinx needs all files in + # the same directory in order to generate the html, so we need to + # copy all the non-gnerated rst files from the source to the build + # directory before we run sphinx. + add_custom_target(copy-clang-rst-docs + COMMAND "${CMAKE_COMMAND}" -E copy_directory + "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" + + COMMAND "${CMAKE_COMMAND}" -E copy_if_different + "${CMAKE_CURRENT_SOURCE_DIR}/../CodeOwners.rst" + "${CMAKE_CURRENT_BINARY_DIR}" + ) + + set(docs_targets "") + if (${SPHINX_OUTPUT_HTML}) add_sphinx_target(html clang SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}") - # Copy rst files to build directory before generating the html - # documentation. Some of the rst files are generated, so they - # only exist in the build directory. Sphinx needs all files in - # the same directory in order to generate the html, so we need to - # copy all the non-gnerated rst files from the source to the build - # directory before we run sphinx. - add_custom_target(copy-clang-rst-docs - COMMAND "${CMAKE_COMMAND}" -E copy_directory - "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" - - COMMAND "${CMAKE_COMMAND}" -E copy_if_different - "${CMAKE_CURRENT_SOURCE_DIR}/../CodeOwners.rst" - "${CMAKE_CURRENT_BINARY_DIR}" - ) - add_dependencies(docs-clang-html copy-clang-rst-docs) - add_custom_command(TARGET docs-clang-html POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/LibASTMatchersReference.html" "${CMAKE_CURRENT_BINARY_DIR}/html/LibASTMatchersReference.html") - # Generated files - gen_rst_file_from_td(AttributeReference.rst -gen-attr-docs ../include/clang/Basic/Attr.td docs-clang-html) - gen_rst_file_from_td(DiagnosticsReference.rst -gen-diag-docs ../include/clang/Basic/Diagnostic.td docs-clang-html) - gen_rst_file_from_td(ClangCommandLineReference.rst -gen-opt-docs ../include/clang/Driver/ClangOptionDocs.td docs-clang-html) + list(APPEND docs_targets "docs-clang-html") endif() if (${SPHINX_OUTPUT_MAN}) - add_sphinx_target(man clang) + add_sphinx_target(man clang SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}") + list(APPEND docs_targets "docs-clang-man") endif() + + # Generated files + gen_rst_file_from_td(AttributeReference.rst -gen-attr-docs ../include/clang/Basic/Attr.td "${docs_targets}") + gen_rst_file_from_td(DiagnosticsReference.rst -gen-diag-docs ../include/clang/Basic/Diagnostic.td "${docs_targets}") + gen_rst_file_from_td(ClangCommandLineReference.rst -gen-opt-docs ../include/clang/Driver/ClangOptionDocs.td "${docs_targets}") + + foreach(target ${docs_targets}) + add_dependencies(${target} copy-clang-rst-docs) + endforeach() endif() endif() diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index bdcd1e88d2404..ce4c39694e0c5 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2453,7 +2453,7 @@ the configuration (without a prefix: ``Auto``). * ``BBCDS_Allowed`` (in configuration: ``Allowed``) Breaking between template declaration and ``concept`` is allowed. The actual behavior depends on the content and line breaking rules and - penalities. + penalties. * ``BBCDS_Always`` (in configuration: ``Always``) Always break before ``concept``, putting it in the line after the diff --git a/clang/docs/CommandGuide/clang.rst b/clang/docs/CommandGuide/clang.rst index 6c59ffd2ab120..faaf9c8d97ef3 100644 --- a/clang/docs/CommandGuide/clang.rst +++ b/clang/docs/CommandGuide/clang.rst @@ -201,6 +201,14 @@ Language Selection and Mode Options ISO C++ 2023 with amendments and GNU extensions + | ``c++2c`` + + Working draft for C++2c + + | ``gnu++2c`` + + Working draft for C++2c with GNU extensions + The default C++ language standard is ``gnu++17``. Supported values for the OpenCL language are: diff --git a/clang/docs/DataFlowSanitizer.rst b/clang/docs/DataFlowSanitizer.rst index 6faca3f2ed913..a18b8ed1948f3 100644 --- a/clang/docs/DataFlowSanitizer.rst +++ b/clang/docs/DataFlowSanitizer.rst @@ -140,7 +140,7 @@ For example: For instrumented functions, the ABI list supports a ``force_zero_labels`` category, which will make all stores and return values set zero labels. Functions should never be labelled with both ``force_zero_labels`` -and ``uninstrumented`` or any of the unistrumented wrapper kinds. +and ``uninstrumented`` or any of the uninstrumented wrapper kinds. For example: diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index cf7b6340e8be7..98ff30d35f0d6 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1370,6 +1370,41 @@ For example, compiling code with ``-fmodules`` enables the use of Modules. More information could be found `here `_. +Language Extensions Back-ported to Previous Standards +===================================================== + +=================================== ================================ ============= ============= ================================== +Feature Feature Test Macro Introduced In Backported To Required Flags +=================================== ================================ ============= ============= ================================== +variadic templates __cpp_variadic_templates C++11 C++03 +Alias templates __cpp_alias_templates C++11 C++03 +Non-static data member initializers __cpp_nsdmi C++11 C++03 +Range-based ``for`` loop __cpp_range_based_for C++11 C++03 +RValue references __cpp_rvalue_references C++11 C++03 +Attributes __cpp_attributes C++11 C++03 -fdouble-square-bracket-attributes +variable templates __cpp_variable_templates C++14 C++03 +Binary literals __cpp_binary_literals C++14 C++03 +Relaxed constexpr __cpp_constexpr C++14 C++11 +``if constexpr`` __cpp_if_constexpr C++17 C++11 +fold expressions __cpp_fold_expressions C++17 C++03 +Lambda capture of \*this by value __cpp_capture_star_this C++17 C++11 +Attributes on enums __cpp_enumerator_attributes C++17 C++11 +Guaranteed copy elision __cpp_guaranteed_copy_elision C++17 C++03 +Hexadecimal floating literals __cpp_hex_float C++17 C++03 +``inline`` variables __cpp_inline_variables C++17 C++03 +Attributes on namespaces __cpp_namespace_attributes C++17 C++11 +Structured bindings __cpp_structured_bindings C++17 C++03 +template template arguments __cpp_template_template_args C++17 C++03 +``static operator[]`` __cpp_multidimensional_subscript C++20 C++03 +Designated initializers __cpp_designated_initializers C++20 C++03 +Conditional ``explicit`` __cpp_conditional_explicit C++20 C++03 +``using enum`` __cpp_using_enum C++20 C++03 +``if consteval`` __cpp_if_consteval C++23 C++20 +``static operator()`` __cpp_static_call_operator C++23 C++03 +----------------------------------- -------------------------------- ------------- ------------- ---------------------------------- +Designated initializers C99 C89 +=================================== ================================ ============= ============= ================================== + Type Trait Primitives ===================== @@ -2578,7 +2613,7 @@ In the format string, a suitable format specifier will be used for builtin types that Clang knows how to format. This includes standard builtin types, as well as aggregate structures, ``void*`` (printed with ``%p``), and ``const char*`` (printed with ``%s``). A ``*%p`` specifier will be used for a field -that Clang doesn't know how to format, and the corresopnding argument will be a +that Clang doesn't know how to format, and the corresponding argument will be a pointer to the field. This allows a C++ templated formatting function to detect this case and implement custom formatting. A ``*`` will otherwise not precede a format specifier. @@ -2928,7 +2963,7 @@ data into the cache before it gets used. **Description**: The ``__builtin_prefetch(addr, rw, locality)`` builtin is expected to be used to -avoid cache misses when the developper has a good understanding of which data +avoid cache misses when the developer has a good understanding of which data are going to be used next. ``addr`` is the address that needs to be brought into the cache. ``rw`` indicates the expected access mode: ``0`` for *read* and ``1`` for *write*. In case of *read write* access, ``1`` is to be used. ``locality`` @@ -3310,7 +3345,7 @@ Floating point builtins double __builtin_canonicalize(double); float __builtin_canonicalizef(float); - long double__builtin_canonicalizel(long double); + long double __builtin_canonicalizel(long double); Returns the platform specific canonical encoding of a floating point number. This canonicalization is useful for implementing certain @@ -3318,6 +3353,28 @@ numeric primitives such as frexp. See `LLVM canonicalize intrinsic `_ for more information on the semantics. +``__builtin_flt_rounds`` and ``__builtin_set_flt_rounds`` +--------------------------------------------------------- + +.. code-block:: c + + int __builtin_flt_rounds(); + void __builtin_set_flt_rounds(int); + +Returns and sets current floating point rounding mode. The encoding of returned +values and input parameters is same as the result of FLT_ROUNDS, specified by C +standard: +- ``0`` - toward zero +- ``1`` - to nearest, ties to even +- ``2`` - toward positive infinity +- ``3`` - toward negative infinity +- ``4`` - to nearest, ties away from zero +The effect of passing some other value to ``__builtin_flt_rounds`` is +implementation-defined. ``__builtin_set_flt_rounds`` is currently only supported +to work on x86, x86_64, Arm and AArch64 targets. These builtins read and modify +the floating-point environment, which is not always allowed and may have unexpected +behavior. Please see the section on `Accessing the floating point environment `_ for more information. + String builtins --------------- @@ -3396,7 +3453,7 @@ longer usable unless re-initialized with a call to ``__builtin_va_start`` or A builtin function for the target-specific ``va_arg`` function-like macro. This function returns the value of the next variadic argument to the call. It is -undefined behavior to call this builtin when there is no next varadic argument +undefined behavior to call this builtin when there is no next variadic argument to retrieve or if the next variadic argument does not have a type compatible with the given ``type-name``. The return type of the function is the ``type-name`` given as the second argument. It is undefined behavior to call diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4f8165bbc8ee5..9601849bd67d3 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -91,6 +91,9 @@ C++20 Feature Support building of standard modules. This diagnostic may be strengthened into an error again in the future once there is a less fragile way to mark a module as being part of the implementation rather than a user module. +- Clang now implements `[temp.deduct]p9`. Substitution failures inside lambdas from + unevaluated contexts will be surfaced as errors. They were previously handled as + SFINAE. C++23 Feature Support ^^^^^^^^^^^^^^^^^^^^^ @@ -103,9 +106,13 @@ C++23 Feature Support Explicitly defaulted functions no longer have to be constexpr-compatible but merely constexpr suitable. We do not support outside of defaulted special memeber functions the change that constexpr functions no longer have to be constexpr compatible but rather support a less restricted requirements for constexpr - functions. Which include allowing non-literal types as return values and paremeters, allow calling of + functions. Which include allowing non-literal types as return values and parameters, allow calling of non-constexpr functions and constructors. +C++2c Feature Support +^^^^^^^^^^^^^^^^^^^^^ +- Compiler flags ``-std=c++2c`` and ``-std=gnu++2c`` have been added for experimental C++2c implementation work. + Resolutions to C++ Defect Reports ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Implemented `DR2397 `_ which allows ``auto`` specifier for pointers @@ -178,7 +185,7 @@ Non-comprehensive list of changes in this release - Clang now supports expressions in ``#pragma clang __debug dump``. - Clang now supports declaration of multi-dimensional arrays with ``__declspec(property)``. -- A new builtin type trait ``__is_trivially_equaltiy_comparable`` has been added, +- A new builtin type trait ``__is_trivially_equality_comparable`` has been added, which checks whether comparing two instances of a type is equivalent to ``memcmp(&lhs, &rhs, sizeof(T)) == 0``. - Clang now ignores null directives outside of the include guard when deciding @@ -189,12 +196,20 @@ New Compiler Flags - The flag ``-std=c++23`` has been added. This behaves the same as the existing flag ``-std=c++2b``. +- ``-dumpdir`` has been implemented to specify auxiliary and dump output + filenames for features like ``-gsplit-dwarf``. + Deprecated Compiler Flags ------------------------- Modified Compiler Flags ----------------------- +- ``clang -g -gsplit-dwarf a.c -o obj/x`` (compile and link) now generates the + ``.dwo`` file at ``obj/x-a.dwo``, instead of a file in the temporary + directory (``/tmp`` on \*NIX systems, if none of the environment variables + TMPDIR, TMP, and TEMP are specified). + Removed Compiler Flags ------------------------- - The deprecated flag `-fmodules-ts` is removed. Please use ``-std=c++20`` @@ -242,7 +257,7 @@ Improvements to Clang's diagnostics - Clang now avoids duplicate warnings on unreachable ``[[fallthrough]];`` statements previously issued from ``-Wunreachable-code`` and ``-Wunreachable-code-fallthrough`` by prioritizing ``-Wunreachable-code-fallthrough``. -- Clang now correctly diagnoses statement attributes ``[[clang::always_inine]]`` and +- Clang now correctly diagnoses statement attributes ``[[clang::always_inline]]`` and ``[[clang::noinline]]`` when used on a statement with dependent call expressions. - Clang now checks for completeness of the second and third arguments in the conditional operator. @@ -261,6 +276,11 @@ Improvements to Clang's diagnostics (`#62247: `_). - Clang now diagnoses shadowing of lambda's template parameter by a capture. (`#61105: `_). +- Address a false positive in ``-Wpacked`` when applied to a non-pod type using + Clang ABI >= 15. + (`#62353: `_, + fallout from the non-POD packing ABI fix in LLVM 15). + Bug Fixes in This Version ------------------------- @@ -299,12 +319,12 @@ Bug Fixes in This Version - Fix crash when using ``[[clang::always_inline]]`` or ``[[clang::noinline]]`` statement attributes on a call to a template function in the body of a template function. -- Fix coroutines issue where ``get_return_object()`` result was always eargerly +- Fix coroutines issue where ``get_return_object()`` result was always eagerly converted to the return type. Eager initialization (allowing RVO) is now only - perfomed when these types match, otherwise deferred initialization is used, + performed when these types match, otherwise deferred initialization is used, enabling short-circuiting coroutines use cases. This fixes (`#56532 `_) in - antecipation of `CWG2563 _`. + anticipation of `CWG2563 _`. - Fix highlighting issue with ``_Complex`` and initialization list with more than 2 items. (`#61518 `_) - Fix ``getSourceRange`` on ``VarTemplateSpecializationDecl`` and @@ -371,6 +391,14 @@ Bug Fixes in This Version - Fix crash when attempting to pass a non-pointer type as first argument of ``__builtin_assume_aligned``. (`#62305 `_) +- A default argument for a non-type template parameter is evaluated and checked + at the point where it is required. This fixes: + (`#62224 `_) and + (`#62596 `_) +- Fix an assertion when instantiating the body of a Class Template Specialization + when it had been instantiated from a partial template specialization with different + template arguments on the containing class. This fixes: + (`#60778 `_). Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -397,7 +425,7 @@ Bug Fixes to C++ Support - Fix incorrect deletion of the default constructor of unions in some cases. (`#48416 `_) - No longer issue a pre-C++23 compatibility warning in ``-pedantic`` mode - regading overloaded `operator[]` with more than one parmeter or for static + regarding overloaded `operator[]` with more than one parameter or for static lambdas. (`#61582 `_) - Stop stripping CV qualifiers from the type of ``this`` when capturing it by value in a lambda. @@ -418,10 +446,15 @@ Bug Fixes to C++ Support - Fix a crash when expanding a pack as the index of a subscript expression. - Fix handling of constexpr dynamic memory allocations in template arguments. (`#62462 `_) +- Some predefined expressions are now treated as string literals in MSVC + compatibility mode. + (`#114 `_) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ +- Preserve ``namespace`` definitions that follow malformed declarations. + Miscellaneous Bug Fixes ^^^^^^^^^^^^^^^^^^^^^^^ @@ -514,6 +547,12 @@ AIX Support This option is an alternative to the `--build-id=0xHEXSTRING` GNU linker option which is currently not supported by the AIX linker. +- Introduced the ``-mxcoff-roptr`` option to place constant objects with + relocatable address values in the read-only data section. This option should + be used with the ``-fdata-sections`` option, and is not supported with + ``-fno-data-sections``. When ``-mxcoff-roptr`` is in effect at link time, + read-only data sections with relocatable address values that resolve to + imported symbols are made writable. WebAssembly Support ^^^^^^^^^^^^^^^^^^^ @@ -575,7 +614,7 @@ libclang - Added check in ``clang_getFieldDeclBitWidth`` for whether a bit-field has an evaluable bit width. Fixes undefined behavior when called on a - bit-field whose width depends on a template paramter. + bit-field whose width depends on a template parameter. Static Analyzer --------------- diff --git a/clang/docs/SourceBasedCodeCoverage.rst b/clang/docs/SourceBasedCodeCoverage.rst index d1d819bf0b692..710f9e9dba0a6 100644 --- a/clang/docs/SourceBasedCodeCoverage.rst +++ b/clang/docs/SourceBasedCodeCoverage.rst @@ -86,9 +86,8 @@ directory structure will be created. Additionally, the following special is specified, the runtime creates a pool of N raw profiles which are used for on-line profile merging. The runtime takes care of selecting a raw profile from the pool, locking it, and updating it before the program exits. If N is - not specified (i.e the pattern is "%m"), it's assumed that ``N = 1``. N must - be between 1 and 9. The merge pool specifier can only occur once per filename - pattern. + not specified (i.e the pattern is "%m"), it's assumed that ``N = 1``. The + merge pool specifier can only occur once per filename pattern. * "%c" expands out to nothing, but enables a mode in which profile counter updates are continuously synced to a file. This means that if the diff --git a/clang/docs/StandardCPlusPlusModules.rst b/clang/docs/StandardCPlusPlusModules.rst index a59a3edbbbac2..6ad33b1b74b2d 100644 --- a/clang/docs/StandardCPlusPlusModules.rst +++ b/clang/docs/StandardCPlusPlusModules.rst @@ -105,7 +105,7 @@ Built Module Interface file ~~~~~~~~~~~~~~~~~~~~~~~~~~~ A ``Built Module Interface file`` stands for the precompiled result of an importable module unit. -It is also called the acronym ``BMI`` genrally. +It is also called the acronym ``BMI`` generally. Global module fragment ~~~~~~~~~~~~~~~~~~~~~~ @@ -331,7 +331,7 @@ How to specify the dependent BMIs There are 3 methods to specify the dependent BMIs: -* (1) ``-fprebuilt-module-path=``. +* (1) ``-fprebuilt-module-path=``. * (2) ``-fmodule-file=`` (Deprecated). * (3) ``-fmodule-file==``. @@ -351,7 +351,7 @@ for the module specified by ```` when necessary. The main differenc with ``-fprebuilt-module-path``. The option ``-fmodule-file=`` for named modules is deprecated and is planning to be removed in future versions. -In case all ``-fprebuilt-module-path=``, ``-fmodule-file=`` and +In case all ``-fprebuilt-module-path=``, ``-fmodule-file=`` and ``-fmodule-file==`` exist, the ``-fmodule-file=`` option takes highest precedence and ``-fmodule-file==`` will take the second highest precedence. @@ -366,7 +366,7 @@ the primary module interface unit. A module-declaration that contains neither an export-keyword nor a module-partition implicitly imports the primary module interface unit of the module as if by a module-import-declaration. -All of the 3 options ``-fprebuilt-module-path=``, ``-fmodule-file=`` +All of the 3 options ``-fprebuilt-module-path=``, ``-fmodule-file=`` and ``-fmodule-file==`` may occur multiple times. For example, the command line to compile ``M.cppm`` in the above example could be rewritten into: @@ -461,109 +461,6 @@ Note that **currently** the compiler doesn't consider inconsistent macro definit Currently Clang would accept the above example. But it may produce surprising results if the debugging code depends on consistent use of ``NDEBUG`` also in other translation units. -Source content consistency -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When the compiler reads a BMI, the compiler will check the consistency of the corresponding -source files. For example: - -.. code-block:: c++ - - // M.cppm - export module M; - export template - T foo(T t) { - return t; - } - - // Use.cpp - import M; - void bar() { - foo(5); - } - -.. code-block:: console - - $ clang++ -std=c++20 M.cppm --precompile -o M.pcm - $ rm M.cppm - $ clang++ -std=c++20 Use.cpp -fmodule-file=M=M.pcm - -The compiler would reject the example since the compiler failed to find the source file to check the consistency. -So the following example would be rejected too. - -.. code-block:: console - - $ clang++ -std=c++20 M.cppm --precompile -o M.pcm - $ echo "int i=0;" >> M.cppm - $ clang++ -std=c++20 Use.cpp -fmodule-file=M=M.pcm - -The compiler would reject it too since the compiler detected the file was changed. - -But it is OK to move the BMI as long as the source files remain: - -.. code-block:: console - - $ clang++ -std=c++20 M.cppm --precompile -o M.pcm - $ mkdir -p tmp - $ mv M.pcm tmp/M.pcm - $ clang++ -std=c++20 Use.cpp -fmodule-file=M=tmp/M.pcm - -The above example would be accepted. - -If the user doesn't want to follow the consistency requirement due to some reasons (e.g., distributing BMI), -the user could try to use ``-Xclang -fmodules-embed-all-files`` when producing BMI. For example: - -.. code-block:: console - - $ clang++ -std=c++20 M.cppm --precompile -Xclang -fmodules-embed-all-files -o M.pcm - $ rm M.cppm - $ clang++ -std=c++20 Use.cpp -fmodule-file=M=M.pcm - -Now the compiler would accept the above example. -Important note: Xclang options are intended to be used by compiler internally and its semantics -are not guaranteed to be preserved in future versions. - -Also the compiler will record the path to the header files included in the global module fragment and compare the -headers when imported. For example, - -.. code-block:: c++ - - // foo.h - #include - void Hello() { - std::cout << "Hello World.\n"; - } - - // foo.cppm - module; - #include "foo.h" - export module foo; - export using ::Hello; - - // Use.cpp - import foo; - int main() { - Hello(); - } - -Then it is problematic if we remove ``foo.h`` before import `foo` module. - -.. code-block:: console - - $ clang++ -std=c++20 foo.cppm --precompile -o foo.pcm - $ mv foo.h foo.orig.h - # The following one is rejected - $ clang++ -std=c++20 Use.cpp -fmodule-file=foo=foo.pcm -c - -The above case will rejected. And we're still able to workaround it by ``-Xclang -fmodules-embed-all-files`` option: - -.. code-block:: console - - $ clang++ -std=c++20 foo.cppm --precompile -Xclang -fmodules-embed-all-files -o foo.pcm - $ mv foo.h foo.orig.h - $ clang++ -std=c++20 Use.cpp -fmodule-file=foo=foo.pcm -c -o Use.o - $ clang++ Use.o foo.pcm - ABI Impacts ----------- @@ -894,7 +791,7 @@ Discover Dependencies ===================== Prior to modules, all the translation units can be compiled parallelly. -But it is not true for the module units. The presense of module units requires +But it is not true for the module units. The presence of module units requires us to compile the translation units in a (topological) order. The clang-scan-deps scanner implemented @@ -1114,10 +1011,10 @@ Then clang-scan-deps will extract the necessary information from the options. Note that we need to specify the path to the compiler executable instead of saying ``clang++`` simply. -The users may want the scanner to get the tranditional dependency information for headers. +The users may want the scanner to get the transitional dependency information for headers. Otherwise, the users have to scan twice for the project, once for headers and once for modules. To address the requirement, clang-scan-deps will recognize the specified preprocessor options -in the given command line and generate the corresponding dependency informaiton. For example, +in the given command line and generate the corresponding dependency information. For example, .. code-block:: console @@ -1137,7 +1034,7 @@ We will get: ... When clang-scan-deps detects ``-MF`` option, clang-scan-deps will try to write the -dependency informaiton for headers to the file specified by ``-MF``. +dependency information for headers to the file specified by ``-MF``. Possible Questions ================== diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 193ba4786a487..54497829f7880 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -810,7 +810,7 @@ compilations steps. The report file specified in the option is locked for write, so this option can be used to collect statistics in parallel builds. The report file is not - cleared, new data is appended to it, thus making posible to accumulate build + cleared, new data is appended to it, thus making possible to accumulate build statistics. You can also use environment variables to control the process statistics reporting. @@ -1787,6 +1787,48 @@ floating point semantic models: precise (the default), strict, and fast. * ``16`` - Forces ``_Float16`` operations to be emitted without using excess precision arithmetic. +.. _floating-point-environment: + +Accessing the floating point environment +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Many targets allow floating point operations to be configured to control things +such as how inexact results should be rounded and how exceptional conditions +should be handled. This configuration is called the floating point environment. +C and C++ restrict access to the floating point environment by default, and the +compiler is allowed to assume that all operations are performed in the default +environment. When code is compiled in this default mode, operations that depend +on the environment (such as floating-point arithmetic and `FLT_ROUNDS`) may have +undefined behavior if the dynamic environment is not the default environment; for +example, `FLT_ROUNDS` may or may not simply return its default value for the target +instead of reading the dynamic environment, and floating-point operations may be +optimized as if the dynamic environment were the default. Similarly, it is undefined +behavior to change the floating point environment in this default mode, for example +by calling the `fesetround` function. +C provides two pragmas to allow code to dynamically modify the floating point environment: + +- ``#pragma STDC FENV_ACCESS ON`` allows dynamic changes to the entire floating + point environment. + +- ``#pragma STDC FENV_ROUND FE_DYNAMIC`` allows dynamic changes to just the floating + point rounding mode. This may be more optimizable than ``FENV_ACCESS ON`` because + the compiler can still ignore the possibility of floating-point exceptions by default. + +Both of these can be used either at the start of a block scope, in which case +they cover all code in that scope (unless they're turned off in a child scope), +or at the top level in a file, in which case they cover all subsequent function +bodies until they're turned off. Note that it is undefined behavior to enter +code that is *not* covered by one of these pragmas from code that *is* covered +by one of these pragmas unless the floating point environment has been restored +to its default state. See the C standard for more information about these pragmas. + +The command line option ``-frounding-math`` behaves as if the translation unit +began with ``#pragma STDC FENV_ROUND FE_DYNAMIC``. The command line option +``-ffp-model=strict`` behaves as if the translation unit began with ``#pragma STDC FENV_ACCESS ON``. + +Code that just wants to use a specific rounding mode for specific floating point +operations can avoid most of the hazards of the dynamic floating point environment +by using ``#pragma STDC FENV_ROUND`` with a value other than ``FE_DYNAMIC``. + .. _crtfastmath.o: A note about ``crtfastmath.o`` @@ -3912,7 +3954,7 @@ mapping of default visibility to an explicit shared object export * ``-mdefault-visibility-export-mapping=none``: no additional export information is created for entities with default visibility. * ``-mdefault-visibility-export-mapping=explicit``: mark entities for export - if they have explict (e.g. via an attribute) default visibility from the + if they have explicit (e.g. via an attribute) default visibility from the source, including RTTI. * ``-mdefault-visibility-export-mapping=all``: set XCOFF exported visibility for all entities with default visibility from any source. This gives a diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 2903b3d46441d..ae2da6d2d96f0 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -2317,7 +2317,7 @@ Corresponds to SEI CERT Rules ENV31-C and ENV34-C. ENV31-C: Rule is about the possible problem with `main` function's third argument, environment pointer, -"envp". When enviornment array is modified using some modification function +"envp". When environment array is modified using some modification function such as putenv, setenv or others, It may happen that memory is reallocated, however "envp" is not updated to reflect the changes and points to old memory region. diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index ed991652f8b64..220c394c94371 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -48,6 +48,10 @@ #define CINDEX_VERSION_STRING \ CINDEX_VERSION_STRINGIZE(CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR) +#ifndef __has_feature +#define __has_feature(feature) 0 +#endif + LLVM_CLANG_C_EXTERN_C_BEGIN /** \defgroup CINDEX libclang: C Interface to Clang @@ -3870,8 +3874,6 @@ typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor, CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent, CXCursorVisitor visitor, CXClientData client_data); -#ifdef __has_feature -#if __has_feature(blocks) /** * Visitor invoked for each cursor found by a traversal. * @@ -3882,8 +3884,12 @@ CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent, * The visitor should return one of the \c CXChildVisitResult values * to direct clang_visitChildrenWithBlock(). */ +#if __has_feature(blocks) typedef enum CXChildVisitResult (^CXCursorVisitorBlock)(CXCursor cursor, CXCursor parent); +#else +typedef struct _CXChildVisitResult *CXCursorVisitorBlock; +#endif /** * Visits the children of a cursor using the specified block. Behaves @@ -3891,8 +3897,6 @@ typedef enum CXChildVisitResult (^CXCursorVisitorBlock)(CXCursor cursor, */ CINDEX_LINKAGE unsigned clang_visitChildrenWithBlock(CXCursor parent, CXCursorVisitorBlock block); -#endif -#endif /** * @} @@ -5893,11 +5897,12 @@ CINDEX_LINKAGE CXResult clang_findReferencesInFile( CINDEX_LINKAGE CXResult clang_findIncludesInFile( CXTranslationUnit TU, CXFile file, CXCursorAndRangeVisitor visitor); -#ifdef __has_feature #if __has_feature(blocks) - typedef enum CXVisitorResult (^CXCursorAndRangeVisitorBlock)(CXCursor, CXSourceRange); +#else +typedef struct _CXCursorAndRangeVisitorBlock *CXCursorAndRangeVisitorBlock; +#endif CINDEX_LINKAGE CXResult clang_findReferencesInFileWithBlock(CXCursor, CXFile, @@ -5907,9 +5912,6 @@ CINDEX_LINKAGE CXResult clang_findIncludesInFileWithBlock(CXTranslationUnit, CXFile, CXCursorAndRangeVisitorBlock); -#endif -#endif - /** * The client's data object that is associated with a CXFile. */ diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 1b2465283df12..5bae6b6b268ca 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -447,9 +447,8 @@ class ASTContext : public RefCountedBase { }; llvm::DenseMap ModuleInitializers; - /// For module code-gen cases, this is the top-level (C++20) Named module - /// we are building. - Module *TopLevelCXXNamedModule = nullptr; + /// This is the top-level (C++20) Named module we are building. + Module *CurrentCXXNamedModule = nullptr; static constexpr unsigned ConstantArrayTypesLog2InitSize = 8; static constexpr unsigned GeneralTypesLog2InitSize = 9; @@ -1052,10 +1051,10 @@ class ASTContext : public RefCountedBase { ArrayRef getModuleInitializers(Module *M); /// Set the (C++20) module we are building. - void setNamedModuleForCodeGen(Module *M) { TopLevelCXXNamedModule = M; } + void setCurrentNamedModule(Module *M); /// Get module under construction, nullptr if this is not a C++20 module. - Module *getNamedModuleForCodeGen() const { return TopLevelCXXNamedModule; } + Module *getCurrentNamedModule() const { return CurrentCXXNamedModule; } TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl->getMostRecentDecl(); diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index e86eadab0a8a4..f7d5b3a83141a 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -644,6 +644,9 @@ class alignas(8) Decl { return getModuleOwnershipKind() > ModuleOwnershipKind::VisibleWhenImported; } + /// Whether this declaration comes from another module unit. + bool isInAnotherModuleUnit() const; + /// FIXME: Implement discarding declarations actually in global module /// fragment. See [module.global.frag]p3,4 for details. bool isDiscardedInGlobalModuleFragment() const { return false; } @@ -1172,6 +1175,12 @@ class alignas(8) Decl { } } + /// Clears the namespace of this declaration. + /// + /// This is useful if we want this declaration to be available for + /// redeclaration lookup but otherwise hidden for ordinary name lookups. + void clearIdentifierNamespace() { IdentifierNamespace = 0; } + enum FriendObjectKind { FOK_None, ///< Not a friend object. FOK_Declared, ///< A friend of a previously-declared entity. @@ -2531,10 +2540,8 @@ class DeclContext { D == LastDecl); } - bool setUseQualifiedLookup(bool use = true) const { - bool old_value = DeclContextBits.UseQualifiedLookup; + void setUseQualifiedLookup(bool use = true) const { DeclContextBits.UseQualifiedLookup = use; - return old_value; } bool shouldUseQualifiedLookup() const { diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 3677335fa176f..7cd505218f2b9 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -2309,9 +2309,15 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl { return static_cast(RedeclarableTemplateDecl::getCommonPtr()); } + void setCommonPtr(Common *C) { + RedeclarableTemplateDecl::Common = C; + } + public: + friend class ASTDeclReader; friend class ASTDeclWriter; + friend class TemplateDeclInstantiator; /// Load any lazily-loaded specializations from the external source. void LoadLazySpecializations() const; diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 079afa7d30b3e..848beeef025e1 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1992,7 +1992,7 @@ class PredefinedExpr final private: PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, - StringLiteral *SL); + bool IsTransparent, StringLiteral *SL); explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName); @@ -2007,8 +2007,12 @@ class PredefinedExpr final public: /// Create a PredefinedExpr. + /// + /// If IsTransparent, the PredefinedExpr is transparently handled as a + /// StringLiteral. static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L, - QualType FNTy, IdentKind IK, StringLiteral *SL); + QualType FNTy, IdentKind IK, bool IsTransparent, + StringLiteral *SL); /// Create an empty PredefinedExpr. static PredefinedExpr *CreateEmpty(const ASTContext &Ctx, @@ -2018,6 +2022,8 @@ class PredefinedExpr final return static_cast(PredefinedExprBits.Kind); } + bool isTransparent() const { return PredefinedExprBits.IsTransparent; } + SourceLocation getLocation() const { return PredefinedExprBits.Loc; } void setLocation(SourceLocation L) { PredefinedExprBits.Loc = L; } diff --git a/clang/include/clang/AST/IgnoreExpr.h b/clang/include/clang/AST/IgnoreExpr.h index f8d2d6c7d00c0..917bada61fa6f 100644 --- a/clang/include/clang/AST/IgnoreExpr.h +++ b/clang/include/clang/AST/IgnoreExpr.h @@ -166,6 +166,11 @@ inline Expr *IgnoreParensSingleStep(Expr *E) { return CE->getChosenSubExpr(); } + else if (auto *PE = dyn_cast(E)) { + if (PE->isTransparent() && PE->getFunctionName()) + return PE->getFunctionName(); + } + return E; } diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index ea979d791ce7b..e466aa1755daf 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -364,6 +364,10 @@ class alignas(void *) Stmt { /// for the predefined identifier. unsigned HasFunctionName : 1; + /// True if this PredefinedExpr should be treated as a StringLiteral (for + /// MSVC compatibility). + unsigned IsTransparent : 1; + /// The location of this PredefinedExpr. SourceLocation Loc; }; diff --git a/clang/include/clang/Analysis/BodyFarm.h b/clang/include/clang/Analysis/BodyFarm.h index eaa6472433dde..52be29cb7885e 100644 --- a/clang/include/clang/Analysis/BodyFarm.h +++ b/clang/include/clang/Analysis/BodyFarm.h @@ -40,6 +40,9 @@ class BodyFarm { /// Remove copy constructor to avoid accidental copying. BodyFarm(const BodyFarm &other) = delete; + /// Delete copy assignment operator. + BodyFarm &operator=(const BodyFarm &other) = delete; + private: typedef llvm::DenseMap> BodyMap; diff --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h index 3495bdfc538cb..b51e2cb23634d 100644 --- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h @@ -32,7 +32,13 @@ namespace dataflow { class ControlFlowContext { public: /// Builds a ControlFlowContext from an AST node. `D` is the function in which - /// `S` resides and must not be null. + /// `S` resides. `D.isTemplated()` must be false. + static llvm::Expected build(const Decl &D, Stmt &S, + ASTContext &C); + + /// Builds a ControlFlowContext from an AST node. `D` is the function in which + /// `S` resides. `D` must not be null and `D->isTemplated()` must be false. + LLVM_DEPRECATED("Use the version that takes a const Decl & instead", "") static llvm::Expected build(const Decl *D, Stmt &S, ASTContext &C); diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 7f24755d9923a..d734ae5c66fe8 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -46,9 +46,6 @@ enum class SkipPast { None, /// An optional reference should be skipped past. Reference, - /// An optional reference should be skipped past, then an optional pointer - /// should be skipped past. - ReferenceThenPointer, }; /// Indicates the result of a tentative comparison. @@ -314,11 +311,7 @@ class Environment { /// Equivalent to `getValue(getStorageLocation(D, SP), SkipPast::None)` if `D` /// is assigned a storage location in the environment, otherwise returns null. - /// - /// The `SP` parameter is deprecated and has no effect. In addition, it is - /// not permitted to pass `SkipPast::ReferenceThenPointer` for this parameter. - /// New uses of this function should use the default argument for `SP`. - Value *getValue(const ValueDecl &D, SkipPast SP = SkipPast::None) const; + Value *getValue(const ValueDecl &D) const; /// Equivalent to `getValue(getStorageLocation(E, SP), SkipPast::None)` if `E` /// is assigned a storage location in the environment, otherwise returns null. @@ -481,6 +474,19 @@ class Environment { AtomicBoolValue *FlowConditionToken; }; +/// Returns the storage location for the implicit object of a +/// `CXXMemberCallExpr`, or null if none is defined in the environment. +/// Dereferences the pointer if the member call expression was written using +/// `->`. +AggregateStorageLocation * +getImplicitObjectLocation(const CXXMemberCallExpr &MCE, const Environment &Env); + +/// Returns the storage location for the base object of a `MemberExpr`, or null +/// if none is defined in the environment. Dereferences the pointer if the +/// member expression was written using `->`. +AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME, + const Environment &Env); + } // namespace dataflow } // namespace clang diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def index 7b7625cf11c5a..1e52d351780c1 100644 --- a/clang/include/clang/Basic/BuiltinsPPC.def +++ b/clang/include/clang/Basic/BuiltinsPPC.def @@ -19,15 +19,33 @@ // The format of this database matches clang/Basic/Builtins.def except for the // MMA builtins that are using their own format documented below. -#if defined(BUILTIN) && !defined(CUSTOM_BUILTIN) -# define CUSTOM_BUILTIN(ID, INTR, TYPES, ACCUMULATE) \ - BUILTIN(__builtin_##ID, "i.", "t") -#elif defined(CUSTOM_BUILTIN) && !defined(BUILTIN) -# define BUILTIN(ID, TYPES, ATTRS) +#ifndef BUILTIN +#define BUILTIN(ID, TYPE, ATTRS) #endif -#define UNALIASED_CUSTOM_BUILTIN(ID, TYPES, ACCUMULATE) \ - CUSTOM_BUILTIN(ID, ID, TYPES, ACCUMULATE) +#if defined(BUILTIN) && !defined(TARGET_BUILTIN) +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS) +#endif + +#ifndef CUSTOM_BUILTIN +#define CUSTOM_BUILTIN(ID, INTR, TYPES, ACCUMULATE, FEATURE) \ + TARGET_BUILTIN(__builtin_##ID, "i.", "t", FEATURE) +#endif + +#define UNALIASED_CUSTOM_BUILTIN(ID, TYPES, ACCUMULATE, FEATURE) \ + CUSTOM_BUILTIN(ID, ID, TYPES, ACCUMULATE, FEATURE) + +// GCC predefined macros to rename builtins, undef them to keep original names. +#if defined(__GNUC__) && !defined(__clang__) +#undef __builtin_vsx_xvnmaddadp +#undef __builtin_vsx_xvnmaddasp +#undef __builtin_vsx_xvmsubasp +#undef __builtin_vsx_xvmsubadp +#undef __builtin_vsx_xvmaddadp +#undef __builtin_vsx_xvnmsubasp +#undef __builtin_vsx_xvnmsubadp +#undef __builtin_vsx_xvmaddasp +#endif // XL Compatibility built-ins BUILTIN(__builtin_ppc_popcntb, "ULiULi", "") @@ -46,7 +64,7 @@ BUILTIN(__builtin_ppc_dcbst, "vvC*", "") BUILTIN(__builtin_ppc_dcbt, "vv*", "") BUILTIN(__builtin_ppc_dcbtst, "vv*", "") BUILTIN(__builtin_ppc_dcbz, "vv*", "") -BUILTIN(__builtin_ppc_icbt, "vv*", "") +TARGET_BUILTIN(__builtin_ppc_icbt, "vv*", "", "isa-v207-instructions") BUILTIN(__builtin_ppc_fric, "dd", "") BUILTIN(__builtin_ppc_frim, "dd", "") BUILTIN(__builtin_ppc_frims, "ff", "") @@ -74,12 +92,12 @@ BUILTIN(__builtin_ppc_fetch_and_swap, "UiUiD*Ui", "") BUILTIN(__builtin_ppc_fetch_and_swaplp, "ULiULiD*ULi", "") BUILTIN(__builtin_ppc_ldarx, "LiLiD*", "") BUILTIN(__builtin_ppc_lwarx, "iiD*", "") -BUILTIN(__builtin_ppc_lharx, "ssD*", "") -BUILTIN(__builtin_ppc_lbarx, "ccD*", "") +TARGET_BUILTIN(__builtin_ppc_lharx, "ssD*", "", "isa-v207-instructions") +TARGET_BUILTIN(__builtin_ppc_lbarx, "ccD*", "", "isa-v207-instructions") BUILTIN(__builtin_ppc_stdcx, "iLiD*Li", "") BUILTIN(__builtin_ppc_stwcx, "iiD*i", "") -BUILTIN(__builtin_ppc_sthcx, "isD*s", "") -BUILTIN(__builtin_ppc_stbcx, "icD*i", "") +TARGET_BUILTIN(__builtin_ppc_sthcx, "isD*s", "", "isa-v207-instructions") +TARGET_BUILTIN(__builtin_ppc_stbcx, "icD*i", "", "isa-v207-instructions") BUILTIN(__builtin_ppc_tdw, "vLLiLLiIUi", "") BUILTIN(__builtin_ppc_tw, "viiIUi", "") BUILTIN(__builtin_ppc_trap, "vi", "") @@ -96,26 +114,27 @@ BUILTIN(__builtin_ppc_swdiv_nochk, "ddd", "") BUILTIN(__builtin_ppc_swdivs_nochk, "fff", "") BUILTIN(__builtin_ppc_alignx, "vIivC*", "nc") BUILTIN(__builtin_ppc_rdlam, "UWiUWiUWiUWIi", "nc") -BUILTIN(__builtin_ppc_compare_exp_uo, "idd", "") -BUILTIN(__builtin_ppc_compare_exp_lt, "idd", "") -BUILTIN(__builtin_ppc_compare_exp_gt, "idd", "") -BUILTIN(__builtin_ppc_compare_exp_eq, "idd", "") -BUILTIN(__builtin_ppc_test_data_class, "idIi", "t") +TARGET_BUILTIN(__builtin_ppc_compare_exp_uo, "idd", "", "isa-v30-instructions,vsx") +TARGET_BUILTIN(__builtin_ppc_compare_exp_lt, "idd", "", "isa-v30-instructions,vsx") +TARGET_BUILTIN(__builtin_ppc_compare_exp_gt, "idd", "", "isa-v30-instructions,vsx") +TARGET_BUILTIN(__builtin_ppc_compare_exp_eq, "idd", "", "isa-v30-instructions,vsx") +TARGET_BUILTIN(__builtin_ppc_test_data_class, "idIi", "t", "isa-v30-instructions,vsx") BUILTIN(__builtin_ppc_swdiv, "ddd", "") BUILTIN(__builtin_ppc_swdivs, "fff", "") // Compare -BUILTIN(__builtin_ppc_cmpeqb, "LLiLLiLLi", "") -BUILTIN(__builtin_ppc_cmprb, "iCIiii", "") -BUILTIN(__builtin_ppc_setb, "LLiLLiLLi", "") +TARGET_BUILTIN(__builtin_ppc_cmpeqb, "LLiLLiLLi", "", "isa-v30-instructions") +TARGET_BUILTIN(__builtin_ppc_cmprb, "iCIiii", "", "isa-v30-instructions") +TARGET_BUILTIN(__builtin_ppc_setb, "LLiLLiLLi", "", "isa-v30-instructions") BUILTIN(__builtin_ppc_cmpb, "LLiLLiLLi", "") // Multiply BUILTIN(__builtin_ppc_mulhd, "LLiLiLi", "") BUILTIN(__builtin_ppc_mulhdu, "ULLiULiULi", "") BUILTIN(__builtin_ppc_mulhw, "iii", "") BUILTIN(__builtin_ppc_mulhwu, "UiUiUi", "") -BUILTIN(__builtin_ppc_maddhd, "LLiLLiLLiLLi", "") -BUILTIN(__builtin_ppc_maddhdu, "ULLiULLiULLiULLi", "") -BUILTIN(__builtin_ppc_maddld, "LLiLLiLLiLLi", "") +TARGET_BUILTIN(__builtin_ppc_maddhd, "LLiLLiLLiLLi", "", "isa-v30-instructions") +TARGET_BUILTIN(__builtin_ppc_maddhdu, "ULLiULLiULLiULLi", "", + "isa-v30-instructions") +TARGET_BUILTIN(__builtin_ppc_maddld, "LLiLLiLLiLLi", "", "isa-v30-instructions") // Rotate BUILTIN(__builtin_ppc_rlwnm, "UiUiUiIUi", "") BUILTIN(__builtin_ppc_rlwimi, "UiUiUiIUiIUi", "") @@ -123,18 +142,18 @@ BUILTIN(__builtin_ppc_rldimi, "ULLiULLiULLiIUiIULLi", "") // load BUILTIN(__builtin_ppc_load2r, "UsUs*", "") BUILTIN(__builtin_ppc_load4r, "UiUi*", "") -BUILTIN(__builtin_ppc_load8r, "ULLiULLi*", "") +TARGET_BUILTIN(__builtin_ppc_load8r, "ULLiULLi*", "", "isa-v206-instructions") // store BUILTIN(__builtin_ppc_store2r, "vUiUs*", "") BUILTIN(__builtin_ppc_store4r, "vUiUi*", "") -BUILTIN(__builtin_ppc_store8r, "vULLiULLi*", "") -BUILTIN(__builtin_ppc_extract_exp, "Uid", "") -BUILTIN(__builtin_ppc_extract_sig, "ULLid", "") +TARGET_BUILTIN(__builtin_ppc_store8r, "vULLiULLi*", "", "isa-v206-instructions") +TARGET_BUILTIN(__builtin_ppc_extract_exp, "Uid", "", "power9-vector") +TARGET_BUILTIN(__builtin_ppc_extract_sig, "ULLid", "", "power9-vector") BUILTIN(__builtin_ppc_mtfsb0, "vUIi", "") BUILTIN(__builtin_ppc_mtfsb1, "vUIi", "") BUILTIN(__builtin_ppc_mtfsf, "vUIiUi", "") BUILTIN(__builtin_ppc_mtfsfi, "vUIiUIi", "") -BUILTIN(__builtin_ppc_insert_exp, "ddULLi", "") +TARGET_BUILTIN(__builtin_ppc_insert_exp, "ddULLi", "", "power9-vector") BUILTIN(__builtin_ppc_fmsub, "dddd", "") BUILTIN(__builtin_ppc_fmsubs, "ffff", "") BUILTIN(__builtin_ppc_fnmadd, "dddd", "") @@ -145,13 +164,13 @@ BUILTIN(__builtin_ppc_fre, "dd", "") BUILTIN(__builtin_ppc_fres, "ff", "") BUILTIN(__builtin_ppc_dcbtstt, "vv*", "") BUILTIN(__builtin_ppc_dcbtt, "vv*", "") -BUILTIN(__builtin_ppc_mftbu, "Ui","") +BUILTIN(__builtin_ppc_mftbu, "Ui", "") BUILTIN(__builtin_ppc_mfmsr, "Ui", "") BUILTIN(__builtin_ppc_mfspr, "ULiIi", "") BUILTIN(__builtin_ppc_mtmsr, "vUi", "") BUILTIN(__builtin_ppc_mtspr, "vIiULi", "") BUILTIN(__builtin_ppc_stfiw, "viC*d", "") -BUILTIN(__builtin_ppc_addex, "LLiLLiLLiCIi", "") +TARGET_BUILTIN(__builtin_ppc_addex, "LLiLLiLLiCIi", "", "isa-v30-instructions") // select BUILTIN(__builtin_ppc_maxfe, "LdLdLdLd.", "t") BUILTIN(__builtin_ppc_maxfl, "dddd.", "t") @@ -166,595 +185,696 @@ BUILTIN(__builtin_ppc_fnabss, "ff", "") BUILTIN(__builtin_ppc_get_timebase, "ULLi", "n") // This is just a placeholder, the types and attributes are wrong. -BUILTIN(__builtin_altivec_vaddcuw, "V4UiV4UiV4Ui", "") - -BUILTIN(__builtin_altivec_vaddsbs, "V16ScV16ScV16Sc", "") -BUILTIN(__builtin_altivec_vaddubs, "V16UcV16UcV16Uc", "") -BUILTIN(__builtin_altivec_vaddshs, "V8SsV8SsV8Ss", "") -BUILTIN(__builtin_altivec_vadduhs, "V8UsV8UsV8Us", "") -BUILTIN(__builtin_altivec_vaddsws, "V4SiV4SiV4Si", "") -BUILTIN(__builtin_altivec_vadduws, "V4UiV4UiV4Ui", "") -BUILTIN(__builtin_altivec_vaddeuqm, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi","") -BUILTIN(__builtin_altivec_vaddcuq, "V1ULLLiV1ULLLiV1ULLLi","") -BUILTIN(__builtin_altivec_vaddecuq, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi","") -BUILTIN(__builtin_altivec_vadduqm, "V1ULLLiV16UcV16Uc","") -BUILTIN(__builtin_altivec_vaddeuqm_c, "V16UcV16UcV16UcV16Uc","") -BUILTIN(__builtin_altivec_vaddcuq_c, "V16UcV16UcV16Uc","") -BUILTIN(__builtin_altivec_vaddecuq_c, "V16UcV16UcV16UcV16Uc","") - -BUILTIN(__builtin_altivec_vsubsbs, "V16ScV16ScV16Sc", "") -BUILTIN(__builtin_altivec_vsububs, "V16UcV16UcV16Uc", "") -BUILTIN(__builtin_altivec_vsubshs, "V8SsV8SsV8Ss", "") -BUILTIN(__builtin_altivec_vsubuhs, "V8UsV8UsV8Us", "") -BUILTIN(__builtin_altivec_vsubsws, "V4SiV4SiV4Si", "") -BUILTIN(__builtin_altivec_vsubuws, "V4UiV4UiV4Ui", "") -BUILTIN(__builtin_altivec_vsubeuqm, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi","") -BUILTIN(__builtin_altivec_vsubcuq, "V1ULLLiV1ULLLiV1ULLLi","") -BUILTIN(__builtin_altivec_vsubecuq, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi","") -BUILTIN(__builtin_altivec_vsubuqm, "V1ULLLiV16UcV16Uc","") -BUILTIN(__builtin_altivec_vsubeuqm_c, "V16UcV16UcV16UcV16Uc","") -BUILTIN(__builtin_altivec_vsubcuq_c, "V16UcV16UcV16Uc","") -BUILTIN(__builtin_altivec_vsubecuq_c, "V16UcV16UcV16UcV16Uc","") - -BUILTIN(__builtin_altivec_vavgsb, "V16ScV16ScV16Sc", "") -BUILTIN(__builtin_altivec_vavgub, "V16UcV16UcV16Uc", "") -BUILTIN(__builtin_altivec_vavgsh, "V8SsV8SsV8Ss", "") -BUILTIN(__builtin_altivec_vavguh, "V8UsV8UsV8Us", "") -BUILTIN(__builtin_altivec_vavgsw, "V4SiV4SiV4Si", "") -BUILTIN(__builtin_altivec_vavguw, "V4UiV4UiV4Ui", "") - -BUILTIN(__builtin_altivec_vrfip, "V4fV4f", "") - -BUILTIN(__builtin_altivec_vcfsx, "V4fV4SiIi", "") -BUILTIN(__builtin_altivec_vcfux, "V4fV4UiIi", "") -BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fIi", "") -BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fIi", "") - -BUILTIN(__builtin_altivec_dss, "vUIi", "") -BUILTIN(__builtin_altivec_dssall, "v", "") -BUILTIN(__builtin_altivec_dst, "vvC*iUIi", "") -BUILTIN(__builtin_altivec_dstt, "vvC*iUIi", "") -BUILTIN(__builtin_altivec_dstst, "vvC*iUIi", "") -BUILTIN(__builtin_altivec_dststt, "vvC*iUIi", "") - -BUILTIN(__builtin_altivec_vexptefp, "V4fV4f", "") - -BUILTIN(__builtin_altivec_vrfim, "V4fV4f", "") - -BUILTIN(__builtin_altivec_lvx, "V4iLivC*", "") -BUILTIN(__builtin_altivec_lvxl, "V4iLivC*", "") -BUILTIN(__builtin_altivec_lvebx, "V16cLivC*", "") -BUILTIN(__builtin_altivec_lvehx, "V8sLivC*", "") -BUILTIN(__builtin_altivec_lvewx, "V4iLivC*", "") - -BUILTIN(__builtin_altivec_vlogefp, "V4fV4f", "") - -BUILTIN(__builtin_altivec_lvsl, "V16cUcvC*", "") -BUILTIN(__builtin_altivec_lvsr, "V16cUcvC*", "") - -BUILTIN(__builtin_altivec_vmaddfp, "V4fV4fV4fV4f", "") -BUILTIN(__builtin_altivec_vmhaddshs, "V8sV8sV8sV8s", "") -BUILTIN(__builtin_altivec_vmhraddshs, "V8sV8sV8sV8s", "") - -BUILTIN(__builtin_altivec_vmsumubm, "V4UiV16UcV16UcV4Ui", "") -BUILTIN(__builtin_altivec_vmsummbm, "V4SiV16ScV16UcV4Si", "") -BUILTIN(__builtin_altivec_vmsumuhm, "V4UiV8UsV8UsV4Ui", "") -BUILTIN(__builtin_altivec_vmsumshm, "V4SiV8SsV8SsV4Si", "") -BUILTIN(__builtin_altivec_vmsumuhs, "V4UiV8UsV8UsV4Ui", "") -BUILTIN(__builtin_altivec_vmsumshs, "V4SiV8SsV8SsV4Si", "") - -BUILTIN(__builtin_altivec_vmuleub, "V8UsV16UcV16Uc", "") -BUILTIN(__builtin_altivec_vmulesb, "V8SsV16ScV16Sc", "") -BUILTIN(__builtin_altivec_vmuleuh, "V4UiV8UsV8Us", "") -BUILTIN(__builtin_altivec_vmulesh, "V4SiV8SsV8Ss", "") -BUILTIN(__builtin_altivec_vmuleuw, "V2ULLiV4UiV4Ui", "") -BUILTIN(__builtin_altivec_vmulesw, "V2SLLiV4SiV4Si", "") -BUILTIN(__builtin_altivec_vmuloub, "V8UsV16UcV16Uc", "") -BUILTIN(__builtin_altivec_vmulosb, "V8SsV16ScV16Sc", "") -BUILTIN(__builtin_altivec_vmulouh, "V4UiV8UsV8Us", "") -BUILTIN(__builtin_altivec_vmulosh, "V4SiV8SsV8Ss", "") -BUILTIN(__builtin_altivec_vmulouw, "V2ULLiV4UiV4Ui", "") -BUILTIN(__builtin_altivec_vmulosw, "V2SLLiV4SiV4Si", "") -BUILTIN(__builtin_altivec_vmuleud, "V1ULLLiV2ULLiV2ULLi", "") -BUILTIN(__builtin_altivec_vmulesd, "V1SLLLiV2SLLiV2SLLi", "") -BUILTIN(__builtin_altivec_vmuloud, "V1ULLLiV2ULLiV2ULLi", "") -BUILTIN(__builtin_altivec_vmulosd, "V1SLLLiV2SLLiV2SLLi", "") -BUILTIN(__builtin_altivec_vmsumcud, "V1ULLLiV2ULLiV2ULLiV1ULLLi", "") - -BUILTIN(__builtin_altivec_vnmsubfp, "V4fV4fV4fV4f", "") - -BUILTIN(__builtin_altivec_vpkpx, "V8sV4UiV4Ui", "") -BUILTIN(__builtin_altivec_vpkuhus, "V16UcV8UsV8Us", "") -BUILTIN(__builtin_altivec_vpkshss, "V16ScV8SsV8Ss", "") -BUILTIN(__builtin_altivec_vpkuwus, "V8UsV4UiV4Ui", "") -BUILTIN(__builtin_altivec_vpkswss, "V8SsV4SiV4Si", "") -BUILTIN(__builtin_altivec_vpkshus, "V16UcV8SsV8Ss", "") -BUILTIN(__builtin_altivec_vpkswus, "V8UsV4SiV4Si", "") -BUILTIN(__builtin_altivec_vpksdss, "V4SiV2SLLiV2SLLi", "") -BUILTIN(__builtin_altivec_vpksdus, "V4UiV2SLLiV2SLLi", "") -BUILTIN(__builtin_altivec_vpkudus, "V4UiV2ULLiV2ULLi", "") -BUILTIN(__builtin_altivec_vpkudum, "V4UiV2ULLiV2ULLi", "") - -BUILTIN(__builtin_altivec_vperm_4si, "V4iV4iV4iV16Uc", "") - -BUILTIN(__builtin_altivec_stvx, "vV4iLiv*", "") -BUILTIN(__builtin_altivec_stvxl, "vV4iLiv*", "") -BUILTIN(__builtin_altivec_stvebx, "vV16cLiv*", "") -BUILTIN(__builtin_altivec_stvehx, "vV8sLiv*", "") -BUILTIN(__builtin_altivec_stvewx, "vV4iLiv*", "") - -BUILTIN(__builtin_altivec_vcmpbfp, "V4iV4fV4f", "") - -BUILTIN(__builtin_altivec_vcmpgefp, "V4iV4fV4f", "") - -BUILTIN(__builtin_altivec_vcmpequb, "V16cV16cV16c", "") -BUILTIN(__builtin_altivec_vcmpequh, "V8sV8sV8s", "") -BUILTIN(__builtin_altivec_vcmpequw, "V4iV4iV4i", "") -BUILTIN(__builtin_altivec_vcmpequd, "V2LLiV2LLiV2LLi", "") -BUILTIN(__builtin_altivec_vcmpeqfp, "V4iV4fV4f", "") - -BUILTIN(__builtin_altivec_vcmpneb, "V16cV16cV16c", "") -BUILTIN(__builtin_altivec_vcmpneh, "V8sV8sV8s", "") -BUILTIN(__builtin_altivec_vcmpnew, "V4iV4iV4i", "") - -BUILTIN(__builtin_altivec_vcmpnezb, "V16cV16cV16c", "") -BUILTIN(__builtin_altivec_vcmpnezh, "V8sV8sV8s", "") -BUILTIN(__builtin_altivec_vcmpnezw, "V4iV4iV4i", "") - -BUILTIN(__builtin_altivec_vcmpgtsb, "V16cV16ScV16Sc", "") -BUILTIN(__builtin_altivec_vcmpgtub, "V16cV16UcV16Uc", "") -BUILTIN(__builtin_altivec_vcmpgtsh, "V8sV8SsV8Ss", "") -BUILTIN(__builtin_altivec_vcmpgtuh, "V8sV8UsV8Us", "") -BUILTIN(__builtin_altivec_vcmpgtsw, "V4iV4SiV4Si", "") -BUILTIN(__builtin_altivec_vcmpgtuw, "V4iV4UiV4Ui", "") -BUILTIN(__builtin_altivec_vcmpgtsd, "V2LLiV2LLiV2LLi", "") -BUILTIN(__builtin_altivec_vcmpgtud, "V2LLiV2ULLiV2ULLi", "") -BUILTIN(__builtin_altivec_vcmpgtfp, "V4iV4fV4f", "") +TARGET_BUILTIN(__builtin_altivec_vaddcuw, "V4UiV4UiV4Ui", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vaddsbs, "V16ScV16ScV16Sc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vaddubs, "V16UcV16UcV16Uc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vaddshs, "V8SsV8SsV8Ss", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vadduhs, "V8UsV8UsV8Us", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vaddsws, "V4SiV4SiV4Si", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vadduws, "V4UiV4UiV4Ui", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vaddeuqm, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vaddcuq, "V1ULLLiV1ULLLiV1ULLLi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vaddecuq, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vadduqm, "V1ULLLiV16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vaddeuqm_c, "V16UcV16UcV16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vaddcuq_c, "V16UcV16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vaddecuq_c, "V16UcV16UcV16UcV16Uc", "", + "power8-vector") + +TARGET_BUILTIN(__builtin_altivec_vsubsbs, "V16ScV16ScV16Sc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vsububs, "V16UcV16UcV16Uc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vsubshs, "V8SsV8SsV8Ss", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vsubuhs, "V8UsV8UsV8Us", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vsubsws, "V4SiV4SiV4Si", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vsubuws, "V4UiV4UiV4Ui", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vsubeuqm, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vsubcuq, "V1ULLLiV1ULLLiV1ULLLi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vsubecuq, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vsubuqm, "V1ULLLiV16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vsubeuqm_c, "V16UcV16UcV16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vsubcuq_c, "V16UcV16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vsubecuq_c, "V16UcV16UcV16UcV16Uc", "", + "power8-vector") + +TARGET_BUILTIN(__builtin_altivec_vavgsb, "V16ScV16ScV16Sc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vavgub, "V16UcV16UcV16Uc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vavgsh, "V8SsV8SsV8Ss", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vavguh, "V8UsV8UsV8Us", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vavgsw, "V4SiV4SiV4Si", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vavguw, "V4UiV4UiV4Ui", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vrfip, "V4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vcfsx, "V4fV4SiIi", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcfux, "V4fV4UiIi", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fIi", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fIi", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_dss, "vUIi", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_dssall, "v", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_dst, "vvC*iUIi", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_dstt, "vvC*iUIi", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_dstst, "vvC*iUIi", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_dststt, "vvC*iUIi", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vexptefp, "V4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vrfim, "V4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_lvx, "V4iLivC*", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_lvxl, "V4iLivC*", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_lvebx, "V16cLivC*", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_lvehx, "V8sLivC*", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_lvewx, "V4iLivC*", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vlogefp, "V4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_lvsl, "V16cUcvC*", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_lvsr, "V16cUcvC*", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vmaddfp, "V4fV4fV4fV4f", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmhaddshs, "V8sV8sV8sV8s", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmhraddshs, "V8sV8sV8sV8s", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vmsumubm, "V4UiV16UcV16UcV4Ui", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmsummbm, "V4SiV16ScV16UcV4Si", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmsumuhm, "V4UiV8UsV8UsV4Ui", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmsumshm, "V4SiV8SsV8SsV4Si", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmsumuhs, "V4UiV8UsV8UsV4Ui", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmsumshs, "V4SiV8SsV8SsV4Si", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vmuleub, "V8UsV16UcV16Uc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmulesb, "V8SsV16ScV16Sc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmuleuh, "V4UiV8UsV8Us", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmulesh, "V4SiV8SsV8Ss", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmuleuw, "V2ULLiV4UiV4Ui", "", "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vmulesw, "V2SLLiV4SiV4Si", "", "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vmuloub, "V8UsV16UcV16Uc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmulosb, "V8SsV16ScV16Sc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmulouh, "V4UiV8UsV8Us", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmulosh, "V4SiV8SsV8Ss", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmulouw, "V2ULLiV4UiV4Ui", "", "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vmulosw, "V2SLLiV4SiV4Si", "", "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vmuleud, "V1ULLLiV2ULLiV2ULLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vmulesd, "V1SLLLiV2SLLiV2SLLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vmuloud, "V1ULLLiV2ULLiV2ULLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vmulosd, "V1SLLLiV2SLLiV2SLLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vmsumcud, "V1ULLLiV2ULLiV2ULLiV1ULLLi", "", + "power10-vector") + +TARGET_BUILTIN(__builtin_altivec_vnmsubfp, "V4fV4fV4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vpkpx, "V8sV4UiV4Ui", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vpkuhus, "V16UcV8UsV8Us", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vpkshss, "V16ScV8SsV8Ss", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vpkuwus, "V8UsV4UiV4Ui", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vpkswss, "V8SsV4SiV4Si", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vpkshus, "V16UcV8SsV8Ss", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vpkswus, "V8UsV4SiV4Si", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vpksdss, "V4SiV2SLLiV2SLLi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vpksdus, "V4UiV2SLLiV2SLLi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vpkudus, "V4UiV2ULLiV2ULLi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vpkudum, "V4UiV2ULLiV2ULLi", "", + "power8-vector") + +TARGET_BUILTIN(__builtin_altivec_vperm_4si, "V4iV4iV4iV16Uc", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_stvx, "vV4iLiv*", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_stvxl, "vV4iLiv*", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_stvebx, "vV16cLiv*", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_stvehx, "vV8sLiv*", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_stvewx, "vV4iLiv*", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vcmpbfp, "V4iV4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vcmpgefp, "V4iV4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vcmpequb, "V16cV16cV16c", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpequh, "V8sV8sV8s", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpequw, "V4iV4iV4i", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpequd, "V2LLiV2LLiV2LLi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vcmpeqfp, "V4iV4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vcmpneb, "V16cV16cV16c", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vcmpneh, "V8sV8sV8s", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vcmpnew, "V4iV4iV4i", "", "power9-vector") + +TARGET_BUILTIN(__builtin_altivec_vcmpnezb, "V16cV16cV16c", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vcmpnezh, "V8sV8sV8s", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vcmpnezw, "V4iV4iV4i", "", "power9-vector") + +TARGET_BUILTIN(__builtin_altivec_vcmpgtsb, "V16cV16ScV16Sc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpgtub, "V16cV16UcV16Uc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpgtsh, "V8sV8SsV8Ss", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpgtuh, "V8sV8UsV8Us", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpgtsw, "V4iV4SiV4Si", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpgtuw, "V4iV4UiV4Ui", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpgtsd, "V2LLiV2LLiV2LLi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vcmpgtud, "V2LLiV2ULLiV2ULLi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vcmpgtfp, "V4iV4fV4f", "", "altivec") // P10 Vector compare builtins. -BUILTIN(__builtin_altivec_vcmpequq, "V1LLLiV1ULLLiV1ULLLi", "") -BUILTIN(__builtin_altivec_vcmpgtsq, "V1LLLiV1SLLLiV1SLLLi", "") -BUILTIN(__builtin_altivec_vcmpgtuq, "V1LLLiV1ULLLiV1ULLLi", "") -BUILTIN(__builtin_altivec_vcmpequq_p, "iiV1ULLLiV1LLLi", "") -BUILTIN(__builtin_altivec_vcmpgtsq_p, "iiV1SLLLiV1SLLLi", "") -BUILTIN(__builtin_altivec_vcmpgtuq_p, "iiV1ULLLiV1ULLLi", "") - -BUILTIN(__builtin_altivec_vmaxsb, "V16ScV16ScV16Sc", "") -BUILTIN(__builtin_altivec_vmaxub, "V16UcV16UcV16Uc", "") -BUILTIN(__builtin_altivec_vmaxsh, "V8SsV8SsV8Ss", "") -BUILTIN(__builtin_altivec_vmaxuh, "V8UsV8UsV8Us", "") -BUILTIN(__builtin_altivec_vmaxsw, "V4SiV4SiV4Si", "") -BUILTIN(__builtin_altivec_vmaxuw, "V4UiV4UiV4Ui", "") -BUILTIN(__builtin_altivec_vmaxsd, "V2LLiV2LLiV2LLi", "") -BUILTIN(__builtin_altivec_vmaxud, "V2ULLiV2ULLiV2ULLi", "") -BUILTIN(__builtin_altivec_vmaxfp, "V4fV4fV4f", "") - -BUILTIN(__builtin_altivec_mfvscr, "V8Us", "") - -BUILTIN(__builtin_altivec_vminsb, "V16ScV16ScV16Sc", "") -BUILTIN(__builtin_altivec_vminub, "V16UcV16UcV16Uc", "") -BUILTIN(__builtin_altivec_vminsh, "V8SsV8SsV8Ss", "") -BUILTIN(__builtin_altivec_vminuh, "V8UsV8UsV8Us", "") -BUILTIN(__builtin_altivec_vminsw, "V4SiV4SiV4Si", "") -BUILTIN(__builtin_altivec_vminuw, "V4UiV4UiV4Ui", "") -BUILTIN(__builtin_altivec_vminsd, "V2LLiV2LLiV2LLi", "") -BUILTIN(__builtin_altivec_vminud, "V2ULLiV2ULLiV2ULLi", "") -BUILTIN(__builtin_altivec_vminfp, "V4fV4fV4f", "") - -BUILTIN(__builtin_altivec_mtvscr, "vV4i", "") - -BUILTIN(__builtin_altivec_vrefp, "V4fV4f", "") - -BUILTIN(__builtin_altivec_vrlb, "V16cV16cV16Uc", "") -BUILTIN(__builtin_altivec_vrlh, "V8sV8sV8Us", "") -BUILTIN(__builtin_altivec_vrlw, "V4iV4iV4Ui", "") -BUILTIN(__builtin_altivec_vrld, "V2LLiV2LLiV2ULLi", "") - -BUILTIN(__builtin_altivec_vsel_4si, "V4iV4iV4iV4Ui", "") - -BUILTIN(__builtin_altivec_vsl, "V4iV4iV4i", "") -BUILTIN(__builtin_altivec_vslo, "V4iV4iV4i", "") - -BUILTIN(__builtin_altivec_vsrab, "V16cV16cV16Uc", "") -BUILTIN(__builtin_altivec_vsrah, "V8sV8sV8Us", "") -BUILTIN(__builtin_altivec_vsraw, "V4iV4iV4Ui", "") - -BUILTIN(__builtin_altivec_vsr, "V4iV4iV4i", "") -BUILTIN(__builtin_altivec_vsro, "V4iV4iV4i", "") +TARGET_BUILTIN(__builtin_altivec_vcmpequq, "V1LLLiV1ULLLiV1ULLLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vcmpgtsq, "V1LLLiV1SLLLiV1SLLLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vcmpgtuq, "V1LLLiV1ULLLiV1ULLLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vcmpequq_p, "iiV1ULLLiV1LLLi", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpgtsq_p, "iiV1SLLLiV1SLLLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vcmpgtuq_p, "iiV1ULLLiV1ULLLi", "", + "power10-vector") + +TARGET_BUILTIN(__builtin_altivec_vmaxsb, "V16ScV16ScV16Sc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmaxub, "V16UcV16UcV16Uc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmaxsh, "V8SsV8SsV8Ss", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmaxuh, "V8UsV8UsV8Us", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmaxsw, "V4SiV4SiV4Si", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmaxuw, "V4UiV4UiV4Ui", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vmaxsd, "V2LLiV2LLiV2LLi", "", "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vmaxud, "V2ULLiV2ULLiV2ULLi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vmaxfp, "V4fV4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_mfvscr, "V8Us", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vminsb, "V16ScV16ScV16Sc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vminub, "V16UcV16UcV16Uc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vminsh, "V8SsV8SsV8Ss", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vminuh, "V8UsV8UsV8Us", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vminsw, "V4SiV4SiV4Si", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vminuw, "V4UiV4UiV4Ui", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vminsd, "V2LLiV2LLiV2LLi", "", "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vminud, "V2ULLiV2ULLiV2ULLi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vminfp, "V4fV4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_mtvscr, "vV4i", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vrefp, "V4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vrlb, "V16cV16cV16Uc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vrlh, "V8sV8sV8Us", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vrlw, "V4iV4iV4Ui", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vrld, "V2LLiV2LLiV2ULLi", "", "power8-vector") + +TARGET_BUILTIN(__builtin_altivec_vsel_4si, "V4iV4iV4iV4Ui", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vsl, "V4iV4iV4i", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vslo, "V4iV4iV4i", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vsrab, "V16cV16cV16Uc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vsrah, "V8sV8sV8Us", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vsraw, "V4iV4iV4Ui", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vsr, "V4iV4iV4i", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vsro, "V4iV4iV4i", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vrfin, "V4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vrsqrtefp, "V4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vsubcuw, "V4UiV4UiV4Ui", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vsum4sbs, "V4SiV16ScV4Si", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vsum4ubs, "V4UiV16UcV4Ui", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vsum4shs, "V4SiV8SsV4Si", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vsum2sws, "V4SiV4SiV4Si", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vsumsws, "V4SiV4SiV4Si", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vrfiz, "V4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vupkhsb, "V8sV16c", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vupkhpx, "V4UiV8s", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vupkhsh, "V4iV8s", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vupkhsw, "V2LLiV4i", "", "power8-vector") + +TARGET_BUILTIN(__builtin_altivec_vupklsb, "V8sV16c", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vupklpx, "V4UiV8s", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vupklsh, "V4iV8s", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vupklsw, "V2LLiV4i", "", "power8-vector") + +TARGET_BUILTIN(__builtin_altivec_vcmpbfp_p, "iiV4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vcmpgefp_p, "iiV4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vcmpequb_p, "iiV16cV16c", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpequh_p, "iiV8sV8s", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpequw_p, "iiV4iV4i", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpequd_p, "iiV2LLiV2LLi", "", "vsx") +TARGET_BUILTIN(__builtin_altivec_vcmpeqfp_p, "iiV4fV4f", "", "altivec") + +TARGET_BUILTIN(__builtin_altivec_vcmpneb_p, "iiV16cV16c", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vcmpneh_p, "iiV8sV8s", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vcmpnew_p, "iiV4iV4i", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vcmpned_p, "iiV2LLiV2LLi", "", "vsx") + +TARGET_BUILTIN(__builtin_altivec_vcmpgtsb_p, "iiV16ScV16Sc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpgtub_p, "iiV16UcV16Uc", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpgtsh_p, "iiV8SsV8Ss", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpgtuh_p, "iiV8UsV8Us", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpgtsw_p, "iiV4SiV4Si", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpgtuw_p, "iiV4UiV4Ui", "", "altivec") +TARGET_BUILTIN(__builtin_altivec_vcmpgtsd_p, "iiV2LLiV2LLi", "", "vsx") +TARGET_BUILTIN(__builtin_altivec_vcmpgtud_p, "iiV2ULLiV2ULLi", "", "vsx") +TARGET_BUILTIN(__builtin_altivec_vcmpgtfp_p, "iiV4fV4f", "", "altivec") -BUILTIN(__builtin_altivec_vrfin, "V4fV4f", "") - -BUILTIN(__builtin_altivec_vrsqrtefp, "V4fV4f", "") - -BUILTIN(__builtin_altivec_vsubcuw, "V4UiV4UiV4Ui", "") - -BUILTIN(__builtin_altivec_vsum4sbs, "V4SiV16ScV4Si", "") -BUILTIN(__builtin_altivec_vsum4ubs, "V4UiV16UcV4Ui", "") -BUILTIN(__builtin_altivec_vsum4shs, "V4SiV8SsV4Si", "") - -BUILTIN(__builtin_altivec_vsum2sws, "V4SiV4SiV4Si", "") - -BUILTIN(__builtin_altivec_vsumsws, "V4SiV4SiV4Si", "") - -BUILTIN(__builtin_altivec_vrfiz, "V4fV4f", "") - -BUILTIN(__builtin_altivec_vupkhsb, "V8sV16c", "") -BUILTIN(__builtin_altivec_vupkhpx, "V4UiV8s", "") -BUILTIN(__builtin_altivec_vupkhsh, "V4iV8s", "") -BUILTIN(__builtin_altivec_vupkhsw, "V2LLiV4i", "") - -BUILTIN(__builtin_altivec_vupklsb, "V8sV16c", "") -BUILTIN(__builtin_altivec_vupklpx, "V4UiV8s", "") -BUILTIN(__builtin_altivec_vupklsh, "V4iV8s", "") -BUILTIN(__builtin_altivec_vupklsw, "V2LLiV4i", "") - -BUILTIN(__builtin_altivec_vcmpbfp_p, "iiV4fV4f", "") - -BUILTIN(__builtin_altivec_vcmpgefp_p, "iiV4fV4f", "") - -BUILTIN(__builtin_altivec_vcmpequb_p, "iiV16cV16c", "") -BUILTIN(__builtin_altivec_vcmpequh_p, "iiV8sV8s", "") -BUILTIN(__builtin_altivec_vcmpequw_p, "iiV4iV4i", "") -BUILTIN(__builtin_altivec_vcmpequd_p, "iiV2LLiV2LLi", "") -BUILTIN(__builtin_altivec_vcmpeqfp_p, "iiV4fV4f", "") - -BUILTIN(__builtin_altivec_vcmpneb_p, "iiV16cV16c", "") -BUILTIN(__builtin_altivec_vcmpneh_p, "iiV8sV8s", "") -BUILTIN(__builtin_altivec_vcmpnew_p, "iiV4iV4i", "") -BUILTIN(__builtin_altivec_vcmpned_p, "iiV2LLiV2LLi", "") - -BUILTIN(__builtin_altivec_vcmpgtsb_p, "iiV16ScV16Sc", "") -BUILTIN(__builtin_altivec_vcmpgtub_p, "iiV16UcV16Uc", "") -BUILTIN(__builtin_altivec_vcmpgtsh_p, "iiV8SsV8Ss", "") -BUILTIN(__builtin_altivec_vcmpgtuh_p, "iiV8UsV8Us", "") -BUILTIN(__builtin_altivec_vcmpgtsw_p, "iiV4SiV4Si", "") -BUILTIN(__builtin_altivec_vcmpgtuw_p, "iiV4UiV4Ui", "") -BUILTIN(__builtin_altivec_vcmpgtsd_p, "iiV2LLiV2LLi", "") -BUILTIN(__builtin_altivec_vcmpgtud_p, "iiV2ULLiV2ULLi", "") -BUILTIN(__builtin_altivec_vcmpgtfp_p, "iiV4fV4f", "") - -BUILTIN(__builtin_altivec_vgbbd, "V16UcV16Uc", "") -BUILTIN(__builtin_altivec_vbpermq, "V2ULLiV16UcV16Uc", "") -BUILTIN(__builtin_altivec_vbpermd, "V2ULLiV2ULLiV16Uc", "") +TARGET_BUILTIN(__builtin_altivec_vgbbd, "V16UcV16Uc", "", "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vbpermq, "V2ULLiV16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vbpermd, "V2ULLiV2ULLiV16Uc", "", + "power9-vector") // P8 Crypto built-ins. -BUILTIN(__builtin_altivec_crypto_vsbox, "V16UcV16Uc", "") -BUILTIN(__builtin_altivec_crypto_vpermxor, "V16UcV16UcV16UcV16Uc", "") -BUILTIN(__builtin_altivec_crypto_vpermxor_be, "V16UcV16UcV16UcV16Uc", "") -BUILTIN(__builtin_altivec_crypto_vshasigmaw, "V4UiV4UiIiIi", "") -BUILTIN(__builtin_altivec_crypto_vshasigmad, "V2ULLiV2ULLiIiIi", "") -BUILTIN(__builtin_altivec_crypto_vcipher, "V16UcV16UcV16Uc", "") -BUILTIN(__builtin_altivec_crypto_vcipherlast, "V16UcV16UcV16Uc", "") -BUILTIN(__builtin_altivec_crypto_vncipher, "V16UcV16UcV16Uc", "") -BUILTIN(__builtin_altivec_crypto_vncipherlast, "V16UcV16UcV16Uc", "") -BUILTIN(__builtin_altivec_crypto_vpmsumb, "V16UcV16UcV16Uc", "") -BUILTIN(__builtin_altivec_crypto_vpmsumh, "V8UsV8UsV8Us", "") -BUILTIN(__builtin_altivec_crypto_vpmsumw, "V4UiV4UiV4Ui", "") -BUILTIN(__builtin_altivec_crypto_vpmsumd, "V2ULLiV2ULLiV2ULLi", "") - -BUILTIN(__builtin_altivec_vclzb, "V16UcV16Uc", "") -BUILTIN(__builtin_altivec_vclzh, "V8UsV8Us", "") -BUILTIN(__builtin_altivec_vclzw, "V4UiV4Ui", "") -BUILTIN(__builtin_altivec_vclzd, "V2ULLiV2ULLi", "") -BUILTIN(__builtin_altivec_vctzb, "V16UcV16Uc", "") -BUILTIN(__builtin_altivec_vctzh, "V8UsV8Us", "") -BUILTIN(__builtin_altivec_vctzw, "V4UiV4Ui", "") -BUILTIN(__builtin_altivec_vctzd, "V2ULLiV2ULLi", "") +TARGET_BUILTIN(__builtin_altivec_crypto_vsbox, "V16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_crypto_vpermxor, "V16UcV16UcV16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_crypto_vpermxor_be, "V16UcV16UcV16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_crypto_vshasigmaw, "V4UiV4UiIiIi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_crypto_vshasigmad, "V2ULLiV2ULLiIiIi", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_crypto_vcipher, "V16UcV16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_crypto_vcipherlast, "V16UcV16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_crypto_vncipher, "V16UcV16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_crypto_vncipherlast, "V16UcV16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_crypto_vpmsumb, "V16UcV16UcV16Uc", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_crypto_vpmsumh, "V8UsV8UsV8Us", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_crypto_vpmsumw, "V4UiV4UiV4Ui", "", + "power8-vector") +TARGET_BUILTIN(__builtin_altivec_crypto_vpmsumd, "V2ULLiV2ULLiV2ULLi", "", + "power8-vector") + +TARGET_BUILTIN(__builtin_altivec_vclzb, "V16UcV16Uc", "", "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vclzh, "V8UsV8Us", "", "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vclzw, "V4UiV4Ui", "", "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vclzd, "V2ULLiV2ULLi", "", "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vctzb, "V16UcV16Uc", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vctzh, "V8UsV8Us", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vctzw, "V4UiV4Ui", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vctzd, "V2ULLiV2ULLi", "", "power9-vector") // P8 BCD builtins. -BUILTIN(__builtin_ppc_bcdadd, "V16UcV16UcV16UcIi", "") -BUILTIN(__builtin_ppc_bcdsub, "V16UcV16UcV16UcIi", "") -BUILTIN(__builtin_ppc_bcdadd_p, "iiV16UcV16Uc", "") -BUILTIN(__builtin_ppc_bcdsub_p, "iiV16UcV16Uc", "") - -BUILTIN(__builtin_altivec_vclzlsbb, "SiV16Uc", "") -BUILTIN(__builtin_altivec_vctzlsbb, "SiV16Uc", "") -BUILTIN(__builtin_altivec_vprtybw, "V4UiV4Ui", "") -BUILTIN(__builtin_altivec_vprtybd, "V2ULLiV2ULLi", "") -BUILTIN(__builtin_altivec_vprtybq, "V1ULLLiV1ULLLi", "") +TARGET_BUILTIN(__builtin_ppc_bcdadd, "V16UcV16UcV16UcIi", "", + "isa-v207-instructions") +TARGET_BUILTIN(__builtin_ppc_bcdsub, "V16UcV16UcV16UcIi", "", + "isa-v207-instructions") +TARGET_BUILTIN(__builtin_ppc_bcdadd_p, "iiV16UcV16Uc", "", + "isa-v207-instructions") +TARGET_BUILTIN(__builtin_ppc_bcdsub_p, "iiV16UcV16Uc", "", + "isa-v207-instructions") + +TARGET_BUILTIN(__builtin_altivec_vclzlsbb, "SiV16Uc", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vctzlsbb, "SiV16Uc", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vprtybw, "V4UiV4Ui", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vprtybd, "V2ULLiV2ULLi", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vprtybq, "V1ULLLiV1ULLLi", "", "power9-vector") // Vector population count built-ins -BUILTIN(__builtin_altivec_vpopcntb, "V16UcV16Uc", "") -BUILTIN(__builtin_altivec_vpopcnth, "V8UsV8Us", "") -BUILTIN(__builtin_altivec_vpopcntw, "V4UiV4Ui", "") -BUILTIN(__builtin_altivec_vpopcntd, "V2ULLiV2ULLi", "") +TARGET_BUILTIN(__builtin_altivec_vpopcntb, "V16UcV16Uc", "", "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vpopcnth, "V8UsV8Us", "", "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vpopcntw, "V4UiV4Ui", "", "power8-vector") +TARGET_BUILTIN(__builtin_altivec_vpopcntd, "V2ULLiV2ULLi", "", "power8-vector") // Absolute difference built-ins -BUILTIN(__builtin_altivec_vabsdub, "V16UcV16UcV16Uc", "") -BUILTIN(__builtin_altivec_vabsduh, "V8UsV8UsV8Us", "") -BUILTIN(__builtin_altivec_vabsduw, "V4UiV4UiV4Ui", "") +TARGET_BUILTIN(__builtin_altivec_vabsdub, "V16UcV16UcV16Uc", "", + "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vabsduh, "V8UsV8UsV8Us", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vabsduw, "V4UiV4UiV4Ui", "", "power9-vector") // P9 Shift built-ins. -BUILTIN(__builtin_altivec_vslv, "V16UcV16UcV16Uc", "") -BUILTIN(__builtin_altivec_vsrv, "V16UcV16UcV16Uc", "") +TARGET_BUILTIN(__builtin_altivec_vslv, "V16UcV16UcV16Uc", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vsrv, "V16UcV16UcV16Uc", "", "power9-vector") // P9 Vector rotate built-ins -BUILTIN(__builtin_altivec_vrlwmi, "V4UiV4UiV4UiV4Ui", "") -BUILTIN(__builtin_altivec_vrldmi, "V2ULLiV2ULLiV2ULLiV2ULLi", "") -BUILTIN(__builtin_altivec_vrlwnm, "V4UiV4UiV4Ui", "") -BUILTIN(__builtin_altivec_vrldnm, "V2ULLiV2ULLiV2ULLi", "") +TARGET_BUILTIN(__builtin_altivec_vrlwmi, "V4UiV4UiV4UiV4Ui", "", + "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vrldmi, "V2ULLiV2ULLiV2ULLiV2ULLi", "", + "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vrlwnm, "V4UiV4UiV4Ui", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vrldnm, "V2ULLiV2ULLiV2ULLi", "", + "power9-vector") // P9 Vector extend sign builtins. -BUILTIN(__builtin_altivec_vextsb2w, "V4SiV16Sc", "") -BUILTIN(__builtin_altivec_vextsb2d, "V2SLLiV16Sc", "") -BUILTIN(__builtin_altivec_vextsh2w, "V4SiV8Ss", "") -BUILTIN(__builtin_altivec_vextsh2d, "V2SLLiV8Ss", "") -BUILTIN(__builtin_altivec_vextsw2d, "V2SLLiV4Si", "") +TARGET_BUILTIN(__builtin_altivec_vextsb2w, "V4SiV16Sc", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vextsb2d, "V2SLLiV16Sc", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vextsh2w, "V4SiV8Ss", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vextsh2d, "V2SLLiV8Ss", "", "power9-vector") +TARGET_BUILTIN(__builtin_altivec_vextsw2d, "V2SLLiV4Si", "", "power9-vector") // P10 Vector extend sign builtins. -BUILTIN(__builtin_altivec_vextsd2q, "V1SLLLiV2SLLi", "") +TARGET_BUILTIN(__builtin_altivec_vextsd2q, "V1SLLLiV2SLLi", "", + "power10-vector") // P10 Vector Extract with Mask built-ins. -BUILTIN(__builtin_altivec_vextractbm, "UiV16Uc", "") -BUILTIN(__builtin_altivec_vextracthm, "UiV8Us", "") -BUILTIN(__builtin_altivec_vextractwm, "UiV4Ui", "") -BUILTIN(__builtin_altivec_vextractdm, "UiV2ULLi", "") -BUILTIN(__builtin_altivec_vextractqm, "UiV1ULLLi", "") +TARGET_BUILTIN(__builtin_altivec_vextractbm, "UiV16Uc", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vextracthm, "UiV8Us", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vextractwm, "UiV4Ui", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vextractdm, "UiV2ULLi", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vextractqm, "UiV1ULLLi", "", "power10-vector") // P10 Vector Divide Extended built-ins. -BUILTIN(__builtin_altivec_vdivesw, "V4SiV4SiV4Si", "") -BUILTIN(__builtin_altivec_vdiveuw, "V4UiV4UiV4Ui", "") -BUILTIN(__builtin_altivec_vdivesd, "V2LLiV2LLiV2LLi", "") -BUILTIN(__builtin_altivec_vdiveud, "V2ULLiV2ULLiV2ULLi", "") -BUILTIN(__builtin_altivec_vdivesq, "V1SLLLiV1SLLLiV1SLLLi", "") -BUILTIN(__builtin_altivec_vdiveuq, "V1ULLLiV1ULLLiV1ULLLi", "") +TARGET_BUILTIN(__builtin_altivec_vdivesw, "V4SiV4SiV4Si", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vdiveuw, "V4UiV4UiV4Ui", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vdivesd, "V2LLiV2LLiV2LLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vdiveud, "V2ULLiV2ULLiV2ULLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vdivesq, "V1SLLLiV1SLLLiV1SLLLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vdiveuq, "V1ULLLiV1ULLLiV1ULLLi", "", + "power10-vector") // P10 Vector Multiply High built-ins. -BUILTIN(__builtin_altivec_vmulhsw, "V4SiV4SiV4Si", "") -BUILTIN(__builtin_altivec_vmulhuw, "V4UiV4UiV4Ui", "") -BUILTIN(__builtin_altivec_vmulhsd, "V2LLiV2LLiV2LLi", "") -BUILTIN(__builtin_altivec_vmulhud, "V2ULLiV2ULLiV2ULLi", "") +TARGET_BUILTIN(__builtin_altivec_vmulhsw, "V4SiV4SiV4Si", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vmulhuw, "V4UiV4UiV4Ui", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vmulhsd, "V2LLiV2LLiV2LLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vmulhud, "V2ULLiV2ULLiV2ULLi", "", + "power10-vector") // P10 Vector Expand with Mask built-ins. -BUILTIN(__builtin_altivec_vexpandbm, "V16UcV16Uc", "") -BUILTIN(__builtin_altivec_vexpandhm, "V8UsV8Us", "") -BUILTIN(__builtin_altivec_vexpandwm, "V4UiV4Ui", "") -BUILTIN(__builtin_altivec_vexpanddm, "V2ULLiV2ULLi", "") -BUILTIN(__builtin_altivec_vexpandqm, "V1ULLLiV1ULLLi", "") +TARGET_BUILTIN(__builtin_altivec_vexpandbm, "V16UcV16Uc", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vexpandhm, "V8UsV8Us", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vexpandwm, "V4UiV4Ui", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vexpanddm, "V2ULLiV2ULLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vexpandqm, "V1ULLLiV1ULLLi", "", + "power10-vector") // P10 Vector Count with Mask built-ins. -BUILTIN(__builtin_altivec_vcntmbb, "ULLiV16UcUi", "") -BUILTIN(__builtin_altivec_vcntmbh, "ULLiV8UsUi", "") -BUILTIN(__builtin_altivec_vcntmbw, "ULLiV4UiUi", "") -BUILTIN(__builtin_altivec_vcntmbd, "ULLiV2ULLiUi", "") +TARGET_BUILTIN(__builtin_altivec_vcntmbb, "ULLiV16UcUi", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vcntmbh, "ULLiV8UsUi", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vcntmbw, "ULLiV4UiUi", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vcntmbd, "ULLiV2ULLiUi", "", "power10-vector") // P10 Move to VSR with Mask built-ins. -BUILTIN(__builtin_altivec_mtvsrbm, "V16UcULLi", "") -BUILTIN(__builtin_altivec_mtvsrhm, "V8UsULLi", "") -BUILTIN(__builtin_altivec_mtvsrwm, "V4UiULLi", "") -BUILTIN(__builtin_altivec_mtvsrdm, "V2ULLiULLi", "") -BUILTIN(__builtin_altivec_mtvsrqm, "V1ULLLiULLi", "") +TARGET_BUILTIN(__builtin_altivec_mtvsrbm, "V16UcULLi", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_mtvsrhm, "V8UsULLi", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_mtvsrwm, "V4UiULLi", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_mtvsrdm, "V2ULLiULLi", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_mtvsrqm, "V1ULLLiULLi", "", "power10-vector") // P10 Vector Parallel Bits built-ins. -BUILTIN(__builtin_altivec_vpdepd, "V2ULLiV2ULLiV2ULLi", "") -BUILTIN(__builtin_altivec_vpextd, "V2ULLiV2ULLiV2ULLi", "") +TARGET_BUILTIN(__builtin_altivec_vpdepd, "V2ULLiV2ULLiV2ULLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vpextd, "V2ULLiV2ULLiV2ULLi", "", + "power10-vector") // P10 Vector String Isolate Built-ins. -BUILTIN(__builtin_altivec_vstribr, "V16UcV16Uc", "") -BUILTIN(__builtin_altivec_vstribl, "V16UcV16Uc", "") -BUILTIN(__builtin_altivec_vstrihr, "V8sV8s", "") -BUILTIN(__builtin_altivec_vstrihl, "V8sV8s", "") -BUILTIN(__builtin_altivec_vstribr_p, "iiV16Uc", "") -BUILTIN(__builtin_altivec_vstribl_p, "iiV16Uc", "") -BUILTIN(__builtin_altivec_vstrihr_p, "iiV8s", "") -BUILTIN(__builtin_altivec_vstrihl_p, "iiV8s", "") +TARGET_BUILTIN(__builtin_altivec_vstribr, "V16UcV16Uc", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vstribl, "V16UcV16Uc", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vstrihr, "V8sV8s", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vstrihl, "V8sV8s", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vstribr_p, "iiV16Uc", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vstribl_p, "iiV16Uc", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vstrihr_p, "iiV8s", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vstrihl_p, "iiV8s", "", "power10-vector") // P10 Vector Centrifuge built-in. -BUILTIN(__builtin_altivec_vcfuged, "V2ULLiV2ULLiV2ULLi", "") +TARGET_BUILTIN(__builtin_altivec_vcfuged, "V2ULLiV2ULLiV2ULLi", "", + "power10-vector") // P10 Vector Gather Every N-th Bit built-in. -BUILTIN(__builtin_altivec_vgnb, "ULLiV1ULLLiIi", "") +TARGET_BUILTIN(__builtin_altivec_vgnb, "ULLiV1ULLLiIi", "", "power10-vector") // P10 Vector Clear Bytes built-ins. -BUILTIN(__builtin_altivec_vclrlb, "V16UcV16UcUi", "") -BUILTIN(__builtin_altivec_vclrrb, "V16UcV16UcUi", "") +TARGET_BUILTIN(__builtin_altivec_vclrlb, "V16UcV16UcUi", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vclrrb, "V16UcV16UcUi", "", "power10-vector") // P10 Vector Count Leading / Trailing Zeroes under bit Mask built-ins. -BUILTIN(__builtin_altivec_vclzdm, "V2ULLiV2ULLiV2ULLi", "") -BUILTIN(__builtin_altivec_vctzdm, "V2ULLiV2ULLiV2ULLi", "") +TARGET_BUILTIN(__builtin_altivec_vclzdm, "V2ULLiV2ULLiV2ULLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vctzdm, "V2ULLiV2ULLiV2ULLi", "", + "power10-vector") // P10 Vector Shift built-ins. -BUILTIN(__builtin_altivec_vsldbi, "V16UcV16UcV16UcIi", "") -BUILTIN(__builtin_altivec_vsrdbi, "V16UcV16UcV16UcIi", "") +TARGET_BUILTIN(__builtin_altivec_vsldbi, "V16UcV16UcV16UcIi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vsrdbi, "V16UcV16UcV16UcIi", "", + "power10-vector") // P10 Vector Insert built-ins. -BUILTIN(__builtin_altivec_vinsblx, "V16UcV16UcUiUi", "") -BUILTIN(__builtin_altivec_vinsbrx, "V16UcV16UcUiUi", "") -BUILTIN(__builtin_altivec_vinshlx, "V8UsV8UsUiUi", "") -BUILTIN(__builtin_altivec_vinshrx, "V8UsV8UsUiUi", "") -BUILTIN(__builtin_altivec_vinswlx, "V4UiV4UiUiUi", "") -BUILTIN(__builtin_altivec_vinswrx, "V4UiV4UiUiUi", "") -BUILTIN(__builtin_altivec_vinsdlx, "V2ULLiV2ULLiULLiULLi", "") -BUILTIN(__builtin_altivec_vinsdrx, "V2ULLiV2ULLiULLiULLi", "") -BUILTIN(__builtin_altivec_vinsbvlx, "V16UcV16UcUiV16Uc", "") -BUILTIN(__builtin_altivec_vinsbvrx, "V16UcV16UcUiV16Uc", "") -BUILTIN(__builtin_altivec_vinshvlx, "V8UsV8UsUiV8Us", "") -BUILTIN(__builtin_altivec_vinshvrx, "V8UsV8UsUiV8Us", "") -BUILTIN(__builtin_altivec_vinswvlx, "V4UiV4UiUiV4Ui", "") -BUILTIN(__builtin_altivec_vinswvrx, "V4UiV4UiUiV4Ui", "") -BUILTIN(__builtin_altivec_vinsw, "V16UcV16UcUiIi", "") -BUILTIN(__builtin_altivec_vinsd, "V16UcV16UcULLiIi", "") -BUILTIN(__builtin_altivec_vinsw_elt, "V16UcV16UcUiiC", "") -BUILTIN(__builtin_altivec_vinsd_elt, "V16UcV16UcULLiiC", "") +TARGET_BUILTIN(__builtin_altivec_vinsblx, "V16UcV16UcUiUi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinsbrx, "V16UcV16UcUiUi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinshlx, "V8UsV8UsUiUi", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinshrx, "V8UsV8UsUiUi", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinswlx, "V4UiV4UiUiUi", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinswrx, "V4UiV4UiUiUi", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinsdlx, "V2ULLiV2ULLiULLiULLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinsdrx, "V2ULLiV2ULLiULLiULLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinsbvlx, "V16UcV16UcUiV16Uc", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinsbvrx, "V16UcV16UcUiV16Uc", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinshvlx, "V8UsV8UsUiV8Us", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinshvrx, "V8UsV8UsUiV8Us", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinswvlx, "V4UiV4UiUiV4Ui", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinswvrx, "V4UiV4UiUiV4Ui", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinsw, "V16UcV16UcUiIi", "", "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinsd, "V16UcV16UcULLiIi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinsw_elt, "V16UcV16UcUiiC", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vinsd_elt, "V16UcV16UcULLiiC", "", + "power10-vector") // P10 Vector Extract built-ins. -BUILTIN(__builtin_altivec_vextdubvlx, "V2ULLiV16UcV16UcUi", "") -BUILTIN(__builtin_altivec_vextdubvrx, "V2ULLiV16UcV16UcUi", "") -BUILTIN(__builtin_altivec_vextduhvlx, "V2ULLiV8UsV8UsUi", "") -BUILTIN(__builtin_altivec_vextduhvrx, "V2ULLiV8UsV8UsUi", "") -BUILTIN(__builtin_altivec_vextduwvlx, "V2ULLiV4UiV4UiUi", "") -BUILTIN(__builtin_altivec_vextduwvrx, "V2ULLiV4UiV4UiUi", "") -BUILTIN(__builtin_altivec_vextddvlx, "V2ULLiV2ULLiV2ULLiUi", "") -BUILTIN(__builtin_altivec_vextddvrx, "V2ULLiV2ULLiV2ULLiUi", "") +TARGET_BUILTIN(__builtin_altivec_vextdubvlx, "V2ULLiV16UcV16UcUi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vextdubvrx, "V2ULLiV16UcV16UcUi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vextduhvlx, "V2ULLiV8UsV8UsUi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vextduhvrx, "V2ULLiV8UsV8UsUi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vextduwvlx, "V2ULLiV4UiV4UiUi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vextduwvrx, "V2ULLiV4UiV4UiUi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vextddvlx, "V2ULLiV2ULLiV2ULLiUi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vextddvrx, "V2ULLiV2ULLiV2ULLiUi", "", + "power10-vector") // P10 Vector rotate built-ins. -BUILTIN(__builtin_altivec_vrlqmi, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi", "") -BUILTIN(__builtin_altivec_vrlqnm, "V1ULLLiV1ULLLiV1ULLLi", "") +TARGET_BUILTIN(__builtin_altivec_vrlqmi, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi", "", + "power10-vector") +TARGET_BUILTIN(__builtin_altivec_vrlqnm, "V1ULLLiV1ULLLiV1ULLLi", "", + "power10-vector") // VSX built-ins. -BUILTIN(__builtin_vsx_lxvd2x, "V2dLivC*", "") -BUILTIN(__builtin_vsx_lxvw4x, "V4iLivC*", "") -BUILTIN(__builtin_vsx_lxvd2x_be, "V2dSLLivC*", "") -BUILTIN(__builtin_vsx_lxvw4x_be, "V4iSLLivC*", "") +TARGET_BUILTIN(__builtin_vsx_lxvd2x, "V2dLivC*", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_lxvw4x, "V4iLivC*", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_lxvd2x_be, "V2dSLLivC*", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_lxvw4x_be, "V4iSLLivC*", "", "vsx") -BUILTIN(__builtin_vsx_stxvd2x, "vV2dLiv*", "") -BUILTIN(__builtin_vsx_stxvw4x, "vV4iLiv*", "") -BUILTIN(__builtin_vsx_stxvd2x_be, "vV2dSLLivC*", "") -BUILTIN(__builtin_vsx_stxvw4x_be, "vV4iSLLivC*", "") +TARGET_BUILTIN(__builtin_vsx_stxvd2x, "vV2dLiv*", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_stxvw4x, "vV4iLiv*", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_stxvd2x_be, "vV2dSLLivC*", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_stxvw4x_be, "vV4iSLLivC*", "", "vsx") -BUILTIN(__builtin_vsx_lxvl, "V4ivC*ULLi", "") -BUILTIN(__builtin_vsx_lxvll, "V4ivC*ULLi", "") -BUILTIN(__builtin_vsx_stxvl, "vV4iv*ULLi", "") -BUILTIN(__builtin_vsx_stxvll, "vV4iv*ULLi", "") -BUILTIN(__builtin_vsx_ldrmb, "V16UcCc*Ii", "") -BUILTIN(__builtin_vsx_strmb, "vCc*IiV16Uc", "") +TARGET_BUILTIN(__builtin_vsx_lxvl, "V4ivC*ULLi", "", "power9-vector") +TARGET_BUILTIN(__builtin_vsx_lxvll, "V4ivC*ULLi", "", "power9-vector") +TARGET_BUILTIN(__builtin_vsx_stxvl, "vV4iv*ULLi", "", "power9-vector") +TARGET_BUILTIN(__builtin_vsx_stxvll, "vV4iv*ULLi", "", "power9-vector") +TARGET_BUILTIN(__builtin_vsx_ldrmb, "V16UcCc*Ii", "", "isa-v207-instructions") +TARGET_BUILTIN(__builtin_vsx_strmb, "vCc*IiV16Uc", "", "isa-v207-instructions") -BUILTIN(__builtin_vsx_xvmaxdp, "V2dV2dV2d", "") -BUILTIN(__builtin_vsx_xvmaxsp, "V4fV4fV4f", "") -BUILTIN(__builtin_vsx_xsmaxdp, "ddd", "") +TARGET_BUILTIN(__builtin_vsx_xvmaxdp, "V2dV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvmaxsp, "V4fV4fV4f", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xsmaxdp, "ddd", "", "vsx") -BUILTIN(__builtin_vsx_xvmindp, "V2dV2dV2d", "") -BUILTIN(__builtin_vsx_xvminsp, "V4fV4fV4f", "") -BUILTIN(__builtin_vsx_xsmindp, "ddd", "") +TARGET_BUILTIN(__builtin_vsx_xvmindp, "V2dV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvminsp, "V4fV4fV4f", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xsmindp, "ddd", "", "vsx") -BUILTIN(__builtin_vsx_xvdivdp, "V2dV2dV2d", "") -BUILTIN(__builtin_vsx_xvdivsp, "V4fV4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvdivdp, "V2dV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvdivsp, "V4fV4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvrdpip, "V2dV2d", "") -BUILTIN(__builtin_vsx_xvrspip, "V4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvrdpip, "V2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvrspip, "V4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvcmpeqdp, "V2ULLiV2dV2d", "") -BUILTIN(__builtin_vsx_xvcmpeqsp, "V4UiV4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvcmpeqdp, "V2ULLiV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcmpeqsp, "V4UiV4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvcmpeqdp_p, "iiV2dV2d", "") -BUILTIN(__builtin_vsx_xvcmpeqsp_p, "iiV4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvcmpeqdp_p, "iiV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcmpeqsp_p, "iiV4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvcmpgedp, "V2ULLiV2dV2d", "") -BUILTIN(__builtin_vsx_xvcmpgesp, "V4UiV4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvcmpgedp, "V2ULLiV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcmpgesp, "V4UiV4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvcmpgedp_p, "iiV2dV2d", "") -BUILTIN(__builtin_vsx_xvcmpgesp_p, "iiV4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvcmpgedp_p, "iiV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcmpgesp_p, "iiV4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvcmpgtdp, "V2ULLiV2dV2d", "") -BUILTIN(__builtin_vsx_xvcmpgtsp, "V4UiV4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvcmpgtdp, "V2ULLiV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcmpgtsp, "V4UiV4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvcmpgtdp_p, "iiV2dV2d", "") -BUILTIN(__builtin_vsx_xvcmpgtsp_p, "iiV4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvcmpgtdp_p, "iiV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcmpgtsp_p, "iiV4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvrdpim, "V2dV2d", "") -BUILTIN(__builtin_vsx_xvrspim, "V4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvrdpim, "V2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvrspim, "V4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvrdpi, "V2dV2d", "") -BUILTIN(__builtin_vsx_xvrspi, "V4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvrdpi, "V2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvrspi, "V4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvrdpic, "V2dV2d", "") -BUILTIN(__builtin_vsx_xvrspic, "V4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvrdpic, "V2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvrspic, "V4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvrdpiz, "V2dV2d", "") -BUILTIN(__builtin_vsx_xvrspiz, "V4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvrdpiz, "V2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvrspiz, "V4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvmaddadp, "V2dV2dV2dV2d", "") -BUILTIN(__builtin_vsx_xvmaddasp, "V4fV4fV4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvmaddadp, "V2dV2dV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvmaddasp, "V4fV4fV4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvmsubadp, "V2dV2dV2dV2d", "") -BUILTIN(__builtin_vsx_xvmsubasp, "V4fV4fV4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvmsubadp, "V2dV2dV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvmsubasp, "V4fV4fV4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvmuldp, "V2dV2dV2d", "") -BUILTIN(__builtin_vsx_xvmulsp, "V4fV4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvmuldp, "V2dV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvmulsp, "V4fV4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvnmaddadp, "V2dV2dV2dV2d", "") -BUILTIN(__builtin_vsx_xvnmaddasp, "V4fV4fV4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvnmaddadp, "V2dV2dV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvnmaddasp, "V4fV4fV4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvnmsubadp, "V2dV2dV2dV2d", "") -BUILTIN(__builtin_vsx_xvnmsubasp, "V4fV4fV4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvnmsubadp, "V2dV2dV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvnmsubasp, "V4fV4fV4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvredp, "V2dV2d", "") -BUILTIN(__builtin_vsx_xvresp, "V4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvredp, "V2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvresp, "V4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvrsqrtedp, "V2dV2d", "") -BUILTIN(__builtin_vsx_xvrsqrtesp, "V4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvrsqrtedp, "V2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvrsqrtesp, "V4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvsqrtdp, "V2dV2d", "") -BUILTIN(__builtin_vsx_xvsqrtsp, "V4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvsqrtdp, "V2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvsqrtsp, "V4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xxleqv, "V4UiV4UiV4Ui", "") +TARGET_BUILTIN(__builtin_vsx_xxleqv, "V4UiV4UiV4Ui", "", "power8-vector") -BUILTIN(__builtin_vsx_xvcpsgndp, "V2dV2dV2d", "") -BUILTIN(__builtin_vsx_xvcpsgnsp, "V4fV4fV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvcpsgndp, "V2dV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcpsgnsp, "V4fV4fV4f", "", "vsx") -BUILTIN(__builtin_vsx_xvabssp, "V4fV4f", "") -BUILTIN(__builtin_vsx_xvabsdp, "V2dV2d", "") +TARGET_BUILTIN(__builtin_vsx_xvabssp, "V4fV4f", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvabsdp, "V2dV2d", "", "vsx") -BUILTIN(__builtin_vsx_xxgenpcvbm, "V16UcV16Uci", "") -BUILTIN(__builtin_vsx_xxgenpcvhm, "V8UsV8Usi", "") -BUILTIN(__builtin_vsx_xxgenpcvwm, "V4UiV4Uii", "") -BUILTIN(__builtin_vsx_xxgenpcvdm, "V2ULLiV2ULLii", "") +TARGET_BUILTIN(__builtin_vsx_xxgenpcvbm, "V16UcV16Uci", "", "power10-vector") +TARGET_BUILTIN(__builtin_vsx_xxgenpcvhm, "V8UsV8Usi", "", "power10-vector") +TARGET_BUILTIN(__builtin_vsx_xxgenpcvwm, "V4UiV4Uii", "", "power10-vector") +TARGET_BUILTIN(__builtin_vsx_xxgenpcvdm, "V2ULLiV2ULLii", "", "power10-vector") // vector Insert/Extract exponent/significand builtins -BUILTIN(__builtin_vsx_xviexpdp, "V2dV2ULLiV2ULLi", "") -BUILTIN(__builtin_vsx_xviexpsp, "V4fV4UiV4Ui", "") -BUILTIN(__builtin_vsx_xvxexpdp, "V2ULLiV2d", "") -BUILTIN(__builtin_vsx_xvxexpsp, "V4UiV4f", "") -BUILTIN(__builtin_vsx_xvxsigdp, "V2ULLiV2d", "") -BUILTIN(__builtin_vsx_xvxsigsp, "V4UiV4f", "") +TARGET_BUILTIN(__builtin_vsx_xviexpdp, "V2dV2ULLiV2ULLi", "", "power9-vector") +TARGET_BUILTIN(__builtin_vsx_xviexpsp, "V4fV4UiV4Ui", "", "power9-vector") +TARGET_BUILTIN(__builtin_vsx_xvxexpdp, "V2ULLiV2d", "", "power9-vector") +TARGET_BUILTIN(__builtin_vsx_xvxexpsp, "V4UiV4f", "", "power9-vector") +TARGET_BUILTIN(__builtin_vsx_xvxsigdp, "V2ULLiV2d", "", "power9-vector") +TARGET_BUILTIN(__builtin_vsx_xvxsigsp, "V4UiV4f", "", "power9-vector") // Conversion builtins -BUILTIN(__builtin_vsx_xvcvdpsxws, "V4SiV2d", "") -BUILTIN(__builtin_vsx_xvcvdpuxws, "V4UiV2d", "") -BUILTIN(__builtin_vsx_xvcvspsxds, "V2SLLiV4f", "") -BUILTIN(__builtin_vsx_xvcvspuxds, "V2ULLiV4f", "") -BUILTIN(__builtin_vsx_xvcvsxwdp, "V2dV4Si", "") -BUILTIN(__builtin_vsx_xvcvuxwdp, "V2dV4Ui", "") -BUILTIN(__builtin_vsx_xvcvspdp, "V2dV4f", "") -BUILTIN(__builtin_vsx_xvcvsxdsp, "V4fV2SLLi", "") -BUILTIN(__builtin_vsx_xvcvuxdsp, "V4fV2ULLi", "") -BUILTIN(__builtin_vsx_xvcvdpsp, "V4fV2d", "") - -BUILTIN(__builtin_vsx_xvcvsphp, "V4fV4f", "") -BUILTIN(__builtin_vsx_xvcvhpsp, "V4fV8Us", "") - -BUILTIN(__builtin_vsx_xvcvspbf16, "V16UcV16Uc", "") -BUILTIN(__builtin_vsx_xvcvbf16spn, "V16UcV16Uc", "") +TARGET_BUILTIN(__builtin_vsx_xvcvdpsxws, "V4SiV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcvdpuxws, "V4UiV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcvspsxds, "V2SLLiV4f", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcvspuxds, "V2ULLiV4f", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcvsxwdp, "V2dV4Si", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcvuxwdp, "V2dV4Ui", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcvspdp, "V2dV4f", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcvsxdsp, "V4fV2SLLi", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcvuxdsp, "V4fV2ULLi", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvcvdpsp, "V4fV2d", "", "vsx") + +TARGET_BUILTIN(__builtin_vsx_xvcvsphp, "V4fV4f", "", "power9-vector") +TARGET_BUILTIN(__builtin_vsx_xvcvhpsp, "V4fV8Us", "", "power9-vector") + +TARGET_BUILTIN(__builtin_vsx_xvcvspbf16, "V16UcV16Uc", "", "power10-vector") +TARGET_BUILTIN(__builtin_vsx_xvcvbf16spn, "V16UcV16Uc", "", "power10-vector") // Vector Test Data Class builtins -BUILTIN(__builtin_vsx_xvtstdcdp, "V2ULLiV2dIi", "") -BUILTIN(__builtin_vsx_xvtstdcsp, "V4UiV4fIi", "") +TARGET_BUILTIN(__builtin_vsx_xvtstdcdp, "V2ULLiV2dIi", "", "power9-vector") +TARGET_BUILTIN(__builtin_vsx_xvtstdcsp, "V4UiV4fIi", "", "power9-vector") -BUILTIN(__builtin_vsx_insertword, "V16UcV4UiV16UcIi", "") -BUILTIN(__builtin_vsx_extractuword, "V2ULLiV16UcIi", "") +TARGET_BUILTIN(__builtin_vsx_insertword, "V16UcV4UiV16UcIi", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_extractuword, "V2ULLiV16UcIi", "", "vsx") -BUILTIN(__builtin_vsx_xxpermdi, "v.", "t") -BUILTIN(__builtin_vsx_xxsldwi, "v.", "t") +TARGET_BUILTIN(__builtin_vsx_xxpermdi, "v.", "t", "vsx") +TARGET_BUILTIN(__builtin_vsx_xxsldwi, "v.", "t", "vsx") -BUILTIN(__builtin_vsx_xxeval, "V2ULLiV2ULLiV2ULLiV2ULLiIi", "") +TARGET_BUILTIN(__builtin_vsx_xxeval, "V2ULLiV2ULLiV2ULLiV2ULLiIi", "", + "power10-vector") -BUILTIN(__builtin_vsx_xvtlsbb, "iV16UcUi", "") +TARGET_BUILTIN(__builtin_vsx_xvtlsbb, "iV16UcUi", "", "power10-vector") -BUILTIN(__builtin_vsx_xvtdivdp, "iV2dV2d", "") -BUILTIN(__builtin_vsx_xvtdivsp, "iV4fV4f", "") -BUILTIN(__builtin_vsx_xvtsqrtdp, "iV2d", "") -BUILTIN(__builtin_vsx_xvtsqrtsp, "iV4f", "") +TARGET_BUILTIN(__builtin_vsx_xvtdivdp, "iV2dV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvtdivsp, "iV4fV4f", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvtsqrtdp, "iV2d", "", "vsx") +TARGET_BUILTIN(__builtin_vsx_xvtsqrtsp, "iV4f", "", "vsx") // P10 Vector Permute Extended built-in. -BUILTIN(__builtin_vsx_xxpermx, "V16UcV16UcV16UcV16UcIi", "") +TARGET_BUILTIN(__builtin_vsx_xxpermx, "V16UcV16UcV16UcV16UcIi", "", + "power10-vector") // P10 Vector Blend built-ins. -BUILTIN(__builtin_vsx_xxblendvb, "V16UcV16UcV16UcV16Uc", "") -BUILTIN(__builtin_vsx_xxblendvh, "V8UsV8UsV8UsV8Us", "") -BUILTIN(__builtin_vsx_xxblendvw, "V4UiV4UiV4UiV4Ui", "") -BUILTIN(__builtin_vsx_xxblendvd, "V2ULLiV2ULLiV2ULLiV2ULLi", "") +TARGET_BUILTIN(__builtin_vsx_xxblendvb, "V16UcV16UcV16UcV16Uc", "", + "power10-vector") +TARGET_BUILTIN(__builtin_vsx_xxblendvh, "V8UsV8UsV8UsV8Us", "", + "power10-vector") +TARGET_BUILTIN(__builtin_vsx_xxblendvw, "V4UiV4UiV4UiV4Ui", "", + "power10-vector") +TARGET_BUILTIN(__builtin_vsx_xxblendvd, "V2ULLiV2ULLiV2ULLiV2ULLi", "", + "power10-vector") // Float 128 built-ins -BUILTIN(__builtin_sqrtf128_round_to_odd, "LLdLLd", "") -BUILTIN(__builtin_addf128_round_to_odd, "LLdLLdLLd", "") -BUILTIN(__builtin_subf128_round_to_odd, "LLdLLdLLd", "") -BUILTIN(__builtin_mulf128_round_to_odd, "LLdLLdLLd", "") -BUILTIN(__builtin_divf128_round_to_odd, "LLdLLdLLd", "") -BUILTIN(__builtin_fmaf128_round_to_odd, "LLdLLdLLdLLd", "") -BUILTIN(__builtin_truncf128_round_to_odd, "dLLd", "") -BUILTIN(__builtin_vsx_scalar_extract_expq, "ULLiLLd", "") -BUILTIN(__builtin_vsx_scalar_insert_exp_qp, "LLdLLdULLi", "") +TARGET_BUILTIN(__builtin_sqrtf128_round_to_odd, "LLdLLd", "", "float128") +TARGET_BUILTIN(__builtin_addf128_round_to_odd, "LLdLLdLLd", "", "float128") +TARGET_BUILTIN(__builtin_subf128_round_to_odd, "LLdLLdLLd", "", "float128") +TARGET_BUILTIN(__builtin_mulf128_round_to_odd, "LLdLLdLLd", "", "float128") +TARGET_BUILTIN(__builtin_divf128_round_to_odd, "LLdLLdLLd", "", "float128") +TARGET_BUILTIN(__builtin_fmaf128_round_to_odd, "LLdLLdLLdLLd", "", "float128") +TARGET_BUILTIN(__builtin_truncf128_round_to_odd, "dLLd", "", "float128") +TARGET_BUILTIN(__builtin_vsx_scalar_extract_expq, "ULLiLLd", "", "float128") +TARGET_BUILTIN(__builtin_vsx_scalar_insert_exp_qp, "LLdLLdULLi", "", "float128") // Fastmath by default builtins BUILTIN(__builtin_ppc_rsqrtf, "V4fV4f", "") @@ -763,60 +883,60 @@ BUILTIN(__builtin_ppc_recipdivf, "V4fV4fV4f", "") BUILTIN(__builtin_ppc_recipdivd, "V2dV2dV2d", "") // HTM builtins -BUILTIN(__builtin_tbegin, "UiUIi", "") -BUILTIN(__builtin_tend, "UiUIi", "") +TARGET_BUILTIN(__builtin_tbegin, "UiUIi", "", "htm") +TARGET_BUILTIN(__builtin_tend, "UiUIi", "", "htm") -BUILTIN(__builtin_tabort, "UiUi", "") -BUILTIN(__builtin_tabortdc, "UiUiUiUi", "") -BUILTIN(__builtin_tabortdci, "UiUiUii", "") -BUILTIN(__builtin_tabortwc, "UiUiUiUi", "") -BUILTIN(__builtin_tabortwci, "UiUiUii", "") +TARGET_BUILTIN(__builtin_tabort, "UiUi", "", "htm") +TARGET_BUILTIN(__builtin_tabortdc, "UiUiUiUi", "", "htm") +TARGET_BUILTIN(__builtin_tabortdci, "UiUiUii", "", "htm") +TARGET_BUILTIN(__builtin_tabortwc, "UiUiUiUi", "", "htm") +TARGET_BUILTIN(__builtin_tabortwci, "UiUiUii", "", "htm") -BUILTIN(__builtin_tcheck, "Ui", "") -BUILTIN(__builtin_treclaim, "UiUi", "") -BUILTIN(__builtin_trechkpt, "Ui", "") -BUILTIN(__builtin_tsr, "UiUi", "") +TARGET_BUILTIN(__builtin_tcheck, "Ui", "", "htm") +TARGET_BUILTIN(__builtin_treclaim, "UiUi", "", "htm") +TARGET_BUILTIN(__builtin_trechkpt, "Ui", "", "htm") +TARGET_BUILTIN(__builtin_tsr, "UiUi", "", "htm") -BUILTIN(__builtin_tendall, "Ui", "") -BUILTIN(__builtin_tresume, "Ui", "") -BUILTIN(__builtin_tsuspend, "Ui", "") +TARGET_BUILTIN(__builtin_tendall, "Ui", "", "htm") +TARGET_BUILTIN(__builtin_tresume, "Ui", "", "htm") +TARGET_BUILTIN(__builtin_tsuspend, "Ui", "", "htm") -BUILTIN(__builtin_get_texasr, "LUi", "c") -BUILTIN(__builtin_get_texasru, "LUi", "c") -BUILTIN(__builtin_get_tfhar, "LUi", "c") -BUILTIN(__builtin_get_tfiar, "LUi", "c") +TARGET_BUILTIN(__builtin_get_texasr, "LUi", "c", "htm") +TARGET_BUILTIN(__builtin_get_texasru, "LUi", "c", "htm") +TARGET_BUILTIN(__builtin_get_tfhar, "LUi", "c", "htm") +TARGET_BUILTIN(__builtin_get_tfiar, "LUi", "c", "htm") -BUILTIN(__builtin_set_texasr, "vLUi", "c") -BUILTIN(__builtin_set_texasru, "vLUi", "c") -BUILTIN(__builtin_set_tfhar, "vLUi", "c") -BUILTIN(__builtin_set_tfiar, "vLUi", "c") +TARGET_BUILTIN(__builtin_set_texasr, "vLUi", "c", "htm") +TARGET_BUILTIN(__builtin_set_texasru, "vLUi", "c", "htm") +TARGET_BUILTIN(__builtin_set_tfhar, "vLUi", "c", "htm") +TARGET_BUILTIN(__builtin_set_tfiar, "vLUi", "c", "htm") -BUILTIN(__builtin_ttest, "LUi", "") +TARGET_BUILTIN(__builtin_ttest, "LUi", "", "htm") // Scalar built-ins -BUILTIN(__builtin_divwe, "SiSiSi", "") -BUILTIN(__builtin_divweu, "UiUiUi", "") -BUILTIN(__builtin_divde, "SLLiSLLiSLLi", "") -BUILTIN(__builtin_divdeu, "ULLiULLiULLi", "") -BUILTIN(__builtin_bpermd, "SLLiSLLiSLLi", "") -BUILTIN(__builtin_pdepd, "ULLiULLiULLi", "") -BUILTIN(__builtin_pextd, "ULLiULLiULLi", "") -BUILTIN(__builtin_cfuged, "ULLiULLiULLi", "") -BUILTIN(__builtin_cntlzdm, "ULLiULLiULLi", "") -BUILTIN(__builtin_cnttzdm, "ULLiULLiULLi", "") +TARGET_BUILTIN(__builtin_divwe, "SiSiSi", "", "extdiv") +TARGET_BUILTIN(__builtin_divweu, "UiUiUi", "", "extdiv") +TARGET_BUILTIN(__builtin_divde, "SLLiSLLiSLLi", "", "extdiv") +TARGET_BUILTIN(__builtin_divdeu, "ULLiULLiULLi", "", "extdiv") +TARGET_BUILTIN(__builtin_bpermd, "SLLiSLLiSLLi", "", "bpermd") +TARGET_BUILTIN(__builtin_pdepd, "ULLiULLiULLi", "", "isa-v31-instructions") +TARGET_BUILTIN(__builtin_pextd, "ULLiULLiULLi", "", "isa-v31-instructions") +TARGET_BUILTIN(__builtin_cfuged, "ULLiULLiULLi", "", "isa-v31-instructions") +TARGET_BUILTIN(__builtin_cntlzdm, "ULLiULLiULLi", "", "isa-v31-instructions") +TARGET_BUILTIN(__builtin_cnttzdm, "ULLiULLiULLi", "", "isa-v31-instructions") // Double-double (un)pack BUILTIN(__builtin_unpack_longdouble, "dLdIi", "") BUILTIN(__builtin_pack_longdouble, "Lddd", "") // Generate random number -BUILTIN(__builtin_darn, "LLi", "") -BUILTIN(__builtin_darn_raw, "LLi", "") -BUILTIN(__builtin_darn_32, "i", "") +TARGET_BUILTIN(__builtin_darn, "LLi", "", "isa-v30-instructions") +TARGET_BUILTIN(__builtin_darn_raw, "LLi", "", "isa-v30-instructions") +TARGET_BUILTIN(__builtin_darn_32, "i", "", "isa-v30-instructions") // Vector int128 (un)pack -BUILTIN(__builtin_unpack_vector_int128, "ULLiV1LLLii", "") -BUILTIN(__builtin_pack_vector_int128, "V1LLLiULLiULLi", "") +TARGET_BUILTIN(__builtin_unpack_vector_int128, "ULLiV1LLLii", "", "vsx") +TARGET_BUILTIN(__builtin_pack_vector_int128, "V1LLLiULLiULLi", "", "vsx") // Set the floating point rounding mode BUILTIN(__builtin_setrnd, "di", "") @@ -850,86 +970,159 @@ BUILTIN(__builtin_dcbf, "vvC*", "") // its given accumulator. // Provided builtins with _mma_ prefix for compatibility. -CUSTOM_BUILTIN(mma_lxvp, vsx_lxvp, "W256SLiW256C*", false) -CUSTOM_BUILTIN(mma_stxvp, vsx_stxvp, "vW256SLiW256*", false) -CUSTOM_BUILTIN(mma_assemble_pair, vsx_assemble_pair, "vW256*VV", false) -CUSTOM_BUILTIN(mma_disassemble_pair, vsx_disassemble_pair, "vv*W256*", false) -CUSTOM_BUILTIN(vsx_build_pair, vsx_assemble_pair, "vW256*VV", false) -CUSTOM_BUILTIN(mma_build_acc, mma_assemble_acc, "vW512*VVVV", false) +CUSTOM_BUILTIN(mma_lxvp, vsx_lxvp, "W256SLiW256C*", false, + "paired-vector-memops") +CUSTOM_BUILTIN(mma_stxvp, vsx_stxvp, "vW256SLiW256*", false, + "paired-vector-memops") +CUSTOM_BUILTIN(mma_assemble_pair, vsx_assemble_pair, "vW256*VV", false, + "paired-vector-memops") +CUSTOM_BUILTIN(mma_disassemble_pair, vsx_disassemble_pair, "vv*W256*", false, + "paired-vector-memops") +CUSTOM_BUILTIN(vsx_build_pair, vsx_assemble_pair, "vW256*VV", false, + "paired-vector-memops") +CUSTOM_BUILTIN(mma_build_acc, mma_assemble_acc, "vW512*VVVV", false, "mma") // UNALIASED_CUSTOM_BUILTIN macro is used for built-ins that have // the same name as that of the intrinsic they generate, i.e. the // ID and INTR are the same. // This avoids repeating the ID and INTR in the macro expression. -UNALIASED_CUSTOM_BUILTIN(vsx_lxvp, "W256SLiW256C*", false) -UNALIASED_CUSTOM_BUILTIN(vsx_stxvp, "vW256SLiW256*", false) -UNALIASED_CUSTOM_BUILTIN(vsx_assemble_pair, "vW256*VV", false) -UNALIASED_CUSTOM_BUILTIN(vsx_disassemble_pair, "vv*W256*", false) - -UNALIASED_CUSTOM_BUILTIN(mma_assemble_acc, "vW512*VVVV", false) -UNALIASED_CUSTOM_BUILTIN(mma_disassemble_acc, "vv*W512*", false) -UNALIASED_CUSTOM_BUILTIN(mma_xxmtacc, "vW512*", true) -UNALIASED_CUSTOM_BUILTIN(mma_xxmfacc, "vW512*", true) -UNALIASED_CUSTOM_BUILTIN(mma_xxsetaccz, "vW512*", false) -UNALIASED_CUSTOM_BUILTIN(mma_xvi4ger8, "vW512*VV", false) -UNALIASED_CUSTOM_BUILTIN(mma_xvi8ger4, "vW512*VV", false) -UNALIASED_CUSTOM_BUILTIN(mma_xvi16ger2, "vW512*VV", false) -UNALIASED_CUSTOM_BUILTIN(mma_xvi16ger2s, "vW512*VV", false) -UNALIASED_CUSTOM_BUILTIN(mma_xvf16ger2, "vW512*VV", false) -UNALIASED_CUSTOM_BUILTIN(mma_xvf32ger, "vW512*VV", false) -UNALIASED_CUSTOM_BUILTIN(mma_xvf64ger, "vW512*W256V", false) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvi4ger8, "vW512*VVi15i15i255", false) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvi8ger4, "vW512*VVi15i15i15", false) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvi16ger2, "vW512*VVi15i15i3", false) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvi16ger2s, "vW512*VVi15i15i3", false) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf16ger2, "vW512*VVi15i15i3", false) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf32ger, "vW512*VVi15i15", false) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf64ger, "vW512*W256Vi15i3", false) -UNALIASED_CUSTOM_BUILTIN(mma_xvi4ger8pp, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvi8ger4pp, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvi8ger4spp, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvi16ger2pp, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvi16ger2spp, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvi4ger8pp, "vW512*VVi15i15i255", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvi8ger4pp, "vW512*VVi15i15i15", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvi8ger4spp, "vW512*VVi15i15i15", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvi16ger2pp, "vW512*VVi15i15i3", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvi16ger2spp, "vW512*VVi15i15i3", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvf16ger2pp, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvf16ger2pn, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvf16ger2np, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvf16ger2nn, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf16ger2pp, "vW512*VVi15i15i3", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf16ger2pn, "vW512*VVi15i15i3", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf16ger2np, "vW512*VVi15i15i3", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf16ger2nn, "vW512*VVi15i15i3", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvf32gerpp, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvf32gerpn, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvf32gernp, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvf32gernn, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf32gerpp, "vW512*VVi15i15", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf32gerpn, "vW512*VVi15i15", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf32gernp, "vW512*VVi15i15", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf32gernn, "vW512*VVi15i15", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvf64gerpp, "vW512*W256V", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvf64gerpn, "vW512*W256V", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvf64gernp, "vW512*W256V", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvf64gernn, "vW512*W256V", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf64gerpp, "vW512*W256Vi15i3", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf64gerpn, "vW512*W256Vi15i3", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf64gernp, "vW512*W256Vi15i3", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvf64gernn, "vW512*W256Vi15i3", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvbf16ger2, "vW512*VV", false) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvbf16ger2, "vW512*VVi15i15i3", false) -UNALIASED_CUSTOM_BUILTIN(mma_xvbf16ger2pp, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvbf16ger2pn, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvbf16ger2np, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_xvbf16ger2nn, "vW512*VV", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvbf16ger2pp, "vW512*VVi15i15i3", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvbf16ger2pn, "vW512*VVi15i15i3", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvbf16ger2np, "vW512*VVi15i15i3", true) -UNALIASED_CUSTOM_BUILTIN(mma_pmxvbf16ger2nn, "vW512*VVi15i15i3", true) +UNALIASED_CUSTOM_BUILTIN(vsx_lxvp, "W256SLiW256C*", false, + "paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(vsx_stxvp, "vW256SLiW256*", false, + "paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(vsx_assemble_pair, "vW256*VV", false, + "paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(vsx_disassemble_pair, "vv*W256*", false, + "paired-vector-memops") + +// TODO: Require only mma after backend supports these without paired memops +UNALIASED_CUSTOM_BUILTIN(mma_assemble_acc, "vW512*VVVV", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_disassemble_acc, "vv*W512*", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xxmtacc, "vW512*", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xxmfacc, "vW512*", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xxsetaccz, "vW512*", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvi4ger8, "vW512*VV", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvi8ger4, "vW512*VV", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvi16ger2, "vW512*VV", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvi16ger2s, "vW512*VV", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf16ger2, "vW512*VV", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf32ger, "vW512*VV", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf64ger, "vW512*W256V", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvi4ger8, "vW512*VVi15i15i255", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvi8ger4, "vW512*VVi15i15i15", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvi16ger2, "vW512*VVi15i15i3", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvi16ger2s, "vW512*VVi15i15i3", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf16ger2, "vW512*VVi15i15i3", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf32ger, "vW512*VVi15i15", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf64ger, "vW512*W256Vi15i3", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvi4ger8pp, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvi8ger4pp, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvi8ger4spp, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvi16ger2pp, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvi16ger2spp, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvi4ger8pp, "vW512*VVi15i15i255", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvi8ger4pp, "vW512*VVi15i15i15", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvi8ger4spp, "vW512*VVi15i15i15", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvi16ger2pp, "vW512*VVi15i15i3", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvi16ger2spp, "vW512*VVi15i15i3", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf16ger2pp, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf16ger2pn, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf16ger2np, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf16ger2nn, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf16ger2pp, "vW512*VVi15i15i3", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf16ger2pn, "vW512*VVi15i15i3", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf16ger2np, "vW512*VVi15i15i3", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf16ger2nn, "vW512*VVi15i15i3", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf32gerpp, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf32gerpn, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf32gernp, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf32gernn, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf32gerpp, "vW512*VVi15i15", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf32gerpn, "vW512*VVi15i15", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf32gernp, "vW512*VVi15i15", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf32gernn, "vW512*VVi15i15", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf64gerpp, "vW512*W256V", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf64gerpn, "vW512*W256V", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf64gernp, "vW512*W256V", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvf64gernn, "vW512*W256V", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf64gerpp, "vW512*W256Vi15i3", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf64gerpn, "vW512*W256Vi15i3", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf64gernp, "vW512*W256Vi15i3", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvf64gernn, "vW512*W256Vi15i3", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvbf16ger2, "vW512*VV", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvbf16ger2, "vW512*VVi15i15i3", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvbf16ger2pp, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvbf16ger2pn, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvbf16ger2np, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_xvbf16ger2nn, "vW512*VV", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvbf16ger2pp, "vW512*VVi15i15i3", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvbf16ger2pn, "vW512*VVi15i15i3", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvbf16ger2np, "vW512*VVi15i15i3", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmxvbf16ger2nn, "vW512*VVi15i15i3", true, + "mma,paired-vector-memops") // FIXME: Obviously incomplete. diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 80cb432cc106b..c4aeb7ff08d23 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -52,6 +52,7 @@ CODEGENOPT(UniqueBasicBlockSectionNames, 1, 1) ///< Set for -funique-basic-block ///< Produce unique section names with ///< basic block sections. CODEGENOPT(EnableAIXExtendedAltivecABI, 1, 0) ///< Set for -mabi=vec-extabi. Enables the extended Altivec ABI on AIX. +CODEGENOPT(XCOFFReadOnlyPointers, 1, 0) ///< Set for -mxcoff-roptr. ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,none CODEGENOPT(ClearASTBeforeBackend , 1, 0) ///< Free the AST before running backend code generation. Only works with -disable-free. diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h index 8ff28944f23d5..2b8fc2a0bb1c3 100644 --- a/clang/include/clang/Basic/Cuda.h +++ b/clang/include/clang/Basic/Cuda.h @@ -92,6 +92,8 @@ enum class CudaArch { GFX90a, GFX90c, GFX940, + GFX941, + GFX942, GFX1010, GFX1011, GFX1012, diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index aebef434d717e..237246b22e8e4 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -125,6 +125,9 @@ def warn_drv_unsupported_option_for_flang : Warning< def warn_drv_unsupported_diag_option_for_flang : Warning< "The warning option '-%0' is not supported">, InGroup; +def warn_drv_unsupported_option_for_processor : Warning< + "ignoring '%0' option as it is not currently supported for processor '%1'">, + InGroup; def err_drv_invalid_thread_model_for_target : Error< "invalid thread model '%0' in '%1' for this target">; @@ -697,6 +700,8 @@ def err_drv_invalid_object_mode : Error< "OBJECT_MODE setting %0 is not recognized and is not a valid setting">; def err_aix_unsupported_tls_model : Error<"TLS model '%0' is not yet supported on AIX">; +def err_roptr_requires_data_sections: Error<"-mxcoff-roptr is supported only with -fdata-sections">; +def err_roptr_cannot_build_shared: Error<"-mxcoff-roptr is not supported with -shared">; def err_invalid_cxx_abi : Error<"invalid C++ ABI name '%0'">; def err_unsupported_cxx_abi : Error<"C++ ABI '%0' is not supported on target triple '%1'">; diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index b0c072620025d..7795b998027bc 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -312,6 +312,11 @@ def : DiagGroup<"c++98-c++11-c++14-c++17-compat-pedantic", def CXXPre23Compat : DiagGroup<"pre-c++23-compat">; def CXXPre23CompatPedantic : DiagGroup<"pre-c++23-compat-pedantic", [CXXPre23Compat]>; +def CXXPre26Compat : DiagGroup<"pre-c++26-compat">; +def CXXPre26CompatPedantic : + DiagGroup<"pre-c++26-compat-pedantic", [CXXPre26Compat]>; +def : DiagGroup<"pre-c++2c-compat", [CXXPre26Compat]>; +def : DiagGroup<"pre-c++2c-compat-pedantic", [CXXPre26CompatPedantic]>; def CXX98CompatBindToTemporaryCopy : DiagGroup<"c++98-compat-bind-to-temporary-copy">; @@ -1120,10 +1125,16 @@ def CXX20 : DiagGroup<"c++20-extensions", [CXX20Designator, CXX20Attrs]>; // earlier C++ versions. def CXX23 : DiagGroup<"c++23-extensions">; +// A warning group for warnings about using C++26 features as extensions in +// earlier C++ versions. +def CXX26 : DiagGroup<"c++26-extensions">; + def : DiagGroup<"c++0x-extensions", [CXX11]>; def : DiagGroup<"c++1y-extensions", [CXX14]>; def : DiagGroup<"c++1z-extensions", [CXX17]>; def : DiagGroup<"c++2a-extensions", [CXX20]>; +def : DiagGroup<"c++2b-extensions", [CXX23]>; +def : DiagGroup<"c++2c-extensions", [CXX26]>; def DelegatingCtorCycles : DiagGroup<"delegating-ctor-cycles">; @@ -1198,6 +1209,7 @@ def MicrosoftCommentPaste : DiagGroup<"microsoft-comment-paste">; def MicrosoftEndOfFile : DiagGroup<"microsoft-end-of-file">; def MicrosoftInaccessibleBase : DiagGroup<"microsoft-inaccessible-base">; def MicrosoftStaticAssert : DiagGroup<"microsoft-static-assert">; +def MicrosoftInitFromPredefined : DiagGroup<"microsoft-init-from-predefined">; // Aliases. def : DiagGroup<"msvc-include", [MicrosoftInclude]>; @@ -1215,7 +1227,7 @@ def Microsoft : DiagGroup<"microsoft", MicrosoftFlexibleArray, MicrosoftExtraQualification, MicrosoftCast, MicrosoftConstInit, MicrosoftVoidPseudoDtor, MicrosoftAnonTag, MicrosoftCommentPaste, MicrosoftEndOfFile, MicrosoftStaticAssert, - MicrosoftInconsistentDllImport]>; + MicrosoftInitFromPredefined, MicrosoftInconsistentDllImport]>; def ClangClPch : DiagGroup<"clang-cl-pch">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 045423096eb12..ded3725c584c0 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -112,6 +112,9 @@ def err_expr_not_string_literal : Error<"expression is not a string literal">; def ext_predef_outside_function : Warning< "predefined identifier is only valid inside function">, InGroup>; +def ext_init_from_predefined : ExtWarn< + "initializing an array from a '%0' predefined identifier is a Microsoft extension">, + InGroup; def warn_float_overflow : Warning< "magnitude of floating-point constant too large for type %0; maximum is %1">, InGroup; @@ -5380,6 +5383,8 @@ def note_constraint_normalization_here : Note< def note_parameter_mapping_substitution_here : Note< "while substituting into concept arguments here; substitution failures not " "allowed in concept arguments">; +def note_lambda_substitution_here : Note< + "while substituting into a lambda expression here">; def note_instantiation_contexts_suppressed : Note< "(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to " "see all)">; @@ -10118,12 +10123,6 @@ def err_mips_builtin_requires_dspr2 : Error< "this builtin requires 'dsp r2' ASE, please use -mdspr2">; def err_mips_builtin_requires_msa : Error< "this builtin requires 'msa' ASE, please use -mmsa">; -def err_ppc_builtin_only_on_arch : Error< - "this builtin is only valid on POWER%0 or later CPUs">; -def err_ppc_builtin_requires_vsx : Error< - "this builtin requires VSX to be enabled">; -def err_ppc_builtin_requires_htm : Error< - "this builtin requires HTM to be enabled">; def err_ppc_builtin_requires_abi : Error< "this builtin requires ABI -mabi=%0">; def err_ppc_invalid_use_mma_type : Error< diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 9ce67959439f5..eca98352b7c83 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -98,6 +98,7 @@ LANGOPT(CPlusPlus14 , 1, 0, "C++14") LANGOPT(CPlusPlus17 , 1, 0, "C++17") LANGOPT(CPlusPlus20 , 1, 0, "C++20") LANGOPT(CPlusPlus23 , 1, 0, "C++23") +LANGOPT(CPlusPlus26 , 1, 0, "C++26") LANGOPT(ObjC , 1, 0, "Objective-C") BENIGN_LANGOPT(ObjCDefaultSynthProperties , 1, 0, "Objective-C auto-synthesized properties") diff --git a/clang/include/clang/Basic/LangStandard.h b/clang/include/clang/Basic/LangStandard.h index ebe14c8a3f8fd..fd949bcd68555 100644 --- a/clang/include/clang/Basic/LangStandard.h +++ b/clang/include/clang/Basic/LangStandard.h @@ -56,11 +56,12 @@ enum LangFeatures { CPlusPlus17 = (1 << 8), CPlusPlus20 = (1 << 9), CPlusPlus23 = (1 << 10), - Digraphs = (1 << 11), - GNUMode = (1 << 12), - HexFloat = (1 << 13), - OpenCL = (1 << 14), - HLSL = (1 << 15) + CPlusPlus26 = (1 << 11), + Digraphs = (1 << 12), + GNUMode = (1 << 13), + HexFloat = (1 << 14), + OpenCL = (1 << 15), + HLSL = (1 << 16) }; /// LangStandard - Information about the properties of a particular language @@ -121,6 +122,9 @@ struct LangStandard { /// isCPlusPlus23 - Language is a post-C++23 variant (or later). bool isCPlusPlus23() const { return Flags & CPlusPlus23; } + /// isCPlusPlus26 - Language is a post-C++26 variant (or later). + bool isCPlusPlus26() const { return Flags & CPlusPlus26; } + /// hasDigraphs - Language supports digraphs. bool hasDigraphs() const { return Flags & Digraphs; } diff --git a/clang/include/clang/Basic/LangStandards.def b/clang/include/clang/Basic/LangStandards.def index 8e4d3759f33b7..911b626e4c966 100644 --- a/clang/include/clang/Basic/LangStandards.def +++ b/clang/include/clang/Basic/LangStandards.def @@ -163,6 +163,18 @@ LANGSTANDARD(gnucxx23, "gnu++23", CPlusPlus20 | CPlusPlus23 | Digraphs | HexFloat | GNUMode) LANGSTANDARD_ALIAS_DEPR(gnucxx23, "gnu++2b") +LANGSTANDARD(cxx26, "c++2c", + CXX, "Working draft for C++2c", + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | + CPlusPlus20 | CPlusPlus23 | CPlusPlus26 | Digraphs | HexFloat) +LANGSTANDARD_ALIAS(cxx26, "c++26") + +LANGSTANDARD(gnucxx26, "gnu++2c", + CXX, "Working draft for C++2c with GNU extensions", + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | + CPlusPlus20 | CPlusPlus23 | CPlusPlus26 | Digraphs | HexFloat | GNUMode) +LANGSTANDARD_ALIAS(gnucxx26, "gnu++26") + // OpenCL LANGSTANDARD(opencl10, "cl1.0", OpenCL, "OpenCL 1.0", diff --git a/clang/include/clang/Driver/Compilation.h b/clang/include/clang/Driver/Compilation.h index 3bb79d1e1f9ed..abeca18592bc0 100644 --- a/clang/include/clang/Driver/Compilation.h +++ b/clang/include/clang/Driver/Compilation.h @@ -112,6 +112,9 @@ class Compilation { /// only be removed if we crash. ArgStringMap FailureResultFiles; + /// -ftime-trace result files. + ArgStringMap TimeTraceFiles; + /// Optional redirection for stdin, stdout, stderr. std::vector> Redirects; @@ -272,6 +275,14 @@ class Compilation { return Name; } + const char *getTimeTraceFile(const JobAction *JA) const { + return TimeTraceFiles.lookup(JA); + } + void addTimeTraceFile(const char *Name, const JobAction *JA) { + assert(!TimeTraceFiles.contains(JA)); + TimeTraceFiles[JA] = Name; + } + /// CleanupFile - Delete a given file. /// /// \param IssueErrors - Report failures as errors. diff --git a/clang/include/clang/Driver/Distro.h b/clang/include/clang/Driver/Distro.h index 0c858b3d716f1..8291f6575a711 100644 --- a/clang/include/clang/Driver/Distro.h +++ b/clang/include/clang/Driver/Distro.h @@ -77,6 +77,7 @@ class Distro { UbuntuJammy, UbuntuKinetic, UbuntuLunar, + UbuntuMantic, UnknownDistro }; @@ -128,7 +129,7 @@ class Distro { } bool IsUbuntu() const { - return DistroVal >= UbuntuHardy && DistroVal <= UbuntuLunar; + return DistroVal >= UbuntuHardy && DistroVal <= UbuntuMantic; } bool IsAlpineLinux() const { return DistroVal == AlpineLinux; } diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 9fb719ef46469..9f1fd2f1950a6 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1180,6 +1180,10 @@ def module_dependency_dir : Separate<["-"], "module-dependency-dir">, def dsym_dir : JoinedOrSeparate<["-"], "dsym-dir">, Flags<[NoXarchOption, RenderAsInput]>, HelpText<"Directory to output dSYM's (if any) to">, MetaVarName<"">; +// GCC style -dumpdir. We intentionally don't implement the less useful -dumpbase{,-ext}. +def dumpdir : Separate<["-"], "dumpdir">, Flags<[CC1Option]>, + MetaVarName<"">, + HelpText<"Use as a prefix to form auxiliary and dump file names">; def dumpmachine : Flag<["-"], "dumpmachine">; def dumpspecs : Flag<["-"], "dumpspecs">, Flags<[Unsupported]>; def dumpversion : Flag<["-"], "dumpversion">; @@ -3167,8 +3171,7 @@ def ftime_trace : Flag<["-"], "ftime-trace">, Group, Turn on time profiler. Generates JSON file based on output filename. Results can be analyzed with chrome://tracing or `Speedscope App `_ for flamegraph visualization.}]>, - Flags<[CC1Option, CoreOption]>, - MarshallingInfoFlag>; + Flags<[CoreOption]>; def ftime_trace_granularity_EQ : Joined<["-"], "ftime-trace-granularity=">, Group, HelpText<"Minimum time granularity (in microseconds) traced by time profiler">, Flags<[CC1Option, CoreOption]>, @@ -3588,6 +3591,7 @@ def vfsoverlay : JoinedOrSeparate<["-", "--"], "vfsoverlay">, Flags<[CC1Option, HelpText<"Overlay the virtual filesystem described by file over the real file system. " "Additionally, pass this overlay file to the linker if it supports it">; def imultilib : Separate<["-"], "imultilib">, Group; +def K : Flag<["-"], "K">, Flags<[LinkerInput]>; def keep__private__externs : Flag<["-"], "keep_private_externs">; def l : JoinedOrSeparate<["-"], "l">, Flags<[LinkerInput, RenderJoined]>, Group; @@ -4070,6 +4074,9 @@ def maix_struct_return : Flag<["-"], "maix-struct-return">, def msvr4_struct_return : Flag<["-"], "msvr4-struct-return">, Group, Flags<[CC1Option]>, HelpText<"Return small structs in registers (PPC32 only)">; +def mxcoff_roptr : Flag<["-"], "mxcoff-roptr">, Group, Flags<[CC1Option]>, + HelpText<"Place constant objects with relocatable address values in the RO data section and add -bforceimprw to the linker flags (AIX only)">; +def mno_xcoff_roptr : Flag<["-"], "mno-xcoff-roptr">, Group; def mvx : Flag<["-"], "mvx">, Group; def mno_vx : Flag<["-"], "mno-vx">, Group; diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index 85183a3812b42..40aa144a0e369 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -283,9 +283,6 @@ class FrontendOptions { /// print the supported cpus for the current target unsigned PrintSupportedCPUs : 1; - /// Output time trace profile. - unsigned TimeTrace : 1; - /// Show the -version text. unsigned ShowVersion : 1; @@ -513,16 +510,16 @@ class FrontendOptions { public: FrontendOptions() : DisableFree(false), RelocatablePCH(false), ShowHelp(false), - ShowStats(false), AppendStats(false), TimeTrace(false), - ShowVersion(false), FixWhatYouCan(false), FixOnlyWarnings(false), - FixAndRecompile(false), FixToTemporaries(false), - ARCMTMigrateEmitARCErrors(false), SkipFunctionBodies(false), - UseGlobalModuleIndex(true), GenerateGlobalModuleIndex(true), - ASTDumpDecls(false), ASTDumpLookups(false), - BuildingImplicitModule(false), BuildingImplicitModuleUsesLock(true), - ModulesEmbedAllFiles(false), IncludeTimestamps(true), - UseTemporary(true), AllowPCMWithCompilerErrors(false), - ModulesShareFileManager(true), TimeTraceGranularity(500) {} + ShowStats(false), AppendStats(false), ShowVersion(false), + FixWhatYouCan(false), FixOnlyWarnings(false), FixAndRecompile(false), + FixToTemporaries(false), ARCMTMigrateEmitARCErrors(false), + SkipFunctionBodies(false), UseGlobalModuleIndex(true), + GenerateGlobalModuleIndex(true), ASTDumpDecls(false), + ASTDumpLookups(false), BuildingImplicitModule(false), + BuildingImplicitModuleUsesLock(true), ModulesEmbedAllFiles(false), + IncludeTimestamps(true), UseTemporary(true), + AllowPCMWithCompilerErrors(false), ModulesShareFileManager(true), + TimeTraceGranularity(500) {} /// getInputKindForExtension - Return the appropriate input kind for a file /// extension. For example, "c" would return Language::C. diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h index 76e3e786ff070..49fb99c1483ce 100644 --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -665,9 +665,13 @@ class HeaderSearch { /// Retrieve all the modules corresponding to the given file. /// + /// \param AllowCreation Whether to allow inference of a new submodule, or to + /// only return existing known modules. + /// /// \ref findModuleForHeader should typically be used instead of this. ArrayRef - findAllModulesForHeader(const FileEntry *File) const; + findAllModulesForHeader(const FileEntry *File, + bool AllowCreation = true) const; /// Read the contents of the given module map file. /// diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index f155c609b06cb..8f8580fd11495 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -448,9 +448,13 @@ class ModuleMap { /// and does not consult the external source. (Those checks are the /// responsibility of \ref HeaderSearch.) /// + /// \param AllowCreation Whether to allow inference of a new submodule, or to + /// only return existing known modules. + /// /// Typically, \ref findModuleForHeader should be used instead, as it picks /// the preferred module for the header. - ArrayRef findAllModulesForHeader(const FileEntry *File); + ArrayRef findAllModulesForHeader(const FileEntry *File, + bool AllowCreation = true); /// Like \ref findAllModulesForHeader, but do not attempt to infer module /// ownership from umbrella headers if we've not already done so. diff --git a/clang/include/clang/Lex/Pragma.h b/clang/include/clang/Lex/Pragma.h index cf8cca5414eac..67eca618f6c4f 100644 --- a/clang/include/clang/Lex/Pragma.h +++ b/clang/include/clang/Lex/Pragma.h @@ -123,6 +123,13 @@ class PragmaNamespace : public PragmaHandler { PragmaNamespace *getIfNamespace() override { return this; } }; +/// Destringize a \c _Pragma("") string according to C11 6.10.9.1: +/// "The string literal is destringized by deleting any encoding prefix, +/// deleting the leading and trailing double-quotes, replacing each escape +/// sequence \" by a double-quote, and replacing each escape sequence \\ by a +/// single backslash." +void prepare_PragmaString(SmallVectorImpl &StrVal); + } // namespace clang #endif // LLVM_CLANG_LEX_PRAGMA_H diff --git a/clang/include/clang/Parse/LoopHint.h b/clang/include/clang/Parse/LoopHint.h index 6e363f72b6587..75705fcd4c75c 100644 --- a/clang/include/clang/Parse/LoopHint.h +++ b/clang/include/clang/Parse/LoopHint.h @@ -23,20 +23,18 @@ struct LoopHint { // Identifier corresponding to the name of the pragma. "loop" for // "#pragma clang loop" directives and "unroll" for "#pragma unroll" // hints. - IdentifierLoc *PragmaNameLoc; + IdentifierLoc *PragmaNameLoc = nullptr; // Name of the loop hint. Examples: "unroll", "vectorize". In the // "#pragma unroll" and "#pragma nounroll" cases, this is identical to // PragmaNameLoc. - IdentifierLoc *OptionLoc; + IdentifierLoc *OptionLoc = nullptr; // Identifier for the hint state argument. If null, then the state is // default value such as for "#pragma unroll". - IdentifierLoc *StateLoc; + IdentifierLoc *StateLoc = nullptr; // Expression for the hint argument if it exists, null otherwise. - Expr *ValueExpr; + Expr *ValueExpr = nullptr; - LoopHint() - : PragmaNameLoc(nullptr), OptionLoc(nullptr), StateLoc(nullptr), - ValueExpr(nullptr) {} + LoopHint() = default; }; } // end namespace clang diff --git a/clang/include/clang/Sema/AnalysisBasedWarnings.h b/clang/include/clang/Sema/AnalysisBasedWarnings.h index 13a88bb9f8968..7d0fa9541c352 100644 --- a/clang/include/clang/Sema/AnalysisBasedWarnings.h +++ b/clang/include/clang/Sema/AnalysisBasedWarnings.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H #define LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H +#include "clang/AST/Decl.h" #include "llvm/ADT/DenseMap.h" #include @@ -23,7 +24,7 @@ class FunctionDecl; class QualType; class Sema; namespace sema { - class FunctionScopeInfo; +class FunctionScopeInfo; } namespace sema { @@ -37,6 +38,7 @@ class AnalysisBasedWarnings { unsigned enableCheckUnreachable : 1; unsigned enableThreadSafetyAnalysis : 1; unsigned enableConsumedAnalysis : 1; + public: Policy(); void disableCheckFallThrough() { enableCheckFallThrough = 0; } @@ -50,7 +52,7 @@ class AnalysisBasedWarnings { std::unique_ptr IPData; enum VisitFlag { NotVisited = 0, Visited = 1, Pending = 2 }; - llvm::DenseMap VisitedFD; + llvm::DenseMap VisitedFD; /// \name Statistics /// @{ @@ -92,8 +94,11 @@ class AnalysisBasedWarnings { AnalysisBasedWarnings(Sema &s); ~AnalysisBasedWarnings(); - void IssueWarnings(Policy P, FunctionScopeInfo *fscope, - const Decl *D, QualType BlockType); + void IssueWarnings(Policy P, FunctionScopeInfo *fscope, const Decl *D, + QualType BlockType); + + // Issue warnings that require whole-translation-unit analysis. + void IssueWarnings(TranslationUnitDecl *D); Policy getDefaultPolicy() { return DefaultPolicy; } diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index b866649bc43be..0e8b94c515f68 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -701,6 +701,7 @@ class AttributePool { AttributePool(AttributeFactory &factory) : Factory(factory) {} AttributePool(const AttributePool &) = delete; + AttributePool &operator=(const AttributePool &) = delete; ~AttributePool() { Factory.reclaimPool(*this); } @@ -917,6 +918,7 @@ class ParsedAttributes : public ParsedAttributesView { public: ParsedAttributes(AttributeFactory &factory) : pool(factory) {} ParsedAttributes(const ParsedAttributes &) = delete; + ParsedAttributes &operator=(const ParsedAttributes &) = delete; AttributePool &getPool() const { return pool; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 8b695ca09fc10..d273d6fa20ed3 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2628,9 +2628,6 @@ class Sema final { return Entity->getOwningModule(); } - // Determine whether the module M belongs to the current TU. - bool isModuleUnitOfCurrentTU(const Module *M) const; - /// Make a merged definition of an existing hidden definition \p ND /// visible at the specified location. void makeMergedDefinitionVisible(NamedDecl *ND); @@ -9544,6 +9541,9 @@ class Sema final { /// a TemplateDecl. DeducedTemplateArgumentSubstitution, + /// We are substituting into a lambda expression. + LambdaExpressionSubstitution, + /// We are substituting prior template arguments into a new /// template parameter. The template parameter itself is either a /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 48e8b78311e12..1de2cc6917b42 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -232,9 +232,21 @@ enum class TemplateSubstitutionKind : char { /// Replaces the current 'innermost' level with the provided argument list. /// This is useful for type deduction cases where we need to get the entire /// list from the AST, but then add the deduced innermost list. - void replaceInnermostTemplateArguments(ArgList Args) { - assert(TemplateArgumentLists.size() > 0 && "Replacing in an empty list?"); - TemplateArgumentLists[0].Args = Args; + void replaceInnermostTemplateArguments(Decl *AssociatedDecl, ArgList Args) { + assert((!TemplateArgumentLists.empty() || NumRetainedOuterLevels) && + "Replacing in an empty list?"); + + if (!TemplateArgumentLists.empty()) { + assert((TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer() || + TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer() == + AssociatedDecl) && + "Trying to change incorrect declaration?"); + TemplateArgumentLists[0].Args = Args; + } else { + --NumRetainedOuterLevels; + TemplateArgumentLists.push_back( + {{AssociatedDecl, /*Final=*/false}, Args}); + } } /// Add an outermost level that we are not substituting. We have no diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index c28ab81fddc00..2e3571679c505 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1153,6 +1153,13 @@ ArrayRef ASTContext::getModuleInitializers(Module *M) { return Inits->Initializers; } +void ASTContext::setCurrentNamedModule(Module *M) { + assert(M->isModulePurview()); + assert(!CurrentCXXNamedModule && + "We should set named module for ASTContext for only once"); + CurrentCXXNamedModule = M; +} + ExternCContextDecl *ASTContext::getExternCContextDecl() const { if (!ExternCContext) ExternCContext = ExternCContextDecl::Create(*this, getTranslationUnitDecl()); @@ -11960,6 +11967,10 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { !isMSStaticDataMemberInlineDefinition(VD)) return false; + // Variables in other module units shouldn't be forced to be emitted. + if (VD->isInAnotherModuleUnit()) + return false; + // Variables that can be needed in other TUs are required. auto Linkage = GetGVALinkageForVariable(VD); if (!isDiscardableGVALinkage(Linkage)) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index e5981cf1fce43..7eeddadc26f4a 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -7074,7 +7074,8 @@ ExpectedStmt ASTNodeImporter::VisitPredefinedExpr(PredefinedExpr *E) { return std::move(Err); return PredefinedExpr::Create(Importer.getToContext(), ToBeginLoc, ToType, - E->getIdentKind(), ToFunctionName); + E->getIdentKind(), E->isTransparent(), + ToFunctionName); } ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index f49945f434193..834beef49a444 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -30,6 +30,7 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/Module.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" @@ -1022,6 +1023,28 @@ bool Decl::isInExportDeclContext() const { return DC && isa(DC); } +bool Decl::isInAnotherModuleUnit() const { + auto *M = getOwningModule(); + + if (!M) + return false; + + M = M->getTopLevelModule(); + // FIXME: It is problematic if the header module lives in another module + // unit. Consider to fix this by techniques like + // ExternalASTSource::hasExternalDefinitions. + if (M->isHeaderLikeModule()) + return false; + + // A global module without parent implies that we're parsing the global + // module. So it can't be in another module unit. + if (M->isGlobalModule()) + return false; + + assert(M->isModulePurview() && "New module kind?"); + return M != getASTContext().getCurrentNamedModule(); +} + static Decl::Kind getKind(const Decl *D) { return D->getKind(); } static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 10561348916a9..95f0276fc3919 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -718,13 +718,14 @@ std::string SYCLUniqueStableIdExpr::ComputeName(ASTContext &Context, } PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, - StringLiteral *SL) + bool IsTransparent, StringLiteral *SL) : Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary) { PredefinedExprBits.Kind = IK; assert((getIdentKind() == IK) && "IdentKind do not fit in PredefinedExprBitfields!"); bool HasFunctionName = SL != nullptr; PredefinedExprBits.HasFunctionName = HasFunctionName; + PredefinedExprBits.IsTransparent = IsTransparent; PredefinedExprBits.Loc = L; if (HasFunctionName) setFunctionName(SL); @@ -738,11 +739,11 @@ PredefinedExpr::PredefinedExpr(EmptyShell Empty, bool HasFunctionName) PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L, QualType FNTy, IdentKind IK, - StringLiteral *SL) { + bool IsTransparent, StringLiteral *SL) { bool HasFunctionName = SL != nullptr; void *Mem = Ctx.Allocate(totalSizeToAlloc(HasFunctionName), alignof(PredefinedExpr)); - return new (Mem) PredefinedExpr(L, FNTy, IK, SL); + return new (Mem) PredefinedExpr(L, FNTy, IK, IsTransparent, SL); } PredefinedExpr *PredefinedExpr::CreateEmpty(const ASTContext &Ctx, diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 3bc5a7daf70d9..47c31c61c728d 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2198,11 +2198,19 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { << (InBits ? 1 : 0); // (byte|bit) } + const auto *CXXRD = dyn_cast(RD); + // Warn if we packed it unnecessarily, when the unpacked alignment is not // greater than the one after packing, the size in bits doesn't change and // the offset of each field is identical. + // Unless the type is non-POD (for Clang ABI > 15), where the packed + // attribute on such a type does allow the type to be packed into other + // structures that use the packed attribute. if (Packed && UnpackedAlignment <= Alignment && - UnpackedSizeInBits == getSizeInBits() && !HasPackedField) + UnpackedSizeInBits == getSizeInBits() && !HasPackedField && + (!CXXRD || CXXRD->isPOD() || + Context.getLangOpts().getClangABICompat() <= + LangOptions::ClangABI::Ver15)) Diag(D->getLocation(), diag::warn_unnecessary_packed) << Context.getTypeDeclType(RD); } diff --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp index 5520633da68ae..4556787d10a8e 100644 --- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp @@ -68,7 +68,12 @@ static llvm::BitVector findReachableBlocks(const CFG &Cfg) { } llvm::Expected -ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) { +ControlFlowContext::build(const Decl &D, Stmt &S, ASTContext &C) { + if (D.isTemplated()) + return llvm::createStringError( + std::make_error_code(std::errc::invalid_argument), + "Cannot analyze templated declarations"); + CFG::BuildOptions Options; Options.PruneTriviallyFalseEdges = true; Options.AddImplicitDtors = true; @@ -79,7 +84,7 @@ ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) { // Ensure that all sub-expressions in basic blocks are evaluated. Options.setAllAlwaysAdd(); - auto Cfg = CFG::buildCFG(D, &S, &C, Options); + auto Cfg = CFG::buildCFG(&D, &S, &C, Options); if (Cfg == nullptr) return llvm::createStringError( std::make_error_code(std::errc::invalid_argument), @@ -90,9 +95,19 @@ ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) { llvm::BitVector BlockReachable = findReachableBlocks(*Cfg); - return ControlFlowContext(D, std::move(Cfg), std::move(StmtToBlock), + return ControlFlowContext(&D, std::move(Cfg), std::move(StmtToBlock), std::move(BlockReachable)); } +llvm::Expected +ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) { + if (D == nullptr) + return llvm::createStringError( + std::make_error_code(std::errc::invalid_argument), + "Declaration must not be null"); + + return build(*D, S, C); +} + } // namespace dataflow } // namespace clang diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp index 5dd390e962d82..73428ac250ad3 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -211,7 +211,7 @@ DataflowAnalysisContext::getControlFlowContext(const FunctionDecl *F) { return &It->second; if (Stmt *Body = F->getBody()) { - auto CFCtx = ControlFlowContext::build(F, *Body, F->getASTContext()); + auto CFCtx = ControlFlowContext::build(*F, *Body, F->getASTContext()); // FIXME: Handle errors. assert(CFCtx); auto Result = FunctionContexts.insert({F, std::move(*CFCtx)}); diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 479aa12d191ee..7b1944f273cf0 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -680,9 +680,7 @@ Value *Environment::getValue(const StorageLocation &Loc) const { return It == LocToVal.end() ? nullptr : It->second; } -Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const { - assert(SP != SkipPast::ReferenceThenPointer); - +Value *Environment::getValue(const ValueDecl &D) const { auto *Loc = getStorageLocation(D); if (Loc == nullptr) return nullptr; @@ -784,11 +782,6 @@ StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const { if (auto *Val = dyn_cast_or_null(getValue(Loc))) return Val->getReferentLoc(); return Loc; - case SkipPast::ReferenceThenPointer: - StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference); - if (auto *Val = dyn_cast_or_null(getValue(LocPastRef))) - return Val->getPointeeLoc(); - return LocPastRef; } llvm_unreachable("bad SkipPast kind"); } @@ -830,5 +823,39 @@ void Environment::dump() const { dump(llvm::dbgs()); } +AggregateStorageLocation * +getImplicitObjectLocation(const CXXMemberCallExpr &MCE, + const Environment &Env) { + Expr *ImplicitObject = MCE.getImplicitObjectArgument(); + if (ImplicitObject == nullptr) + return nullptr; + StorageLocation *Loc = + Env.getStorageLocation(*ImplicitObject, SkipPast::Reference); + if (Loc == nullptr) + return nullptr; + if (ImplicitObject->getType()->isPointerType()) { + if (auto *Val = cast_or_null(Env.getValue(*Loc))) + return &cast(Val->getPointeeLoc()); + return nullptr; + } + return cast(Loc); +} + +AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME, + const Environment &Env) { + Expr *Base = ME.getBase(); + if (Base == nullptr) + return nullptr; + StorageLocation *Loc = Env.getStorageLocation(*Base, SkipPast::Reference); + if (Loc == nullptr) + return nullptr; + if (ME.isArrow()) { + if (auto *Val = cast_or_null(Env.getValue(*Loc))) + return &cast(Val->getPointeeLoc()); + return nullptr; + } + return cast(Loc); +} + } // namespace dataflow } // namespace clang diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp index e306b55753752..b46a57f47f982 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -372,10 +372,26 @@ bool isNonEmptyOptional(const Value &OptionalVal, const Environment &Env) { return HasValueVal != nullptr && Env.flowConditionImplies(*HasValueVal); } +StorageLocation *maybeSkipPointer(StorageLocation *Loc, + const Environment &Env) { + if (Loc == nullptr) + return nullptr; + if (auto *Val = dyn_cast_or_null(Env.getValue(*Loc))) + return &Val->getPointeeLoc(); + return Loc; +} + +Value *getValueBehindPossiblePointer(const Expr &E, const Environment &Env) { + Value *Val = Env.getValue(E, SkipPast::Reference); + if (auto *PointerVal = dyn_cast_or_null(Val)) + return Env.getValue(PointerVal->getPointeeLoc()); + return Val; +} + void transferUnwrapCall(const Expr *UnwrapExpr, const Expr *ObjectExpr, LatticeTransferState &State) { if (auto *OptionalVal = - State.Env.getValue(*ObjectExpr, SkipPast::ReferenceThenPointer)) { + getValueBehindPossiblePointer(*ObjectExpr, State.Env)) { if (State.Env.getStorageLocation(*UnwrapExpr, SkipPast::None) == nullptr) if (auto *Loc = maybeInitializeOptionalValueMember( UnwrapExpr->getType(), *OptionalVal, State.Env)) @@ -396,8 +412,8 @@ void transferOptionalHasValueCall(const CXXMemberCallExpr *CallExpr, const MatchFinder::MatchResult &, LatticeTransferState &State) { if (auto *HasValueVal = getHasValue( - State.Env, State.Env.getValue(*CallExpr->getImplicitObjectArgument(), - SkipPast::ReferenceThenPointer))) { + State.Env, getValueBehindPossiblePointer( + *CallExpr->getImplicitObjectArgument(), State.Env))) { auto &CallExprLoc = State.Env.createStorageLocation(*CallExpr); State.Env.setValue(CallExprLoc, *HasValueVal); State.Env.setStorageLocation(*CallExpr, CallExprLoc); @@ -419,8 +435,7 @@ void transferValueOrImpl(const clang::Expr *ValueOrPredExpr, ->getImplicitObjectArgument(); auto *HasValueVal = getHasValue( - State.Env, - State.Env.getValue(*ObjectArgumentExpr, SkipPast::ReferenceThenPointer)); + State.Env, getValueBehindPossiblePointer(*ObjectArgumentExpr, State.Env)); if (HasValueVal == nullptr) return; @@ -472,8 +487,8 @@ void transferCallReturningOptional(const CallExpr *E, void assignOptionalValue(const Expr &E, Environment &Env, BoolValue &HasValueVal) { - if (auto *OptionalLoc = - Env.getStorageLocation(E, SkipPast::ReferenceThenPointer)) { + if (auto *OptionalLoc = maybeSkipPointer( + Env.getStorageLocation(E, SkipPast::Reference), Env)) { Env.setValue(*OptionalLoc, createOptionalValue(Env, HasValueVal)); } } @@ -550,13 +565,11 @@ void transferNulloptAssignment(const CXXOperatorCallExpr *E, transferAssignment(E, State.Env.getBoolLiteralValue(false), State); } -void transferSwap(const Expr &E1, SkipPast E1Skip, const Expr &E2, +void transferSwap(StorageLocation *Loc1, StorageLocation *Loc2, Environment &Env) { // We account for cases where one or both of the optionals are not modeled, // either lacking associated storage locations, or lacking values associated // to such storage locations. - auto *Loc1 = Env.getStorageLocation(E1, E1Skip); - auto *Loc2 = Env.getStorageLocation(E2, SkipPast::Reference); if (Loc1 == nullptr) { if (Loc2 != nullptr) @@ -590,14 +603,20 @@ void transferSwapCall(const CXXMemberCallExpr *E, const MatchFinder::MatchResult &, LatticeTransferState &State) { assert(E->getNumArgs() == 1); - transferSwap(*E->getImplicitObjectArgument(), SkipPast::ReferenceThenPointer, - *E->getArg(0), State.Env); + transferSwap(maybeSkipPointer( + State.Env.getStorageLocation(*E->getImplicitObjectArgument(), + SkipPast::Reference), + State.Env), + State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference), + State.Env); } void transferStdSwapCall(const CallExpr *E, const MatchFinder::MatchResult &, LatticeTransferState &State) { assert(E->getNumArgs() == 2); - transferSwap(*E->getArg(0), SkipPast::Reference, *E->getArg(1), State.Env); + transferSwap(State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference), + State.Env.getStorageLocation(*E->getArg(1), SkipPast::Reference), + State.Env); } void transferStdForwardCall(const CallExpr *E, const MatchFinder::MatchResult &, @@ -756,6 +775,17 @@ auto buildTransferMatchSwitch() { }) // optional::operator*, optional::operator-> + // FIXME: This does something slightly strange for `operator->`. + // `transferUnwrapCall()` may create a new value of type `T` for the + // `optional`, and it associates that value with `E`. In the case of + // `operator->`, `E` is a pointer. As a result, we associate an + // expression of pointer type with a storage location of non-pointer type + // `T`. This can confound other code that expects expressions of + // pointer type to be associated with `PointerValue`s, such as the + // centrally provided accessors `getImplicitObjectLocation()` and + // `getBaseObjectLocation()`, and this is the reason we need to use our + // own 'maybeSkipPointer()` and `getValueBehindPossiblePointer()` instead + // of these accessors. .CaseOfCFGStmt(valueOperatorCall(std::nullopt), [](const CallExpr *E, const MatchFinder::MatchResult &, @@ -837,8 +867,7 @@ auto buildTransferMatchSwitch() { std::vector diagnoseUnwrapCall(const Expr *UnwrapExpr, const Expr *ObjectExpr, const Environment &Env) { - if (auto *OptionalVal = - Env.getValue(*ObjectExpr, SkipPast::ReferenceThenPointer)) { + if (auto *OptionalVal = getValueBehindPossiblePointer(*ObjectExpr, Env)) { auto *Prop = OptionalVal->getProperty("has_value"); if (auto *HasValueVal = cast_or_null(Prop)) { if (Env.flowConditionImplies(*HasValueVal)) diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 50eb7e9011bda..95810a47fc632 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -424,9 +424,8 @@ class TransferVisitor : public ConstStmtVisitor { switch (S->getOpcode()) { case UO_Deref: { - // Skip past a reference to handle dereference of a dependent pointer. - const auto *SubExprVal = cast_or_null( - Env.getValue(*SubExpr, SkipPast::Reference)); + const auto *SubExprVal = + cast_or_null(Env.getValue(*SubExpr, SkipPast::None)); if (SubExprVal == nullptr) break; @@ -542,10 +541,7 @@ class TransferVisitor : public ConstStmtVisitor { } } - // The receiver can be either a value or a pointer to a value. Skip past the - // indirection to handle both cases. - auto *BaseLoc = cast_or_null( - Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer)); + AggregateStorageLocation *BaseLoc = getBaseObjectLocation(*S, Env); if (BaseLoc == nullptr) return; diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index 7871fed519b98..700a09445b508 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -762,7 +762,9 @@ class Strategy { public: Strategy() = default; Strategy(const Strategy &) = delete; // Let's avoid copies. + Strategy &operator=(const Strategy &) = delete; Strategy(Strategy &&) = default; + Strategy &operator=(Strategy &&) = default; void set(const VarDecl *VD, Kind K) { Map[VD] = K; } diff --git a/clang/lib/Basic/Cuda.cpp b/clang/lib/Basic/Cuda.cpp index b4cf6cbe95f8b..db30142ad866d 100644 --- a/clang/lib/Basic/Cuda.cpp +++ b/clang/lib/Basic/Cuda.cpp @@ -114,6 +114,8 @@ static const CudaArchToStringMap arch_names[] = { GFX(90a), // gfx90a GFX(90c), // gfx90c GFX(940), // gfx940 + GFX(941), // gfx941 + GFX(942), // gfx942 GFX(1010), // gfx1010 GFX(1011), // gfx1011 GFX(1012), // gfx1012 diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp index 1abbaa9e4b2b4..b44c71f572bee 100644 --- a/clang/lib/Basic/LangOptions.cpp +++ b/clang/lib/Basic/LangOptions.cpp @@ -118,6 +118,7 @@ void LangOptions::setLangDefaults(LangOptions &Opts, Language Lang, Opts.CPlusPlus17 = Std.isCPlusPlus17(); Opts.CPlusPlus20 = Std.isCPlusPlus20(); Opts.CPlusPlus23 = Std.isCPlusPlus23(); + Opts.CPlusPlus26 = Std.isCPlusPlus26(); Opts.GNUMode = Std.isGNUMode(); Opts.GNUCVersion = 0; Opts.HexFloats = Std.hasHexFloats(); diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp index 6a38c0aa1ef76..6bf296091ec32 100644 --- a/clang/lib/Basic/Targets/AMDGPU.cpp +++ b/clang/lib/Basic/Targets/AMDGPU.cpp @@ -17,7 +17,6 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetBuiltins.h" - using namespace clang; using namespace clang::targets; @@ -244,6 +243,7 @@ AMDGPUTargetInfo::AMDGPUTargetInfo(const llvm::Triple &Triple, } MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + CUMode = !(GPUFeatures & llvm::AMDGPU::FEATURE_WGP); } void AMDGPUTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) { @@ -316,6 +316,7 @@ void AMDGPUTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("FP_FAST_FMA"); Builder.defineMacro("__AMDGCN_WAVEFRONT_SIZE", Twine(WavefrontSize)); + Builder.defineMacro("__AMDGCN_CUMODE__", Twine(CUMode)); } void AMDGPUTargetInfo::setAuxTarget(const TargetInfo *Aux) { diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h index 89c7bc5e1fdd3..9a8faee55d2e5 100644 --- a/clang/lib/Basic/Targets/AMDGPU.h +++ b/clang/lib/Basic/Targets/AMDGPU.h @@ -43,6 +43,9 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { unsigned GPUFeatures; unsigned WavefrontSize; + /// Whether to use cumode or WGP mode. True for cumode. False for WGP mode. + bool CUMode; + /// Target ID is device name followed by optional feature name postfixed /// by plus or minus sign delimitted by colon, e.g. gfx908:xnack+:sramecc-. /// If the target ID contains feature+, map it to true. @@ -445,6 +448,10 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { assert(F.front() == '+' || F.front() == '-'); if (F == "+wavefrontsize64") WavefrontSize = 64; + else if (F == "+cumode") + CUMode = true; + else if (F == "-cumode") + CUMode = false; bool IsOn = F.front() == '+'; StringRef Name = StringRef(F).drop_front(); if (!llvm::is_contained(TargetIDFeatures, Name)) diff --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp index 513da77ba08ac..9af871895f742 100644 --- a/clang/lib/Basic/Targets/LoongArch.cpp +++ b/clang/lib/Basic/Targets/LoongArch.cpp @@ -31,34 +31,79 @@ ArrayRef LoongArchTargetInfo::getGCCRegNames() const { "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", - "$f28", "$f29", "$f30", "$f31"}; + "$f28", "$f29", "$f30", "$f31", + // Condition flag registers. + "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5", "$fcc6", "$fcc7"}; return llvm::ArrayRef(GCCRegNames); } ArrayRef LoongArchTargetInfo::getGCCRegAliases() const { static const TargetInfo::GCCRegAlias GCCRegAliases[] = { - {{"$zero"}, "$r0"}, {{"$ra"}, "$r1"}, {{"$tp"}, "$r2"}, - {{"$sp"}, "$r3"}, {{"$a0"}, "$r4"}, {{"$a1"}, "$r5"}, - {{"$a2"}, "$r6"}, {{"$a3"}, "$r7"}, {{"$a4"}, "$r8"}, - {{"$a5"}, "$r9"}, {{"$a6"}, "$r10"}, {{"$a7"}, "$r11"}, - {{"$t0"}, "$r12"}, {{"$t1"}, "$r13"}, {{"$t2"}, "$r14"}, - {{"$t3"}, "$r15"}, {{"$t4"}, "$r16"}, {{"$t5"}, "$r17"}, - {{"$t6"}, "$r18"}, {{"$t7"}, "$r19"}, {{"$t8"}, "$r20"}, - {{"$fp", "$s9"}, "$r22"}, {{"$s0"}, "$r23"}, {{"$s1"}, "$r24"}, - {{"$s2"}, "$r25"}, {{"$s3"}, "$r26"}, {{"$s4"}, "$r27"}, - {{"$s5"}, "$r28"}, {{"$s6"}, "$r29"}, {{"$s7"}, "$r30"}, - {{"$s8"}, "$r31"}, {{"$fa0"}, "$f0"}, {{"$fa1"}, "$f1"}, - {{"$fa2"}, "$f2"}, {{"$fa3"}, "$f3"}, {{"$fa4"}, "$f4"}, - {{"$fa5"}, "$f5"}, {{"$fa6"}, "$f6"}, {{"$fa7"}, "$f7"}, - {{"$ft0"}, "$f8"}, {{"$ft1"}, "$f9"}, {{"$ft2"}, "$f10"}, - {{"$ft3"}, "$f11"}, {{"$ft4"}, "$f12"}, {{"$ft5"}, "$f13"}, - {{"$ft6"}, "$f14"}, {{"$ft7"}, "$f15"}, {{"$ft8"}, "$f16"}, - {{"$ft9"}, "$f17"}, {{"$ft10"}, "$f18"}, {{"$ft11"}, "$f19"}, - {{"$ft12"}, "$f20"}, {{"$ft13"}, "$f21"}, {{"$ft14"}, "$f22"}, - {{"$ft15"}, "$f23"}, {{"$fs0"}, "$f24"}, {{"$fs1"}, "$f25"}, - {{"$fs2"}, "$f26"}, {{"$fs3"}, "$f27"}, {{"$fs4"}, "$f28"}, - {{"$fs5"}, "$f29"}, {{"$fs6"}, "$f30"}, {{"$fs7"}, "$f31"}, + {{"zero", "$zero", "r0"}, "$r0"}, + {{"ra", "$ra", "r1"}, "$r1"}, + {{"tp", "$tp", "r2"}, "$r2"}, + {{"sp", "$sp", "r3"}, "$r3"}, + {{"a0", "$a0", "r4"}, "$r4"}, + {{"a1", "$a1", "r5"}, "$r5"}, + {{"a2", "$a2", "r6"}, "$r6"}, + {{"a3", "$a3", "r7"}, "$r7"}, + {{"a4", "$a4", "r8"}, "$r8"}, + {{"a5", "$a5", "r9"}, "$r9"}, + {{"a6", "$a6", "r10"}, "$r10"}, + {{"a7", "$a7", "r11"}, "$r11"}, + {{"t0", "$t0", "r12"}, "$r12"}, + {{"t1", "$t1", "r13"}, "$r13"}, + {{"t2", "$t2", "r14"}, "$r14"}, + {{"t3", "$t3", "r15"}, "$r15"}, + {{"t4", "$t4", "r16"}, "$r16"}, + {{"t5", "$t5", "r17"}, "$r17"}, + {{"t6", "$t6", "r18"}, "$r18"}, + {{"t7", "$t7", "r19"}, "$r19"}, + {{"t8", "$t8", "r20"}, "$r20"}, + {{"r21"}, "$r21"}, + {{"s9", "$s9", "r22", "fp", "$fp"}, "$r22"}, + {{"s0", "$s0", "r23"}, "$r23"}, + {{"s1", "$s1", "r24"}, "$r24"}, + {{"s2", "$s2", "r25"}, "$r25"}, + {{"s3", "$s3", "r26"}, "$r26"}, + {{"s4", "$s4", "r27"}, "$r27"}, + {{"s5", "$s5", "r28"}, "$r28"}, + {{"s6", "$s6", "r29"}, "$r29"}, + {{"s7", "$s7", "r30"}, "$r30"}, + {{"s8", "$s8", "r31"}, "$r31"}, + {{"$fa0"}, "$f0"}, + {{"$fa1"}, "$f1"}, + {{"$fa2"}, "$f2"}, + {{"$fa3"}, "$f3"}, + {{"$fa4"}, "$f4"}, + {{"$fa5"}, "$f5"}, + {{"$fa6"}, "$f6"}, + {{"$fa7"}, "$f7"}, + {{"$ft0"}, "$f8"}, + {{"$ft1"}, "$f9"}, + {{"$ft2"}, "$f10"}, + {{"$ft3"}, "$f11"}, + {{"$ft4"}, "$f12"}, + {{"$ft5"}, "$f13"}, + {{"$ft6"}, "$f14"}, + {{"$ft7"}, "$f15"}, + {{"$ft8"}, "$f16"}, + {{"$ft9"}, "$f17"}, + {{"$ft10"}, "$f18"}, + {{"$ft11"}, "$f19"}, + {{"$ft12"}, "$f20"}, + {{"$ft13"}, "$f21"}, + {{"$ft14"}, "$f22"}, + {{"$ft15"}, "$f23"}, + {{"$fs0"}, "$f24"}, + {{"$fs1"}, "$f25"}, + {{"$fs2"}, "$f26"}, + {{"$fs3"}, "$f27"}, + {{"$fs4"}, "$f28"}, + {{"$fs5"}, "$f29"}, + {{"$fs6"}, "$f30"}, + {{"$fs7"}, "$f31"}, }; return llvm::ArrayRef(GCCRegAliases); } diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp index 309c9e4b5c8a3..d82c4d3b3c535 100644 --- a/clang/lib/Basic/Targets/NVPTX.cpp +++ b/clang/lib/Basic/Targets/NVPTX.cpp @@ -199,6 +199,8 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, case CudaArch::GFX90a: case CudaArch::GFX90c: case CudaArch::GFX940: + case CudaArch::GFX941: + case CudaArch::GFX942: case CudaArch::GFX1010: case CudaArch::GFX1011: case CudaArch::GFX1012: diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index b27561729dfc4..bfef91affc482 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -21,6 +21,8 @@ using namespace clang::targets; static constexpr Builtin::Info BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsPPC.def" diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 26963286ad132..7194af970bbb9 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -445,6 +445,7 @@ static bool initTargetOptions(DiagnosticsEngine &Diags, Options.ObjectFilenameForDebug = CodeGenOpts.ObjectFilenameForDebug; Options.Hotpatch = CodeGenOpts.HotPatch; Options.JMCInstrument = CodeGenOpts.JMCInstrument; + Options.XCOFFReadOnlyPointers = CodeGenOpts.XCOFFReadOnlyPointers; switch (CodeGenOpts.getSwiftAsyncFramePointer()) { case CodeGenOptions::SwiftAsyncFramePointerKind::Auto: diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 32759ed31906d..5db327ae06051 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -16554,7 +16554,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, // use custom code generation to expand a builtin call with a pointer to a // load (if the corresponding instruction accumulates its result) followed by // the call to the intrinsic and a store of the result. -#define CUSTOM_BUILTIN(Name, Intr, Types, Accumulate) \ +#define CUSTOM_BUILTIN(Name, Intr, Types, Accumulate, Feature) \ case PPC::BI__builtin_##Name: #include "clang/Basic/BuiltinsPPC.def" { @@ -16604,7 +16604,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, } bool Accumulate; switch (BuiltinID) { - #define CUSTOM_BUILTIN(Name, Intr, Types, Acc) \ + #define CUSTOM_BUILTIN(Name, Intr, Types, Acc, Feature) \ case PPC::BI__builtin_##Name: \ ID = Intrinsic::ppc_##Intr; \ Accumulate = Acc; \ diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 72e32cce7b2a9..f9d96be0d2fc9 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -887,12 +887,12 @@ CodeGenModule::EmitCXXGlobalInitFunc() { // with priority emitted above. Module implementation units behave the same // way as a non-modular TU with imports. llvm::Function *Fn; - if (CXX20ModuleInits && getContext().getNamedModuleForCodeGen() && - !getContext().getNamedModuleForCodeGen()->isModuleImplementation()) { + if (CXX20ModuleInits && getContext().getCurrentNamedModule() && + !getContext().getCurrentNamedModule()->isModuleImplementation()) { SmallString<256> InitFnName; llvm::raw_svector_ostream Out(InitFnName); cast(getCXXABI().getMangleContext()) - .mangleModuleInitializer(getContext().getNamedModuleForCodeGen(), Out); + .mangleModuleInitializer(getContext().getCurrentNamedModule(), Out); Fn = CreateGlobalInitOrCleanUpFunction( FTy, llvm::Twine(InitFnName), FI, SourceLocation(), false, llvm::GlobalVariable::ExternalLinkage); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 5479555e402b2..eeb8670eeb881 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -2126,7 +2126,8 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { // Update heapallocsite metadata when there is an explicit pointer cast. if (auto *CI = dyn_cast(Src)) { - if (CI->getMetadata("heapallocsite") && isa(CE)) { + if (CI->getMetadata("heapallocsite") && isa(CE) && + !isa(E)) { QualType PointeeType = DestTy->getPointeeType(); if (!PointeeType.isNull()) CGF.getDebugInfo()->addHeapAllocSiteMetadata(CI, PointeeType, diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index 68c4fc872e3b8..74f8c19e1bc7e 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -3580,6 +3580,8 @@ void CGOpenMPRuntimeGPU::processRequiresDirective( case CudaArch::GFX90a: case CudaArch::GFX90c: case CudaArch::GFX940: + case CudaArch::GFX941: + case CudaArch::GFX942: case CudaArch::GFX1010: case CudaArch::GFX1011: case CudaArch::GFX1012: diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index edeb422de3b8e..d5d1287d169dd 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -571,7 +571,7 @@ static llvm::MDNode *getAspectEnumValueMD(ASTContext &ASTContext, } void CodeGenModule::Release() { - Module *Primary = getContext().getNamedModuleForCodeGen(); + Module *Primary = getContext().getCurrentNamedModule(); if (CXX20ModuleInits && Primary && !Primary->isHeaderLikeModule()) EmitModuleInitializers(Primary); EmitDeferred(); diff --git a/clang/lib/CodeGen/CodeGenPGO.h b/clang/lib/CodeGen/CodeGenPGO.h index 66c93cba4bb0e..392ec5a144fee 100644 --- a/clang/lib/CodeGen/CodeGenPGO.h +++ b/clang/lib/CodeGen/CodeGenPGO.h @@ -114,7 +114,12 @@ class CodeGenPGO { return 0; if (!haveRegionCounts()) return 0; - return RegionCounts[(*RegionCounterMap)[S]]; + // With profiles from a differing version of clang we can have mismatched + // decl counts. Don't crash in such a case. + auto Index = (*RegionCounterMap)[S]; + if (Index >= RegionCounts.size()) + return 0; + return RegionCounts[Index]; } }; diff --git a/clang/lib/Driver/Distro.cpp b/clang/lib/Driver/Distro.cpp index 85d82180a805c..e86b589a1cfb5 100644 --- a/clang/lib/Driver/Distro.cpp +++ b/clang/lib/Driver/Distro.cpp @@ -93,6 +93,7 @@ static Distro::DistroType DetectLsbRelease(llvm::vfs::FileSystem &VFS) { .Case("jammy", Distro::UbuntuJammy) .Case("kinetic", Distro::UbuntuKinetic) .Case("lunar", Distro::UbuntuLunar) + .Case("mantic", Distro::UbuntuMantic) .Default(Distro::UnknownDistro); return Version; } diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 06dd81b695c6f..82dcb322e2cfe 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1714,6 +1714,7 @@ Compilation *Driver::BuildCompilation(ArrayRef ArgList) { !Args.hasArg(options::OPT_fmodules) && Std && (Std->containsValue("c++20") || Std->containsValue("c++2a") || Std->containsValue("c++23") || Std->containsValue("c++2b") || + Std->containsValue("c++26") || Std->containsValue("c++2c") || Std->containsValue("c++latest")); // Process -fmodule-header{=} flags. @@ -6788,6 +6789,21 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, !Args.getLastArgValue(options::OPT_fuse_ld_EQ) .equals_insensitive("lld")) Diag(clang::diag::err_drv_lto_without_lld); + + // If -dumpdir is not specified, give a default prefix derived from the link + // output filename. For example, `clang -g -gsplit-dwarf a.c -o x` passes + // `-dumpdir x-` to cc1. If -o is unspecified, use + // stem(getDefaultImageName()) (usually stem("a.out") = "a"). + if (!Args.hasArg(options::OPT_dumpdir)) { + Arg *Arg = Args.MakeSeparateArg( + nullptr, getOpts().getOption(options::OPT_dumpdir), + Args.MakeArgString(Args.getLastArgValue( + options::OPT_o, + llvm::sys::path::stem(getDefaultImageName())) + + "-")); + Arg->claim(); + Args.append(Arg); + } } if (FinalPhase == phases::Preprocess || Args.hasArg(options::OPT__SLASH_Y_)) { @@ -8302,6 +8318,37 @@ InputInfoList Driver::BuildJobsForAction( return Result; } +static void handleTimeTrace(Compilation &C, const ArgList &Args, + const JobAction *JA, const char *BaseInput, + const InputInfo &Result) { + Arg *A = + Args.getLastArg(options::OPT_ftime_trace, options::OPT_ftime_trace_EQ); + if (!A) + return; + SmallString<128> Path; + if (A->getOption().matches(options::OPT_ftime_trace_EQ)) { + Path = A->getValue(); + if (llvm::sys::fs::is_directory(Path)) { + SmallString<128> Tmp(Result.getFilename()); + llvm::sys::path::replace_extension(Tmp, "json"); + llvm::sys::path::append(Path, llvm::sys::path::filename(Tmp)); + } + } else { + if (Arg *DumpDir = Args.getLastArgNoClaim(options::OPT_dumpdir)) { + // The trace file is ${dumpdir}${basename}.json. Note that dumpdir may not + // end with a path separator. + Path = DumpDir->getValue(); + Path += llvm::sys::path::filename(BaseInput); + } else { + Path = Result.getFilename(); + } + llvm::sys::path::replace_extension(Path, "json"); + } + const char *ResultFile = C.getArgs().MakeArgString(Path); + C.addTimeTraceFile(ResultFile, JA); + C.addResultFile(ResultFile, JA); +} + InputInfoList Driver::BuildJobsForActionNoCache( Compilation &C, const Action *A, const ToolChain *TC, StringRef BoundArch, bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, @@ -8756,6 +8803,8 @@ InputInfoList Driver::BuildJobsForActionNoCache( AtTopLevel, MultipleArchs, OffloadingPrefix), BaseInput); + if (T->canEmitIR() && OffloadingPrefix.empty()) + handleTimeTrace(C, Args, JA, BaseInput, Result); } if (CCCPrintBindings && !CCGenDiagnostics) { diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp index 0ac261b548718..46ad8231764db 100644 --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -122,6 +122,17 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-bnoentry"); } + if (Args.hasFlag(options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr, + false)) { + if (Args.hasArg(options::OPT_shared)) + D.Diag(diag::err_roptr_cannot_build_shared); + + // The `-mxcoff-roptr` option places constants in RO sections as much as + // possible. Then `-bforceimprw` changes such sections to RW if they contain + // imported symbols that need to be resolved. + CmdArgs.push_back("-bforceimprw"); + } + // PGO instrumentation generates symbols belonging to special sections, and // the linker needs to place all symbols in a particular section together in // memory; the AIX linker does that under an option. diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index 1a5374700f4a8..3ec34b0dda450 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -11,7 +11,6 @@ #include "clang/Basic/TargetID.h" #include "clang/Config/config.h" #include "clang/Driver/Compilation.h" -#include "clang/Driver/Distro.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" @@ -309,13 +308,10 @@ RocmInstallationDetector::getInstallationPathCandidates() { ROCmSearchDirs.emplace_back(D.SysRoot + "/opt/" + LatestROCm, /*StrictChecking=*/true); - Distro Dist(D.getVFS(), llvm::Triple(llvm::sys::getProcessTriple())); - if (Dist.IsDebian() || Dist.IsRedhat()) { - ROCmSearchDirs.emplace_back(D.SysRoot + "/usr/local", - /*StrictChecking=*/true); - ROCmSearchDirs.emplace_back(D.SysRoot + "/usr", - /*StrictChecking=*/true); - } + ROCmSearchDirs.emplace_back(D.SysRoot + "/usr/local", + /*StrictChecking=*/true); + ROCmSearchDirs.emplace_back(D.SysRoot + "/usr", + /*StrictChecking=*/true); DoPrintROCmSearchDirs(); return ROCmSearchDirs; @@ -586,8 +582,8 @@ void amdgpu::getAMDGPUTargetFeatures(const Driver &D, options::OPT_mno_wavefrontsize64, false)) Features.push_back("+wavefrontsize64"); - handleTargetFeaturesGroup( - Args, Features, options::OPT_m_amdgpu_Features_Group); + handleTargetFeaturesGroup(D, Triple, Args, Features, + options::OPT_m_amdgpu_Features_Group); } /// AMDGPU Toolchain diff --git a/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/clang/lib/Driver/ToolChains/Arch/PPC.cpp index 4287d41534693..befbd365fd03f 100644 --- a/clang/lib/Driver/ToolChains/Arch/PPC.cpp +++ b/clang/lib/Driver/ToolChains/Arch/PPC.cpp @@ -116,7 +116,8 @@ void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (Triple.getSubArch() == llvm::Triple::PPCSubArch_spe) Features.push_back("+spe"); - handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group); + handleTargetFeaturesGroup(D, Triple, Args, Features, + options::OPT_m_ppc_Features_Group); ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args); if (FloatABI == ppc::FloatABI::Soft) diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index a26c9caf64c70..162523e6268f0 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -169,7 +169,8 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, // Now add any that the user explicitly requested on the command line, // which may override the defaults. - handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group); + handleTargetFeaturesGroup(D, Triple, Args, Features, + options::OPT_m_riscv_Features_Group); } StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index bab2ef99e70ce..241ce3623cb54 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -431,6 +431,20 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args, if (Args.hasArg(options::OPT_pg) && !Args.hasArg(options::OPT_mfentry)) return true; + if (Triple.isAndroid()) { + switch (Triple.getArch()) { + case llvm::Triple::aarch64: + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::riscv64: + return true; + default: + break; + } + } + switch (Triple.getArch()) { case llvm::Triple::xcore: case llvm::Triple::wasm32: @@ -470,9 +484,6 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args, case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: - if (Triple.isAndroid()) - return true; - [[fallthrough]]; case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::mips: @@ -526,7 +537,8 @@ getFramePointerKind(const ArgList &Args, const llvm::Triple &Triple) { bool OmitLeafFP = Args.hasFlag(options::OPT_momit_leaf_frame_pointer, options::OPT_mno_omit_leaf_frame_pointer, - Triple.isAArch64() || Triple.isPS() || Triple.isVE()); + Triple.isAArch64() || Triple.isPS() || Triple.isVE() || + (Triple.isAndroid() && Triple.isRISCV64())); if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) || (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) { if (OmitLeafFP) @@ -3795,6 +3807,7 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D, IsCXX && Std && (Std->containsValue("c++2a") || Std->containsValue("c++20") || Std->containsValue("c++2b") || Std->containsValue("c++23") || + Std->containsValue("c++2c") || Std->containsValue("c++26") || Std->containsValue("c++latest")); bool HaveModules = HaveStdCXXModules; @@ -5456,6 +5469,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + Args.AddLastArg(CmdArgs, options::OPT_dumpdir); + if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_index_EQ)) { if (!types::isLLVMIR(Input.getType())) D.Diag(diag::err_drv_arg_requires_bitcode_input) << A->getAsString(Args); @@ -5854,6 +5869,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, << A->getSpelling() << RawTriple.str(); } + if (Args.hasArg(options::OPT_mxcoff_roptr) || + Args.hasArg(options::OPT_mno_xcoff_roptr)) { + bool HasRoptr = Args.hasFlag(options::OPT_mxcoff_roptr, + options::OPT_mno_xcoff_roptr, false); + StringRef OptStr = HasRoptr ? "-mxcoff-roptr" : "-mno-xcoff-roptr"; + if (!Triple.isOSAIX()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << OptStr << RawTriple.str(); + + if (HasRoptr) + CmdArgs.push_back("-mxcoff-roptr"); + } + if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) { StringRef V = A->getValue(), V1 = V; unsigned Size; @@ -6980,6 +7008,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + if (Arg *A = Args.getLastArgNoClaim(options::OPT_K); + A && !TC.getTriple().isOSAIX()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + if (Args.getLastArg(options::OPT_fapple_kext) || (Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType))) CmdArgs.push_back("-fapple-kext"); @@ -6991,13 +7024,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits); Args.AddLastArg(CmdArgs, options::OPT_ftime_report); Args.AddLastArg(CmdArgs, options::OPT_ftime_report_EQ); - Args.AddLastArg(CmdArgs, options::OPT_ftime_trace); - Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); - Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_EQ); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); Args.AddLastArg(CmdArgs, options::OPT_malign_double); Args.AddLastArg(CmdArgs, options::OPT_fno_temp_file); + if (const char *Name = C.getTimeTraceFile(&JA)) { + CmdArgs.push_back(Args.MakeArgString("-ftime-trace=" + Twine(Name))); + Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); + } + if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) { CmdArgs.push_back("-ftrapv-handler"); CmdArgs.push_back(A->getValue()); @@ -7296,8 +7331,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, .Case("c++14", "-std=c++14") .Case("c++17", "-std=c++17") .Case("c++20", "-std=c++20") - // TODO add c++23 when MSVC supports it. - .Case("c++latest", "-std=c++23") + // TODO add c++23 and c++26 when MSVC supports it. + .Case("c++latest", "-std=c++26") .Default(""); if (LanguageStandard.empty()) D.Diag(clang::diag::warn_drv_unused_argument) diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 4d046dd458a90..e1ced4a3810e9 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -131,15 +131,33 @@ static void renderRemarksHotnessOptions(const ArgList &Args, "opt-remarks-hotness-threshold=" + A->getValue())); } +static bool shouldIgnoreUnsupportedTargetFeature(const Arg &TargetFeatureArg, + llvm::Triple T, + StringRef Processor) { + // Warn no-cumode for AMDGCN processors not supporing WGP mode. + if (!T.isAMDGPU()) + return false; + auto GPUKind = T.isAMDGCN() ? llvm::AMDGPU::parseArchAMDGCN(Processor) + : llvm::AMDGPU::parseArchR600(Processor); + auto GPUFeatures = T.isAMDGCN() ? llvm::AMDGPU::getArchAttrAMDGCN(GPUKind) + : llvm::AMDGPU::getArchAttrR600(GPUKind); + if (GPUFeatures & llvm::AMDGPU::FEATURE_WGP) + return false; + return TargetFeatureArg.getOption().matches(options::OPT_mno_cumode); +} + void tools::addPathIfExists(const Driver &D, const Twine &Path, ToolChain::path_list &Paths) { if (D.getVFS().exists(Path)) Paths.push_back(Path.str()); } -void tools::handleTargetFeaturesGroup(const ArgList &Args, +void tools::handleTargetFeaturesGroup(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args, std::vector &Features, OptSpecifier Group) { + std::set Warned; for (const Arg *A : Args.filtered(Group)) { StringRef Name = A->getOption().getName(); A->claim(); @@ -148,9 +166,21 @@ void tools::handleTargetFeaturesGroup(const ArgList &Args, assert(Name.startswith("m") && "Invalid feature name."); Name = Name.substr(1); + auto Proc = getCPUName(D, Args, Triple); + if (shouldIgnoreUnsupportedTargetFeature(*A, Triple, Proc)) { + if (Warned.count(Name) == 0) { + D.getDiags().Report( + clang::diag::warn_drv_unsupported_option_for_processor) + << A->getAsString(Args) << Proc; + Warned.insert(Name); + } + continue; + } + bool IsNegative = Name.startswith("no-"); if (IsNegative) Name = Name.substr(3); + Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); } } @@ -232,9 +262,11 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input); // LIBRARY_PATH are included before user inputs and only supported on native - // toolchains. + // toolchains. Otherwise only add the '-L' arguments requested by the user. if (!TC.isCrossCompiling()) addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); + else + Args.AddAllArgs(CmdArgs, options::OPT_L); for (const auto &II : Inputs) { // If the current tool chain refers to an OpenMP offloading host, we @@ -469,9 +501,12 @@ std::string tools::getCPUName(const Driver &D, const ArgList &Args, } } -static void getWebAssemblyTargetFeatures(const ArgList &Args, +static void getWebAssemblyTargetFeatures(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args, std::vector &Features) { - handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group); + handleTargetFeaturesGroup(D, Triple, Args, Features, + options::OPT_m_wasm_Features_Group); } void tools::getTargetFeatures(const Driver &D, const llvm::Triple &Triple, @@ -516,11 +551,11 @@ void tools::getTargetFeatures(const Driver &D, const llvm::Triple &Triple, x86::getX86TargetFeatures(D, Triple, Args, Features); break; case llvm::Triple::hexagon: - hexagon::getHexagonTargetFeatures(D, Args, Features); + hexagon::getHexagonTargetFeatures(D, Triple, Args, Features); break; case llvm::Triple::wasm32: case llvm::Triple::wasm64: - getWebAssemblyTargetFeatures(Args, Features); + getWebAssemblyTargetFeatures(D, Triple, Args, Features); break; case llvm::Triple::sparc: case llvm::Triple::sparcel: @@ -725,6 +760,26 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, CmdArgs.push_back( Args.MakeArgString(Twine(PluginOptPrefix) + "-data-sections=0")); + if (Args.hasArg(options::OPT_mxcoff_roptr) || + Args.hasArg(options::OPT_mno_xcoff_roptr)) { + bool HasRoptr = Args.hasFlag(options::OPT_mxcoff_roptr, + options::OPT_mno_xcoff_roptr, false); + StringRef OptStr = HasRoptr ? "-mxcoff-roptr" : "-mno-xcoff-roptr"; + + if (!IsOSAIX) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << OptStr << ToolChain.getTriple().str(); + + if (HasRoptr) { + if (!Args.hasFlag(options::OPT_fdata_sections, + options::OPT_fno_data_sections, UseSeparateSections)) + D.Diag(diag::err_roptr_requires_data_sections); + + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-mxcoff-roptr")); + } + } + // Pass an option to enable split machine functions. if (auto *A = Args.getLastArg(options::OPT_fsplit_machine_functions, options::OPT_fno_split_machine_functions)) { @@ -1268,23 +1323,24 @@ const char *tools::SplitDebugName(const JobAction &JA, const ArgList &Args, if (StringRef(A->getValue()) == "single") return Args.MakeArgString(Output.getFilename()); - Arg *FinalOutput = Args.getLastArg(options::OPT_o); - if (FinalOutput && Args.hasArg(options::OPT_c)) { - SmallString<128> T(FinalOutput->getValue()); - llvm::sys::path::remove_filename(T); - llvm::sys::path::append(T, llvm::sys::path::stem(FinalOutput->getValue())); - AddPostfix(T); - return Args.MakeArgString(T); + SmallString<128> T; + if (const Arg *A = Args.getLastArg(options::OPT_dumpdir)) { + T = A->getValue(); } else { - // Use the compilation dir. - Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ, - options::OPT_fdebug_compilation_dir_EQ); - SmallString<128> T(A ? A->getValue() : ""); - SmallString<128> F(llvm::sys::path::stem(Input.getBaseInput())); - AddPostfix(F); - T += F; - return Args.MakeArgString(T); + Arg *FinalOutput = Args.getLastArg(options::OPT_o); + if (FinalOutput && Args.hasArg(options::OPT_c)) { + T = FinalOutput->getValue(); + llvm::sys::path::remove_filename(T); + llvm::sys::path::append(T, + llvm::sys::path::stem(FinalOutput->getValue())); + AddPostfix(T); + return Args.MakeArgString(T); + } } + + T += llvm::sys::path::stem(Input.getBaseInput()); + AddPostfix(T); + return Args.MakeArgString(T); } void tools::SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h index 78ccadb1d6dc6..8332a8dfb613c 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -190,7 +190,8 @@ void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, /// Note: Since \p Features may contain default values before calling /// this function, or may be appended with entries to override arguments, /// entries in \p Features are not unique. -void handleTargetFeaturesGroup(const llvm::opt::ArgList &Args, +void handleTargetFeaturesGroup(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, std::vector &Features, llvm::opt::OptSpecifier Group); diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index a255761a7e7b0..edb1ed5102cd0 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -796,8 +796,7 @@ NVPTXToolChain::NVPTXToolChain(const Driver &D, const llvm::Triple &Triple, /// system's default triple if not provided. NVPTXToolChain::NVPTXToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : NVPTXToolChain(D, Triple, - llvm::Triple(llvm::sys::getDefaultTargetTriple()), Args, + : NVPTXToolChain(D, Triple, llvm::Triple(LLVM_HOST_TRIPLE), Args, /*Freestanding=*/true) {} llvm::opt::DerivedArgList * diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp index 09d2f41ab0667..c21cff21680a4 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -159,9 +159,11 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args, } // Hexagon target features. -void hexagon::getHexagonTargetFeatures(const Driver &D, const ArgList &Args, +void hexagon::getHexagonTargetFeatures(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args, std::vector &Features) { - handleTargetFeaturesGroup(Args, Features, + handleTargetFeaturesGroup(D, Triple, Args, Features, options::OPT_m_hexagon_Features_Group); bool UseLongCalls = false; diff --git a/clang/lib/Driver/ToolChains/Hexagon.h b/clang/lib/Driver/ToolChains/Hexagon.h index 47a3304c46ae6..4799c3028ff9a 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.h +++ b/clang/lib/Driver/ToolChains/Hexagon.h @@ -50,7 +50,8 @@ class LLVM_LIBRARY_VISIBILITY Linker : public Tool { const char *LinkingOutput) const override; }; -void getHexagonTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, +void getHexagonTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, std::vector &Features); } // end namespace hexagon. diff --git a/clang/lib/Format/SortJavaScriptImports.cpp b/clang/lib/Format/SortJavaScriptImports.cpp index ce83ddea3e076..e24fe051a26ce 100644 --- a/clang/lib/Format/SortJavaScriptImports.cpp +++ b/clang/lib/Format/SortJavaScriptImports.cpp @@ -72,6 +72,7 @@ struct JsImportedSymbol { struct JsModuleReference { bool FormattingOff = false; bool IsExport = false; + bool IsTypeOnly = false; // Module references are sorted into these categories, in order. enum ReferenceCategory { SIDE_EFFECT, // "import 'something';" @@ -306,6 +307,7 @@ class JavaScriptImportSorter : public TokenAnalyzer { if (Reference->Category == JsModuleReference::SIDE_EFFECT || PreviousReference->Category == JsModuleReference::SIDE_EFFECT || Reference->IsExport != PreviousReference->IsExport || + Reference->IsTypeOnly != PreviousReference->IsTypeOnly || !PreviousReference->Prefix.empty() || !Reference->Prefix.empty() || !PreviousReference->DefaultImport.empty() || !Reference->DefaultImport.empty() || Reference->Symbols.empty() || @@ -488,6 +490,11 @@ class JavaScriptImportSorter : public TokenAnalyzer { bool parseStarBinding(const AdditionalKeywords &Keywords, JsModuleReference &Reference) { // * as prefix from '...'; + if (Current->is(Keywords.kw_type) && Current->Next && + Current->Next->is(tok::star)) { + Reference.IsTypeOnly = true; + nextToken(); + } if (Current->isNot(tok::star)) return false; nextToken(); @@ -503,8 +510,14 @@ class JavaScriptImportSorter : public TokenAnalyzer { bool parseNamedBindings(const AdditionalKeywords &Keywords, JsModuleReference &Reference) { + if (Current->is(Keywords.kw_type) && Current->Next && + Current->Next->isOneOf(tok::identifier, tok::l_brace)) { + Reference.IsTypeOnly = true; + nextToken(); + } + // eat a potential "import X, " prefix. - if (Current->is(tok::identifier)) { + if (!Reference.IsExport && Current->is(tok::identifier)) { Reference.DefaultImport = Current->TokenText; nextToken(); if (Current->is(Keywords.kw_from)) @@ -535,14 +548,19 @@ class JavaScriptImportSorter : public TokenAnalyzer { nextToken(); if (Current->is(tok::r_brace)) break; - if (!Current->isOneOf(tok::identifier, tok::kw_default)) + bool isTypeOnly = + Current->is(Keywords.kw_type) && Current->Next && + Current->Next->isOneOf(tok::identifier, tok::kw_default); + if (!isTypeOnly && !Current->isOneOf(tok::identifier, tok::kw_default)) return false; JsImportedSymbol Symbol; - Symbol.Symbol = Current->TokenText; // Make sure to include any preceding comments. Symbol.Range.setBegin( Current->getPreviousNonComment()->Next->WhitespaceRange.getBegin()); + if (isTypeOnly) + nextToken(); + Symbol.Symbol = Current->TokenText; nextToken(); if (Current->is(Keywords.kw_as)) { diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 2e5bdf96deb88..64035b0976f55 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -4068,7 +4068,9 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() { // parsing the structural element, i.e. the declaration or expression for // `export default`. if (!IsImport && !FormatTok->isOneOf(tok::l_brace, tok::star) && - !FormatTok->isStringLiteral()) { + !FormatTok->isStringLiteral() && + !(FormatTok->is(Keywords.kw_type) && + Tokens->peekNextToken()->isOneOf(tok::l_brace, tok::star))) { return; } diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index d2be3b3a77df4..040b9536b6305 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -49,8 +49,16 @@ void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces, unsigned StartOfTokenColumn, bool IsAligned, bool InPPDirective) { - if (Tok.Finalized || (Tok.MacroCtx && Tok.MacroCtx->Role == MR_ExpandedArg)) + auto PPBranchDirectiveStartsLine = [&Tok] { + return Tok.is(tok::hash) && !Tok.Previous && Tok.Next && + Tok.Next->isOneOf(tok::pp_if, tok::pp_ifdef, tok::pp_ifndef, + tok::pp_elif, tok::pp_elifdef, tok::pp_elifndef, + tok::pp_else, tok::pp_endif); + }; + if ((Tok.Finalized && !PPBranchDirectiveStartsLine()) || + (Tok.MacroCtx && Tok.MacroCtx->Role == MR_ExpandedArg)) { return; + } Tok.setDecision((Newlines > 0) ? FD_Break : FD_Continue); Changes.push_back(Change(Tok, /*CreateReplacement=*/true, Tok.WhitespaceRange, Spaces, StartOfTokenColumn, Newlines, "", "", @@ -522,13 +530,6 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, ? Changes[StartAt].indentAndNestingLevel() : std::tuple(); - // Keep track if the first token has a non-zero indent and nesting level. - // This can happen when aligning the contents of "#else" preprocessor blocks, - // which is done separately. - bool HasInitialIndentAndNesting = - StartAt == 0 && - IndentAndNestingLevel > std::tuple(); - // Keep track of the number of commas before the matching tokens, we will only // align a sequence of matching tokens if they are preceded by the same number // of commas. @@ -563,19 +564,8 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, unsigned i = StartAt; for (unsigned e = Changes.size(); i != e; ++i) { - if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) { - if (!HasInitialIndentAndNesting) - break; - // The contents of preprocessor blocks are aligned separately. - // If the initial preprocessor block is indented or nested (e.g. it's in - // a function), do not align and exit after finishing this scope block. - // Instead, align, and then lower the baseline indent and nesting level - // in order to continue aligning subsequent blocks. - EndOfSequence = i; - AlignCurrentSequence(); - IndentAndNestingLevel = - Changes[i].indentAndNestingLevel(); // new baseline - } + if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) + break; if (Changes[i].NewlinesBefore != 0) { CommasBeforeMatch = 0; diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index bda49fb68e460..b1e7db1f6b39e 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -879,7 +879,7 @@ std::unique_ptr ASTUnit::LoadFromASTFile( Module *M = HeaderInfo.lookupModule(AST->getLangOpts().CurrentModule); if (M && AST->getLangOpts().isCompilingModule() && M->isModulePurview()) - AST->Ctx->setNamedModuleForCodeGen(M); + AST->Ctx->setCurrentNamedModule(M); // Create an AST consumer, even though it isn't used. if (ToLoad >= LoadASTOnly) diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 0ce6b584f548d..40cfe3f3dc821 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1567,6 +1567,9 @@ void CompilerInvocation::GenerateCodeGenArgs( if (Opts.EnableAIXExtendedAltivecABI) GenerateArg(Args, OPT_mabi_EQ_vec_extabi, SA); + if (Opts.XCOFFReadOnlyPointers) + GenerateArg(Args, OPT_mxcoff_roptr, SA); + if (!Opts.OptRecordPasses.empty()) GenerateArg(Args, OPT_opt_record_passes, Opts.OptRecordPasses, SA); @@ -1947,6 +1950,25 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.SPIRITTAnnotations = true; } + if (Arg *A = Args.getLastArg(OPT_mxcoff_roptr)) { + if (!T.isOSAIX()) + Diags.Report(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << T.str(); + + // Since the storage mapping class is specified per csect, + // without using data sections, it is less effective to use read-only + // pointers. Using read-only pointers may cause other RO variables in the + // same csect to become RW when the linker acts upon `-bforceimprw`; + // therefore, we require that separate data sections + // are used when `-mxcoff-roptr` is in effect. We respect the setting of + // data-sections since we have not found reasons to do otherwise that + // overcome the user surprise of not respecting the setting. + if (!Args.hasFlag(OPT_fdata_sections, OPT_fno_data_sections, false)) + Diags.Report(diag::err_roptr_requires_data_sections); + + Opts.XCOFFReadOnlyPointers = true; + } + if (Arg *A = Args.getLastArg(OPT_mabi_EQ_quadword_atomics)) { if (!T.isOSAIX() || T.isPPC32()) Diags.Report(diag::err_drv_unsupported_opt_for_target) diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index c947772ec3e70..f62a29c02ee13 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -372,6 +372,8 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback { return "ExplicitTemplateArgumentSubstitution"; case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: return "DeducedTemplateArgumentSubstitution"; + case CodeSynthesisContext::LambdaExpressionSubstitution: + return "LambdaExpressionSubstitution"; case CodeSynthesisContext::PriorTemplateArgumentSubstitution: return "PriorTemplateArgumentSubstitution"; case CodeSynthesisContext::DefaultTemplateArgumentChecking: diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 9565bb101f78b..4098bede878d9 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -451,9 +451,11 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__STDC_VERSION__", "199409L"); } else { // -- __cplusplus - // FIXME: Use correct value for C++23. - if (LangOpts.CPlusPlus23) - Builder.defineMacro("__cplusplus", "202101L"); + if (LangOpts.CPlusPlus26) + // FIXME: Use correct value for C++26. + Builder.defineMacro("__cplusplus", "202400L"); + else if (LangOpts.CPlusPlus23) + Builder.defineMacro("__cplusplus", "202302L"); // [C++20] The integer literal 202002L. else if (LangOpts.CPlusPlus20) Builder.defineMacro("__cplusplus", "202002L"); diff --git a/clang/lib/Headers/avx2intrin.h b/clang/lib/Headers/avx2intrin.h index 33f24f2443b3a..1fbc4edafbd7f 100644 --- a/clang/lib/Headers/avx2intrin.h +++ b/clang/lib/Headers/avx2intrin.h @@ -493,108 +493,404 @@ _mm256_sign_epi32(__m256i __a, __m256i __b) return (__m256i)__builtin_ia32_psignd256((__v8si)__a, (__v8si)__b); } +/// Shifts each 128-bit half of the 256-bit integer vector \a a left by +/// \a imm bytes, shifting in zero bytes, and returns the result. If \a imm +/// is greater than 15, the returned result is all zeroes. +/// +/// \headerfile +/// +/// \code +/// __m256i _mm256_slli_si256(__m256i a, const int imm); +/// \endcode +/// +/// This intrinsic corresponds to the \c VPSLLDQ instruction. +/// +/// \param a +/// A 256-bit integer vector to be shifted. +/// \param imm +/// An unsigned immediate value specifying the shift count (in bytes). +/// \returns A 256-bit integer vector containing the result. #define _mm256_slli_si256(a, imm) \ ((__m256i)__builtin_ia32_pslldqi256_byteshift((__v4di)(__m256i)(a), (int)(imm))) +/// Shifts each 128-bit half of the 256-bit integer vector \a a left by +/// \a imm bytes, shifting in zero bytes, and returns the result. If \a imm +/// is greater than 15, the returned result is all zeroes. +/// +/// \headerfile +/// +/// \code +/// __m256i _mm256_bslli_epi128(__m256i a, const int imm); +/// \endcode +/// +/// This intrinsic corresponds to the \c VPSLLDQ instruction. +/// +/// \param a +/// A 256-bit integer vector to be shifted. +/// \param imm +/// An unsigned immediate value specifying the shift count (in bytes). +/// \returns A 256-bit integer vector containing the result. #define _mm256_bslli_epi128(a, imm) \ ((__m256i)__builtin_ia32_pslldqi256_byteshift((__v4di)(__m256i)(a), (int)(imm))) +/// Shifts each 16-bit element of the 256-bit vector of [16 x i16] in \a __a +/// left by \a __count bits, shifting in zero bits, and returns the result. +/// If \a __count is greater than 15, the returned result is all zeroes. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSLLW instruction. +/// +/// \param __a +/// A 256-bit vector of [16 x i16] to be shifted. +/// \param __count +/// An unsigned integer value specifying the shift count (in bits). +/// \returns A 256-bit vector of [16 x i16] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_slli_epi16(__m256i __a, int __count) { return (__m256i)__builtin_ia32_psllwi256((__v16hi)__a, __count); } +/// Shifts each 16-bit element of the 256-bit vector of [16 x i16] in \a __a +/// left by the number of bits specified by the lower 64 bits of \a __count, +/// shifting in zero bits, and returns the result. If \a __count is greater +/// than 15, the returned result is all zeroes. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSLLW instruction. +/// +/// \param __a +/// A 256-bit vector of [16 x i16] to be shifted. +/// \param __count +/// A 128-bit vector of [2 x i64] whose lower element gives the unsigned +/// shift count (in bits). The upper element is ignored. +/// \returns A 256-bit vector of [16 x i16] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_sll_epi16(__m256i __a, __m128i __count) { return (__m256i)__builtin_ia32_psllw256((__v16hi)__a, (__v8hi)__count); } +/// Shifts each 32-bit element of the 256-bit vector of [8 x i32] in \a __a +/// left by \a __count bits, shifting in zero bits, and returns the result. +/// If \a __count is greater than 31, the returned result is all zeroes. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSLLD instruction. +/// +/// \param __a +/// A 256-bit vector of [8 x i32] to be shifted. +/// \param __count +/// An unsigned integer value specifying the shift count (in bits). +/// \returns A 256-bit vector of [8 x i32] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_slli_epi32(__m256i __a, int __count) { return (__m256i)__builtin_ia32_pslldi256((__v8si)__a, __count); } +/// Shifts each 32-bit element of the 256-bit vector of [8 x i32] in \a __a +/// left by the number of bits given in the lower 64 bits of \a __count, +/// shifting in zero bits, and returns the result. If \a __count is greater +/// than 31, the returned result is all zeroes. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSLLD instruction. +/// +/// \param __a +/// A 256-bit vector of [8 x i32] to be shifted. +/// \param __count +/// A 128-bit vector of [2 x i64] whose lower element gives the unsigned +/// shift count (in bits). The upper element is ignored. +/// \returns A 256-bit vector of [8 x i32] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_sll_epi32(__m256i __a, __m128i __count) { return (__m256i)__builtin_ia32_pslld256((__v8si)__a, (__v4si)__count); } +/// Shifts each 64-bit element of the 256-bit vector of [4 x i64] in \a __a +/// left by \a __count bits, shifting in zero bits, and returns the result. +/// If \a __count is greater than 63, the returned result is all zeroes. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSLLQ instruction. +/// +/// \param __a +/// A 256-bit vector of [4 x i64] to be shifted. +/// \param __count +/// An unsigned integer value specifying the shift count (in bits). +/// \returns A 256-bit vector of [4 x i64] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_slli_epi64(__m256i __a, int __count) { return __builtin_ia32_psllqi256((__v4di)__a, __count); } +/// Shifts each 64-bit element of the 256-bit vector of [4 x i64] in \a __a +/// left by the number of bits given in the lower 64 bits of \a __count, +/// shifting in zero bits, and returns the result. If \a __count is greater +/// than 63, the returned result is all zeroes. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSLLQ instruction. +/// +/// \param __a +/// A 256-bit vector of [4 x i64] to be shifted. +/// \param __count +/// A 128-bit vector of [2 x i64] whose lower element gives the unsigned +/// shift count (in bits). The upper element is ignored. +/// \returns A 256-bit vector of [4 x i64] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_sll_epi64(__m256i __a, __m128i __count) { return __builtin_ia32_psllq256((__v4di)__a, __count); } +/// Shifts each 16-bit element of the 256-bit vector of [16 x i16] in \a __a +/// right by \a __count bits, shifting in sign bits, and returns the result. +/// If \a __count is greater than 15, each element of the result is either +/// 0 or -1 according to the corresponding input sign bit. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRAW instruction. +/// +/// \param __a +/// A 256-bit vector of [16 x i16] to be shifted. +/// \param __count +/// An unsigned integer value specifying the shift count (in bits). +/// \returns A 256-bit vector of [16 x i16] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_srai_epi16(__m256i __a, int __count) { return (__m256i)__builtin_ia32_psrawi256((__v16hi)__a, __count); } +/// Shifts each 16-bit element of the 256-bit vector of [16 x i16] in \a __a +/// right by the number of bits given in the lower 64 bits of \a __count, +/// shifting in sign bits, and returns the result. If \a __count is greater +/// than 15, each element of the result is either 0 or -1 according to the +/// corresponding input sign bit. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRAW instruction. +/// +/// \param __a +/// A 256-bit vector of [16 x i16] to be shifted. +/// \param __count +/// A 128-bit vector of [2 x i64] whose lower element gives the unsigned +/// shift count (in bits). The upper element is ignored. +/// \returns A 256-bit vector of [16 x i16] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_sra_epi16(__m256i __a, __m128i __count) { return (__m256i)__builtin_ia32_psraw256((__v16hi)__a, (__v8hi)__count); } +/// Shifts each 32-bit element of the 256-bit vector of [8 x i32] in \a __a +/// right by \a __count bits, shifting in sign bits, and returns the result. +/// If \a __count is greater than 31, each element of the result is either +/// 0 or -1 according to the corresponding input sign bit. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRAD instruction. +/// +/// \param __a +/// A 256-bit vector of [8 x i32] to be shifted. +/// \param __count +/// An unsigned integer value specifying the shift count (in bits). +/// \returns A 256-bit vector of [8 x i32] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_srai_epi32(__m256i __a, int __count) { return (__m256i)__builtin_ia32_psradi256((__v8si)__a, __count); } +/// Shifts each 32-bit element of the 256-bit vector of [8 x i32] in \a __a +/// right by the number of bits given in the lower 64 bits of \a __count, +/// shifting in sign bits, and returns the result. If \a __count is greater +/// than 31, each element of the result is either 0 or -1 according to the +/// corresponding input sign bit. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRAD instruction. +/// +/// \param __a +/// A 256-bit vector of [8 x i32] to be shifted. +/// \param __count +/// A 128-bit vector of [2 x i64] whose lower element gives the unsigned +/// shift count (in bits). The upper element is ignored. +/// \returns A 256-bit vector of [8 x i32] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_sra_epi32(__m256i __a, __m128i __count) { return (__m256i)__builtin_ia32_psrad256((__v8si)__a, (__v4si)__count); } +/// Shifts each 128-bit half of the 256-bit integer vector in \a a right by +/// \a imm bytes, shifting in zero bytes, and returns the result. If +/// \a imm is greater than 15, the returned result is all zeroes. +/// +/// \headerfile +/// +/// \code +/// __m256i _mm256_srli_si256(__m256i a, const int imm); +/// \endcode +/// +/// This intrinsic corresponds to the \c VPSRLDQ instruction. +/// +/// \param a +/// A 256-bit integer vector to be shifted. +/// \param imm +/// An unsigned immediate value specifying the shift count (in bytes). +/// \returns A 256-bit integer vector containing the result. #define _mm256_srli_si256(a, imm) \ ((__m256i)__builtin_ia32_psrldqi256_byteshift((__m256i)(a), (int)(imm))) +/// Shifts each 128-bit half of the 256-bit integer vector in \a a right by +/// \a imm bytes, shifting in zero bytes, and returns the result. If +/// \a imm is greater than 15, the returned result is all zeroes. +/// +/// \headerfile +/// +/// \code +/// __m256i _mm256_bsrli_epi128(__m256i a, const int imm); +/// \endcode +/// +/// This intrinsic corresponds to the \c VPSRLDQ instruction. +/// +/// \param a +/// A 256-bit integer vector to be shifted. +/// \param imm +/// An unsigned immediate value specifying the shift count (in bytes). +/// \returns A 256-bit integer vector containing the result. #define _mm256_bsrli_epi128(a, imm) \ ((__m256i)__builtin_ia32_psrldqi256_byteshift((__m256i)(a), (int)(imm))) +/// Shifts each 16-bit element of the 256-bit vector of [16 x i16] in \a __a +/// right by \a __count bits, shifting in zero bits, and returns the result. +/// If \a __count is greater than 15, the returned result is all zeroes. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRLW instruction. +/// +/// \param __a +/// A 256-bit vector of [16 x i16] to be shifted. +/// \param __count +/// An unsigned integer value specifying the shift count (in bits). +/// \returns A 256-bit vector of [16 x i16] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_srli_epi16(__m256i __a, int __count) { return (__m256i)__builtin_ia32_psrlwi256((__v16hi)__a, __count); } +/// Shifts each 16-bit element of the 256-bit vector of [16 x i16] in \a __a +/// right by the number of bits given in the lower 64 bits of \a __count, +/// shifting in zero bits, and returns the result. If \a __count is greater +/// than 15, the returned result is all zeroes. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRLW instruction. +/// +/// \param __a +/// A 256-bit vector of [16 x i16] to be shifted. +/// \param __count +/// A 128-bit vector of [2 x i64] whose lower element gives the unsigned +/// shift count (in bits). The upper element is ignored. +/// \returns A 256-bit vector of [16 x i16] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_srl_epi16(__m256i __a, __m128i __count) { return (__m256i)__builtin_ia32_psrlw256((__v16hi)__a, (__v8hi)__count); } +/// Shifts each 32-bit element of the 256-bit vector of [8 x i32] in \a __a +/// right by \a __count bits, shifting in zero bits, and returns the result. +/// If \a __count is greater than 31, the returned result is all zeroes. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRLD instruction. +/// +/// \param __a +/// A 256-bit vector of [8 x i32] to be shifted. +/// \param __count +/// An unsigned integer value specifying the shift count (in bits). +/// \returns A 256-bit vector of [8 x i32] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_srli_epi32(__m256i __a, int __count) { return (__m256i)__builtin_ia32_psrldi256((__v8si)__a, __count); } +/// Shifts each 32-bit element of the 256-bit vector of [8 x i32] in \a __a +/// right by the number of bits given in the lower 64 bits of \a __count, +/// shifting in zero bits, and returns the result. If \a __count is greater +/// than 31, the returned result is all zeroes. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRLD instruction. +/// +/// \param __a +/// A 256-bit vector of [8 x i32] to be shifted. +/// \param __count +/// A 128-bit vector of [2 x i64] whose lower element gives the unsigned +/// shift count (in bits). The upper element is ignored. +/// \returns A 256-bit vector of [8 x i32] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_srl_epi32(__m256i __a, __m128i __count) { return (__m256i)__builtin_ia32_psrld256((__v8si)__a, (__v4si)__count); } +/// Shifts each 64-bit element of the 256-bit vector of [4 x i64] in \a __a +/// right by \a __count bits, shifting in zero bits, and returns the result. +/// If \a __count is greater than 63, the returned result is all zeroes. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRLQ instruction. +/// +/// \param __a +/// A 256-bit vector of [4 x i64] to be shifted. +/// \param __count +/// An unsigned integer value specifying the shift count (in bits). +/// \returns A 256-bit vector of [4 x i64] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_srli_epi64(__m256i __a, int __count) { return __builtin_ia32_psrlqi256((__v4di)__a, __count); } +/// Shifts each 64-bit element of the 256-bit vector of [4 x i64] in \a __a +/// right by the number of bits given in the lower 64 bits of \a __count, +/// shifting in zero bits, and returns the result. If \a __count is greater +/// than 63, the returned result is all zeroes. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRLQ instruction. +/// +/// \param __a +/// A 256-bit vector of [4 x i64] to be shifted. +/// \param __count +/// A 128-bit vector of [2 x i64] whose lower element gives the unsigned +/// shift count (in bits). The upper element is ignored. +/// \returns A 256-bit vector of [4 x i64] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_srl_epi64(__m256i __a, __m128i __count) { @@ -875,60 +1171,222 @@ _mm_maskstore_epi64(long long *__X, __m128i __M, __m128i __Y) __builtin_ia32_maskstoreq(( __v2di *)__X, (__v2di)__M, (__v2di)__Y); } +/// Shifts each 32-bit element of the 256-bit vector of [8 x i32] in \a __X +/// left by the number of bits given in the corresponding element of the +/// 256-bit vector of [8 x i32] in \a __Y, shifting in zero bits, and +/// returns the result. If the shift count for any element is greater than +/// 31, the result for that element is zero. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSLLVD instruction. +/// +/// \param __X +/// A 256-bit vector of [8 x i32] to be shifted. +/// \param __Y +/// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in +/// bits). +/// \returns A 256-bit vector of [8 x i32] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_sllv_epi32(__m256i __X, __m256i __Y) { return (__m256i)__builtin_ia32_psllv8si((__v8si)__X, (__v8si)__Y); } +/// Shifts each 32-bit element of the 128-bit vector of [4 x i32] in \a __X +/// left by the number of bits given in the corresponding element of the +/// 128-bit vector of [4 x i32] in \a __Y, shifting in zero bits, and +/// returns the result. If the shift count for any element is greater than +/// 31, the result for that element is zero. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSLLVD instruction. +/// +/// \param __X +/// A 128-bit vector of [4 x i32] to be shifted. +/// \param __Y +/// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in +/// bits). +/// \returns A 128-bit vector of [4 x i32] containing the result. static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_sllv_epi32(__m128i __X, __m128i __Y) { return (__m128i)__builtin_ia32_psllv4si((__v4si)__X, (__v4si)__Y); } +/// Shifts each 64-bit element of the 256-bit vector of [4 x i64] in \a __X +/// left by the number of bits given in the corresponding element of the +/// 128-bit vector of [4 x i64] in \a __Y, shifting in zero bits, and +/// returns the result. If the shift count for any element is greater than +/// 63, the result for that element is zero. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSLLVQ instruction. +/// +/// \param __X +/// A 256-bit vector of [4 x i64] to be shifted. +/// \param __Y +/// A 256-bit vector of [4 x i64] containing the unsigned shift counts (in +/// bits). +/// \returns A 256-bit vector of [4 x i64] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_sllv_epi64(__m256i __X, __m256i __Y) { return (__m256i)__builtin_ia32_psllv4di((__v4di)__X, (__v4di)__Y); } +/// Shifts each 64-bit element of the 128-bit vector of [2 x i64] in \a __X +/// left by the number of bits given in the corresponding element of the +/// 128-bit vector of [2 x i64] in \a __Y, shifting in zero bits, and +/// returns the result. If the shift count for any element is greater than +/// 63, the result for that element is zero. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSLLVQ instruction. +/// +/// \param __X +/// A 128-bit vector of [2 x i64] to be shifted. +/// \param __Y +/// A 128-bit vector of [2 x i64] containing the unsigned shift counts (in +/// bits). +/// \returns A 128-bit vector of [2 x i64] containing the result. static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_sllv_epi64(__m128i __X, __m128i __Y) { return (__m128i)__builtin_ia32_psllv2di((__v2di)__X, (__v2di)__Y); } +/// Shifts each 32-bit element of the 256-bit vector of [8 x i32] in \a __X +/// right by the number of bits given in the corresponding element of the +/// 256-bit vector of [8 x i32] in \a __Y, shifting in sign bits, and +/// returns the result. If the shift count for any element is greater than +/// 31, the result for that element is 0 or -1 according to the sign bit +/// for that element. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRAVD instruction. +/// +/// \param __X +/// A 256-bit vector of [8 x i32] to be shifted. +/// \param __Y +/// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in +/// bits). +/// \returns A 256-bit vector of [8 x i32] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_srav_epi32(__m256i __X, __m256i __Y) { return (__m256i)__builtin_ia32_psrav8si((__v8si)__X, (__v8si)__Y); } +/// Shifts each 32-bit element of the 128-bit vector of [4 x i32] in \a __X +/// right by the number of bits given in the corresponding element of the +/// 128-bit vector of [4 x i32] in \a __Y, shifting in sign bits, and +/// returns the result. If the shift count for any element is greater than +/// 31, the result for that element is 0 or -1 according to the sign bit +/// for that element. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRAVD instruction. +/// +/// \param __X +/// A 128-bit vector of [4 x i32] to be shifted. +/// \param __Y +/// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in +/// bits). +/// \returns A 128-bit vector of [4 x i32] containing the result. static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_srav_epi32(__m128i __X, __m128i __Y) { return (__m128i)__builtin_ia32_psrav4si((__v4si)__X, (__v4si)__Y); } +/// Shifts each 32-bit element of the 256-bit vector of [8 x i32] in \a __X +/// right by the number of bits given in the corresponding element of the +/// 256-bit vector of [8 x i32] in \a __Y, shifting in zero bits, and +/// returns the result. If the shift count for any element is greater than +/// 31, the result for that element is zero. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRLVD instruction. +/// +/// \param __X +/// A 256-bit vector of [8 x i32] to be shifted. +/// \param __Y +/// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in +/// bits). +/// \returns A 256-bit vector of [8 x i32] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_srlv_epi32(__m256i __X, __m256i __Y) { return (__m256i)__builtin_ia32_psrlv8si((__v8si)__X, (__v8si)__Y); } +/// Shifts each 32-bit element of the 128-bit vector of [4 x i32] in \a __X +/// right by the number of bits given in the corresponding element of the +/// 128-bit vector of [4 x i32] in \a __Y, shifting in zero bits, and +/// returns the result. If the shift count for any element is greater than +/// 31, the result for that element is zero. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRLVD instruction. +/// +/// \param __X +/// A 128-bit vector of [4 x i32] to be shifted. +/// \param __Y +/// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in +/// bits). +/// \returns A 128-bit vector of [4 x i32] containing the result. static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_srlv_epi32(__m128i __X, __m128i __Y) { return (__m128i)__builtin_ia32_psrlv4si((__v4si)__X, (__v4si)__Y); } +/// Shifts each 64-bit element of the 256-bit vector of [4 x i64] in \a __X +/// right by the number of bits given in the corresponding element of the +/// 128-bit vector of [4 x i64] in \a __Y, shifting in zero bits, and +/// returns the result. If the shift count for any element is greater than +/// 63, the result for that element is zero. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRLVQ instruction. +/// +/// \param __X +/// A 256-bit vector of [4 x i64] to be shifted. +/// \param __Y +/// A 256-bit vector of [4 x i64] containing the unsigned shift counts (in +/// bits). +/// \returns A 256-bit vector of [4 x i64] containing the result. static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_srlv_epi64(__m256i __X, __m256i __Y) { return (__m256i)__builtin_ia32_psrlv4di((__v4di)__X, (__v4di)__Y); } +/// Shifts each 64-bit element of the 128-bit vector of [2 x i64] in \a __X +/// right by the number of bits given in the corresponding element of the +/// 128-bit vector of [2 x i64] in \a __Y, shifting in zero bits, and +/// returns the result. If the shift count for any element is greater than +/// 63, the result for that element is zero. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the \c VPSRLVQ instruction. +/// +/// \param __X +/// A 128-bit vector of [2 x i64] to be shifted. +/// \param __Y +/// A 128-bit vector of [2 x i64] containing the unsigned shift counts (in +/// bits). +/// \returns A 128-bit vector of [2 x i64] containing the result. static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_srlv_epi64(__m128i __X, __m128i __Y) { diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp index 2c87bfdc11339..a54386f9e8411 100644 --- a/clang/lib/Index/USRGeneration.cpp +++ b/clang/lib/Index/USRGeneration.cpp @@ -226,6 +226,11 @@ void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) { if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D))) return; + if (D->getType().isNull()) { + IgnoreResults = true; + return; + } + const unsigned StartSize = Buf.size(); VisitDeclContext(D->getDeclContext()); if (Buf.size() == StartSize) diff --git a/clang/lib/Lex/DependencyDirectivesScanner.cpp b/clang/lib/Lex/DependencyDirectivesScanner.cpp index a506b49176302..2bd2c5f8388c0 100644 --- a/clang/lib/Lex/DependencyDirectivesScanner.cpp +++ b/clang/lib/Lex/DependencyDirectivesScanner.cpp @@ -19,6 +19,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/Lexer.h" +#include "clang/Lex/Pragma.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" @@ -72,6 +73,8 @@ struct Scanner { // Set the lexer to use 'tok::at' for '@', instead of 'tok::unknown'. LangOpts.ObjC = true; LangOpts.LineComment = true; + // FIXME: we do not enable C11 or C++11, so we are missing u/u8/U"" and + // R"()" literals. return LangOpts; } @@ -91,6 +94,10 @@ struct Scanner { void skipLine(const char *&First, const char *const End); void skipDirective(StringRef Name, const char *&First, const char *const End); + /// Returns the spelling of a string literal or identifier after performing + /// any processing needed to handle \c clang::Token::NeedsCleaning. + StringRef cleanStringIfNeeded(const dependency_directives_scan::Token &Tok); + /// Lexes next token and if it is identifier returns its string, otherwise /// it skips the current line and returns \p std::nullopt. /// @@ -112,6 +119,22 @@ struct Scanner { const char *&First, const char *const End); + /// Lexes next token and returns true iff it matches the kind \p K. + /// Otherwise it skips the current line and returns false. + /// + /// In any case (whatever the token kind) \p First and the \p Lexer will + /// advance beyond the token. + [[nodiscard]] bool isNextTokenOrSkipLine(tok::TokenKind K, const char *&First, + const char *const End); + + /// Lexes next token and if it is string literal, returns its string. + /// Otherwise, it skips the current line and returns \p std::nullopt. + /// + /// In any case (whatever the token kind) \p First and the \p Lexer will + /// advance beyond the token. + [[nodiscard]] std::optional + tryLexStringLiteralOrSkipLine(const char *&First, const char *const End); + [[nodiscard]] bool scanImpl(const char *First, const char *const End); [[nodiscard]] bool lexPPLine(const char *&First, const char *const End); [[nodiscard]] bool lexAt(const char *&First, const char *const End); @@ -119,6 +142,7 @@ struct Scanner { [[nodiscard]] bool lexDefine(const char *HashLoc, const char *&First, const char *const End); [[nodiscard]] bool lexPragma(const char *&First, const char *const End); + [[nodiscard]] bool lex_Pragma(const char *&First, const char *const End); [[nodiscard]] bool lexEndif(const char *&First, const char *const End); [[nodiscard]] bool lexDefault(DirectiveKind Kind, const char *&First, const char *const End); @@ -525,15 +549,8 @@ void Scanner::lexPPDirectiveBody(const char *&First, const char *const End) { } } -[[nodiscard]] std::optional -Scanner::tryLexIdentifierOrSkipLine(const char *&First, const char *const End) { - const dependency_directives_scan::Token &Tok = lexToken(First, End); - if (Tok.isNot(tok::raw_identifier)) { - if (!Tok.is(tok::eod)) - skipLine(First, End); - return std::nullopt; - } - +StringRef +Scanner::cleanStringIfNeeded(const dependency_directives_scan::Token &Tok) { bool NeedsCleaning = Tok.Flags & clang::Token::NeedsCleaning; if (LLVM_LIKELY(!NeedsCleaning)) return Input.slice(Tok.Offset, Tok.getEnd()); @@ -541,6 +558,9 @@ Scanner::tryLexIdentifierOrSkipLine(const char *&First, const char *const End) { SmallString<64> Spelling; Spelling.resize(Tok.Length); + // FIXME: C++11 raw string literals need special handling (see getSpellingSlow + // in the Lexer). Currently we cannot see them due to our LangOpts. + unsigned SpellingLength = 0; const char *BufPtr = Input.begin() + Tok.Offset; const char *AfterIdent = Input.begin() + Tok.getEnd(); @@ -555,6 +575,18 @@ Scanner::tryLexIdentifierOrSkipLine(const char *&First, const char *const End) { .first->first(); } +std::optional +Scanner::tryLexIdentifierOrSkipLine(const char *&First, const char *const End) { + const dependency_directives_scan::Token &Tok = lexToken(First, End); + if (Tok.isNot(tok::raw_identifier)) { + if (!Tok.is(tok::eod)) + skipLine(First, End); + return std::nullopt; + } + + return cleanStringIfNeeded(Tok); +} + StringRef Scanner::lexIdentifier(const char *&First, const char *const End) { std::optional Id = tryLexIdentifierOrSkipLine(First, End); assert(Id && "expected identifier token"); @@ -572,6 +604,28 @@ bool Scanner::isNextIdentifierOrSkipLine(StringRef Id, const char *&First, return false; } +bool Scanner::isNextTokenOrSkipLine(tok::TokenKind K, const char *&First, + const char *const End) { + const dependency_directives_scan::Token &Tok = lexToken(First, End); + if (Tok.is(K)) + return true; + skipLine(First, End); + return false; +} + +std::optional +Scanner::tryLexStringLiteralOrSkipLine(const char *&First, + const char *const End) { + const dependency_directives_scan::Token &Tok = lexToken(First, End); + if (!tok::isStringLiteral(Tok.Kind)) { + if (!Tok.is(tok::eod)) + skipLine(First, End); + return std::nullopt; + } + + return cleanStringIfNeeded(Tok); +} + bool Scanner::lexAt(const char *&First, const char *const End) { // Handle "@import". @@ -629,6 +683,41 @@ bool Scanner::lexModule(const char *&First, const char *const End) { return lexModuleDirectiveBody(Kind, First, End); } +bool Scanner::lex_Pragma(const char *&First, const char *const End) { + if (!isNextTokenOrSkipLine(tok::l_paren, First, End)) + return false; + + std::optional Str = tryLexStringLiteralOrSkipLine(First, End); + + if (!Str || !isNextTokenOrSkipLine(tok::r_paren, First, End)) + return false; + + SmallString<64> Buffer(*Str); + prepare_PragmaString(Buffer); + + // Use a new scanner instance since the tokens will be inside the allocated + // string. We should already have captured all the relevant tokens in the + // current scanner. + SmallVector DiscardTokens; + const char *Begin = Buffer.c_str(); + Scanner PragmaScanner{StringRef(Begin, Buffer.size()), DiscardTokens, Diags, + InputSourceLoc}; + + PragmaScanner.TheLexer.setParsingPreprocessorDirective(true); + if (PragmaScanner.lexPragma(Begin, Buffer.end())) + return true; + + DirectiveKind K = PragmaScanner.topDirective(); + if (K == pp_none) { + skipLine(First, End); + return false; + } + + assert(Begin == Buffer.end()); + pushDirective(K); + return false; +} + bool Scanner::lexPragma(const char *&First, const char *const End) { std::optional FoundId = tryLexIdentifierOrSkipLine(First, End); if (!FoundId) @@ -713,6 +802,7 @@ static bool isStartOfRelevantLine(char First) { case 'i': case 'e': case 'm': + case '_': return true; } return false; @@ -749,6 +839,12 @@ bool Scanner::lexPPLine(const char *&First, const char *const End) { if (*First == 'i' || *First == 'e' || *First == 'm') return lexModule(First, End); + if (*First == '_') { + if (isNextIdentifierOrSkipLine("_Pragma", First, End)) + return lex_Pragma(First, End); + return false; + } + // Handle preprocessing directives. TheLexer.setParsingPreprocessorDirective(true); diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index 5a7357a5ada43..a650bbea1e488 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -1565,13 +1565,14 @@ HeaderSearch::findModuleForHeader(const FileEntry *File, bool AllowTextual, } ArrayRef -HeaderSearch::findAllModulesForHeader(const FileEntry *File) const { +HeaderSearch::findAllModulesForHeader(const FileEntry *File, + bool AllowCreation) const { if (ExternalSource) { // Make sure the external source has handled header info about this file, // which includes whether the file is part of a module. (void)getExistingFileInfo(File); } - return ModMap.findAllModulesForHeader(File); + return ModMap.findAllModulesForHeader(File, AllowCreation); } static bool suggestModule(HeaderSearch &HS, const FileEntry *File, diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 0e148a43dc92f..66e9a7e1dbea7 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -683,12 +683,12 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File) { } ArrayRef -ModuleMap::findAllModulesForHeader(const FileEntry *File) { +ModuleMap::findAllModulesForHeader(const FileEntry *File, bool AllowCreation) { HeadersMap::iterator Known = findKnownHeader(File); if (Known != Headers.end()) return Known->second; - if (findOrCreateModuleForHeaderInUmbrellaDir(File)) + if (AllowCreation && findOrCreateModuleForHeaderInUmbrellaDir(File)) return Headers.find(File)->second; return std::nullopt; diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index db8a5891679f4..0b892a3755a50 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -262,17 +262,48 @@ void Preprocessor::Handle_Pragma(Token &Tok) { SourceLocation RParenLoc = Tok.getLocation(); bool Invalid = false; - std::string StrVal = getSpelling(StrTok, &Invalid); + SmallString<64> StrVal; + StrVal.resize(StrTok.getLength()); + StringRef StrValRef = getSpelling(StrTok, StrVal, &Invalid); if (Invalid) { Diag(PragmaLoc, diag::err__Pragma_malformed); return; } - // The _Pragma is lexically sound. Destringize according to C11 6.10.9.1: - // "The string literal is destringized by deleting any encoding prefix, - // deleting the leading and trailing double-quotes, replacing each escape - // sequence \" by a double-quote, and replacing each escape sequence \\ by a - // single backslash." + assert(StrValRef.size() <= StrVal.size()); + + // If the token was spelled somewhere else, copy it. + if (StrValRef.begin() != StrVal.begin()) + StrVal.assign(StrValRef); + // Truncate if necessary. + else if (StrValRef.size() != StrVal.size()) + StrVal.resize(StrValRef.size()); + + // The _Pragma is lexically sound. Destringize according to C11 6.10.9.1. + prepare_PragmaString(StrVal); + + // Plop the string (including the newline and trailing null) into a buffer + // where we can lex it. + Token TmpTok; + TmpTok.startToken(); + CreateString(StrVal, TmpTok); + SourceLocation TokLoc = TmpTok.getLocation(); + + // Make and enter a lexer object so that we lex and expand the tokens just + // like any others. + Lexer *TL = Lexer::Create_PragmaLexer(TokLoc, PragmaLoc, RParenLoc, + StrVal.size(), *this); + + EnterSourceFileWithLexer(TL, nullptr); + + // With everything set up, lex this as a #pragma directive. + HandlePragmaDirective({PIK__Pragma, PragmaLoc}); + + // Finally, return whatever came after the pragma directive. + return Lex(Tok); +} + +void clang::prepare_PragmaString(SmallVectorImpl &StrVal) { if (StrVal[0] == 'L' || StrVal[0] == 'U' || (StrVal[0] == 'u' && StrVal[1] != '8')) StrVal.erase(StrVal.begin()); @@ -296,8 +327,8 @@ void Preprocessor::Handle_Pragma(Token &Tok) { // Remove 'R " d-char-sequence' and 'd-char-sequence "'. We'll replace the // parens below. - StrVal.erase(0, 2 + NumDChars); - StrVal.erase(StrVal.size() - 1 - NumDChars); + StrVal.erase(StrVal.begin(), StrVal.begin() + 2 + NumDChars); + StrVal.erase(StrVal.end() - 1 - NumDChars, StrVal.end()); } else { assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' && "Invalid string token!"); @@ -319,27 +350,7 @@ void Preprocessor::Handle_Pragma(Token &Tok) { StrVal[0] = ' '; // Replace the terminating quote with a \n. - StrVal[StrVal.size()-1] = '\n'; - - // Plop the string (including the newline and trailing null) into a buffer - // where we can lex it. - Token TmpTok; - TmpTok.startToken(); - CreateString(StrVal, TmpTok); - SourceLocation TokLoc = TmpTok.getLocation(); - - // Make and enter a lexer object so that we lex and expand the tokens just - // like any others. - Lexer *TL = Lexer::Create_PragmaLexer(TokLoc, PragmaLoc, RParenLoc, - StrVal.size(), *this); - - EnterSourceFileWithLexer(TL, nullptr); - - // With everything set up, lex this as a #pragma directive. - HandlePragmaDirective({PIK__Pragma, PragmaLoc}); - - // Finally, return whatever came after the pragma directive. - return Lex(Tok); + StrVal[StrVal.size() - 1] = '\n'; } /// HandleMicrosoft__pragma - Like Handle_Pragma except the pragma text diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 249b151cc61ad..54cbc07daa634 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2176,13 +2176,16 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, return Actions.ConvertDeclToDeclGroup(TheDecl); } - if (isDeclarationSpecifier(ImplicitTypenameContext::No)) { - // If there is an invalid declaration specifier right after the - // function prototype, then we must be in a missing semicolon case - // where this isn't actually a body. Just fall through into the code - // that handles it as a prototype, and let the top-level code handle - // the erroneous declspec where it would otherwise expect a comma or - // semicolon. + if (isDeclarationSpecifier(ImplicitTypenameContext::No) || + Tok.is(tok::kw_namespace)) { + // If there is an invalid declaration specifier or a namespace + // definition right after the function prototype, then we must be in a + // missing semicolon case where this isn't actually a body. Just fall + // through into the code that handles it as a prototype, and let the + // top-level code handle the erroneous declspec where it would + // otherwise expect a comma or semicolon. Note that + // isDeclarationSpecifier already covers 'inline namespace', since + // 'inline' can be a declaration specifier. } else { Diag(Tok, diag::err_expected_fn_body); SkipUntil(tok::semi); @@ -2303,10 +2306,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // Okay, there was no semicolon and one was expected. If we see a // declaration specifier, just assume it was missing and continue parsing. // Otherwise things are very confused and we skip to recover. - if (!isDeclarationSpecifier(ImplicitTypenameContext::No)) { - SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); - TryConsumeToken(tok::semi); - } + if (!isDeclarationSpecifier(ImplicitTypenameContext::No)) + SkipMalformedDecl(); } return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup); diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 72df117c123e6..964d985b6b6e6 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -275,10 +275,7 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { - // If so, skip until the semi-colon or a }. - SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); - if (Tok.is(tok::semi)) - ConsumeToken(); + SkipMalformedDecl(); return nullptr; } diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index f5c48ed89e93d..c2b6d362d966d 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -1,4 +1,5 @@ -//=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- C++ -*-=// +//=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- C++ +//-*-=// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/AnalysisBasedWarnings.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/EvaluatedExprVisitor.h" @@ -25,6 +27,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/Type.h" #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" #include "clang/Analysis/Analyses/CalledOnceCheck.h" #include "clang/Analysis/Analyses/Consumed.h" @@ -35,6 +38,7 @@ #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/CFGStmtMap.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" @@ -43,6 +47,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -59,61 +64,60 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace { - class UnreachableCodeHandler : public reachable_code::Callback { - Sema &S; - SourceRange PreviousSilenceableCondVal; - - public: - UnreachableCodeHandler(Sema &s) : S(s) {} - - void HandleUnreachable(reachable_code::UnreachableKind UK, SourceLocation L, - SourceRange SilenceableCondVal, SourceRange R1, - SourceRange R2, bool HasFallThroughAttr) override { - // If the diagnosed code is `[[fallthrough]];` and - // `-Wunreachable-code-fallthrough` is enabled, suppress `code will never - // be executed` warning to avoid generating diagnostic twice - if (HasFallThroughAttr && - !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr, - SourceLocation())) - return; - - // Avoid reporting multiple unreachable code diagnostics that are - // triggered by the same conditional value. - if (PreviousSilenceableCondVal.isValid() && - SilenceableCondVal.isValid() && - PreviousSilenceableCondVal == SilenceableCondVal) - return; - PreviousSilenceableCondVal = SilenceableCondVal; - - unsigned diag = diag::warn_unreachable; - switch (UK) { - case reachable_code::UK_Break: - diag = diag::warn_unreachable_break; - break; - case reachable_code::UK_Return: - diag = diag::warn_unreachable_return; - break; - case reachable_code::UK_Loop_Increment: - diag = diag::warn_unreachable_loop_increment; - break; - case reachable_code::UK_Other: - break; - } +class UnreachableCodeHandler : public reachable_code::Callback { + Sema &S; + SourceRange PreviousSilenceableCondVal; - S.Diag(L, diag) << R1 << R2; +public: + UnreachableCodeHandler(Sema &s) : S(s) {} + + void HandleUnreachable(reachable_code::UnreachableKind UK, SourceLocation L, + SourceRange SilenceableCondVal, SourceRange R1, + SourceRange R2, bool HasFallThroughAttr) override { + // If the diagnosed code is `[[fallthrough]];` and + // `-Wunreachable-code-fallthrough` is enabled, suppress `code will never + // be executed` warning to avoid generating diagnostic twice + if (HasFallThroughAttr && + !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr, + SourceLocation())) + return; - SourceLocation Open = SilenceableCondVal.getBegin(); - if (Open.isValid()) { - SourceLocation Close = SilenceableCondVal.getEnd(); - Close = S.getLocForEndOfToken(Close); - if (Close.isValid()) { - S.Diag(Open, diag::note_unreachable_silence) + // Avoid reporting multiple unreachable code diagnostics that are + // triggered by the same conditional value. + if (PreviousSilenceableCondVal.isValid() && SilenceableCondVal.isValid() && + PreviousSilenceableCondVal == SilenceableCondVal) + return; + PreviousSilenceableCondVal = SilenceableCondVal; + + unsigned diag = diag::warn_unreachable; + switch (UK) { + case reachable_code::UK_Break: + diag = diag::warn_unreachable_break; + break; + case reachable_code::UK_Return: + diag = diag::warn_unreachable_return; + break; + case reachable_code::UK_Loop_Increment: + diag = diag::warn_unreachable_loop_increment; + break; + case reachable_code::UK_Other: + break; + } + + S.Diag(L, diag) << R1 << R2; + + SourceLocation Open = SilenceableCondVal.getBegin(); + if (Open.isValid()) { + SourceLocation Close = SilenceableCondVal.getEnd(); + Close = S.getLocForEndOfToken(Close); + if (Close.isValid()) { + S.Diag(Open, diag::note_unreachable_silence) << FixItHint::CreateInsertion(Open, "/* DISABLES CODE */ (") << FixItHint::CreateInsertion(Close, ")"); - } } } - }; + } +}; } // anonymous namespace /// CheckUnreachable - Check for unreachable code. @@ -273,7 +277,8 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, return; CFG *cfg = AC.getCFG(); - if (!cfg) return; + if (!cfg) + return; // If the exit block is unreachable, skip processing the function. if (cfg->getExit().pred_empty()) @@ -309,10 +314,9 @@ static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock, if (Succ->getBlockID() == Body->getExit().getBlockID()) return true; - if (auto *Catch = - dyn_cast_or_null(Succ->getLabel())) { + if (auto *Catch = dyn_cast_or_null(Succ->getLabel())) { QualType Caught = Catch->getCaughtType(); - if (Caught.isNull() || // catch (...) catches everything + if (Caught.isNull() || // catch (...) catches everything !E->getSubExpr() || // throw; is considered cuaght by any handler S.handlerCanCatch(Caught, E->getSubExpr()->getType())) // Exception doesn't escape via this path. @@ -331,7 +335,8 @@ static void visitReachableThrows( CFG *BodyCFG, llvm::function_ref Visit) { llvm::BitVector Reachable(BodyCFG->getNumBlockIDs()); - clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(), Reachable); + clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(), + Reachable); for (CFGBlock *B : *BodyCFG) { if (!Reachable[B->getBlockID()]) continue; @@ -354,8 +359,8 @@ static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, (isa(FD) || FD->getDeclName().getCXXOverloadedOperator() == OO_Delete || FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) { - if (const auto *Ty = FD->getTypeSourceInfo()->getType()-> - getAs()) + if (const auto *Ty = + FD->getTypeSourceInfo()->getType()->getAs()) S.Diag(FD->getLocation(), diag::note_throw_in_dtor) << !isa(FD) << !Ty->hasExceptionSpec() << FD->getExceptionSpecSourceRange(); @@ -372,10 +377,11 @@ static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, return; if (BodyCFG->getExit().pred_empty()) return; - visitReachableThrows(BodyCFG, [&](const CXXThrowExpr *Throw, CFGBlock &Block) { - if (throwEscapes(S, Throw, Block, BodyCFG)) - EmitDiagForCXXThrowInNonThrowingFunc(S, Throw->getThrowLoc(), FD); - }); + visitReachableThrows( + BodyCFG, [&](const CXXThrowExpr *Throw, CFGBlock &Block) { + if (throwEscapes(S, Throw, Block, BodyCFG)) + EmitDiagForCXXThrowInNonThrowingFunc(S, Throw->getThrowLoc(), FD); + }); } static bool isNoexcept(const FunctionDecl *FD) { @@ -408,13 +414,14 @@ enum ControlFlowKind { /// will return. static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { CFG *cfg = AC.getCFG(); - if (!cfg) return UnknownFallThrough; + if (!cfg) + return UnknownFallThrough; // The CFG leaves in dead things, and we don't want the dead code paths to // confuse us, so we mark all live things first. llvm::BitVector live(cfg->getNumBlockIDs()); - unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(), - live); + unsigned count = + reachable_code::ScanReachableFromBlock(&cfg->getEntry(), live); bool AddEHEdges = AC.getAddEHEdges(); if (!AddEHEdges && count != cfg->getNumBlockIDs()) @@ -467,7 +474,7 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { // statement (if it exists). CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend(); - for ( ; ri != re ; ++ri) + for (; ri != re; ++ri) if (ri->getAs()) break; @@ -541,14 +548,12 @@ struct CheckFallThroughDiagnostics { static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) { CheckFallThroughDiagnostics D; D.FuncLoc = Func->getLocation(); - D.diag_MaybeFallThrough_HasNoReturn = - diag::warn_falloff_noreturn_function; + D.diag_MaybeFallThrough_HasNoReturn = diag::warn_falloff_noreturn_function; D.diag_MaybeFallThrough_ReturnsNonVoid = - diag::warn_maybe_falloff_nonvoid_function; - D.diag_AlwaysFallThrough_HasNoReturn = - diag::warn_falloff_noreturn_function; + diag::warn_maybe_falloff_nonvoid_function; + D.diag_AlwaysFallThrough_HasNoReturn = diag::warn_falloff_noreturn_function; D.diag_AlwaysFallThrough_ReturnsNonVoid = - diag::warn_falloff_nonvoid_function; + diag::warn_falloff_nonvoid_function; // Don't suggest that virtual functions be marked "noreturn", since they // might be overridden by non-noreturn functions. @@ -562,8 +567,7 @@ struct CheckFallThroughDiagnostics { isTemplateInstantiation = Function->isTemplateInstantiation(); if (!isVirtualMethod && !isTemplateInstantiation) - D.diag_NeverFallThroughOrReturn = - diag::warn_suggest_noreturn_function; + D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function; else D.diag_NeverFallThroughOrReturn = 0; @@ -588,13 +592,12 @@ struct CheckFallThroughDiagnostics { static CheckFallThroughDiagnostics MakeForBlock() { CheckFallThroughDiagnostics D; D.diag_MaybeFallThrough_HasNoReturn = - diag::err_noreturn_block_has_return_expr; + diag::err_noreturn_block_has_return_expr; D.diag_MaybeFallThrough_ReturnsNonVoid = - diag::err_maybe_falloff_nonvoid_block; + diag::err_maybe_falloff_nonvoid_block; D.diag_AlwaysFallThrough_HasNoReturn = - diag::err_noreturn_block_has_return_expr; - D.diag_AlwaysFallThrough_ReturnsNonVoid = - diag::err_falloff_nonvoid_block; + diag::err_noreturn_block_has_return_expr; + D.diag_AlwaysFallThrough_ReturnsNonVoid = diag::err_falloff_nonvoid_block; D.diag_NeverFallThroughOrReturn = 0; D.funMode = Block; return D; @@ -603,13 +606,12 @@ struct CheckFallThroughDiagnostics { static CheckFallThroughDiagnostics MakeForLambda() { CheckFallThroughDiagnostics D; D.diag_MaybeFallThrough_HasNoReturn = - diag::err_noreturn_lambda_has_return_expr; + diag::err_noreturn_lambda_has_return_expr; D.diag_MaybeFallThrough_ReturnsNonVoid = - diag::warn_maybe_falloff_nonvoid_lambda; + diag::warn_maybe_falloff_nonvoid_lambda; D.diag_AlwaysFallThrough_HasNoReturn = - diag::err_noreturn_lambda_has_return_expr; - D.diag_AlwaysFallThrough_ReturnsNonVoid = - diag::warn_falloff_nonvoid_lambda; + diag::err_noreturn_lambda_has_return_expr; + D.diag_AlwaysFallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid_lambda; D.diag_NeverFallThroughOrReturn = 0; D.funMode = Lambda; return D; @@ -661,14 +663,12 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, else ReturnsVoid = FD->getReturnType()->isVoidType(); HasNoReturn = FD->isNoReturn(); - } - else if (const auto *MD = dyn_cast(D)) { + } else if (const auto *MD = dyn_cast(D)) { ReturnsVoid = MD->getReturnType()->isVoidType(); HasNoReturn = MD->hasAttr(); - } - else if (isa(D)) { + } else if (isa(D)) { if (const FunctionType *FT = - BlockType->getPointeeType()->getAs()) { + BlockType->getPointeeType()->getAs()) { if (FT->getReturnType()->isVoidType()) ReturnsVoid = true; if (FT->getNoReturnAttr()) @@ -680,7 +680,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, // Short circuit for compilation speed. if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) - return; + return; SourceLocation LBrace = Body->getBeginLoc(), RBrace = Body->getEndLoc(); auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) { if (IsCoroutine) @@ -695,34 +695,34 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, // Either in a function body compound statement, or a function-try-block. switch (CheckFallThrough(AC)) { - case UnknownFallThrough: - break; + case UnknownFallThrough: + break; - case MaybeFallThrough: - if (HasNoReturn) - EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn); - else if (!ReturnsVoid) - EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid); - break; - case AlwaysFallThrough: - if (HasNoReturn) - EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn); - else if (!ReturnsVoid) - EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid); - break; - case NeverFallThroughOrReturn: - if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) { - if (const FunctionDecl *FD = dyn_cast(D)) { - S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD; - } else if (const ObjCMethodDecl *MD = dyn_cast(D)) { - S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD; - } else { - S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn); - } + case MaybeFallThrough: + if (HasNoReturn) + EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn); + else if (!ReturnsVoid) + EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid); + break; + case AlwaysFallThrough: + if (HasNoReturn) + EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn); + else if (!ReturnsVoid) + EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid); + break; + case NeverFallThroughOrReturn: + if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) { + if (const FunctionDecl *FD = dyn_cast(D)) { + S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD; + } else if (const ObjCMethodDecl *MD = dyn_cast(D)) { + S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD; + } else { + S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn); } - break; - case NeverFallThrough: - break; + } + break; + case NeverFallThrough: + break; } } @@ -742,7 +742,7 @@ class ContainsReference : public ConstEvaluatedExprVisitor { typedef ConstEvaluatedExprVisitor Inherited; ContainsReference(ASTContext &Context, const DeclRefExpr *Needle) - : Inherited(Context), FoundReference(false), Needle(Needle) {} + : Inherited(Context), FoundReference(false), Needle(Needle) {} void VisitExpr(const Expr *E) { // Stop evaluating if we already have a reference. @@ -765,8 +765,7 @@ class ContainsReference : public ConstEvaluatedExprVisitor { static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) { QualType VariableTy = VD->getType().getCanonicalType(); - if (VariableTy->isBlockPointerType() && - !VD->hasAttr()) { + if (VariableTy->isBlockPointerType() && !VD->hasAttr()) { S.Diag(VD->getLocation(), diag::note_block_var_fixit_add_initialization) << VD->getDeclName() << FixItHint::CreateInsertion(VD->getLocation(), "__block "); @@ -788,16 +787,16 @@ static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) { if (Init.empty()) return false; - S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName() - << FixItHint::CreateInsertion(Loc, Init); + S.Diag(Loc, diag::note_var_fixit_add_initialization) + << VD->getDeclName() << FixItHint::CreateInsertion(Loc, Init); return true; } /// Create a fixit to remove an if-like statement, on the assumption that its /// condition is CondVal. static void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then, - const Stmt *Else, bool CondVal, - FixItHint &Fixit1, FixItHint &Fixit2) { + const Stmt *Else, bool CondVal, FixItHint &Fixit1, + FixItHint &Fixit2) { if (CondVal) { // If condition is always true, remove all but the 'then'. Fixit1 = FixItHint::CreateRemoval( @@ -833,10 +832,10 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, case UninitUse::AfterDecl: case UninitUse::AfterCall: S.Diag(VD->getLocation(), diag::warn_sometimes_uninit_var) - << VD->getDeclName() << IsCapturedByBlock - << (Use.getKind() == UninitUse::AfterDecl ? 4 : 5) - << const_cast(VD->getLexicalDeclContext()) - << VD->getSourceRange(); + << VD->getDeclName() << IsCapturedByBlock + << (Use.getKind() == UninitUse::AfterDecl ? 4 : 5) + << const_cast(VD->getLexicalDeclContext()) + << VD->getSourceRange(); S.Diag(Use.getUser()->getBeginLoc(), diag::note_uninit_var_use) << IsCapturedByBlock << Use.getUser()->getSourceRange(); return; @@ -865,9 +864,9 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, // For all binary terminators, branch 0 is taken if the condition is true, // and branch 1 is taken if the condition is false. int RemoveDiagKind = -1; - const char *FixitStr = - S.getLangOpts().CPlusPlus ? (I->Output ? "true" : "false") - : (I->Output ? "1" : "0"); + const char *FixitStr = S.getLangOpts().CPlusPlus + ? (I->Output ? "true" : "false") + : (I->Output ? "1" : "0"); FixItHint Fixit1, Fixit2; switch (Term ? Term->getStmtClass() : Stmt::DeclStmtClass) { @@ -883,8 +882,8 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, Str = "if"; Range = IS->getCond()->getSourceRange(); RemoveDiagKind = 0; - CreateIfFixit(S, IS, IS->getThen(), IS->getElse(), - I->Output, Fixit1, Fixit2); + CreateIfFixit(S, IS, IS->getThen(), IS->getElse(), I->Output, Fixit1, + Fixit2); break; } case Stmt::ConditionalOperatorClass: { @@ -893,8 +892,8 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, Str = "?:"; Range = CO->getCond()->getSourceRange(); RemoveDiagKind = 0; - CreateIfFixit(S, CO, CO->getTrueExpr(), CO->getFalseExpr(), - I->Output, Fixit1, Fixit2); + CreateIfFixit(S, CO, CO->getTrueExpr(), CO->getFalseExpr(), I->Output, + Fixit1, Fixit2); break; } case Stmt::BinaryOperatorClass: { @@ -969,13 +968,13 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, } S.Diag(Range.getBegin(), diag::warn_sometimes_uninit_var) - << VD->getDeclName() << IsCapturedByBlock << DiagKind - << Str << I->Output << Range; + << VD->getDeclName() << IsCapturedByBlock << DiagKind << Str + << I->Output << Range; S.Diag(User->getBeginLoc(), diag::note_uninit_var_use) << IsCapturedByBlock << User->getSourceRange(); if (RemoveDiagKind != -1) S.Diag(Fixit1.RemoveRange.getBegin(), diag::note_uninit_fixit_remove_cond) - << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2; + << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2; Diagnosed = true; } @@ -1050,81 +1049,77 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, } namespace { - class FallthroughMapper : public RecursiveASTVisitor { - public: - FallthroughMapper(Sema &S) - : FoundSwitchStatements(false), - S(S) { - } +class FallthroughMapper : public RecursiveASTVisitor { +public: + FallthroughMapper(Sema &S) : FoundSwitchStatements(false), S(S) {} - bool foundSwitchStatements() const { return FoundSwitchStatements; } + bool foundSwitchStatements() const { return FoundSwitchStatements; } - void markFallthroughVisited(const AttributedStmt *Stmt) { - bool Found = FallthroughStmts.erase(Stmt); - assert(Found); - (void)Found; - } + void markFallthroughVisited(const AttributedStmt *Stmt) { + bool Found = FallthroughStmts.erase(Stmt); + assert(Found); + (void)Found; + } + + typedef llvm::SmallPtrSet AttrStmts; - typedef llvm::SmallPtrSet AttrStmts; + const AttrStmts &getFallthroughStmts() const { return FallthroughStmts; } - const AttrStmts &getFallthroughStmts() const { - return FallthroughStmts; + void fillReachableBlocks(CFG *Cfg) { + assert(ReachableBlocks.empty() && "ReachableBlocks already filled"); + std::deque BlockQueue; + + ReachableBlocks.insert(&Cfg->getEntry()); + BlockQueue.push_back(&Cfg->getEntry()); + // Mark all case blocks reachable to avoid problems with switching on + // constants, covered enums, etc. + // These blocks can contain fall-through annotations, and we don't want to + // issue a warn_fallthrough_attr_unreachable for them. + for (const auto *B : *Cfg) { + const Stmt *L = B->getLabel(); + if (L && isa(L) && ReachableBlocks.insert(B).second) + BlockQueue.push_back(B); } - void fillReachableBlocks(CFG *Cfg) { - assert(ReachableBlocks.empty() && "ReachableBlocks already filled"); - std::deque BlockQueue; - - ReachableBlocks.insert(&Cfg->getEntry()); - BlockQueue.push_back(&Cfg->getEntry()); - // Mark all case blocks reachable to avoid problems with switching on - // constants, covered enums, etc. - // These blocks can contain fall-through annotations, and we don't want to - // issue a warn_fallthrough_attr_unreachable for them. - for (const auto *B : *Cfg) { - const Stmt *L = B->getLabel(); - if (L && isa(L) && ReachableBlocks.insert(B).second) + while (!BlockQueue.empty()) { + const CFGBlock *P = BlockQueue.front(); + BlockQueue.pop_front(); + for (const CFGBlock *B : P->succs()) { + if (B && ReachableBlocks.insert(B).second) BlockQueue.push_back(B); } - - while (!BlockQueue.empty()) { - const CFGBlock *P = BlockQueue.front(); - BlockQueue.pop_front(); - for (const CFGBlock *B : P->succs()) { - if (B && ReachableBlocks.insert(B).second) - BlockQueue.push_back(B); - } - } } + } - bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt, - bool IsTemplateInstantiation) { - assert(!ReachableBlocks.empty() && "ReachableBlocks empty"); + bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt, + bool IsTemplateInstantiation) { + assert(!ReachableBlocks.empty() && "ReachableBlocks empty"); - int UnannotatedCnt = 0; - AnnotatedCnt = 0; + int UnannotatedCnt = 0; + AnnotatedCnt = 0; - std::deque BlockQueue(B.pred_begin(), B.pred_end()); - while (!BlockQueue.empty()) { - const CFGBlock *P = BlockQueue.front(); - BlockQueue.pop_front(); - if (!P) continue; + std::deque BlockQueue(B.pred_begin(), B.pred_end()); + while (!BlockQueue.empty()) { + const CFGBlock *P = BlockQueue.front(); + BlockQueue.pop_front(); + if (!P) + continue; - const Stmt *Term = P->getTerminatorStmt(); - if (Term && isa(Term)) - continue; // Switch statement, good. + const Stmt *Term = P->getTerminatorStmt(); + if (Term && isa(Term)) + continue; // Switch statement, good. - const SwitchCase *SW = dyn_cast_or_null(P->getLabel()); - if (SW && SW->getSubStmt() == B.getLabel() && P->begin() == P->end()) - continue; // Previous case label has no statements, good. + const SwitchCase *SW = dyn_cast_or_null(P->getLabel()); + if (SW && SW->getSubStmt() == B.getLabel() && P->begin() == P->end()) + continue; // Previous case label has no statements, good. - const LabelStmt *L = dyn_cast_or_null(P->getLabel()); - if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end()) - continue; // Case label is preceded with a normal label, good. + const LabelStmt *L = dyn_cast_or_null(P->getLabel()); + if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end()) + continue; // Case label is preceded with a normal label, good. - if (!ReachableBlocks.count(P)) { - for (const CFGElement &Elem : llvm::reverse(*P)) { - if (std::optional CS = Elem.getAs()) { + if (!ReachableBlocks.count(P)) { + for (const CFGElement &Elem : llvm::reverse(*P)) { + if (std::optional CS = Elem.getAs()) { if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) { // Don't issue a warning for an unreachable fallthrough // attribute in template instantiations as it may not be @@ -1137,110 +1132,109 @@ namespace { break; } // Don't care about other unreachable statements. - } } - // If there are no unreachable statements, this may be a special - // case in CFG: - // case X: { - // A a; // A has a destructor. - // break; - // } - // // <<<< This place is represented by a 'hanging' CFG block. - // case Y: - continue; - } - - const Stmt *LastStmt = getLastStmt(*P); - if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) { - markFallthroughVisited(AS); - ++AnnotatedCnt; - continue; // Fallthrough annotation, good. - } - - if (!LastStmt) { // This block contains no executable statements. - // Traverse its predecessors. - std::copy(P->pred_begin(), P->pred_end(), - std::back_inserter(BlockQueue)); - continue; } + // If there are no unreachable statements, this may be a special + // case in CFG: + // case X: { + // A a; // A has a destructor. + // break; + // } + // // <<<< This place is represented by a 'hanging' CFG block. + // case Y: + continue; + } - ++UnannotatedCnt; + const Stmt *LastStmt = getLastStmt(*P); + if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) { + markFallthroughVisited(AS); + ++AnnotatedCnt; + continue; // Fallthrough annotation, good. } - return !!UnannotatedCnt; - } - // RecursiveASTVisitor setup. - bool shouldWalkTypesOfTypeLocs() const { return false; } + if (!LastStmt) { // This block contains no executable statements. + // Traverse its predecessors. + std::copy(P->pred_begin(), P->pred_end(), + std::back_inserter(BlockQueue)); + continue; + } - bool VisitAttributedStmt(AttributedStmt *S) { - if (asFallThroughAttr(S)) - FallthroughStmts.insert(S); - return true; + ++UnannotatedCnt; } + return !!UnannotatedCnt; + } - bool VisitSwitchStmt(SwitchStmt *S) { - FoundSwitchStatements = true; - return true; - } + // RecursiveASTVisitor setup. + bool shouldWalkTypesOfTypeLocs() const { return false; } - // We don't want to traverse local type declarations. We analyze their - // methods separately. - bool TraverseDecl(Decl *D) { return true; } + bool VisitAttributedStmt(AttributedStmt *S) { + if (asFallThroughAttr(S)) + FallthroughStmts.insert(S); + return true; + } - // We analyze lambda bodies separately. Skip them here. - bool TraverseLambdaExpr(LambdaExpr *LE) { - // Traverse the captures, but not the body. - for (const auto C : zip(LE->captures(), LE->capture_inits())) - TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C)); - return true; - } + bool VisitSwitchStmt(SwitchStmt *S) { + FoundSwitchStatements = true; + return true; + } - private: + // We don't want to traverse local type declarations. We analyze their + // methods separately. + bool TraverseDecl(Decl *D) { return true; } - static const AttributedStmt *asFallThroughAttr(const Stmt *S) { - if (const AttributedStmt *AS = dyn_cast_or_null(S)) { - if (hasSpecificAttr(AS->getAttrs())) - return AS; - } - return nullptr; - } + // We analyze lambda bodies separately. Skip them here. + bool TraverseLambdaExpr(LambdaExpr *LE) { + // Traverse the captures, but not the body. + for (const auto C : zip(LE->captures(), LE->capture_inits())) + TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C)); + return true; + } - static const Stmt *getLastStmt(const CFGBlock &B) { - if (const Stmt *Term = B.getTerminatorStmt()) - return Term; - for (const CFGElement &Elem : llvm::reverse(B)) - if (std::optional CS = Elem.getAs()) - return CS->getStmt(); - // Workaround to detect a statement thrown out by CFGBuilder: - // case X: {} case Y: - // case X: ; case Y: - if (const SwitchCase *SW = dyn_cast_or_null(B.getLabel())) - if (!isa(SW->getSubStmt())) - return SW->getSubStmt(); - - return nullptr; +private: + static const AttributedStmt *asFallThroughAttr(const Stmt *S) { + if (const AttributedStmt *AS = dyn_cast_or_null(S)) { + if (hasSpecificAttr(AS->getAttrs())) + return AS; } + return nullptr; + } - bool FoundSwitchStatements; - AttrStmts FallthroughStmts; - Sema &S; - llvm::SmallPtrSet ReachableBlocks; - }; + static const Stmt *getLastStmt(const CFGBlock &B) { + if (const Stmt *Term = B.getTerminatorStmt()) + return Term; + for (const CFGElement &Elem : llvm::reverse(B)) + if (std::optional CS = Elem.getAs()) + return CS->getStmt(); + // Workaround to detect a statement thrown out by CFGBuilder: + // case X: {} case Y: + // case X: ; case Y: + if (const SwitchCase *SW = dyn_cast_or_null(B.getLabel())) + if (!isa(SW->getSubStmt())) + return SW->getSubStmt(); + + return nullptr; + } + + bool FoundSwitchStatements; + AttrStmts FallthroughStmts; + Sema &S; + llvm::SmallPtrSet ReachableBlocks; +}; } // anonymous namespace static StringRef getFallthroughAttrSpelling(Preprocessor &PP, SourceLocation Loc) { - TokenValue FallthroughTokens[] = { - tok::l_square, tok::l_square, - PP.getIdentifierInfo("fallthrough"), - tok::r_square, tok::r_square - }; - - TokenValue ClangFallthroughTokens[] = { - tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"), - tok::coloncolon, PP.getIdentifierInfo("fallthrough"), - tok::r_square, tok::r_square - }; + TokenValue FallthroughTokens[] = {tok::l_square, tok::l_square, + PP.getIdentifierInfo("fallthrough"), + tok::r_square, tok::r_square}; + + TokenValue ClangFallthroughTokens[] = {tok::l_square, + tok::l_square, + PP.getIdentifierInfo("clang"), + tok::coloncolon, + PP.getIdentifierInfo("fallthrough"), + tok::r_square, + tok::r_square}; bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17 && !PP.getLangOpts().C2x; @@ -1355,13 +1349,12 @@ static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM, static void diagnoseRepeatedUseOfWeak(Sema &S, const sema::FunctionScopeInfo *CurFn, - const Decl *D, - const ParentMap &PM) { + const Decl *D, const ParentMap &PM) { typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy; typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap; typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector; typedef std::pair - StmtUsesPair; + StmtUsesPair; ASTContext &Ctx = S.getASTContext(); @@ -1375,7 +1368,7 @@ static void diagnoseRepeatedUseOfWeak(Sema &S, // Find the first read of the weak object. WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end(); - for ( ; UI != UE; ++UI) { + for (; UI != UE; ++UI) { if (UI->isUnsafe()) break; } @@ -1432,12 +1425,7 @@ static void diagnoseRepeatedUseOfWeak(Sema &S, // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak. // FIXME: Should we use a common classification enum and the same set of // possibilities all throughout Sema? - enum { - Function, - Method, - Block, - Lambda - } FunctionKind; + enum { Function, Method, Block, Lambda } FunctionKind; if (isa(CurFn)) FunctionKind = Block; @@ -1468,12 +1456,7 @@ static void diagnoseRepeatedUseOfWeak(Sema &S, // Classify the weak object being accessed for better warning text. // This enum should stay in sync with the cases in // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak. - enum { - Variable, - Property, - ImplicitProperty, - Ivar - } ObjectKind; + enum { Variable, Property, ImplicitProperty, Ivar } ObjectKind; const NamedDecl *KeyProp = Key.getProperty(); if (isa(KeyProp)) @@ -1638,7 +1621,7 @@ class UninitValsDiagReporter : public UninitVariablesHandler { } private: - static bool hasAlwaysUninitializedUse(const UsesVec* vec) { + static bool hasAlwaysUninitializedUse(const UsesVec *vec) { return llvm::any_of(*vec, [](const UninitUse &U) { return U.getKind() == UninitUse::Always || U.getKind() == UninitUse::AfterCall || @@ -1834,10 +1817,10 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { : getNotes(); } - public: +public: ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL) - : S(S), FunLocation(FL), FunEndLocation(FEL), - CurrentFunction(nullptr), Verbose(false) {} + : S(S), FunLocation(FL), FunEndLocation(FEL), CurrentFunction(nullptr), + Verbose(false) {} void setVerbose(bool b) { Verbose = b; } @@ -1899,24 +1882,24 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { LockErrorKind LEK) override { unsigned DiagID = 0; switch (LEK) { - case LEK_LockedSomePredecessors: - DiagID = diag::warn_lock_some_predecessors; - break; - case LEK_LockedSomeLoopIterations: - DiagID = diag::warn_expecting_lock_held_on_loop; - break; - case LEK_LockedAtEndOfFunction: - DiagID = diag::warn_no_unlock; - break; - case LEK_NotLockedAtEndOfFunction: - DiagID = diag::warn_expecting_locked; - break; + case LEK_LockedSomePredecessors: + DiagID = diag::warn_lock_some_predecessors; + break; + case LEK_LockedSomeLoopIterations: + DiagID = diag::warn_expecting_lock_held_on_loop; + break; + case LEK_LockedAtEndOfFunction: + DiagID = diag::warn_no_unlock; + break; + case LEK_NotLockedAtEndOfFunction: + DiagID = diag::warn_expecting_locked; + break; } if (LocEndOfScope.isInvalid()) LocEndOfScope = FunEndLocation; - PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << Kind - << LockName); + PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) + << Kind << LockName); Warnings.emplace_back(std::move(Warning), makeLockedHereNote(LocLocked, Kind)); } @@ -1936,11 +1919,11 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { AccessKind AK, SourceLocation Loc) override { assert((POK == POK_VarAccess || POK == POK_VarDereference) && "Only works for variables"); - unsigned DiagID = POK == POK_VarAccess? - diag::warn_variable_requires_any_lock: - diag::warn_var_deref_requires_any_lock; + unsigned DiagID = POK == POK_VarAccess + ? diag::warn_variable_requires_any_lock + : diag::warn_var_deref_requires_any_lock; PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) - << D << getLockKindFromAccessKind(AK)); + << D << getLockKindFromAccessKind(AK)); Warnings.emplace_back(std::move(Warning), getNotes()); } @@ -1951,25 +1934,24 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { unsigned DiagID = 0; if (PossibleMatch) { switch (POK) { - case POK_VarAccess: - DiagID = diag::warn_variable_requires_lock_precise; - break; - case POK_VarDereference: - DiagID = diag::warn_var_deref_requires_lock_precise; - break; - case POK_FunctionCall: - DiagID = diag::warn_fun_requires_lock_precise; - break; - case POK_PassByRef: - DiagID = diag::warn_guarded_pass_by_reference; - break; - case POK_PtPassByRef: - DiagID = diag::warn_pt_guarded_pass_by_reference; - break; + case POK_VarAccess: + DiagID = diag::warn_variable_requires_lock_precise; + break; + case POK_VarDereference: + DiagID = diag::warn_var_deref_requires_lock_precise; + break; + case POK_FunctionCall: + DiagID = diag::warn_fun_requires_lock_precise; + break; + case POK_PassByRef: + DiagID = diag::warn_guarded_pass_by_reference; + break; + case POK_PtPassByRef: + DiagID = diag::warn_pt_guarded_pass_by_reference; + break; } - PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind - << D - << LockName << LK); + PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) + << Kind << D << LockName << LK); PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match) << *PossibleMatch); if (Verbose && POK == POK_VarAccess) { @@ -1981,25 +1963,24 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { Warnings.emplace_back(std::move(Warning), getNotes(Note)); } else { switch (POK) { - case POK_VarAccess: - DiagID = diag::warn_variable_requires_lock; - break; - case POK_VarDereference: - DiagID = diag::warn_var_deref_requires_lock; - break; - case POK_FunctionCall: - DiagID = diag::warn_fun_requires_lock; - break; - case POK_PassByRef: - DiagID = diag::warn_guarded_pass_by_reference; - break; - case POK_PtPassByRef: - DiagID = diag::warn_pt_guarded_pass_by_reference; - break; + case POK_VarAccess: + DiagID = diag::warn_variable_requires_lock; + break; + case POK_VarDereference: + DiagID = diag::warn_var_deref_requires_lock; + break; + case POK_FunctionCall: + DiagID = diag::warn_fun_requires_lock; + break; + case POK_PassByRef: + DiagID = diag::warn_guarded_pass_by_reference; + break; + case POK_PtPassByRef: + DiagID = diag::warn_pt_guarded_pass_by_reference; + break; } - PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind - << D - << LockName << LK); + PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) + << Kind << D << LockName << LK); if (Verbose && POK == POK_VarAccess) { PartialDiagnosticAt Note(D->getLocation(), S.PDiag(diag::note_guarded_by_declared_here)); @@ -2011,9 +1992,9 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg, SourceLocation Loc) override { - PartialDiagnosticAt Warning(Loc, - S.PDiag(diag::warn_acquire_requires_negative_cap) - << Kind << LockName << Neg); + PartialDiagnosticAt Warning( + Loc, S.PDiag(diag::warn_acquire_requires_negative_cap) + << Kind << LockName << Neg); Warnings.emplace_back(std::move(Warning), getNotes()); } @@ -2033,22 +2014,20 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name, SourceLocation Loc) override { - PartialDiagnosticAt Warning(Loc, - S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name); + PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_acquired_before) + << Kind << L1Name << L2Name); Warnings.emplace_back(std::move(Warning), getNotes()); } void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) override { - PartialDiagnosticAt Warning(Loc, - S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name); + PartialDiagnosticAt Warning( + Loc, S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name); Warnings.emplace_back(std::move(Warning), getNotes()); } - void enterFunction(const FunctionDecl* FD) override { - CurrentFunction = FD; - } + void enterFunction(const FunctionDecl *FD) override { CurrentFunction = FD; } - void leaveFunction(const FunctionDecl* FD) override { + void leaveFunction(const FunctionDecl *FD) override { CurrentFunction = nullptr; } }; @@ -2069,7 +2048,6 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase { DiagList Warnings; public: - ConsumedWarningsHandler(Sema &S) : S(S) {} void emitDiagnostics() override { @@ -2083,8 +2061,8 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase { void warnLoopStateMismatch(SourceLocation Loc, StringRef VariableName) override { - PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch) << - VariableName); + PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch) + << VariableName); Warnings.emplace_back(std::move(Warning), OptionalNotes()); } @@ -2094,9 +2072,9 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase { StringRef ExpectedState, StringRef ObservedState) override { - PartialDiagnosticAt Warning(Loc, S.PDiag( - diag::warn_param_return_typestate_mismatch) << VariableName << - ExpectedState << ObservedState); + PartialDiagnosticAt Warning( + Loc, S.PDiag(diag::warn_param_return_typestate_mismatch) + << VariableName << ExpectedState << ObservedState); Warnings.emplace_back(std::move(Warning), OptionalNotes()); } @@ -2104,16 +2082,18 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase { void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState, StringRef ObservedState) override { - PartialDiagnosticAt Warning(Loc, S.PDiag( - diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState); + PartialDiagnosticAt Warning(Loc, + S.PDiag(diag::warn_param_typestate_mismatch) + << ExpectedState << ObservedState); Warnings.emplace_back(std::move(Warning), OptionalNotes()); } void warnReturnTypestateForUnconsumableType(SourceLocation Loc, StringRef TypeName) override { - PartialDiagnosticAt Warning(Loc, S.PDiag( - diag::warn_return_typestate_for_unconsumable_type) << TypeName); + PartialDiagnosticAt Warning( + Loc, S.PDiag(diag::warn_return_typestate_for_unconsumable_type) + << TypeName); Warnings.emplace_back(std::move(Warning), OptionalNotes()); } @@ -2121,8 +2101,9 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase { void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState, StringRef ObservedState) override { - PartialDiagnosticAt Warning(Loc, S.PDiag( - diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState); + PartialDiagnosticAt Warning(Loc, + S.PDiag(diag::warn_return_typestate_mismatch) + << ExpectedState << ObservedState); Warnings.emplace_back(std::move(Warning), OptionalNotes()); } @@ -2130,8 +2111,9 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase { void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State, SourceLocation Loc) override { - PartialDiagnosticAt Warning(Loc, S.PDiag( - diag::warn_use_of_temp_in_invalid_state) << MethodName << State); + PartialDiagnosticAt Warning(Loc, + S.PDiag(diag::warn_use_of_temp_in_invalid_state) + << MethodName << State); Warnings.emplace_back(std::move(Warning), OptionalNotes()); } @@ -2139,8 +2121,9 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase { void warnUseInInvalidState(StringRef MethodName, StringRef VariableName, StringRef State, SourceLocation Loc) override { - PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) << - MethodName << VariableName << State); + PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) + << MethodName << VariableName + << State); Warnings.emplace_back(std::move(Warning), OptionalNotes()); } @@ -2290,6 +2273,85 @@ static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope) { S.Diag(D.Loc, D.PD); } +// An AST Visitor that calls a callback function on each callable DEFINITION +// that is NOT in a dependent context: +class CallableVisitor : public RecursiveASTVisitor { +private: + llvm::function_ref Callback; + +public: + CallableVisitor(llvm::function_ref Callback) + : Callback(Callback) {} + + bool VisitFunctionDecl(FunctionDecl *Node) { + if (cast(Node)->isDependentContext()) + return true; // Not to analyze dependent decl + // `FunctionDecl->hasBody()` returns true if the function has a body + // somewhere defined. But we want to know if this `Node` has a body + // child. So we use `doesThisDeclarationHaveABody`: + if (Node->doesThisDeclarationHaveABody()) + Callback(Node); + return true; + } + + bool VisitBlockDecl(BlockDecl *Node) { + if (cast(Node)->isDependentContext()) + return true; // Not to analyze dependent decl + Callback(Node); + return true; + } + + bool VisitObjCMethodDecl(ObjCMethodDecl *Node) { + if (cast(Node)->isDependentContext()) + return true; // Not to analyze dependent decl + if (Node->hasBody()) + Callback(Node); + return true; + } + + bool VisitLambdaExpr(LambdaExpr *Node) { + return VisitFunctionDecl(Node->getCallOperator()); + } + + bool shouldVisitTemplateInstantiations() const { return true; } + bool shouldVisitImplicitCode() const { return false; } +}; + +void clang::sema::AnalysisBasedWarnings::IssueWarnings( + TranslationUnitDecl *TU) { + if (!TU) + return; // This is unexpected, give up quietly. + + DiagnosticsEngine &Diags = S.getDiagnostics(); + + if (S.hasUncompilableErrorOccurred() || Diags.getIgnoreAllWarnings()) + // exit if having uncompilable errors or ignoring all warnings: + return; + + // Whether -Wunsafe-buffer-usage should emit fix-its: + const bool UnsafeBufferEmitFixits = + Diags.getDiagnosticOptions().ShowFixits && S.getLangOpts().CPlusPlus20; + UnsafeBufferUsageReporter R(S); + + // The Callback function that performs analyses: + auto CallAnalyzers = [&](const Decl *Node) -> void { + // Perform unsafe buffer analysis: + if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, + Node->getBeginLoc()) || + !Diags.isIgnored(diag::warn_unsafe_buffer_variable, + Node->getBeginLoc())) + clang::checkUnsafeBufferUsage(Node, R, UnsafeBufferEmitFixits); + + // More analysis ... + }; + // Emit per-function analysis-based warnings that require the whole-TU + // reasoning. Check if any of them is enabled at all before scanning the AST: + if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, SourceLocation()) || + !Diags.isIgnored(diag::warn_unsafe_buffer_variable, SourceLocation())) { + CallableVisitor(CallAnalyzers).TraverseTranslationUnitDecl(TU); + } +} + void clang::sema::AnalysisBasedWarnings::IssueWarnings( sema::AnalysisBasedWarnings::Policy P, sema::FunctionScopeInfo *fscope, const Decl *D, QualType BlockType) { @@ -2344,16 +2406,15 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( P.enableConsumedAnalysis) { // Unreachable code analysis and thread safety require a linearized CFG. AC.getCFGBuildOptions().setAllAlwaysAdd(); - } - else { + } else { AC.getCFGBuildOptions() - .setAlwaysAdd(Stmt::BinaryOperatorClass) - .setAlwaysAdd(Stmt::CompoundAssignOperatorClass) - .setAlwaysAdd(Stmt::BlockExprClass) - .setAlwaysAdd(Stmt::CStyleCastExprClass) - .setAlwaysAdd(Stmt::DeclRefExprClass) - .setAlwaysAdd(Stmt::ImplicitCastExprClass) - .setAlwaysAdd(Stmt::UnaryOperatorClass); + .setAlwaysAdd(Stmt::BinaryOperatorClass) + .setAlwaysAdd(Stmt::CompoundAssignOperatorClass) + .setAlwaysAdd(Stmt::BlockExprClass) + .setAlwaysAdd(Stmt::CStyleCastExprClass) + .setAlwaysAdd(Stmt::DeclRefExprClass) + .setAlwaysAdd(Stmt::ImplicitCastExprClass) + .setAlwaysAdd(Stmt::UnaryOperatorClass); } // Install the logical handler. @@ -2407,15 +2468,14 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( // Warning: check missing 'return' if (P.enableCheckFallThrough) { const CheckFallThroughDiagnostics &CD = - (isa(D) - ? CheckFallThroughDiagnostics::MakeForBlock() - : (isa(D) && - cast(D)->getOverloadedOperator() == OO_Call && - cast(D)->getParent()->isLambda()) - ? CheckFallThroughDiagnostics::MakeForLambda() - : (fscope->isCoroutine() - ? CheckFallThroughDiagnostics::MakeForCoroutine(D) - : CheckFallThroughDiagnostics::MakeForFunction(D))); + (isa(D) ? CheckFallThroughDiagnostics::MakeForBlock() + : (isa(D) && + cast(D)->getOverloadedOperator() == OO_Call && + cast(D)->getParent()->isLambda()) + ? CheckFallThroughDiagnostics::MakeForLambda() + : (fscope->isCoroutine() + ? CheckFallThroughDiagnostics::MakeForCoroutine(D) + : CheckFallThroughDiagnostics::MakeForFunction(D))); CheckFallThroughForBody(S, D, Body, BlockType, CD, AC, fscope); } @@ -2469,12 +2529,10 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( ++NumUninitAnalysisFunctions; NumUninitAnalysisVariables += stats.NumVariablesAnalyzed; NumUninitAnalysisBlockVisits += stats.NumBlockVisits; - MaxUninitAnalysisVariablesPerFunction = - std::max(MaxUninitAnalysisVariablesPerFunction, - stats.NumVariablesAnalyzed); - MaxUninitAnalysisBlockVisitsPerFunction = - std::max(MaxUninitAnalysisBlockVisitsPerFunction, - stats.NumBlockVisits); + MaxUninitAnalysisVariablesPerFunction = std::max( + MaxUninitAnalysisVariablesPerFunction, stats.NumVariablesAnalyzed); + MaxUninitAnalysisBlockVisitsPerFunction = std::max( + MaxUninitAnalysisBlockVisitsPerFunction, stats.NumBlockVisits); } } } @@ -2503,7 +2561,6 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, D->getBeginLoc())) diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap()); - // Check for infinite self-recursion in functions if (!Diags.isIgnored(diag::warn_infinite_recursive_function, D->getBeginLoc())) { @@ -2518,16 +2575,6 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( if (S.getLangOpts().CPlusPlus && !fscope->isCoroutine() && isNoexcept(FD)) checkThrowInNonThrowingFunc(S, FD, AC); - // Emit unsafe buffer usage warnings and fixits. - if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, D->getBeginLoc()) || - !Diags.isIgnored(diag::warn_unsafe_buffer_variable, D->getBeginLoc())) { - UnsafeBufferUsageReporter R(S); - checkUnsafeBufferUsage( - D, R, - /*EmitFixits=*/S.getDiagnostics().getDiagnosticOptions().ShowFixits && - S.getLangOpts().CPlusPlus20); - } - // If none of the previous checks caused a CFG build, trigger one here // for the logical error handler. if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { @@ -2541,8 +2588,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( // If we successfully built a CFG for this context, record some more // detail information about it. NumCFGBlocks += cfg->getNumBlockIDs(); - MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction, - cfg->getNumBlockIDs()); + MaxCFGBlocksPerFunction = + std::max(MaxCFGBlocksPerFunction, cfg->getNumBlockIDs()); } else { ++NumFunctionsWithBadCFGs; } @@ -2554,7 +2601,7 @@ void clang::sema::AnalysisBasedWarnings::PrintStats() const { unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs; unsigned AvgCFGBlocksPerFunction = - !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt; + !NumCFGsBuilt ? 0 : NumCFGBlocks / NumCFGsBuilt; llvm::errs() << NumFunctionsAnalyzed << " functions analyzed (" << NumFunctionsWithBadCFGs << " w/o CFGs).\n" << " " << NumCFGBlocks << " CFG blocks built.\n" @@ -2563,10 +2610,14 @@ void clang::sema::AnalysisBasedWarnings::PrintStats() const { << " " << MaxCFGBlocksPerFunction << " max CFG blocks per function.\n"; - unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0 - : NumUninitAnalysisVariables/NumUninitAnalysisFunctions; - unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0 - : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions; + unsigned AvgUninitVariablesPerFunction = + !NumUninitAnalysisFunctions + ? 0 + : NumUninitAnalysisVariables / NumUninitAnalysisFunctions; + unsigned AvgUninitBlockVisitsPerFunction = + !NumUninitAnalysisFunctions + ? 0 + : NumUninitAnalysisBlockVisits / NumUninitAnalysisFunctions; llvm::errs() << NumUninitAnalysisFunctions << " functions analyzed for uninitialiazed variables\n" << " " << NumUninitAnalysisVariables << " variables analyzed.\n" diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 7c34c60329664..7db643421622f 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1469,6 +1469,8 @@ void Sema::ActOnEndOfTranslationUnit() { } } + AnalysisWarnings.IssueWarnings(Context.getTranslationUnitDecl()); + // Check we've noticed that we're no longer parsing the initializer for every // variable. If we miss cases, then at best we have a performance issue and // at worst a rejects-valid bug. diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index d2b40eb53f4ad..0cc0bddfad14a 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -4197,21 +4197,6 @@ static bool isPPC_64Builtin(unsigned BuiltinID) { return false; } -static bool SemaFeatureCheck(Sema &S, CallExpr *TheCall, - StringRef FeatureToCheck, unsigned DiagID, - StringRef DiagArg = "") { - if (S.Context.getTargetInfo().hasFeature(FeatureToCheck)) - return false; - - if (DiagArg.empty()) - S.Diag(TheCall->getBeginLoc(), DiagID) << TheCall->getSourceRange(); - else - S.Diag(TheCall->getBeginLoc(), DiagID) - << DiagArg << TheCall->getSourceRange(); - - return true; -} - /// Returns true if the argument consists of one contiguous run of 1s with any /// number of 0s on either side. The 1s are allowed to wrap from LSB to MSB, so /// 0x000FFF0, 0x0000FFFF, 0xFF0000FF, 0x0 are all runs. 0x0F0F0000 is not, @@ -4256,42 +4241,16 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3); case PPC::BI__builtin_tbegin: case PPC::BI__builtin_tend: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1) || - SemaFeatureCheck(*this, TheCall, "htm", - diag::err_ppc_builtin_requires_htm); + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1); case PPC::BI__builtin_tsr: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 7) || - SemaFeatureCheck(*this, TheCall, "htm", - diag::err_ppc_builtin_requires_htm); + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 7); case PPC::BI__builtin_tabortwc: case PPC::BI__builtin_tabortdc: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || - SemaFeatureCheck(*this, TheCall, "htm", - diag::err_ppc_builtin_requires_htm); + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31); case PPC::BI__builtin_tabortwci: case PPC::BI__builtin_tabortdci: - return SemaFeatureCheck(*this, TheCall, "htm", - diag::err_ppc_builtin_requires_htm) || - (SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 31)); - case PPC::BI__builtin_tabort: - case PPC::BI__builtin_tcheck: - case PPC::BI__builtin_treclaim: - case PPC::BI__builtin_trechkpt: - case PPC::BI__builtin_tendall: - case PPC::BI__builtin_tresume: - case PPC::BI__builtin_tsuspend: - case PPC::BI__builtin_get_texasr: - case PPC::BI__builtin_get_texasru: - case PPC::BI__builtin_get_tfhar: - case PPC::BI__builtin_get_tfiar: - case PPC::BI__builtin_set_texasr: - case PPC::BI__builtin_set_texasru: - case PPC::BI__builtin_set_tfhar: - case PPC::BI__builtin_set_tfiar: - case PPC::BI__builtin_ttest: - return SemaFeatureCheck(*this, TheCall, "htm", - diag::err_ppc_builtin_requires_htm); + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || + SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); // According to GCC 'Basic PowerPC Built-in Functions Available on ISA 2.05', // __builtin_(un)pack_longdouble are available only if long double uses IBM // extended double representation. @@ -4312,26 +4271,8 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case PPC::BI__builtin_vsx_xxpermdi: case PPC::BI__builtin_vsx_xxsldwi: return SemaBuiltinVSX(TheCall); - case PPC::BI__builtin_divwe: - case PPC::BI__builtin_divweu: - case PPC::BI__builtin_divde: - case PPC::BI__builtin_divdeu: - return SemaFeatureCheck(*this, TheCall, "extdiv", - diag::err_ppc_builtin_only_on_arch, "7"); - case PPC::BI__builtin_bpermd: - return SemaFeatureCheck(*this, TheCall, "bpermd", - diag::err_ppc_builtin_only_on_arch, "7"); case PPC::BI__builtin_unpack_vector_int128: - return SemaFeatureCheck(*this, TheCall, "vsx", - diag::err_ppc_builtin_only_on_arch, "7") || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); - case PPC::BI__builtin_pack_vector_int128: - return SemaFeatureCheck(*this, TheCall, "vsx", - diag::err_ppc_builtin_only_on_arch, "7"); - case PPC::BI__builtin_pdepd: - case PPC::BI__builtin_pextd: - return SemaFeatureCheck(*this, TheCall, "isa-v31-instructions", - diag::err_ppc_builtin_only_on_arch, "10"); + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); case PPC::BI__builtin_altivec_vgnb: return SemaBuiltinConstantArgRange(TheCall, 1, 2, 7); case PPC::BI__builtin_vsx_xxeval: @@ -4345,17 +4286,8 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case PPC::BI__builtin_ppc_tw: case PPC::BI__builtin_ppc_tdw: return SemaBuiltinConstantArgRange(TheCall, 2, 1, 31); - case PPC::BI__builtin_ppc_cmpeqb: - case PPC::BI__builtin_ppc_setb: - case PPC::BI__builtin_ppc_maddhd: - case PPC::BI__builtin_ppc_maddhdu: - case PPC::BI__builtin_ppc_maddld: - return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", - diag::err_ppc_builtin_only_on_arch, "9"); case PPC::BI__builtin_ppc_cmprb: - return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", - diag::err_ppc_builtin_only_on_arch, "9") || - SemaBuiltinConstantArgRange(TheCall, 0, 0, 1); + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1); // For __rlwnm, __rlwimi and __rldimi, the last parameter mask must // be a constant that represents a contiguous bit field. case PPC::BI__builtin_ppc_rlwnm: @@ -4364,15 +4296,8 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case PPC::BI__builtin_ppc_rldimi: return SemaBuiltinConstantArg(TheCall, 2, Result) || SemaValueIsRunOfOnes(TheCall, 3); - case PPC::BI__builtin_ppc_extract_exp: - case PPC::BI__builtin_ppc_extract_sig: - case PPC::BI__builtin_ppc_insert_exp: - return SemaFeatureCheck(*this, TheCall, "power9-vector", - diag::err_ppc_builtin_only_on_arch, "9"); case PPC::BI__builtin_ppc_addex: { - if (SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", - diag::err_ppc_builtin_only_on_arch, "9") || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 3)) + if (SemaBuiltinConstantArgRange(TheCall, 2, 0, 3)) return true; // Output warning for reserved values 1 to 3. int ArgValue = @@ -4394,41 +4319,19 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, return SemaBuiltinConstantArgPower2(TheCall, 0); case PPC::BI__builtin_ppc_rdlam: return SemaValueIsRunOfOnes(TheCall, 2); - case PPC::BI__builtin_ppc_icbt: - case PPC::BI__builtin_ppc_sthcx: - case PPC::BI__builtin_ppc_stbcx: - case PPC::BI__builtin_ppc_lharx: - case PPC::BI__builtin_ppc_lbarx: - return SemaFeatureCheck(*this, TheCall, "isa-v207-instructions", - diag::err_ppc_builtin_only_on_arch, "8"); case PPC::BI__builtin_vsx_ldrmb: case PPC::BI__builtin_vsx_strmb: - return SemaFeatureCheck(*this, TheCall, "isa-v207-instructions", - diag::err_ppc_builtin_only_on_arch, "8") || - SemaBuiltinConstantArgRange(TheCall, 1, 1, 16); + return SemaBuiltinConstantArgRange(TheCall, 1, 1, 16); case PPC::BI__builtin_altivec_vcntmbb: case PPC::BI__builtin_altivec_vcntmbh: case PPC::BI__builtin_altivec_vcntmbw: case PPC::BI__builtin_altivec_vcntmbd: return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); - case PPC::BI__builtin_darn: - case PPC::BI__builtin_darn_raw: - case PPC::BI__builtin_darn_32: - return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", - diag::err_ppc_builtin_only_on_arch, "9"); case PPC::BI__builtin_vsx_xxgenpcvbm: case PPC::BI__builtin_vsx_xxgenpcvhm: case PPC::BI__builtin_vsx_xxgenpcvwm: case PPC::BI__builtin_vsx_xxgenpcvdm: return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3); - case PPC::BI__builtin_ppc_compare_exp_uo: - case PPC::BI__builtin_ppc_compare_exp_lt: - case PPC::BI__builtin_ppc_compare_exp_gt: - case PPC::BI__builtin_ppc_compare_exp_eq: - return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", - diag::err_ppc_builtin_only_on_arch, "9") || - SemaFeatureCheck(*this, TheCall, "vsx", - diag::err_ppc_builtin_requires_vsx); case PPC::BI__builtin_ppc_test_data_class: { // Check if the first argument of the __builtin_ppc_test_data_class call is // valid. The argument must be 'float' or 'double' or '__float128'. @@ -4438,11 +4341,7 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, ArgType != QualType(Context.Float128Ty)) return Diag(TheCall->getBeginLoc(), diag::err_ppc_invalid_test_data_class_type); - return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", - diag::err_ppc_builtin_only_on_arch, "9") || - SemaFeatureCheck(*this, TheCall, "vsx", - diag::err_ppc_builtin_requires_vsx) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 127); + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 127); } case PPC::BI__builtin_ppc_maxfe: case PPC::BI__builtin_ppc_minfe: @@ -4471,11 +4370,7 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, << TheCall->getArg(I)->getType() << ArgType << 1 << 0 << 0; return false; } - case PPC::BI__builtin_ppc_load8r: - case PPC::BI__builtin_ppc_store8r: - return SemaFeatureCheck(*this, TheCall, "isa-v206-instructions", - diag::err_ppc_builtin_only_on_arch, "7"); -#define CUSTOM_BUILTIN(Name, Intr, Types, Acc) \ +#define CUSTOM_BUILTIN(Name, Intr, Types, Acc, Feature) \ case PPC::BI__builtin_##Name: \ return SemaBuiltinPPCMMACall(TheCall, BuiltinID, Types); #include "clang/Basic/BuiltinsPPC.def" @@ -8835,29 +8730,6 @@ bool Sema::SemaBuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, assert((TypeStr[0] != '\0') && "Invalid types in PPC MMA builtin declaration"); - switch (BuiltinID) { - default: - // This function is called in CheckPPCBuiltinFunctionCall where the - // BuiltinID is guaranteed to be an MMA or pair vector memop builtin, here - // we are isolating the pair vector memop builtins that can be used with mma - // off so the default case is every builtin that requires mma and paired - // vector memops. - if (SemaFeatureCheck(*this, TheCall, "paired-vector-memops", - diag::err_ppc_builtin_only_on_arch, "10") || - SemaFeatureCheck(*this, TheCall, "mma", - diag::err_ppc_builtin_only_on_arch, "10")) - return true; - break; - case PPC::BI__builtin_vsx_lxvp: - case PPC::BI__builtin_vsx_stxvp: - case PPC::BI__builtin_vsx_assemble_pair: - case PPC::BI__builtin_vsx_disassemble_pair: - if (SemaFeatureCheck(*this, TheCall, "paired-vector-memops", - diag::err_ppc_builtin_only_on_arch, "10")) - return true; - break; - } - unsigned Mask = 0; unsigned ArgNum = 0; diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 7aa06b615fec2..1126c2c517fe4 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -722,7 +722,7 @@ CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND, ND, /*Final=*/false, /*Innermost=*/nullptr, /*RelativeToPrimary=*/true, /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true, SkipForSpecialization); - return MLTAL.getNumSubstitutedLevels(); + return MLTAL.getNumLevels(); } namespace { @@ -753,27 +753,44 @@ namespace { }; } // namespace +static const Expr *SubstituteConstraintExpression(Sema &S, const NamedDecl *ND, + const Expr *ConstrExpr) { + MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( + ND, /*Final=*/false, /*Innermost=*/nullptr, + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true, + /*SkipForSpecialization*/ false); + if (MLTAL.getNumSubstitutedLevels() == 0) + return ConstrExpr; + + Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/false); + std::optional ThisScope; + if (auto *RD = dyn_cast(ND->getDeclContext())) + ThisScope.emplace(S, const_cast(RD), Qualifiers()); + ExprResult SubstConstr = + S.SubstConstraintExpr(const_cast(ConstrExpr), MLTAL); + if (SFINAE.hasErrorOccurred() || !SubstConstr.isUsable()) + return nullptr; + return SubstConstr.get(); +} + bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old, const Expr *OldConstr, const NamedDecl *New, const Expr *NewConstr) { + if (OldConstr == NewConstr) + return true; if (Old && New && Old != New) { - unsigned Depth1 = CalculateTemplateDepthForConstraints( - *this, Old); - unsigned Depth2 = CalculateTemplateDepthForConstraints( - *this, New); - - // Adjust the 'shallowest' verison of this to increase the depth to match - // the 'other'. - if (Depth2 > Depth1) { - OldConstr = AdjustConstraintDepth(*this, Depth2 - Depth1) - .TransformExpr(const_cast(OldConstr)) - .get(); - } else if (Depth1 > Depth2) { - NewConstr = AdjustConstraintDepth(*this, Depth1 - Depth2) - .TransformExpr(const_cast(NewConstr)) - .get(); - } + if (const Expr *SubstConstr = + SubstituteConstraintExpression(*this, Old, OldConstr)) + OldConstr = SubstConstr; + else + return false; + if (const Expr *SubstConstr = + SubstituteConstraintExpression(*this, New, NewConstr)) + NewConstr = SubstConstr; + else + return false; } llvm::FoldingSetNodeID ID1, ID2; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 7ec102d4d1dda..30741ff69d2b5 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1821,17 +1821,21 @@ bool Sema::IsRedefinitionInModule(const NamedDecl *New, return OldM == NewM; } -static bool isUsingDecl(NamedDecl *D) { +static bool isUsingDeclNotAtClassScope(NamedDecl *D) { + if (D->getDeclContext()->isFileContext()) + return false; + return isa(D) || isa(D) || isa(D); } -/// Removes using shadow declarations from the lookup results. +/// Removes using shadow declarations not at class scope from the lookup +/// results. static void RemoveUsingDecls(LookupResult &R) { LookupResult::Filter F = R.makeFilter(); while (F.hasNext()) - if (isUsingDecl(F.next())) + if (isUsingDeclNotAtClassScope(F.next())) F.erase(); F.done(); @@ -6430,10 +6434,6 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, // containing the two f's declared in X, but neither of them // matches. - // C++ [dcl.meaning]p1: - // [...] the member shall not merely have been introduced by a - // using-declaration in the scope of the class or namespace nominated by - // the nested-name-specifier of the declarator-id. RemoveUsingDecls(Previous); } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 16c3425c9951c..36ce9ea335aba 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11613,6 +11613,10 @@ NamespaceDecl *Sema::getOrCreateStdNamespace() { &PP.getIdentifierTable().get("std"), /*PrevDecl=*/nullptr, /*Nested=*/false); getStdNamespace()->setImplicit(true); + // We want the created NamespaceDecl to be available for redeclaration + // lookups, but not for regular name lookups. + Context.getTranslationUnitDecl()->addDecl(getStdNamespace()); + getStdNamespace()->clearIdentifierNamespace(); } return getStdNamespace(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e2e5581f9efda..c7e8d8ee42caf 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3626,7 +3626,8 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, } } - return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL); + return PredefinedExpr::Create(Context, Loc, ResTy, IK, LangOpts.MicrosoftExt, + SL); } ExprResult Sema::BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc, diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 9f6c778c26416..fa00804eeff03 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -174,6 +174,8 @@ static void updateStringLiteralType(Expr *E, QualType Ty) { E = GSE->getResultExpr(); } else if (ChooseExpr *CE = dyn_cast(E)) { E = CE->getChosenSubExpr(); + } else if (PredefinedExpr *PE = dyn_cast(E)) { + E = PE->getFunctionName(); } else { llvm_unreachable("unexpected expr in string literal init"); } @@ -8509,6 +8511,15 @@ ExprResult InitializationSequence::Perform(Sema &S, << Init->getSourceRange(); } + if (S.getLangOpts().MicrosoftExt && Args.size() == 1 && + isa(Args[0]) && Entity.getType()->isArrayType()) { + // Produce a Microsoft compatibility warning when initializing from a + // predefined expression since MSVC treats predefined expressions as string + // literals. + Expr *Init = Args[0]; + S.Diag(Init->getBeginLoc(), diag::ext_init_from_predefined) << Init; + } + // OpenCL v2.0 s6.13.11.1. atomic variables can be initialized in global scope QualType ETy = Entity.getType(); bool HasGlobalAS = ETy.hasAddressSpace() && diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 7b97132780f50..f3583d8a59416 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1928,14 +1928,14 @@ bool Sema::isModuleVisible(const Module *M, bool ModulePrivate) { if (LookupModules.empty()) return false; + // If our lookup set contains the module, it's visible. + if (LookupModules.count(M)) + return true; + // The global module fragments are visible to its corresponding module unit. // So the global module fragment should be visible if the its corresponding // module unit is visible. - if (M->isGlobalModule()) - M = M->getTopLevelModule(); - - // If our lookup set contains the module, it's visible. - if (LookupModules.count(M)) + if (M->isGlobalModule() && LookupModules.count(M->getTopLevelModule())) return true; // For a module-private query, that's everywhere we get to look. @@ -1956,14 +1956,11 @@ bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) { Module *DeclModule = SemaRef.getOwningModule(D); assert(DeclModule && "hidden decl has no owning module"); - // Entities in module map modules are reachable only if they're visible. - if (DeclModule->isModuleMapModule()) + // Entities in header like modules are reachable only if they're visible. + if (DeclModule->isHeaderLikeModule()) return false; - // If D comes from a module and SemaRef doesn't own a module, it implies D - // comes from another TU. In case SemaRef owns a module, we could judge if D - // comes from another TU by comparing the module unit. - if (SemaRef.isModuleUnitOfCurrentTU(DeclModule)) + if (!D->isInAnotherModuleUnit()) return true; // [module.reach]/p3: @@ -2478,8 +2475,9 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool oldVal; DeclContext *Context; // Set flag in DeclContext informing debugger that we're looking for qualified name - QualifiedLookupInScope(DeclContext *ctx) : Context(ctx) { - oldVal = ctx->setUseQualifiedLookup(); + QualifiedLookupInScope(DeclContext *ctx) + : oldVal(ctx->shouldUseQualifiedLookup()), Context(ctx) { + ctx->setUseQualifiedLookup(); } ~QualifiedLookupInScope() { Context->setUseQualifiedLookup(oldVal); @@ -3943,14 +3941,12 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, "bad export context"); // .. are attached to a named module M, do not appear in the // translation unit containing the point of the lookup.. - if (!isModuleUnitOfCurrentTU(FM) && + if (D->isInAnotherModuleUnit() && llvm::any_of(AssociatedClasses, [&](auto *E) { // ... and have the same innermost enclosing non-inline // namespace scope as a declaration of an associated entity // attached to M - if (!E->hasOwningModule() || - E->getOwningModule()->getTopLevelModuleName() != - FM->getTopLevelModuleName()) + if (E->getOwningModule() != FM) return false; // TODO: maybe this could be cached when generating the // associated namespaces / entities. diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index 53e453b117e17..58157950b3da3 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -389,7 +389,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, // statements, so imports are allowed. ImportState = ModuleImportState::ImportAllowed; - getASTContext().setNamedModuleForCodeGen(Mod); + getASTContext().setCurrentNamedModule(Mod); // We already potentially made an implicit import (in the case of a module // implementation unit importing its interface). Make this module visible @@ -1021,16 +1021,3 @@ void Sema::PopImplicitGlobalModuleFragment() { "left the wrong module scope, which is not global module fragment"); ModuleScopes.pop_back(); } - -bool Sema::isModuleUnitOfCurrentTU(const Module *M) const { - assert(M); - - Module *CurrentModuleUnit = getCurrentModule(); - - // If we are not in a module currently, M must not be the module unit of - // current TU. - if (!CurrentModuleUnit) - return false; - - return M->isSubModuleOf(CurrentModuleUnit->getTopLevelModule()); -} diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index b3d4fffced7db..9222799f455ba 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1297,7 +1297,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, // We check the return type and template parameter lists for function // templates first; the remaining checks follow. bool SameTemplateParameterList = TemplateParameterListsAreEqual( - NewTemplate->getTemplateParameters(), + NewTemplate, NewTemplate->getTemplateParameters(), OldTemplate, OldTemplate->getTemplateParameters(), false, TPL_TemplateMatch); bool SameReturnType = Context.hasSameType(Old->getDeclaredReturnType(), New->getDeclaredReturnType()); @@ -6560,23 +6560,20 @@ void Sema::AddOverloadCandidate( } // Functions with internal linkage are only viable in the same module unit. - if (auto *MF = Function->getOwningModule()) { - if (getLangOpts().CPlusPlusModules && !MF->isModuleMapModule() && - !isModuleUnitOfCurrentTU(MF)) { - /// FIXME: Currently, the semantics of linkage in clang is slightly - /// different from the semantics in C++ spec. In C++ spec, only names - /// have linkage. So that all entities of the same should share one - /// linkage. But in clang, different entities of the same could have - /// different linkage. - NamedDecl *ND = Function; - if (auto *SpecInfo = Function->getTemplateSpecializationInfo()) - ND = SpecInfo->getTemplate(); - - if (ND->getFormalLinkage() == Linkage::InternalLinkage) { - Candidate.Viable = false; - Candidate.FailureKind = ovl_fail_module_mismatched; - return; - } + if (getLangOpts().CPlusPlusModules && Function->isInAnotherModuleUnit()) { + /// FIXME: Currently, the semantics of linkage in clang is slightly + /// different from the semantics in C++ spec. In C++ spec, only names + /// have linkage. So that all entities of the same should share one + /// linkage. But in clang, different entities of the same could have + /// different linkage. + NamedDecl *ND = Function; + if (auto *SpecInfo = Function->getTemplateSpecializationInfo()) + ND = SpecInfo->getTemplate(); + + if (ND->getFormalLinkage() == Linkage::InternalLinkage) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_module_mismatched; + return; } } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 4fe4b9192ecd3..b3a180e909b3f 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1610,16 +1610,6 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument)) return Param; - TemplateArgument SugaredConverted, CanonicalConverted; - ExprResult DefaultRes = CheckTemplateArgument( - Param, Param->getType(), Default, SugaredConverted, CanonicalConverted, - CTAK_Specified); - if (DefaultRes.isInvalid()) { - Param->setInvalidDecl(); - return Param; - } - Default = DefaultRes.get(); - Param->setDefaultArgument(Default); } @@ -2861,8 +2851,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc(); SawDefaultArgument = true; - if (!OldTypeParm->getOwningModule() || - isModuleUnitOfCurrentTU(OldTypeParm->getOwningModule())) + if (!OldTypeParm->isInAnotherModuleUnit()) RedundantDefaultArg = true; else if (!getASTContext().isSameDefaultTemplateArgument(OldTypeParm, NewTypeParm)) { @@ -2914,8 +2903,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc(); NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc(); SawDefaultArgument = true; - if (!OldNonTypeParm->getOwningModule() || - isModuleUnitOfCurrentTU(OldNonTypeParm->getOwningModule())) + if (!OldNonTypeParm->isInAnotherModuleUnit()) RedundantDefaultArg = true; else if (!getASTContext().isSameDefaultTemplateArgument( OldNonTypeParm, NewNonTypeParm)) { @@ -2966,8 +2954,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation(); NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation(); SawDefaultArgument = true; - if (!OldTemplateParm->getOwningModule() || - isModuleUnitOfCurrentTU(OldTemplateParm->getOwningModule())) + if (!OldTemplateParm->isInAnotherModuleUnit()) RedundantDefaultArg = true; else if (!getASTContext().isSameDefaultTemplateArgument( OldTemplateParm, NewTemplateParm)) { diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index b249d389bb677..db72b8b3089e6 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2882,7 +2882,7 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template, // not class-scope explicit specialization, so replace with Deduced Args // instead of adding to inner-most. if (NeedsReplacement) - MLTAL.replaceInnermostTemplateArguments(CanonicalDeducedArgs); + MLTAL.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs); if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL, Info.getLocation(), diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 32f99b5464c54..5c331b87f4bfa 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -35,6 +35,7 @@ #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TimeProfiler.h" #include @@ -132,6 +133,14 @@ HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP, return Response::Done(); } +Response HandlePartialClassTemplateSpec( + const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec, + MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) { + if (!SkipForSpecialization) + Result.addOuterRetainedLevels(PartialClassTemplSpec->getTemplateDepth()); + return Response::Done(); +} + // Add template arguments from a class template instantiation. Response HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec, @@ -154,6 +163,14 @@ HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec, assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?"); if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization()) return Response::Done(); + + // If this was instantiated from a partial template specialization, we need + // to get the next level of declaration context from the partial + // specialization, as the ClassTemplateSpecializationDecl's + // DeclContext/LexicalDeclContext will be for the primary template. + if (auto *InstFromPartialTempl = ClassTemplSpec->getSpecializedTemplateOrPartial() + .dyn_cast()) + return Response::ChangeDecl(InstFromPartialTempl->getLexicalDeclContext()); } return Response::UseNextDecl(ClassTemplSpec); } @@ -209,6 +226,21 @@ Response HandleFunction(const FunctionDecl *Function, return Response::UseNextDecl(Function); } +Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD, + MultiLevelTemplateArgumentList &Result) { + if (!isa(FTD->getDeclContext())) { + NestedNameSpecifier *NNS = FTD->getTemplatedDecl()->getQualifier(); + const Type *Ty; + const TemplateSpecializationType *TSTy; + if (NNS && (Ty = NNS->getAsType()) && + (TSTy = Ty->getAs())) + Result.addOuterTemplateArguments(const_cast(FTD), + TSTy->template_arguments(), + /*Final=*/false); + } + return Response::ChangeDecl(FTD->getLexicalDeclContext()); +} + Response HandleRecordDecl(const CXXRecordDecl *Rec, MultiLevelTemplateArgumentList &Result, ASTContext &Context, @@ -219,15 +251,10 @@ Response HandleRecordDecl(const CXXRecordDecl *Rec, "Outer template not instantiated?"); if (ClassTemplate->isMemberSpecialization()) return Response::Done(); - if (ForConstraintInstantiation) { - QualType RecordType = Context.getTypeDeclType(Rec); - QualType Injected = cast(RecordType) - ->getInjectedSpecializationType(); - const auto *InjectedType = cast(Injected); + if (ForConstraintInstantiation) Result.addOuterTemplateArguments(const_cast(Rec), - InjectedType->template_arguments(), + ClassTemplate->getInjectedTemplateArgs(), /*Final=*/false); - } } bool IsFriend = Rec->getFriendObjectKind() || @@ -295,18 +322,23 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; - if (Innermost) + using namespace TemplateInstArgsHelpers; + const Decl *CurDecl = ND; + if (Innermost) { Result.addOuterTemplateArguments(const_cast(ND), Innermost->asArray(), Final); - - const Decl *CurDecl = ND; + CurDecl = Response::UseNextDecl(ND).NextDecl; + } while (!CurDecl->isFileContextDecl()) { - using namespace TemplateInstArgsHelpers; Response R; if (const auto *VarTemplSpec = dyn_cast(CurDecl)) { R = HandleVarTemplateSpec(VarTemplSpec, Result, SkipForSpecialization); + } else if (const auto *PartialClassTemplSpec = + dyn_cast(CurDecl)) { + R = HandlePartialClassTemplateSpec(PartialClassTemplSpec, Result, + SkipForSpecialization); } else if (const auto *ClassTemplSpec = dyn_cast(CurDecl)) { R = HandleClassTemplateSpec(ClassTemplSpec, Result, @@ -319,6 +351,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( } else if (const auto *CSD = dyn_cast(CurDecl)) { R = HandleImplicitConceptSpecializationDecl(CSD, Result); + } else if (const auto *FTD = dyn_cast(CurDecl)) { + R = HandleFunctionTemplateDecl(FTD, Result); } else if (!isa(CurDecl)) { R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl); if (CurDecl->getDeclContext()->isTranslationUnit()) { @@ -368,6 +402,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case InitializingStructuredBinding: case MarkingClassDllexported: case BuildingBuiltinDumpStructCall: + case LambdaExpressionSubstitution: return false; // This function should never be called when Kind's value is Memoization. @@ -962,6 +997,10 @@ void Sema::PrintInstantiationStack() { case CodeSynthesisContext::Memoization: break; + case CodeSynthesisContext::LambdaExpressionSubstitution: + Diags.Report(Active->PointOfInstantiation, + diag::note_lambda_substitution_here); + break; case CodeSynthesisContext::ConstraintsCheck: { unsigned DiagID = 0; if (!Active->Entity) { @@ -1017,6 +1056,7 @@ std::optional Sema::isSFINAEContext() const { if (InNonInstantiationSFINAEContext) return std::optional(nullptr); + bool SawLambdaSubstitution = false; for (SmallVectorImpl::const_reverse_iterator Active = CodeSynthesisContexts.rbegin(), ActiveEnd = CodeSynthesisContexts.rend(); @@ -1038,6 +1078,15 @@ std::optional Sema::isSFINAEContext() const { case CodeSynthesisContext::NestedRequirementConstraintsCheck: // This is a template instantiation, so there is no SFINAE. return std::nullopt; + case CodeSynthesisContext::LambdaExpressionSubstitution: + // [temp.deduct]p9 + // A lambda-expression appearing in a function type or a template + // parameter is not considered part of the immediate context for the + // purposes of template argument deduction. + + // We need to check parents. + SawLambdaSubstitution = true; + break; case CodeSynthesisContext::DefaultTemplateArgumentInstantiation: case CodeSynthesisContext::PriorTemplateArgumentSubstitution: @@ -1050,12 +1099,17 @@ std::optional Sema::isSFINAEContext() const { case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution: case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: + // We're either substituting explicitly-specified template arguments, + // deduced template arguments. SFINAE applies unless we are in a lambda + // expression, see [temp.deduct]p9. + if (SawLambdaSubstitution) + return std::nullopt; + [[fallthrough]]; case CodeSynthesisContext::ConstraintSubstitution: case CodeSynthesisContext::RequirementInstantiation: case CodeSynthesisContext::RequirementParameterInstantiation: - // We're either substituting explicitly-specified template arguments, - // deduced template arguments, a constraint expression or a requirement - // in a requires expression, so SFINAE applies. + // SFINAE always applies in a constraint expression or a requirement + // in a requires expression. assert(Active->DeductionInfo && "Missing deduction info pointer"); return Active->DeductionInfo; @@ -1367,6 +1421,14 @@ namespace { ExprResult TransformLambdaExpr(LambdaExpr *E) { LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); Sema::ConstraintEvalRAII RAII(*this); + + Sema::CodeSynthesisContext C; + C.Kind = clang::Sema::CodeSynthesisContext::LambdaExpressionSubstitution; + C.PointOfInstantiation = E->getBeginLoc(); + SemaRef.pushCodeSynthesisContext(C); + auto PopCtx = + llvm::make_scope_exit([this] { SemaRef.popCodeSynthesisContext(); }); + ExprResult Result = inherited::TransformLambdaExpr(E); if (Result.isInvalid()) return Result; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index bd0340da30b5a..3435df43cbea4 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2138,33 +2138,12 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { << QualifierLoc.getSourceRange(); return nullptr; } - - if (PrevClassTemplate) { - const ClassTemplateDecl *MostRecentPrevCT = - PrevClassTemplate->getMostRecentDecl(); - TemplateParameterList *PrevParams = - MostRecentPrevCT->getTemplateParameters(); - - // Make sure the parameter lists match. - if (!SemaRef.TemplateParameterListsAreEqual( - D->getTemplatedDecl(), InstParams, - MostRecentPrevCT->getTemplatedDecl(), PrevParams, true, - Sema::TPL_TemplateMatch)) - return nullptr; - - // Do some additional validation, then merge default arguments - // from the existing declarations. - if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams, - Sema::TPC_ClassTemplate)) - return nullptr; - } } CXXRecordDecl *RecordInst = CXXRecordDecl::Create( SemaRef.Context, Pattern->getTagKind(), DC, Pattern->getBeginLoc(), Pattern->getLocation(), Pattern->getIdentifier(), PrevDecl, /*DelayTypeCreation=*/true); - if (QualifierLoc) RecordInst->setQualifierInfo(QualifierLoc); @@ -2174,16 +2153,38 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { ClassTemplateDecl *Inst = ClassTemplateDecl::Create(SemaRef.Context, DC, D->getLocation(), D->getIdentifier(), InstParams, RecordInst); - assert(!(isFriend && Owner->isDependentContext())); - Inst->setPreviousDecl(PrevClassTemplate); - RecordInst->setDescribedClassTemplate(Inst); if (isFriend) { - if (PrevClassTemplate) + assert(!Owner->isDependentContext()); + Inst->setLexicalDeclContext(Owner); + RecordInst->setLexicalDeclContext(Owner); + + if (PrevClassTemplate) { + Inst->setCommonPtr(PrevClassTemplate->getCommonPtr()); + RecordInst->setTypeForDecl( + PrevClassTemplate->getTemplatedDecl()->getTypeForDecl()); + const ClassTemplateDecl *MostRecentPrevCT = + PrevClassTemplate->getMostRecentDecl(); + TemplateParameterList *PrevParams = + MostRecentPrevCT->getTemplateParameters(); + + // Make sure the parameter lists match. + if (!SemaRef.TemplateParameterListsAreEqual( + RecordInst, InstParams, MostRecentPrevCT->getTemplatedDecl(), + PrevParams, true, Sema::TPL_TemplateMatch)) + return nullptr; + + // Do some additional validation, then merge default arguments + // from the existing declarations. + if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams, + Sema::TPC_ClassTemplate)) + return nullptr; + Inst->setAccess(PrevClassTemplate->getAccess()); - else + } else { Inst->setAccess(D->getAccess()); + } Inst->setObjectOfFriendDecl(); // TODO: do we want to track the instantiation progeny of this @@ -2194,15 +2195,15 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { Inst->setInstantiatedFromMemberTemplate(D); } + Inst->setPreviousDecl(PrevClassTemplate); + // Trigger creation of the type for the instantiation. - SemaRef.Context.getInjectedClassNameType(RecordInst, - Inst->getInjectedClassNameSpecialization()); + SemaRef.Context.getInjectedClassNameType( + RecordInst, Inst->getInjectedClassNameSpecialization()); // Finish handling of friends. if (isFriend) { DC->makeDeclVisibleInContext(Inst); - Inst->setLexicalDeclContext(Owner); - RecordInst->setLexicalDeclContext(Owner); return Inst; } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 2bdfc61fee998..795ef3adf1516 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4507,18 +4507,16 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, } } - if (PP.getHeaderSearchInfo() - .getHeaderSearchOpts() - .ModulesValidateOncePerBuildSession) { + HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); + if (HSOpts.ModulesValidateOncePerBuildSession) { // Now we are certain that the module and all modules it depends on are - // up to date. Create or update timestamp files for modules that are - // located in the module cache (not for PCH files that could be anywhere - // in the filesystem). + // up-to-date. For implicitly-built module files, ensure the corresponding + // timestamp files are up-to-date in this build session. for (unsigned I = 0, N = Loaded.size(); I != N; ++I) { ImportedModule &M = Loaded[I]; - if (M.Mod->Kind == MK_ImplicitModule) { + if (M.Mod->Kind == MK_ImplicitModule && + M.Mod->InputFilesValidationTimestamp < HSOpts.BuildSessionTimestamp) updateModuleTimestamp(*M.Mod); - } } } diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index e0831fb164af6..b6796c769e489 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -592,6 +592,7 @@ void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) { bool HasFunctionName = Record.readInt(); E->PredefinedExprBits.HasFunctionName = HasFunctionName; E->PredefinedExprBits.Kind = Record.readInt(); + E->PredefinedExprBits.IsTransparent = Record.readInt(); E->setLocation(readSourceLocation()); if (HasFunctionName) E->setFunctionName(cast(Record.readSubExpr())); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index e124cb4c5f81d..06d758b36c59d 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -185,7 +185,8 @@ std::set GetAffectingModuleMaps(const Preprocessor &PP, if (!HFI || (HFI->isModuleHeader && !HFI->isCompilingModuleHeader)) continue; - for (const auto &KH : HS.findAllModulesForHeader(File)) { + for (const auto &KH : + HS.findAllModulesForHeader(File, /*AllowCreation=*/false)) { if (!KH.getModule()) continue; ModulesToProcess.push_back(KH.getModule()); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 42ab42719ec91..527cdee7af767 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -42,6 +42,7 @@ namespace clang { Code(serialization::STMT_NULL_PTR), AbbrevToUse(0) {} ASTStmtWriter(const ASTStmtWriter&) = delete; + ASTStmtWriter &operator=(const ASTStmtWriter &) = delete; uint64_t Emit() { assert(Code != serialization::STMT_NULL_PTR && @@ -604,6 +605,7 @@ void ASTStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) { bool HasFunctionName = E->getFunctionName() != nullptr; Record.push_back(HasFunctionName); Record.push_back(E->getIdentKind()); // FIXME: stable encoding + Record.push_back(E->isTransparent()); Record.AddSourceLocation(E->getLocation()); if (HasFunctionName) Record.AddStmt(E->getFunctionName()); diff --git a/clang/test/AST/ast-dump-decl.cpp b/clang/test/AST/ast-dump-decl.cpp index 63148d54962f4..3be99c9489640 100644 --- a/clang/test/AST/ast-dump-decl.cpp +++ b/clang/test/AST/ast-dump-decl.cpp @@ -455,9 +455,7 @@ namespace testClassTemplateDecl { // CHECK: ClassTemplateDecl 0x{{.+}} <{{.+}}:[[@LINE-148]]:3, col:31> col:31 TestTemplateDefaultNonType // CHECK-NEXT: |-NonTypeTemplateParmDecl 0x{{.+}} col:16 'int' depth 0 index 0 I // CHECK-NEXT: | `-TemplateArgument expr -// CHECK-NEXT: | `-ConstantExpr 0x{{.+}} 'int' -// CHECK-NEXT: | |-value: Int 42 -// CHECK-NEXT: | `-IntegerLiteral 0x{{.+}} 'int' 42 +// CHECK-NEXT: | `-IntegerLiteral 0x{{.+}} 'int' 42 // CHECK-NEXT: `-CXXRecordDecl 0x{{.+}} col:31 struct TestTemplateDefaultNonType // CHECK: ClassTemplateDecl 0x{{.+}} <{{.+}}:{{.*}}:3, col:68> col:68 TestTemplateTemplateDefaultType @@ -661,9 +659,7 @@ namespace TestNonTypeTemplateParmDecl { // CHECK-NEXT: FunctionTemplateDecl // CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} 'int' depth 0 index 0 I // CHECK-NEXT: TemplateArgument expr -// CHECK-NEXT: ConstantExpr{{.*}} 'int' -// CHECK-NEXT: value: Int 1 -// CHECK-NEXT: IntegerLiteral{{.*}} 'int' 1 +// CHECK-NEXT: IntegerLiteral{{.*}} 'int' 1 // CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} 'int' depth 0 index 1 ... J namespace TestTemplateTemplateParmDecl { diff --git a/clang/test/Analysis/Inputs/std-c-library-functions-POSIX.h b/clang/test/Analysis/Inputs/std-c-library-functions-POSIX.h new file mode 100644 index 0000000000000..942c918c3da2f --- /dev/null +++ b/clang/test/Analysis/Inputs/std-c-library-functions-POSIX.h @@ -0,0 +1,181 @@ +#include "std-c-library-functions.h" + +typedef int off_t; +typedef unsigned int mode_t; +typedef __WCHAR_TYPE__ wchar_t; +typedef unsigned int dev_t; +typedef unsigned int uid_t; +typedef unsigned int gid_t; +typedef unsigned long socklen_t; +typedef unsigned long int pthread_t; +typedef unsigned long time_t; +typedef unsigned long clockid_t; +typedef __INT64_TYPE__ off64_t; + +typedef struct { + int a; +} DIR; +struct stat { + int a; +}; +struct timespec { int x; }; +struct timeval { int x; }; +struct sockaddr; +struct sockaddr_at; +struct msghdr; +struct utimbuf; +struct itimerval; +typedef union { + int x; +} pthread_cond_t; +typedef union { + int x; +} pthread_attr_t; +typedef union { + int x; +} pthread_mutex_t; +typedef union { + int x; +} pthread_mutexattr_t; + +FILE *fopen(const char *restrict pathname, const char *restrict mode); +FILE *tmpfile(void); +FILE *freopen(const char *restrict pathname, const char *restrict mode, + FILE *restrict stream); +int fclose(FILE *stream); +int fseek(FILE *stream, long offset, int whence); +int fileno(FILE *stream); +long a64l(const char *str64); +char *l64a(long value); +int access(const char *pathname, int amode); +int faccessat(int dirfd, const char *pathname, int mode, int flags); +int dup(int fildes); +int dup2(int fildes1, int filedes2); +int fdatasync(int fildes); +int fnmatch(const char *pattern, const char *string, int flags); +int fsync(int fildes); +int truncate(const char *path, off_t length); +int symlink(const char *oldpath, const char *newpath); +int symlinkat(const char *oldpath, int newdirfd, const char *newpath); +int lockf(int fd, int cmd, off_t len); +int creat(const char *pathname, mode_t mode); +unsigned int sleep(unsigned int seconds); +int dirfd(DIR *dirp); +unsigned int alarm(unsigned int seconds); +int closedir(DIR *dir); +char *strdup(const char *s); +char *strndup(const char *s, size_t n); +wchar_t *wcsdup(const wchar_t *s); +int mkstemp(char *template); +char *mkdtemp(char *template); +char *getcwd(char *buf, size_t size); +int mkdir(const char *pathname, mode_t mode); +int mkdirat(int dirfd, const char *pathname, mode_t mode); +int mknod(const char *pathname, mode_t mode, dev_t dev); +int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev); +int chmod(const char *path, mode_t mode); +int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags); +int fchmod(int fildes, mode_t mode); +int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags); +int chown(const char *path, uid_t owner, gid_t group); +int lchown(const char *path, uid_t owner, gid_t group); +int fchown(int fildes, uid_t owner, gid_t group); +int rmdir(const char *pathname); +int chdir(const char *path); +int link(const char *oldpath, const char *newpath); +int linkat(int fd1, const char *path1, int fd2, const char *path2, int flag); +int unlink(const char *pathname); +int unlinkat(int fd, const char *path, int flag); +int fstat(int fd, struct stat *statbuf); +int stat(const char *restrict path, struct stat *restrict buf); +int lstat(const char *restrict path, struct stat *restrict buf); +int fstatat(int fd, const char *restrict path, struct stat *restrict buf, int flag); +DIR *opendir(const char *name); +DIR *fdopendir(int fd); +int isatty(int fildes); +FILE *popen(const char *command, const char *type); +int pclose(FILE *stream); +int close(int fildes); +long fpathconf(int fildes, int name); +long pathconf(const char *path, int name); +FILE *fdopen(int fd, const char *mode); +void rewinddir(DIR *dir); +void seekdir(DIR *dirp, long loc); +int rand_r(unsigned int *seedp); +int fileno(FILE *stream); +int fseeko(FILE *stream, off_t offset, int whence); +off_t ftello(FILE *stream); +void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); +void *mmap64(void *addr, size_t length, int prot, int flags, int fd, off64_t offset); +int pipe(int fildes[2]); +off_t lseek(int fildes, off_t offset, int whence); +ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize); +ssize_t readlinkat(int fd, const char *restrict path, char *restrict buf, size_t bufsize); +int renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); +char *realpath(const char *restrict file_name, char *restrict resolved_name); +int execv(const char *path, char *const argv[]); +int execvp(const char *file, char *const argv[]); +int getopt(int argc, char *const argv[], const char *optstring); + +// In some libc implementations, sockaddr parameter is a transparent +// union of the underlying sockaddr_ pointers instead of being a +// pointer to struct sockaddr. +// We match that with the joker Irrelevant type. +#define __SOCKADDR_ALLTYPES \ + __SOCKADDR_ONETYPE(sockaddr) \ + __SOCKADDR_ONETYPE(sockaddr_at) +#define __SOCKADDR_ONETYPE(type) struct type *restrict __##type##__; +typedef union { + __SOCKADDR_ALLTYPES +} __SOCKADDR_ARG __attribute__((__transparent_union__)); +#undef __SOCKADDR_ONETYPE +#define __SOCKADDR_ONETYPE(type) const struct type *restrict __##type##__; +typedef union { + __SOCKADDR_ALLTYPES +} __CONST_SOCKADDR_ARG __attribute__((__transparent_union__)); +#undef __SOCKADDR_ONETYPE + +int accept(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len); +int bind(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len); +int getpeername(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len); +int getsockname(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len); +int connect(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len); +ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags, __SOCKADDR_ARG address, socklen_t *restrict address_len); +ssize_t sendto(int socket, const void *message, size_t length, int flags, __CONST_SOCKADDR_ARG dest_addr, socklen_t dest_len); +int listen(int sockfd, int backlog); +ssize_t recv(int sockfd, void *buf, size_t len, int flags); +ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); +ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); +int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len); +int getsockopt(int socket, int level, int option_name, void *restrict option_value, socklen_t *restrict option_len); +ssize_t send(int sockfd, const void *buf, size_t len, int flags); +int socketpair(int domain, int type, int protocol, int sv[2]); +int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, char *restrict node, socklen_t nodelen, char *restrict service, socklen_t servicelen, int flags); +int utime(const char *filename, struct utimbuf *buf); +int futimens(int fd, const struct timespec times[2]); +int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags); +int utimes(const char *filename, const struct timeval times[2]); +int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); +struct tm *localtime(const time_t *tp); +struct tm *localtime_r(const time_t *restrict timer, struct tm *restrict result); +char *asctime_r(const struct tm *restrict tm, char *restrict buf); +char *ctime_r(const time_t *timep, char *buf); +struct tm *gmtime_r(const time_t *restrict timer, struct tm *restrict result); +struct tm *gmtime(const time_t *tp); +int clock_gettime(clockid_t clock_id, struct timespec *tp); +int getitimer(int which, struct itimerval *curr_value); + +int pthread_cond_signal(pthread_cond_t *cond); +int pthread_cond_broadcast(pthread_cond_t *cond); +int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void *), void *restrict arg); +int pthread_attr_destroy(pthread_attr_t *attr); +int pthread_attr_init(pthread_attr_t *attr); +int pthread_attr_getstacksize(const pthread_attr_t *restrict attr, size_t *restrict stacksize); +int pthread_attr_getguardsize(const pthread_attr_t *restrict attr, size_t *restrict guardsize); +int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); +int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize); +int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); +int pthread_mutex_destroy(pthread_mutex_t *mutex); +int pthread_mutex_lock(pthread_mutex_t *mutex); +int pthread_mutex_trylock(pthread_mutex_t *mutex); +int pthread_mutex_unlock(pthread_mutex_t *mutex); diff --git a/clang/test/Analysis/Inputs/std-c-library-functions.h b/clang/test/Analysis/Inputs/std-c-library-functions.h new file mode 100644 index 0000000000000..7c86c359ee21d --- /dev/null +++ b/clang/test/Analysis/Inputs/std-c-library-functions.h @@ -0,0 +1,47 @@ +typedef __SIZE_TYPE__ size_t; +#define __SSIZE_TYPE__ \ + __typeof__(_Generic((__SIZE_TYPE__)0, \ + unsigned long long int : (long long int)0, \ + unsigned long int : (long int)0, \ + unsigned int : (int)0, \ + unsigned short : (short)0)) +typedef __SSIZE_TYPE__ ssize_t; +typedef struct { + int x; +} FILE; + +// do not use the default values for these constants to verify that this +// definition is found +#define EOF (-2) +#define AT_FDCWD (-101) + +#ifdef __cplusplus +#define restrict /*restrict*/ +#endif + +int isascii(int); +int islower(int); +int isalpha(int); +int isalnum(int); +int isblank(int); +int ispunct(int); +int isupper(int); +int isgraph(int); +int isprint(int); +int isdigit(int); +int isspace(int); +int isxdigit(int); +int toupper(int); +int tolower(int); +int toascii(int); + +int getc(FILE *); +int fgetc(FILE *); +int getchar(void); +size_t fread(void *restrict, size_t, size_t, FILE *restrict); +size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict); +ssize_t read(int, void *, size_t); +ssize_t write(int, const void *, size_t); +ssize_t getline(char **restrict, size_t *restrict, FILE *restrict); +ssize_t getdelim(char **restrict, size_t *restrict, int, FILE *restrict); +char *getenv(const char *); diff --git a/clang/test/Analysis/std-c-library-functions-POSIX.c b/clang/test/Analysis/std-c-library-functions-POSIX.c index 12ee769dc8e50..a646e63b856e6 100644 --- a/clang/test/Analysis/std-c-library-functions-POSIX.c +++ b/clang/test/Analysis/std-c-library-functions-POSIX.c @@ -126,188 +126,7 @@ // CHECK: Loaded summary for: int pthread_mutex_trylock(pthread_mutex_t *mutex) // CHECK: Loaded summary for: int pthread_mutex_unlock(pthread_mutex_t *mutex) -typedef struct { - int x; -} FILE; -FILE *fopen(const char *restrict pathname, const char *restrict mode); -FILE *tmpfile(void); -FILE *freopen(const char *restrict pathname, const char *restrict mode, - FILE *restrict stream); -int fclose(FILE *stream); -int fseek(FILE *stream, long offset, int whence); -int fileno(FILE *stream); -long a64l(const char *str64); -char *l64a(long value); -int access(const char *pathname, int amode); -int faccessat(int dirfd, const char *pathname, int mode, int flags); -int dup(int fildes); -int dup2(int fildes1, int filedes2); -int fdatasync(int fildes); -int fnmatch(const char *pattern, const char *string, int flags); -int fsync(int fildes); -typedef unsigned long off_t; -int truncate(const char *path, off_t length); -int symlink(const char *oldpath, const char *newpath); -int symlinkat(const char *oldpath, int newdirfd, const char *newpath); -int lockf(int fd, int cmd, off_t len); -typedef unsigned mode_t; -int creat(const char *pathname, mode_t mode); -unsigned int sleep(unsigned int seconds); -typedef struct { - int a; -} DIR; -int dirfd(DIR *dirp); -unsigned int alarm(unsigned int seconds); -int closedir(DIR *dir); -char *strdup(const char *s); -typedef typeof(sizeof(int)) size_t; -char *strndup(const char *s, size_t n); -/*FIXME How to define wchar_t in the test?*/ -/*typedef __wchar_t wchar_t;*/ -/*wchar_t *wcsdup(const wchar_t *s);*/ -int mkstemp(char *template); -char *mkdtemp(char *template); -char *getcwd(char *buf, size_t size); -int mkdir(const char *pathname, mode_t mode); -int mkdirat(int dirfd, const char *pathname, mode_t mode); -typedef int dev_t; -int mknod(const char *pathname, mode_t mode, dev_t dev); -int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev); -int chmod(const char *path, mode_t mode); -int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags); -int fchmod(int fildes, mode_t mode); -typedef int uid_t; -typedef int gid_t; -int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags); -int chown(const char *path, uid_t owner, gid_t group); -int lchown(const char *path, uid_t owner, gid_t group); -int fchown(int fildes, uid_t owner, gid_t group); -int rmdir(const char *pathname); -int chdir(const char *path); -int link(const char *oldpath, const char *newpath); -int linkat(int fd1, const char *path1, int fd2, const char *path2, int flag); -int unlink(const char *pathname); -int unlinkat(int fd, const char *path, int flag); -struct stat; -int fstat(int fd, struct stat *statbuf); -int stat(const char *restrict path, struct stat *restrict buf); -int lstat(const char *restrict path, struct stat *restrict buf); -int fstatat(int fd, const char *restrict path, struct stat *restrict buf, int flag); -DIR *opendir(const char *name); -DIR *fdopendir(int fd); -int isatty(int fildes); -FILE *popen(const char *command, const char *type); -int pclose(FILE *stream); -int close(int fildes); -long fpathconf(int fildes, int name); -long pathconf(const char *path, int name); -FILE *fdopen(int fd, const char *mode); -void rewinddir(DIR *dir); -void seekdir(DIR *dirp, long loc); -int rand_r(unsigned int *seedp); -int fileno(FILE *stream); -int fseeko(FILE *stream, off_t offset, int whence); -off_t ftello(FILE *stream); -void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); -typedef off_t off64_t; -void *mmap64(void *addr, size_t length, int prot, int flags, int fd, off64_t offset); -int pipe(int fildes[2]); -off_t lseek(int fildes, off_t offset, int whence); -typedef size_t ssize_t; -ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize); -ssize_t readlinkat(int fd, const char *restrict path, char *restrict buf, size_t bufsize); -int renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); -char *realpath(const char *restrict file_name, char *restrict resolved_name); -int execv(const char *path, char *const argv[]); -int execvp(const char *file, char *const argv[]); -int getopt(int argc, char *const argv[], const char *optstring); - -// In some libc implementations, sockaddr parameter is a transparent -// union of the underlying sockaddr_ pointers instead of being a -// pointer to struct sockaddr. -// We match that with the joker Irrelevant type. -struct sockaddr; -struct sockaddr_at; -#define __SOCKADDR_ALLTYPES \ - __SOCKADDR_ONETYPE(sockaddr) \ - __SOCKADDR_ONETYPE(sockaddr_at) -#define __SOCKADDR_ONETYPE(type) struct type *__restrict __##type##__; -typedef union { - __SOCKADDR_ALLTYPES -} __SOCKADDR_ARG __attribute__((__transparent_union__)); -#undef __SOCKADDR_ONETYPE -#define __SOCKADDR_ONETYPE(type) const struct type *__restrict __##type##__; -typedef union { - __SOCKADDR_ALLTYPES -} __CONST_SOCKADDR_ARG __attribute__((__transparent_union__)); -#undef __SOCKADDR_ONETYPE -typedef unsigned socklen_t; - -int accept(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len); -int bind(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len); -int getpeername(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len); -int getsockname(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len); -int connect(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len); -ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags, __SOCKADDR_ARG address, socklen_t *restrict address_len); -ssize_t sendto(int socket, const void *message, size_t length, int flags, __CONST_SOCKADDR_ARG dest_addr, socklen_t dest_len); - -int listen(int sockfd, int backlog); -ssize_t recv(int sockfd, void *buf, size_t len, int flags); -struct msghdr; -ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); -ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); -int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len); -int getsockopt(int socket, int level, int option_name, void *restrict option_value, socklen_t *restrict option_len); -ssize_t send(int sockfd, const void *buf, size_t len, int flags); -int socketpair(int domain, int type, int protocol, int sv[2]); -int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, char *restrict node, socklen_t nodelen, char *restrict service, socklen_t servicelen, int flags); -struct utimbuf; -struct timespec { int x; }; -struct timeval { int x; }; -int utime(const char *filename, struct utimbuf *buf); -int futimens(int fd, const struct timespec times[2]); -int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags); -int utimes(const char *filename, const struct timeval times[2]); -int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); -typedef unsigned long time_t; -struct tm *localtime(const time_t *tp); -struct tm *localtime_r(const time_t *restrict timer, struct tm *restrict result); -char *asctime_r(const struct tm *restrict tm, char *restrict buf); -char *ctime_r(const time_t *timep, char *buf); -struct tm *gmtime_r(const time_t *restrict timer, struct tm *restrict result); -struct tm *gmtime(const time_t *tp); -typedef unsigned long clockid_t; -int clock_gettime(clockid_t clock_id, struct timespec *tp); -struct itimerval; -int getitimer(int which, struct itimerval *curr_value); - -typedef union { - int x; -} pthread_cond_t; -int pthread_cond_signal(pthread_cond_t *cond); -int pthread_cond_broadcast(pthread_cond_t *cond); -typedef union { - int x; -} pthread_attr_t; -typedef unsigned long int pthread_t; -int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void *), void *restrict arg); -int pthread_attr_destroy(pthread_attr_t *attr); -int pthread_attr_init(pthread_attr_t *attr); -int pthread_attr_getstacksize(const pthread_attr_t *restrict attr, size_t *restrict stacksize); -int pthread_attr_getguardsize(const pthread_attr_t *restrict attr, size_t *restrict guardsize); -int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); -int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize); -typedef union { - int x; -} pthread_mutex_t; -typedef union { - int x; -} pthread_mutexattr_t; -int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); -int pthread_mutex_destroy(pthread_mutex_t *mutex); -int pthread_mutex_lock(pthread_mutex_t *mutex); -int pthread_mutex_trylock(pthread_mutex_t *mutex); -int pthread_mutex_unlock(pthread_mutex_t *mutex); +#include "Inputs/std-c-library-functions-POSIX.h" // Must have at least one call expression to initialize the summary map. int bar(void); diff --git a/clang/test/Analysis/std-c-library-functions-arg-constraints.c b/clang/test/Analysis/std-c-library-functions-arg-constraints.c index 83666f3fe91e9..1d9e3ae688cc7 100644 --- a/clang/test/Analysis/std-c-library-functions-arg-constraints.c +++ b/clang/test/Analysis/std-c-library-functions-arg-constraints.c @@ -19,15 +19,13 @@ // RUN: -analyzer-output=text \ // RUN: -verify=bugpath +#include "Inputs/std-c-library-functions-POSIX.h" + void clang_analyzer_eval(int); void clang_analyzer_warnIfReached(); int glob; -#define EOF -1 - -int isalnum(int); - void test_alnum_concrete(int v) { int ret = isalnum(256); // \ // report-warning{{The 1st argument to 'isalnum' is 256 but should be an unsigned char value or EOF}} \ @@ -63,8 +61,6 @@ void test_alnum_symbolic2(int x) { } } -int toupper(int); - void test_toupper_concrete(int v) { int ret = toupper(256); // \ // report-warning{{The 1st argument to 'toupper' is 256 but should be an unsigned char value or EOF}} \ @@ -99,8 +95,6 @@ void test_toupper_symbolic2(int x) { } } -int tolower(int); - void test_tolower_concrete(int v) { int ret = tolower(256); // \ // report-warning{{The 1st argument to 'tolower' is 256 but should be an unsigned char value or EOF}} \ @@ -135,8 +129,6 @@ void test_tolower_symbolic2(int x) { } } -int toascii(int); - void test_toascii_concrete(int v) { int ret = toascii(256); // \ // report-warning{{The 1st argument to 'toascii' is 256 but should be an unsigned char value or EOF}} \ @@ -171,9 +163,6 @@ void test_toascii_symbolic2(int x) { } } -typedef struct FILE FILE; -typedef typeof(sizeof(int)) size_t; -size_t fread(void *restrict, size_t, size_t, FILE *restrict); void test_notnull_concrete(FILE *fp) { fread(0, sizeof(int), 10, fp); // \ // report-warning{{The 1st argument to 'fread' is NULL but should not be NULL}} \ @@ -208,7 +197,6 @@ void test_no_node_after_bug(FILE *fp, size_t size, size_t n, void *buf) { clang_analyzer_warnIfReached(); // not reachable } -typedef __WCHAR_TYPE__ wchar_t; // This is one test case for the ARR38-C SEI-CERT rule. void ARR38_C_F(FILE *file) { enum { BUFFER_SIZE = 1024 }; diff --git a/clang/test/Analysis/std-c-library-functions.c b/clang/test/Analysis/std-c-library-functions.c index a4032298734d0..419f98b7a6bbb 100644 --- a/clang/test/Analysis/std-c-library-functions.c +++ b/clang/test/Analysis/std-c-library-functions.c @@ -50,6 +50,9 @@ // CHECK-NEXT: Loaded summary for: int isspace(int) // CHECK-NEXT: Loaded summary for: int isupper(int) // CHECK-NEXT: Loaded summary for: int isxdigit(int) +// CHECK-NEXT: Loaded summary for: int toupper(int) +// CHECK-NEXT: Loaded summary for: int tolower(int) +// CHECK-NEXT: Loaded summary for: int toascii(int) // CHECK-NEXT: Loaded summary for: int getc(FILE *) // CHECK-NEXT: Loaded summary for: int fgetc(FILE *) // CHECK-NEXT: Loaded summary for: int getchar(void) @@ -59,16 +62,14 @@ // CHECK-NEXT: Loaded summary for: ssize_t write(int, const void *, size_t) // CHECK-NEXT: Loaded summary for: ssize_t getline(char **restrict, size_t *restrict, FILE *restrict) // CHECK-NEXT: Loaded summary for: ssize_t getdelim(char **restrict, size_t *restrict, int, FILE *restrict) +// CHECK-NEXT: Loaded summary for: char *getenv(const char *) +#include "Inputs/std-c-library-functions.h" void clang_analyzer_eval(int); int glob; -typedef struct FILE FILE; -#define EOF -1 - -int getc(FILE *); void test_getc(FILE *fp) { int x; while ((x = getc(fp)) != EOF) { @@ -77,17 +78,11 @@ void test_getc(FILE *fp) { } } -int fgetc(FILE *); void test_fgets(FILE *fp) { clang_analyzer_eval(fgetc(fp) < 256); // expected-warning{{TRUE}} clang_analyzer_eval(fgetc(fp) >= 0); // expected-warning{{UNKNOWN}} } - -typedef typeof(sizeof(int)) size_t; -typedef signed long ssize_t; -ssize_t read(int, void *, size_t); -ssize_t write(int, const void *, size_t); void test_read_write(int fd, char *buf) { glob = 1; ssize_t x = write(fd, buf, 10); @@ -106,8 +101,6 @@ void test_read_write(int fd, char *buf) { } } -size_t fread(void *restrict, size_t, size_t, FILE *restrict); -size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict); void test_fread_fwrite(FILE *fp, int *buf) { size_t x = fwrite(buf, sizeof(int), 10, fp); @@ -128,8 +121,6 @@ void test_fread_uninitialized(void) { (void)fread(ptr, sz, nmem, fp); // expected-warning {{1st function call argument is an uninitialized value}} } -ssize_t getline(char **restrict, size_t *restrict, FILE *restrict); -ssize_t getdelim(char **restrict, size_t *restrict, int, FILE *restrict); void test_getline(FILE *fp) { char *line = 0; size_t n = 0; @@ -139,7 +130,6 @@ void test_getline(FILE *fp) { } } -int isascii(int); void test_isascii(int x) { clang_analyzer_eval(isascii(123)); // expected-warning{{TRUE}} clang_analyzer_eval(isascii(-1)); // expected-warning{{FALSE}} @@ -157,7 +147,6 @@ void test_isascii(int x) { clang_analyzer_eval(glob); // expected-warning{{TRUE}} } -int islower(int); void test_islower(int x) { clang_analyzer_eval(islower('x')); // expected-warning{{TRUE}} clang_analyzer_eval(islower('X')); // expected-warning{{FALSE}} @@ -165,7 +154,6 @@ void test_islower(int x) { clang_analyzer_eval(x < 'a'); // expected-warning{{FALSE}} } -int getchar(void); void test_getchar(void) { int x = getchar(); if (x == EOF) @@ -174,27 +162,23 @@ void test_getchar(void) { clang_analyzer_eval(x < 256); // expected-warning{{TRUE}} } -int isalpha(int); void test_isalpha(void) { clang_analyzer_eval(isalpha(']')); // expected-warning{{FALSE}} clang_analyzer_eval(isalpha('Q')); // expected-warning{{TRUE}} clang_analyzer_eval(isalpha(128)); // expected-warning{{UNKNOWN}} } -int isalnum(int); void test_alnum(void) { clang_analyzer_eval(isalnum('1')); // expected-warning{{TRUE}} clang_analyzer_eval(isalnum(')')); // expected-warning{{FALSE}} } -int isblank(int); void test_isblank(void) { clang_analyzer_eval(isblank('\t')); // expected-warning{{TRUE}} clang_analyzer_eval(isblank(' ')); // expected-warning{{TRUE}} clang_analyzer_eval(isblank('\n')); // expected-warning{{FALSE}} } -int ispunct(int); void test_ispunct(int x) { clang_analyzer_eval(ispunct(' ')); // expected-warning{{FALSE}} clang_analyzer_eval(ispunct(-1)); // expected-warning{{FALSE}} @@ -204,21 +188,17 @@ void test_ispunct(int x) { clang_analyzer_eval(x < 127); // expected-warning{{TRUE}} } -int isupper(int); void test_isupper(int x) { if (isupper(x)) clang_analyzer_eval(x < 'A'); // expected-warning{{FALSE}} } -int isgraph(int); -int isprint(int); void test_isgraph_isprint(int x) { char y = x; if (isgraph(y)) clang_analyzer_eval(isprint(x)); // expected-warning{{TRUE}} } -int isdigit(int); void test_mixed_branches(int x) { if (isdigit(x)) { clang_analyzer_eval(isgraph(x)); // expected-warning{{TRUE}} @@ -230,7 +210,6 @@ void test_mixed_branches(int x) { } } -int isspace(int); void test_isspace(int x) { if (!isascii(x)) return; @@ -239,7 +218,6 @@ void test_isspace(int x) { clang_analyzer_eval(isspace(x)); // expected-warning{{TRUE}} } -int isxdigit(int); void test_isxdigit(int x) { if (isxdigit(x) && isupper(x)) { clang_analyzer_eval(x >= 'A'); // expected-warning{{TRUE}} @@ -255,7 +233,6 @@ void test_call_by_pointer(void) { clang_analyzer_eval(f('A')); // expected-warning{{FALSE}} } -char *getenv(const char *name); void test_getenv(void) { // getenv() bifurcates here. clang_analyzer_eval(getenv("FOO") == 0); diff --git a/clang/test/CXX/expr/expr.const/p3-0x.cpp b/clang/test/CXX/expr/expr.const/p3-0x.cpp index 47968eed75b66..5bd70c5250b59 100644 --- a/clang/test/CXX/expr/expr.const/p3-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p3-0x.cpp @@ -10,6 +10,7 @@ void NonConstF() { case nonconst: // expected-error {{case value is not a constant expression}} expected-note {{read of non-const}} break; } + NonConstT<> V; // expected-note {{while checking a default template argument used here}} return; } diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp index 72265d77700aa..c5d08ec404a7c 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp @@ -35,7 +35,8 @@ struct NoDefaultCtor { template void defargs_in_template_unused(T t) { auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} \ - // expected-note {{in instantiation of default function argument expression for 'operator()' required here}} + // expected-note {{in instantiation of default function argument expression for 'operator()' required here}} \ + // expected-note {{while substituting into a lambda expression here}} l1(t); } @@ -45,7 +46,8 @@ template void defargs_in_template_unused(NoDefaultCtor); // expected-note{{in i template void defargs_in_template_used() { auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} \ - // expected-note {{in instantiation of default function argument expression for 'operator()' required here}} + // expected-note {{in instantiation of default function argument expression for 'operator()' required here}} \ + // expected-note {{while substituting into a lambda expression here}} l1(); } diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp index 6ae7b5bdc8083..aa3b4588ce397 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp @@ -41,6 +41,7 @@ auto init_kind_2 = [ec = ExplicitCopy()] {}; // expected-error {{no matching con template void init_kind_template() { auto init_kind_1 = [ec(T())] {}; auto init_kind_2 = [ec = T()] {}; // expected-error {{no matching constructor}} + // expected-note@-1 {{while substituting into a lambda expression here}} } template void init_kind_template(); template void init_kind_template(); // expected-note {{instantiation of}} @@ -58,6 +59,7 @@ auto bad_init_6 = [a{overload_fn}] {}; // expected-error {{cannot deduce type fo auto bad_init_7 = [a{{1}}] {}; // expected-error {{cannot deduce type for lambda capture 'a' from nested initializer list}} template void pack_1(T...t) { (void)[a(t...)] {}; } // expected-error {{initializer missing for lambda capture 'a'}} + // expected-note@-1 {{while substituting into a lambda expression here}} template void pack_1<>(); // expected-note {{instantiation of}} // No lifetime-extension of the temporary here. @@ -80,6 +82,7 @@ auto s = [s(move(S()))] {}; template T instantiate_test(T t) { [x(&t)]() { *x = 1; } (); // expected-error {{assigning to 'const char *'}} + // expected-note@-1 {{while substituting into a lambda expression here}} return t; } int instantiate_test_1 = instantiate_test(0); diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp index 028fcee5fda43..a5278c27bf25c 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp @@ -85,6 +85,7 @@ void init_capture_pack_err(Args ...args) { template void init_capture_pack_multi(Args ...args) { [as(args...)] {} (); // expected-error {{initializer missing for lambda capture 'as'}} expected-error {{multiple}} + // expected-note@-1 2{{while substituting into a lambda expression}} } template void init_capture_pack_multi(); // expected-note {{instantiation}} template void init_capture_pack_multi(int); diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp index 660f6091bb663..ffac9112491fe 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp @@ -54,6 +54,7 @@ void test_result_type(int N) { template void test_result_type_tpl(int N) { auto l1 = []() -> T {}; // expected-error{{incomplete result type 'Incomplete' in lambda expression}} + // expected-note@-1{{while substituting into a lambda expression here}} typedef int vla[N]; auto l2 = []() -> vla {}; // expected-error{{function cannot return array type 'vla' (aka 'int[N]')}} } diff --git a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp index 6579eb19a7596..0c357db764a92 100644 --- a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp +++ b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp @@ -80,6 +80,7 @@ namespace generic_lambda { [](auto x) { if constexpr (sizeof(T) == 1 && sizeof(x) == 1) T::error(); // expected-error 2{{'::'}} + // expected-note@-3 2{{while substituting into a lambda expression here}} } (0); } @@ -88,6 +89,7 @@ namespace generic_lambda { if constexpr (sizeof(T) == 1) if constexpr (sizeof(x) == 1) T::error(); // expected-error {{'::'}} + // expected-note@-4 {{while substituting into a lambda expression here}} } (0); } diff --git a/clang/test/CXX/temp/temp.deduct/p9.cpp b/clang/test/CXX/temp/temp.deduct/p9.cpp new file mode 100644 index 0000000000000..23bcd2a1892e7 --- /dev/null +++ b/clang/test/CXX/temp/temp.deduct/p9.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -std=c++20 -verify %s +// [temp.deduct.p9] +// A lambda-expression appearing in a function type or a template parameter is +// not considered part of the immediate context for the purposes of template +// argument deduction. +// [Note: The intent is to avoid requiring implementations to deal with +// substitution failure involving arbitrary statements.] +template +auto f(T) -> decltype([]() { T::invalid; } ()); +void f(...); +void test_f() { + f(0); // expected-error@-3 {{type 'int' cannot be used prior to '::'}} + // expected-note@-1 {{while substituting deduced template arguments}} + // expected-note@-5 {{while substituting into a lambda expression here}} +} + +template +void g(T); +void g(...); +void test_g() { + g(0); // expected-error@-4 {{type 'int' cannot be used prior to '::'}} + // expected-note@-4 {{in instantiation of default argument}} + // expected-note@-2 {{while substituting deduced template arguments}} + // expected-note@-7 {{while substituting into a lambda expression here}} +} + +template +auto h(T) -> decltype([x = T::invalid]() { }); +void h(...); +void test_h() { + h(0); // expected-error@-3 {{type 'int' cannot be used prior to '::'}} + // expected-note@-1 {{while substituting deduced template arguments}} + // expected-note@-5 {{while substituting into a lambda expression here}} +} + +template +auto i(T) -> decltype([]() -> typename T::invalid { }); +void i(...); +void test_i() { + i(0); // expected-error@-3 {{type 'int' cannot be used prior to '::'}} + // expected-note@-1 {{while substituting deduced template arguments}} + // expected-note@-5 {{while substituting into a lambda expression here}} +} + + +// In this example, the lambda itself is not part of an immediate context, but +// substitution to the lambda expression succeeds, producing dependent +// `decltype(x.invalid)`. The call to the lambda, however, is in the immediate context +// and it produces a SFINAE failure. Hence, we pick the second overload +// and don't produce any errors. +template +auto j(T t) -> decltype([](auto x) -> decltype(x.invalid) { } (t)); // #1 +void j(...); // #2 +void test_j() { + j(0); // deduction fails on #1, calls #2. +} diff --git a/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp b/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp index 63f56640b1ce9..83144a494937b 100644 --- a/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp +++ b/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp @@ -141,6 +141,7 @@ template struct A { B() { consume([]{ int arr[Vs]; // expected-error {{negative size}} + // expected-note@-2 {{while substituting into a lambda expression here}} }...); } }; diff --git a/clang/test/ClangScanDeps/_Pragma-once.c b/clang/test/ClangScanDeps/_Pragma-once.c new file mode 100644 index 0000000000000..573f82c85698f --- /dev/null +++ b/clang/test/ClangScanDeps/_Pragma-once.c @@ -0,0 +1,24 @@ +// Test scanning deps works with _Pragma syntax when not inside a macro. + +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json + +// RUN: clang-scan-deps -compilation-database %t/cdb.json -j 1 + +//--- cdb.json.template +[{ + "directory": "DIR", + "command": "clang -fsyntax-only DIR/tu.c", + "file": "DIR/tu.c" +}] + +//--- a.h +_Pragma("once") +#include "b.h" + +//--- b.h +#include "a.h" + +//--- tu.c +#include "a.h" diff --git a/clang/test/CodeGen/LoongArch/inline-asm-gcc-regs-error.c b/clang/test/CodeGen/LoongArch/inline-asm-gcc-regs-error.c index 39450c4657ae6..c5ecf0c929af8 100644 --- a/clang/test/CodeGen/LoongArch/inline-asm-gcc-regs-error.c +++ b/clang/test/CodeGen/LoongArch/inline-asm-gcc-regs-error.c @@ -11,12 +11,10 @@ void test(void) { /// Names not prefixed with '$' are invalid. -// CHECK: :[[#@LINE+1]]:24: error: unknown register name 'r4' in asm - register int a3 asm ("r4"); -// CHECK: :[[#@LINE+1]]:24: error: unknown register name 'a0' in asm - register int a4 asm ("a0"); // CHECK: :[[#@LINE+1]]:26: error: unknown register name 'f0' in asm register float a5 asm ("f0"); // CHECK: :[[#@LINE+1]]:26: error: unknown register name 'fa0' in asm register float a6 asm ("fa0"); +// CHECK: :[[#@LINE+1]]:15: error: unknown register name 'fcc0' in asm + asm ("" ::: "fcc0"); } diff --git a/clang/test/CodeGen/LoongArch/inline-asm-gcc-regs.c b/clang/test/CodeGen/LoongArch/inline-asm-gcc-regs.c index 0676453664436..e1015f6fc01d5 100644 --- a/clang/test/CodeGen/LoongArch/inline-asm-gcc-regs.c +++ b/clang/test/CodeGen/LoongArch/inline-asm-gcc-regs.c @@ -7,56 +7,72 @@ // CHECK: call void asm sideeffect "", "{$r0}"(i32 undef) void test_r0() { register int a asm ("$r0"); + register int b asm ("r0"); asm ("" :: "r" (a)); + asm ("" :: "r" (b)); } // CHECK-LABEL: @test_r12 // CHECK: call void asm sideeffect "", "{$r12}"(i32 undef) void test_r12() { register int a asm ("$r12"); + register int b asm ("r12"); asm ("" :: "r" (a)); + asm ("" :: "r" (b)); } // CHECK-LABEL: @test_r31 // CHECK: call void asm sideeffect "", "{$r31}"(i32 undef) void test_r31() { register int a asm ("$r31"); + register int b asm ("r31"); asm ("" :: "r" (a)); + asm ("" :: "r" (b)); } // CHECK-LABEL: @test_zero // CHECK: call void asm sideeffect "", "{$r0}"(i32 undef) void test_zero() { register int a asm ("$zero"); + register int b asm ("zero"); asm ("" :: "r" (a)); + asm ("" :: "r" (b)); } // CHECK-LABEL: @test_a0 // CHECK: call void asm sideeffect "", "{$r4}"(i32 undef) void test_a0() { register int a asm ("$a0"); + register int b asm ("a0"); asm ("" :: "r" (a)); + asm ("" :: "r" (b)); } // CHECK-LABEL: @test_t1 // CHECK: call void asm sideeffect "", "{$r13}"(i32 undef) void test_t1() { register int a asm ("$t1"); + register int b asm ("t1"); asm ("" :: "r" (a)); + asm ("" :: "r" (b)); } // CHECK-LABEL: @test_fp // CHECK: call void asm sideeffect "", "{$r22}"(i32 undef) void test_fp() { register int a asm ("$fp"); + register int b asm ("fp"); asm ("" :: "r" (a)); + asm ("" :: "r" (b)); } // CHECK-LABEL: @test_s2 // CHECK: call void asm sideeffect "", "{$r25}"(i32 undef) void test_s2() { register int a asm ("$s2"); + register int b asm ("s2"); asm ("" :: "r" (a)); + asm ("" :: "r" (b)); } // CHECK-LABEL: @test_f0 @@ -100,3 +116,11 @@ void test_fs2() { register float a asm ("$fs2"); asm ("" :: "f" (a)); } + +// CHECK-LABEL: @test_fcc +// CHECK: call void asm sideeffect "", "~{$fcc0}"() +// CHECK: call void asm sideeffect "", "~{$fcc7}"() +void test_fcc() { + asm ("" ::: "$fcc0"); + asm ("" ::: "$fcc7"); +} diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-altivec.c b/clang/test/CodeGen/PowerPC/builtins-ppc-altivec.c index 2310082a2aac5..90c28ddd316ee 100644 --- a/clang/test/CodeGen/PowerPC/builtins-ppc-altivec.c +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-altivec.c @@ -9526,80 +9526,6 @@ void test10() { // CHECK-LE: store <4 x float> %{{[0-9]+}}, ptr %{{.+}}, align 1 } -/* ----------------------------- vec_xl_be ---------------------------------- */ -void test11() { - // CHECK-LABEL: define{{.*}} void @test11 - // CHECK-LE-LABEL: define{{.*}} void @test11 - res_vsc = vec_xl_be(param_sll, param_sc_ld); - // CHECK: load <16 x i8>, ptr %{{.+}}, align 1 - // CHECK-LE: call <2 x double> @llvm.ppc.vsx.lxvd2x.be(ptr %{{[0-9]+}}) - // CHECK-LE: shufflevector <16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}}, <16 x i32> - - res_vuc = vec_xl_be(param_sll, param_uc_ld); - // CHECK: load <16 x i8>, ptr %{{.+}}, align 1 - // CHECK-LE: call <2 x double> @llvm.ppc.vsx.lxvd2x.be(ptr %{{[0-9]+}}) - // CHECK-LE: shufflevector <16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}}, <16 x i32> - - res_vs = vec_xl_be(param_sll, param_s_ld); - // CHECK: load <8 x i16>, ptr %{{.+}}, align 1 - // CHECK-LE: call <2 x double> @llvm.ppc.vsx.lxvd2x.be(ptr %{{[0-9]+}}) - // CHECK-LE: shufflevector <8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}}, <8 x i32> - - res_vus = vec_xl_be(param_sll, param_us_ld); - // CHECK: load <8 x i16>, ptr %{{.+}}, align 1 - // CHECK-LE: call <2 x double> @llvm.ppc.vsx.lxvd2x.be(ptr %{{[0-9]+}}) - // CHECK-LE: shufflevector <8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}}, <8 x i32> - - res_vi = vec_xl_be(param_sll, param_i_ld); - // CHECK: load <4 x i32>, ptr %{{.+}}, align 1 - // CHECK-LE: call <4 x i32> @llvm.ppc.vsx.lxvw4x.be(ptr %{{[0-9]+}}) - - res_vui = vec_xl_be(param_sll, param_ui_ld); - // CHECK: load <4 x i32>, ptr %{{.+}}, align 1 - // CHECK-LE: call <4 x i32> @llvm.ppc.vsx.lxvw4x.be(ptr %{{[0-9]+}}) - - res_vf = vec_xl_be(param_sll, param_f_ld); - // CHECK: load <4 x float>, ptr %{{.+}}, align 1 - // CHECK-LE: call <4 x i32> @llvm.ppc.vsx.lxvw4x.be(ptr %{{[0-9]+}}) -} - -/* ----------------------------- vec_xst_be --------------------------------- */ -void test12() { - // CHECK-LABEL: define{{.*}} void @test12 - // CHECK-LE-LABEL: define{{.*}} void @test12 - vec_xst_be(vsc, param_sll, ¶m_sc); - // CHECK: store <16 x i8> %{{[0-9]+}}, ptr %{{.+}}, align 1 - // CHECK-LE: shufflevector <16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}}, <16 x i32> - // CHECK-LE: call void @llvm.ppc.vsx.stxvd2x.be(<2 x double> %{{[0-9]+}}, ptr %{{[0-9]+}}) - - vec_xst_be(vuc, param_sll, ¶m_uc); - // CHECK: store <16 x i8> %{{[0-9]+}}, ptr %{{.+}}, align 1 - // CHECK-LE: shufflevector <16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}}, <16 x i32> - // CHECK-LE: call void @llvm.ppc.vsx.stxvd2x.be(<2 x double> %{{[0-9]+}}, ptr %{{[0-9]+}}) - - vec_xst_be(vs, param_sll, ¶m_s); - // CHECK: store <8 x i16> %{{[0-9]+}}, ptr %{{.+}}, align 1 - // CHECK-LE: shufflevector <8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}}, <8 x i32> - // CHECK-LE: call void @llvm.ppc.vsx.stxvd2x.be(<2 x double> %{{[0-9]+}}, ptr %{{[0-9]+}}) - - vec_xst_be(vus, param_sll, ¶m_us); - // CHECK: store <8 x i16> %{{[0-9]+}}, ptr %{{.+}}, align 1 - // CHECK-LE: shufflevector <8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}}, <8 x i32> - // CHECK-LE: call void @llvm.ppc.vsx.stxvd2x.be(<2 x double> %{{[0-9]+}}, ptr %{{[0-9]+}}) - - vec_xst_be(vi, param_sll, ¶m_i); - // CHECK: store <4 x i32> %{{[0-9]+}}, ptr %{{.+}}, align 1 - // CHECK-LE: call void @llvm.ppc.vsx.stxvw4x.be(<4 x i32> %{{[0-9]+}}, ptr %{{[0-9]+}}) - - vec_xst_be(vui, param_sll, ¶m_ui); - // CHECK: store <4 x i32> %{{[0-9]+}}, ptr %{{.+}}, align 1 - // CHECK-LE: call void @llvm.ppc.vsx.stxvw4x.be(<4 x i32> %{{[0-9]+}}, ptr %{{[0-9]+}}) - - vec_xst_be(vf, param_sll, ¶m_f); - // CHECK: store <4 x float> %{{[0-9]+}}, ptr %{{.+}}, align 1 - // CHECK-LE: call void @llvm.ppc.vsx.stxvw4x.be(<4 x i32> %{{[0-9]+}}, ptr %{{[0-9]+}}) -} - vector float test_rsqrtf(vector float a, vector float b) { // CHECK-LABEL: test_rsqrtf // CHECK: call fast <4 x float> @llvm.sqrt.v4f32 diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c b/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c index 111302337954b..61421fbf2fecd 100644 --- a/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -triple powerpc64le-gnu-linux \ -// RUN: -target-feature +altivec -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck \ +// RUN: -target-feature +vsx -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck \ // RUN: %s typedef __attribute__((vector_size(4 * sizeof(float)))) float vec_float; diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-fpconstrained.c b/clang/test/CodeGen/PowerPC/builtins-ppc-fpconstrained.c index 6fc70ed74cc43..b4f6fa0471aa7 100644 --- a/clang/test/CodeGen/PowerPC/builtins-ppc-fpconstrained.c +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-fpconstrained.c @@ -12,7 +12,7 @@ // RUN: -o - %s | FileCheck --check-prefix=CHECK-ASM \ // RUN: --check-prefix=FIXME-CHECK %s // RUN: %clang_cc1 -triple powerpcspe -S -ffp-exception-behavior=strict \ -// RUN: -target-feature +spe -fexperimental-strict-floating-point -emit-llvm \ +// RUN: -target-feature +vsx -fexperimental-strict-floating-point -emit-llvm \ // RUN: %s -o - | FileCheck --check-prefix=CHECK-CONSTRAINED %s typedef __attribute__((vector_size(4 * sizeof(float)))) float vec_float; diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-htm.c b/clang/test/CodeGen/PowerPC/builtins-ppc-htm.c index d518c00f12caf..51585f27e0bc7 100644 --- a/clang/test/CodeGen/PowerPC/builtins-ppc-htm.c +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-htm.c @@ -7,82 +7,82 @@ void test1(long int *r, int code, long int *a, long int *b) { r[0] = __builtin_tbegin (0); // CHECK: @llvm.ppc.tbegin -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_tbegin' needs target feature htm r[1] = __builtin_tbegin (1); // CHECK: @llvm.ppc.tbegin -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_tbegin' needs target feature htm r[2] = __builtin_tend (0); // CHECK: @llvm.ppc.tend -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_tend' needs target feature htm r[3] = __builtin_tendall (); // CHECK: @llvm.ppc.tendall -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_tendall' needs target feature htm r[4] = __builtin_tabort (code); // CHECK: @llvm.ppc.tabort -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_tabort' needs target feature htm r[5] = __builtin_tabort (0x1); // CHECK: @llvm.ppc.tabort -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_tabort' needs target feature htm r[6] = __builtin_tabortdc (0xf, a[0], b[0]); // CHECK: @llvm.ppc.tabortdc -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_tabortdc' needs target feature htm r[7] = __builtin_tabortdci (0xf, a[1], 0x1); // CHECK: @llvm.ppc.tabortdc -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_tabortdci' needs target feature htm r[8] = __builtin_tabortwc (0xf, a[2], b[2]); // CHECK: @llvm.ppc.tabortwc -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_tabortwc' needs target feature htm r[9] = __builtin_tabortwci (0xf, a[3], 0x1); // CHECK: @llvm.ppc.tabortwc -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_tabortwci' needs target feature htm r[10] = __builtin_tcheck (); // CHECK: @llvm.ppc.tcheck -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_tcheck' needs target feature htm r[11] = __builtin_trechkpt (); // CHECK: @llvm.ppc.trechkpt -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_trechkpt' needs target feature htm r[12] = __builtin_treclaim (0); // CHECK: @llvm.ppc.treclaim -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_treclaim' needs target feature htm r[13] = __builtin_tresume (); // CHECK: @llvm.ppc.tresume -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_tresume' needs target feature htm r[14] = __builtin_tsuspend (); // CHECK: @llvm.ppc.tsuspend -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_tsuspend' needs target feature htm r[15] = __builtin_tsr (0); // CHECK: @llvm.ppc.tsr -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_tsr' needs target feature htm r[16] = __builtin_ttest (); // CHECK: @llvm.ppc.ttest -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_ttest' needs target feature htm r[17] = __builtin_get_texasr (); // CHECK: @llvm.ppc.get.texasr -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_get_texasr' needs target feature htm r[18] = __builtin_get_texasru (); // CHECK: @llvm.ppc.get.texasru -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_get_texasru' needs target feature htm r[19] = __builtin_get_tfhar (); // CHECK: @llvm.ppc.get.tfhar -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_get_tfhar' needs target feature htm r[20] = __builtin_get_tfiar (); // CHECK: @llvm.ppc.get.tfiar -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_get_tfiar' needs target feature htm __builtin_set_texasr (a[21]); // CHECK: @llvm.ppc.set.texasr -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_set_texasr' needs target feature htm __builtin_set_texasru (a[22]); // CHECK: @llvm.ppc.set.texasru -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_set_texasru' needs target feature htm __builtin_set_tfhar (a[23]); // CHECK: @llvm.ppc.set.tfhar -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_set_tfhar' needs target feature htm __builtin_set_tfiar (a[24]); // CHECK: @llvm.ppc.set.tfiar -// ERROR: error: this builtin requires HTM to be enabled +// ERROR: error: '__builtin_set_tfiar' needs target feature htm } diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-p7-disabled.c b/clang/test/CodeGen/PowerPC/builtins-ppc-p7-disabled.c index 2a6a4f8dbc8e8..686ef5f626bda 100644 --- a/clang/test/CodeGen/PowerPC/builtins-ppc-p7-disabled.c +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-p7-disabled.c @@ -6,6 +6,7 @@ // RUN: not %clang_cc1 -triple powerpc-unknown-unknown -emit-llvm %s -o - 2>&1 \ // RUN: -target-cpu pwr7 | FileCheck %s -check-prefix=CHECK-32 +// CHECK: error: use of '__int128' with '__vector' requires extended Altivec support (available on POWER8 or later) vector signed __int128 vslll = {33}; void call_p7_builtins(void) @@ -19,20 +20,6 @@ void call_p7_builtins(void) __builtin_unpack_vector_int128(vslll, 1); } -// CHECK: error: this builtin is only valid on POWER7 or later CPUs -// CHECK: __builtin_divwe -// CHECK: error: this builtin is only valid on POWER7 or later CPUs -// CHECK: __builtin_divweu -// CHECK: error: this builtin is only valid on POWER7 or later CPUs -// CHECK: __builtin_divde -// CHECK: error: this builtin is only valid on POWER7 or later CPUs -// CHECK: __builtin_divdeu -// CHECK: error: this builtin is only valid on POWER7 or later CPUs -// CHECK: __builtin_bpermd -// CHECK: error: this builtin is only valid on POWER7 or later CPUs -// CHECK: __builtin_pack_vector_int128 -// CHECK: error: this builtin is only valid on POWER7 or later CPUs -// CHECK: __builtin_unpack_vector_int128 // CHECK-32: error: this builtin is only available on 64-bit targets // CHECK-32: __builtin_divde // CHECK-32: error: this builtin is only available on 64-bit targets diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-p8vector.c b/clang/test/CodeGen/PowerPC/builtins-ppc-p8vector.c index e21161feac4da..69ce9d6214e3c 100644 --- a/clang/test/CodeGen/PowerPC/builtins-ppc-p8vector.c +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-p8vector.c @@ -1,6 +1,6 @@ // REQUIRES: powerpc-registered-target -// RUN: %clang_cc1 -flax-vector-conversions=none -target-feature +altivec -target-feature +power8-vector -triple powerpc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -flax-vector-conversions=none -target-feature +altivec -target-feature +power8-vector -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-LE +// RUN: %clang_cc1 -flax-vector-conversions=none -target-feature +altivec -target-feature +isa-v207-instructions -target-feature +power8-vector -triple powerpc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -flax-vector-conversions=none -target-feature +altivec -target-feature +isa-v207-instructions -target-feature +power8-vector -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-LE // RUN: not %clang_cc1 -target-feature +altivec -target-feature +vsx -triple powerpc64-unknown-unknown -emit-llvm %s -o - 2>&1 | FileCheck %s -check-prefix=CHECK-PPC // Added -target-feature +vsx above to avoid errors about "vector double" and to // generate the correct errors for functions that are only overloaded with VSX diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-pwr10-64bit.c b/clang/test/CodeGen/PowerPC/builtins-ppc-pwr10-64bit.c index c6922eae6bf58..4ae6c30edda79 100644 --- a/clang/test/CodeGen/PowerPC/builtins-ppc-pwr10-64bit.c +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-pwr10-64bit.c @@ -16,19 +16,15 @@ extern unsigned long long ull; -unsigned long long test_builtin_pextd() { - // CHECK-LABEL: @test_builtin_pextd( - // CHECK: %2 = call i64 @llvm.ppc.pextd(i64 %0, i64 %1) +void test_xlcompat() { + // CHECK-LABEL: @test_xlcompat( + // CHECK: %2 = call i64 @llvm.ppc.pextd(i64 %0, i64 %1) // CHECK-32-ERROR: error: this builtin is only available on 64-bit targets - // CHECK-NONPWR10-ERR: error: this builtin is only valid on POWER10 or later CPUs - return __builtin_pextd(ull, ull); -} + // CHECK-NONPWR10-ERR: error: '__builtin_pextd' needs target feature isa-v31-instructions + ull = __builtin_pextd(ull, ull); -unsigned long long test_builtin_pdepd() { - // CHECK-LABEL: @test_builtin_pdepd( - // CHECK: %2 = call i64 @llvm.ppc.pdepd(i64 %0, i64 %1) + // CHECK: %5 = call i64 @llvm.ppc.pdepd(i64 %3, i64 %4) // CHECK-32-ERROR: error: this builtin is only available on 64-bit targets - // CHECK-NONPWR10-ERR: error: this builtin is only valid on POWER10 or later CPUs - return __builtin_pdepd(ull, ull); + // CHECK-NONPWR10-ERR: error: '__builtin_pdepd' needs target feature isa-v31-instructions + ull = __builtin_pdepd(ull, ull); } - diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-vsx.c b/clang/test/CodeGen/PowerPC/builtins-ppc-vsx.c index e85a09be64230..790f886985a9f 100644 --- a/clang/test/CodeGen/PowerPC/builtins-ppc-vsx.c +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-vsx.c @@ -1977,6 +1977,38 @@ res_vd = vec_xl_be(sll, ad); // CHECK: load <2 x double>, ptr %{{[0-9]+}}, align 1 // CHECK-LE: call <2 x double> @llvm.ppc.vsx.lxvd2x.be(ptr %{{[0-9]+}}) +res_vsc = vec_xl_be(sll, asc); +// CHECK: load <16 x i8>, ptr %{{.+}}, align 1 +// CHECK-LE: call <2 x double> @llvm.ppc.vsx.lxvd2x.be(ptr %{{[0-9]+}}) +// CHECK-LE: shufflevector <16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}}, <16 x i32> + +res_vuc = vec_xl_be(sll, auc); +// CHECK: load <16 x i8>, ptr %{{.+}}, align 1 +// CHECK-LE: call <2 x double> @llvm.ppc.vsx.lxvd2x.be(ptr %{{[0-9]+}}) +// CHECK-LE: shufflevector <16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}}, <16 x i32> + +res_vss = vec_xl_be(sll, ass); +// CHECK: load <8 x i16>, ptr %{{.+}}, align 1 +// CHECK-LE: call <2 x double> @llvm.ppc.vsx.lxvd2x.be(ptr %{{[0-9]+}}) +// CHECK-LE: shufflevector <8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}}, <8 x i32> + +res_vus = vec_xl_be(sll, aus); +// CHECK: load <8 x i16>, ptr %{{.+}}, align 1 +// CHECK-LE: call <2 x double> @llvm.ppc.vsx.lxvd2x.be(ptr %{{[0-9]+}}) +// CHECK-LE: shufflevector <8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}}, <8 x i32> + +res_vsi = vec_xl_be(sll, asi); +// CHECK: load <4 x i32>, ptr %{{.+}}, align 1 +// CHECK-LE: call <4 x i32> @llvm.ppc.vsx.lxvw4x.be(ptr %{{[0-9]+}}) + +res_vui = vec_xl_be(sll, aui); +// CHECK: load <4 x i32>, ptr %{{.+}}, align 1 +// CHECK-LE: call <4 x i32> @llvm.ppc.vsx.lxvw4x.be(ptr %{{[0-9]+}}) + +res_vf = vec_xl_be(sll, af); +// CHECK: load <4 x float>, ptr %{{.+}}, align 1 +// CHECK-LE: call <4 x i32> @llvm.ppc.vsx.lxvw4x.be(ptr %{{[0-9]+}}) + res_vsll = vec_xlds(sll, asll); // CHECK: load i64 // CHECK: insertelement <2 x i64> @@ -2061,6 +2093,38 @@ vec_xst_be(vd, sll, ad); // CHECK: store <2 x double> %{{[0-9]+}}, ptr %{{[0-9]+}}, align 1 // CHECK-LE: call void @llvm.ppc.vsx.stxvd2x.be(<2 x double> %{{[0-9]+}}, ptr %{{[0-9]+}}) +vec_xst_be(vsc, sll, asc); +// CHECK: store <16 x i8> %{{[0-9]+}}, ptr %{{.+}}, align 1 +// CHECK-LE: shufflevector <16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}}, <16 x i32> +// CHECK-LE: call void @llvm.ppc.vsx.stxvd2x.be(<2 x double> %{{[0-9]+}}, ptr %{{[0-9]+}}) + +vec_xst_be(vuc, sll, auc); +// CHECK: store <16 x i8> %{{[0-9]+}}, ptr %{{.+}}, align 1 +// CHECK-LE: shufflevector <16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}}, <16 x i32> +// CHECK-LE: call void @llvm.ppc.vsx.stxvd2x.be(<2 x double> %{{[0-9]+}}, ptr %{{[0-9]+}}) + +vec_xst_be(vss, sll, ass); +// CHECK: store <8 x i16> %{{[0-9]+}}, ptr %{{.+}}, align 1 +// CHECK-LE: shufflevector <8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}}, <8 x i32> +// CHECK-LE: call void @llvm.ppc.vsx.stxvd2x.be(<2 x double> %{{[0-9]+}}, ptr %{{[0-9]+}}) + +vec_xst_be(vus, sll, aus); +// CHECK: store <8 x i16> %{{[0-9]+}}, ptr %{{.+}}, align 1 +// CHECK-LE: shufflevector <8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}}, <8 x i32> +// CHECK-LE: call void @llvm.ppc.vsx.stxvd2x.be(<2 x double> %{{[0-9]+}}, ptr %{{[0-9]+}}) + +vec_xst_be(vsi, sll, asi); +// CHECK: store <4 x i32> %{{[0-9]+}}, ptr %{{.+}}, align 1 +// CHECK-LE: call void @llvm.ppc.vsx.stxvw4x.be(<4 x i32> %{{[0-9]+}}, ptr %{{[0-9]+}}) + +vec_xst_be(vui, sll, aui); +// CHECK: store <4 x i32> %{{[0-9]+}}, ptr %{{.+}}, align 1 +// CHECK-LE: call void @llvm.ppc.vsx.stxvw4x.be(<4 x i32> %{{[0-9]+}}, ptr %{{[0-9]+}}) + +vec_xst_be(vf, sll, af); +// CHECK: store <4 x float> %{{[0-9]+}}, ptr %{{.+}}, align 1 +// CHECK-LE: call void @llvm.ppc.vsx.stxvw4x.be(<4 x i32> %{{[0-9]+}}, ptr %{{[0-9]+}}) + res_vf = vec_neg(vf); // CHECK: fneg <4 x float> {{%[0-9]+}} // CHECK-LE: fneg <4 x float> {{%[0-9]+}} diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr8.c b/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr8.c index 38caa70d27542..16cdbebbee45f 100644 --- a/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr8.c +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr8.c @@ -16,41 +16,31 @@ extern void *a; extern volatile char *c_addr; +extern char *ptr; extern char c; +extern int i; +extern vector unsigned char vuc; -void test_icbt() { -// CHECK-LABEL: @test_icbt( - +void test_xlcompat() { + // CHECK-PWR8-LABEL: @test_xlcompat( + // CHECK-PWR8: call void @llvm.ppc.icbt(ptr %{{[0-9]+}}) + // CHECK-NOPWR8: error: '__builtin_ppc_icbt' needs target feature isa-v207-instructions __icbt(a); -// CHECK-PWR8: call void @llvm.ppc.icbt(ptr %0) -// CHECK-NOPWR8: error: this builtin is only valid on POWER8 or later CPUs -} - -void test_builtin_ppc_icbt() { -// CHECK-LABEL: @test_builtin_ppc_icbt( + // CHECK-PWR8: call void @llvm.ppc.icbt(ptr %{{[0-9]+}}) + // CHECK-NOPWR8: error: '__builtin_ppc_icbt' needs target feature isa-v207-instructions __builtin_ppc_icbt(a); -// CHECK-PWR8: call void @llvm.ppc.icbt(ptr %0) -// CHECK-NOPWR8: error: this builtin is only valid on POWER8 or later CPUs -} -int test_builtin_ppc_stbcx() { -// CHECK-PWR8-LABEL: @test_builtin_ppc_stbcx( -// CHECK-PWR8: [[TMP0:%.*]] = load ptr, ptr @c_addr, align {{[0-9]+}} -// CHECK-PWR8-NEXT: [[TMP1:%.*]] = load i8, ptr @c, align 1 -// CHECK-PWR8-NEXT: [[TMP2:%.*]] = sext i8 [[TMP1]] to i32 -// CHECK-PWR8-NEXT: [[TMP3:%.*]] = call i32 @llvm.ppc.stbcx(ptr [[TMP0]], i32 [[TMP2]]) -// CHECK-PWR8-NEXT: ret i32 [[TMP3]] -// CHECK-NOPWR8: error: this builtin is only valid on POWER8 or later CPUs - return __builtin_ppc_stbcx(c_addr, c); -} + // CHECK-PWR8: [[TMP0:%.*]] = load ptr, ptr @c_addr, align {{[0-9]+}} + // CHECK-PWR8-NEXT: [[TMP1:%.*]] = load i8, ptr @c, align 1 + // CHECK-PWR8-NEXT: [[TMP2:%.*]] = sext i8 [[TMP1]] to i32 + // CHECK-PWR8-NEXT: [[TMP3:%.*]] = call i32 @llvm.ppc.stbcx(ptr [[TMP0]], i32 [[TMP2]]) + // CHECK-NOPWR8: error: '__builtin_ppc_stbcx' needs target feature isa-v207-instructions + i = __builtin_ppc_stbcx(c_addr, c); -vector unsigned char test_ldrmb(char *ptr) { - // CHECK-NOPWR8: error: this builtin is only valid on POWER8 or later CPUs - return __builtin_vsx_ldrmb(ptr, 14); -} + // CHECK-NOPWR8: error: '__builtin_vsx_ldrmb' needs target feature isa-v207-instructions + vuc = __builtin_vsx_ldrmb(ptr, 14); -void test_strmbb(char *ptr, vector unsigned char data) { - // CHECK-NOPWR8: error: this builtin is only valid on POWER8 or later CPUs - __builtin_vsx_strmb(ptr, 14, data); + // CHECK-NOPWR8: error: '__builtin_vsx_strmb' needs target feature isa-v207-instructions + __builtin_vsx_strmb(ptr, 14, vuc); } diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr9-64bit.c b/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr9-64bit.c index 00ca15a31d212..02c5d7f4822b0 100644 --- a/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr9-64bit.c +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr9-64bit.c @@ -12,87 +12,57 @@ extern signed long long sll; extern unsigned long long ull; +double d; -signed long long test_builtin_ppc_cmpeqb() { - // CHECK-LABEL: @test_builtin_ppc_cmpeqb( - // CHECK: %2 = call i64 @llvm.ppc.cmpeqb(i64 %0, i64 %1) +void test_compat_builtins() { + // CHECK-LABEL: @test_compat_builtins( + // CHECK: %2 = call i64 @llvm.ppc.cmpeqb(i64 %0, i64 %1) // CHECK-32-ERROR: error: this builtin is only available on 64-bit targets - // CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs - return __builtin_ppc_cmpeqb(sll, sll); -} + // CHECK-NONPWR9-ERR: error: '__builtin_ppc_cmpeqb' needs target feature isa-v30-instructions + sll = __builtin_ppc_cmpeqb(sll, sll); -long long test_builtin_ppc_setb() { - // CHECK-LABEL: @test_builtin_ppc_setb( - // CHECK: %2 = call i64 @llvm.ppc.setb(i64 %0, i64 %1) + // CHECK: %5 = call i64 @llvm.ppc.setb(i64 %3, i64 %4) // CHECK-32-ERROR: error: this builtin is only available on 64-bit targets - // CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs - return __builtin_ppc_setb(sll, sll); -} + // CHECK-NONPWR9-ERR: error: '__builtin_ppc_setb' needs target feature isa-v30-instructions + sll = __builtin_ppc_setb(sll, sll); -signed long long test_builtin_ppc_maddhd() { - // CHECK-LABEL: @test_builtin_ppc_maddhd( - // CHECK: %3 = call i64 @llvm.ppc.maddhd(i64 %0, i64 %1, i64 %2) + // CHECK: %9 = call i64 @llvm.ppc.maddhd(i64 %6, i64 %7, i64 %8) // CHECK-32-ERROR: error: this builtin is only available on 64-bit targets - // CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs - return __builtin_ppc_maddhd(sll, sll, sll); -} + // CHECK-NONPWR9-ERR: error: '__builtin_ppc_maddhd' needs target feature isa-v30-instructions + sll = __builtin_ppc_maddhd(sll, sll, sll); -unsigned long long test_builtin_ppc_maddhdu() { - // CHECK-LABEL: @test_builtin_ppc_maddhdu( - // CHECK: %3 = call i64 @llvm.ppc.maddhdu(i64 %0, i64 %1, i64 %2) + // CHECK: %13 = call i64 @llvm.ppc.maddhdu(i64 %10, i64 %11, i64 %12) // CHECK-32-ERROR: error: this builtin is only available on 64-bit targets - // CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs - return __builtin_ppc_maddhdu(ull, ull, ull); -} + // CHECK-NONPWR9-ERR: error: '__builtin_ppc_maddhdu' needs target feature isa-v30-instructions + ull = __builtin_ppc_maddhdu(ull, ull, ull); -signed long long test_builtin_ppc_maddld() { - // CHECK-LABEL: @test_builtin_ppc_maddld( - // CHECK: %3 = call i64 @llvm.ppc.maddld(i64 %0, i64 %1, i64 %2) + // CHECK: %17 = call i64 @llvm.ppc.maddld(i64 %14, i64 %15, i64 %16) // CHECK-32-ERROR: error: this builtin is only available on 64-bit targets - // CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs - return __builtin_ppc_maddld(sll, sll, sll); -} + // CHECK-NONPWR9-ERR: error: '__builtin_ppc_maddld' needs target feature isa-v30-instructions + sll = __builtin_ppc_maddld(sll, sll, sll); -unsigned long long test_builtin_ppc_maddld_unsigned() { - // CHECK-LABEL: @test_builtin_ppc_maddld_unsigned( - // CHECK: %3 = call i64 @llvm.ppc.maddld(i64 %0, i64 %1, i64 %2) + // CHECK: %21 = call i64 @llvm.ppc.maddld(i64 %18, i64 %19, i64 %20) // CHECK-32-ERROR: error: this builtin is only available on 64-bit targets - // CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs - return __builtin_ppc_maddld(ull, ull, ull); -} + // CHECK-NONPWR9-ERR: error: '__builtin_ppc_maddld' needs target feature isa-v30-instructions + ull = __builtin_ppc_maddld(ull, ull, ull); -unsigned long long extract_sig (double d) { -// CHECK-LABEL: @extract_sig( -// CHECK: [[TMP1:%.*]] = call i64 @llvm.ppc.extract.sig(double %0) -// CHECK-NEXT: ret i64 [[TMP1]] -// -// CHECK-32-ERROR: error: this builtin is only available on 64-bit targets -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs - return __extract_sig (d); -} + // CHECK: %23 = call i64 @llvm.ppc.extract.sig(double %22) + // CHECK-32-ERROR: error: this builtin is only available on 64-bit targets + // CHECK-NONPWR9-ERR: error: '__builtin_ppc_extract_sig' needs target feature power9-vector + ull = __extract_sig (d); -double insert_exp (double d, unsigned long long ull) { -// CHECK-LABEL: @insert_exp( -// CHECK: [[TMP2:%.*]] = call double @llvm.ppc.insert.exp(double %0, i64 %1) -// CHECK-NEXT: ret double [[TMP2]] -// -// CHECK-32-ERROR: error: this builtin is only available on 64-bit targets -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs - return __insert_exp (d, ull); -} + // CHECK: %26 = call double @llvm.ppc.insert.exp(double %24, i64 %25) + // CHECK-32-ERROR: error: this builtin is only available on 64-bit targets + // CHECK-NONPWR9-ERR: error: '__builtin_ppc_insert_exp' needs target feature power9-vector + d = __insert_exp (d, ull); -signed long long test_builtin_ppc_addex0() { - // CHECK-LABEL: @test_builtin_ppc_addex0 - // CHECK: %2 = call i64 @llvm.ppc.addex(i64 %0, i64 %1, i32 0) + // CHECK: %29 = call i64 @llvm.ppc.addex(i64 %27, i64 %28, i32 0) // CHECK-32-ERROR: error: this builtin is only available on 64-bit targets - // CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs - return __builtin_ppc_addex(sll, sll, 0); -} + // CHECK-NONPWR9-ERR: error: '__builtin_ppc_addex' needs target feature isa-v30-instructions + sll = __builtin_ppc_addex(sll, sll, 0); -unsigned long long test_builtin_ppc_addex1() { - // CHECK-LABEL: @test_builtin_ppc_addex1 - // CHECK: %2 = call i64 @llvm.ppc.addex(i64 %0, i64 %1, i32 0) + // CHECK: %32 = call i64 @llvm.ppc.addex(i64 %30, i64 %31, i32 0) // CHECK-32-ERROR: error: this builtin is only available on 64-bit targets - // CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs - return __builtin_ppc_addex(ull, ull, 0); + // CHECK-NONPWR9-ERR: error: '__builtin_ppc_addex' needs target feature isa-v30-instructions + ull = __builtin_ppc_addex(ull, ull, 0); } diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr9.c b/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr9.c index ded3f113b3564..1c7a07d760ae4 100644 --- a/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr9.c +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr9.c @@ -12,18 +12,12 @@ extern unsigned int ui; -int test_builtin_ppc_cmprb() { - // CHECK-LABEL: @test_builtin_ppc_cmprb( +int test_builtin_ppc_cmprb_extract_exp(double d) { + // CHECK-LABEL: @test_builtin_ppc_cmprb_extract_exp( // CHECK: %2 = call i32 @llvm.ppc.cmprb(i32 0, i32 %0, i32 %1) // CHECK: %5 = call i32 @llvm.ppc.cmprb(i32 1, i32 %3, i32 %4) - // CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs - return __builtin_ppc_cmprb(0, ui, ui) + __builtin_ppc_cmprb(1, ui, ui); -} - -unsigned int extract_exp (double d) { -// CHECK-LABEL: @extract_exp -// CHECK: [[TMP1:%.*]] = call i32 @llvm.ppc.extract.exp(double %0) -// CHECK-NEXT: ret i32 [[TMP1]] -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs - return __extract_exp (d); + // CHECK: %7 = call i32 @llvm.ppc.extract.exp(double %6) + // CHECK-NONPWR9-ERR: error: '__builtin_ppc_cmprb' needs target feature isa-v30-instructions + // CHECK-NONPWR9-ERR: error: '__builtin_ppc_extract_exp' needs target feature power9-vector + return __builtin_ppc_cmprb(0, ui, ui) + __builtin_ppc_cmprb(1, ui, ui) + __extract_exp(d); } diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-test.c b/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-test.c index 0449bab066f5c..a1b5469aa4322 100644 --- a/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-test.c +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-test.c @@ -16,110 +16,58 @@ extern double d; extern float f; -int test_builtin_ppc_compare_exp_uo() { -// CHECK-LABEL: @test_builtin_ppc_compare_exp_uo -// CHECK: [[TMP:%.*]] = call i32 @llvm.ppc.compare.exp.uo(double %0, double %1) -// CHECK-NEXT: ret i32 [[TMP]] -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs -// CHECK-NOVSX-ERR: error: this builtin requires VSX to be enabled - return __builtin_ppc_compare_exp_uo(d, d); -} - -int test_builtin_ppc_compare_exp_lt() { -// CHECK-LABEL: @test_builtin_ppc_compare_exp_lt -// CHECK: [[TMP:%.*]] = call i32 @llvm.ppc.compare.exp.lt(double %0, double %1) -// CHECK-NEXT: ret i32 [[TMP]] -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs -// CHECK-NOVSX-ERR: error: this builtin requires VSX to be enabled - return __builtin_ppc_compare_exp_lt(d, d); -} - -int test_builtin_ppc_compare_exp_gt() { -// CHECK-LABEL: @test_builtin_ppc_compare_exp_gt -// CHECK: [[TMP:%.*]] = call i32 @llvm.ppc.compare.exp.gt(double %0, double %1) -// CHECK-NEXT: ret i32 [[TMP]] -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs -// CHECK-NOVSX-ERR: error: this builtin requires VSX to be enabled - return __builtin_ppc_compare_exp_gt(d, d); -} - -int test_builtin_ppc_compare_exp_eq() { -// CHECK-LABEL: @test_builtin_ppc_compare_exp_eq -// CHECK: [[TMP:%.*]] = call i32 @llvm.ppc.compare.exp.eq(double %0, double %1) -// CHECK-NEXT: ret i32 [[TMP]] -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs -// CHECK-NOVSX-ERR: error: this builtin requires VSX to be enabled - return __builtin_ppc_compare_exp_eq(d, d); -} - -int test_builtin_ppc_test_data_class_d() { -// CHECK-LABEL: @test_builtin_ppc_test_data_class_d -// CHECK: [[TMP:%.*]] = call i32 @llvm.ppc.test.data.class.f64(double %0, i32 0) -// CHECK-NEXT: ret i32 [[TMP]] -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs -// CHECK-NOVSX-ERR: error: this builtin requires VSX to be enabled - return __builtin_ppc_test_data_class(d, 0); -} - -int test_builtin_ppc_test_data_class_f() { -// CHECK-LABEL: @test_builtin_ppc_test_data_class_f -// CHECK: [[TMP:%.*]] = call i32 @llvm.ppc.test.data.class.f32(float %0, i32 0) -// CHECK-NEXT: ret i32 [[TMP]] -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs -// CHECK-NOVSX-ERR: error: this builtin requires VSX to be enabled - return __builtin_ppc_test_data_class(f, 0); -} - -int test_compare_exp_uo() { -// CHECK-LABEL: @test_compare_exp_uo -// CHECK: [[TMP:%.*]] = call i32 @llvm.ppc.compare.exp.uo(double %0, double %1) -// CHECK-NEXT: ret i32 [[TMP]] -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs -// CHECK-NOVSX-ERR: error: this builtin requires VSX to be enabled - return __compare_exp_uo(d, d); -} - -int test_compare_exp_lt() { -// CHECK-LABEL: @test_compare_exp_lt -// CHECK: [[TMP:%.*]] = call i32 @llvm.ppc.compare.exp.lt(double %0, double %1) -// CHECK-NEXT: ret i32 [[TMP]] -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs -// CHECK-NOVSX-ERR: error: this builtin requires VSX to be enabled - return __compare_exp_lt(d, d); -} +int test_builtin_ppc_test() { +// CHECK-LABEL: @test_builtin_ppc_test +// CHECK: call i32 @llvm.ppc.compare.exp.uo(double %0, double %1) +// CHECK: call i32 @llvm.ppc.compare.exp.lt(double %3, double %4) +// CHECK: call i32 @llvm.ppc.compare.exp.gt(double %6, double %7) +// CHECK: call i32 @llvm.ppc.compare.exp.eq(double %9, double %10) +// CHECK: call i32 @llvm.ppc.test.data.class.f64(double %12, i32 0) +// CHECK: call i32 @llvm.ppc.test.data.class.f32(float %13, i32 0) +// CHECK: call i32 @llvm.ppc.compare.exp.uo(double %14, double %15) +// CHECK: call i32 @llvm.ppc.compare.exp.lt(double %17, double %18) +// CHECK: call i32 @llvm.ppc.compare.exp.gt(double %20, double %21) +// CHECK: call i32 @llvm.ppc.compare.exp.eq(double %23, double %24) +// CHECK: call i32 @llvm.ppc.test.data.class.f64(double %26, i32 127) +// CHECK: call i32 @llvm.ppc.test.data.class.f32(float %27, i32 127) -int test_compare_exp_gt() { -// CHECK-LABEL: @test_compare_exp_gt -// CHECK: [[TMP:%.*]] = call i32 @llvm.ppc.compare.exp.gt(double %0, double %1) -// CHECK-NEXT: ret i32 [[TMP]] -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs -// CHECK-NOVSX-ERR: error: this builtin requires VSX to be enabled - return __compare_exp_gt(d, d); -} - -int test_compare_exp_eq() { -// CHECK-LABEL: @test_compare_exp_eq -// CHECK: [[TMP:%.*]] = call i32 @llvm.ppc.compare.exp.eq(double %0, double %1) -// CHECK-NEXT: ret i32 [[TMP]] -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs -// CHECK-NOVSX-ERR: error: this builtin requires VSX to be enabled - return __compare_exp_eq(d, d); -} - -int test_test_data_class_d() { -// CHECK-LABEL: @test_test_data_class_d -// CHECK: [[TMP:%.*]] = call i32 @llvm.ppc.test.data.class.f64(double %0, i32 127) -// CHECK-NEXT: ret i32 [[TMP]] -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs -// CHECK-NOVSX-ERR: error: this builtin requires VSX to be enabled - return __test_data_class(d, 127); -} +// CHECK-NONPWR9-ERR: error: '__builtin_ppc_compare_exp_uo' needs target feature isa-v30-instructions +// CHECK-NONPWR9-ERR: error: '__builtin_ppc_compare_exp_lt' needs target feature isa-v30-instructions +// CHECK-NONPWR9-ERR: error: '__builtin_ppc_compare_exp_gt' needs target feature isa-v30-instructions +// CHECK-NONPWR9-ERR: error: '__builtin_ppc_compare_exp_eq' needs target feature isa-v30-instructions +// CHECK-NONPWR9-ERR: error: '__builtin_ppc_test_data_class' needs target feature isa-v30-instructions +// CHECK-NONPWR9-ERR: error: '__builtin_ppc_test_data_class' needs target feature isa-v30-instructions +// CHECK-NONPWR9-ERR: error: '__builtin_ppc_compare_exp_uo' needs target feature isa-v30-instructions +// CHECK-NONPWR9-ERR: error: '__builtin_ppc_compare_exp_lt' needs target feature isa-v30-instructions +// CHECK-NONPWR9-ERR: error: '__builtin_ppc_compare_exp_gt' needs target feature isa-v30-instructions +// CHECK-NONPWR9-ERR: error: '__builtin_ppc_compare_exp_eq' needs target feature isa-v30-instructions +// CHECK-NONPWR9-ERR: error: '__builtin_ppc_test_data_class' needs target feature isa-v30-instructions +// CHECK-NONPWR9-ERR: error: '__builtin_ppc_test_data_class' needs target feature isa-v30-instructions -int test_test_data_class_f() { -// CHECK-LABEL: @test_test_data_class_f -// CHECK: [[TMP:%.*]] = call i32 @llvm.ppc.test.data.class.f32(float %0, i32 127) -// CHECK-NEXT: ret i32 [[TMP]] -// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs -// CHECK-NOVSX-ERR: error: this builtin requires VSX to be enabled - return __test_data_class(f, 127); +// CHECK-NOVSX-ERR: error: '__builtin_ppc_compare_exp_uo' needs target feature isa-v30-instructions,vsx +// CHECK-NOVSX-ERR: error: '__builtin_ppc_compare_exp_lt' needs target feature isa-v30-instructions,vsx +// CHECK-NOVSX-ERR: error: '__builtin_ppc_compare_exp_gt' needs target feature isa-v30-instructions,vsx +// CHECK-NOVSX-ERR: error: '__builtin_ppc_compare_exp_eq' needs target feature isa-v30-instructions,vsx +// CHECK-NOVSX-ERR: error: '__builtin_ppc_test_data_class' needs target feature isa-v30-instructions,vsx +// CHECK-NOVSX-ERR: error: '__builtin_ppc_test_data_class' needs target feature isa-v30-instructions,vsx +// CHECK-NOVSX-ERR: error: '__builtin_ppc_compare_exp_uo' needs target feature isa-v30-instructions,vsx +// CHECK-NOVSX-ERR: error: '__builtin_ppc_compare_exp_lt' needs target feature isa-v30-instructions,vsx +// CHECK-NOVSX-ERR: error: '__builtin_ppc_compare_exp_gt' needs target feature isa-v30-instructions,vsx +// CHECK-NOVSX-ERR: error: '__builtin_ppc_compare_exp_eq' needs target feature isa-v30-instructions,vsx +// CHECK-NOVSX-ERR: error: '__builtin_ppc_test_data_class' needs target feature isa-v30-instructions,vsx +// CHECK-NOVSX-ERR: error: '__builtin_ppc_test_data_class' needs target feature isa-v30-instructions,vsx + int i; + i = __builtin_ppc_compare_exp_uo(d, d); + i = __builtin_ppc_compare_exp_lt(d, d); + i = __builtin_ppc_compare_exp_gt(d, d); + i = __builtin_ppc_compare_exp_eq(d, d); + i = __builtin_ppc_test_data_class(d, 0); + i = __builtin_ppc_test_data_class(f, 0); + i = __compare_exp_uo(d, d); + i = __compare_exp_lt(d, d); + i = __compare_exp_gt(d, d); + i = __compare_exp_eq(d, d); + i = __test_data_class(d, 127); + i = __test_data_class(f, 127); + return i; } diff --git a/clang/test/CodeGen/PowerPC/ppc-p10-mma-builtin-err.c b/clang/test/CodeGen/PowerPC/ppc-p10-mma-builtin-err.c new file mode 100644 index 0000000000000..7ba071fef1656 --- /dev/null +++ b/clang/test/CodeGen/PowerPC/ppc-p10-mma-builtin-err.c @@ -0,0 +1,13 @@ +// RUN: not %clang_cc1 -triple powerpc64le-unknown-linux-gnu -target-cpu pwr10 \ +// RUN: %s -emit-llvm-only 2>&1 | FileCheck %s + +__attribute__((target("no-mma"))) +void test_mma(unsigned char *vqp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { + __vector_quad vq = *((__vector_quad *)vqp); + __vector_pair vp = *((__vector_pair *)vpp); + __builtin_mma_xxmtacc(&vq); + *((__vector_quad *)resp) = vq; + __builtin_mma_pmxvf64ger(&vq, vp, vc, 0, 0); +// CHECK: error: '__builtin_mma_xxmtacc' needs target feature mma,paired-vector-memops +// CHECK: error: '__builtin_mma_pmxvf64ger' needs target feature mma,paired-vector-memops +} diff --git a/clang/test/CodeGen/PowerPC/ppc-p10-paired-vec-memops-builtin-err.c b/clang/test/CodeGen/PowerPC/ppc-p10-paired-vec-memops-builtin-err.c new file mode 100644 index 0000000000000..0c5e6d59607d2 --- /dev/null +++ b/clang/test/CodeGen/PowerPC/ppc-p10-paired-vec-memops-builtin-err.c @@ -0,0 +1,20 @@ +// RUN: not %clang_cc1 -triple powerpc64le-unknown-linux-gnu -target-cpu pwr10 \ +// RUN: %s -emit-llvm-only 2>&1 | FileCheck %s + +__attribute__((target("no-paired-vector-memops"))) +void test_pair(unsigned char *vqp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { + __vector_pair res; + signed long offset; + __builtin_vsx_assemble_pair(&res, vc, vc); + __builtin_vsx_disassemble_pair(resp, (__vector_pair*)vpp); + __vector_pair vp = __builtin_vsx_lxvp(offset, (const __vector_pair*)vpp); + __builtin_vsx_stxvp(vp, offset, (__vector_pair*)vpp); + __builtin_mma_xxmtacc((__vector_quad *)vpp); + __builtin_mma_pmxvf64ger((__vector_quad *)vpp, vp, vc, 0, 0); +// CHECK: error: '__builtin_vsx_assemble_pair' needs target feature paired-vector-memops +// CHECK: error: '__builtin_vsx_disassemble_pair' needs target feature paired-vector-memops +// CHECK: error: '__builtin_vsx_lxvp' needs target feature paired-vector-memops +// CHECK: error: '__builtin_vsx_stxvp' needs target feature paired-vector-memops +// CHECK: error: '__builtin_mma_xxmtacc' needs target feature mma,paired-vector-memops +// CHECK: error: '__builtin_mma_pmxvf64ger' needs target feature mma,paired-vector-memops +} diff --git a/clang/test/CodeGen/debug-info-codeview-heapallocsite.c b/clang/test/CodeGen/debug-info-codeview-heapallocsite.c index a8cae112dcec2..6cc34f688e4dc 100644 --- a/clang/test/CodeGen/debug-info-codeview-heapallocsite.c +++ b/clang/test/CodeGen/debug-info-codeview-heapallocsite.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-windows-msvc -debug-info-kind=limited -gcodeview -fdeclspec -S -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-windows-msvc -debug-info-kind=limited -gcodeview -fdeclspec -S -emit-llvm %s -o - | FileCheck %s struct Foo; struct Bar; @@ -14,10 +14,10 @@ void call_alloc(void) { } // CHECK-LABEL: define {{.*}}void @call_alloc -// CHECK: call i8* {{.*}}@alloc_void{{.*}} !heapallocsite [[DBG1:!.*]] -// CHECK: call %struct.Foo* {{.*}}@alloc_foo{{.*}} !heapallocsite [[DBG2:!.*]] -// CHECK: call i8* {{.*}}@alloc_void{{.*}} !heapallocsite [[DBG2]] -// CHECK: call i8* {{.*}}@alloc_void{{.*}} !heapallocsite [[DBG3:!.*]] +// CHECK: call ptr {{.*}}@alloc_void{{.*}} !heapallocsite [[DBG1:!.*]] +// CHECK: call ptr {{.*}}@alloc_foo{{.*}} !heapallocsite [[DBG2:!.*]] +// CHECK: call ptr {{.*}}@alloc_void{{.*}} !heapallocsite [[DBG2]] +// CHECK: call ptr {{.*}}@alloc_void{{.*}} !heapallocsite [[DBG3:!.*]] // CHECK: [[DBG2]] = !DICompositeType(tag: DW_TAG_structure_type, // CHECK-SAME: name: "Foo" diff --git a/clang/test/CodeGen/thinlto-distributed-supports-hot-cold-new.ll b/clang/test/CodeGen/thinlto-distributed-supports-hot-cold-new.ll index e213fbaf3fa14..08c1a2946971c 100644 --- a/clang/test/CodeGen/thinlto-distributed-supports-hot-cold-new.ll +++ b/clang/test/CodeGen/thinlto-distributed-supports-hot-cold-new.ll @@ -22,7 +22,7 @@ ; RUN: %clang -target x86_64-unknown-linux-gnu -O2 -o %t1.o -x ir %t.o -c -fthinlto-index=%t.o.thinlto.bc -save-temps=obj -; RUN: llvm-dis %t.s.0.preopt.bc -o - | FileCheck %s --check-prefix=CHECK-IR +; RUN: llvm-dis %t.s.3.import.bc -o - | FileCheck %s --check-prefix=CHECK-IR ; CHECK-IR: !memprof {{.*}} !callsite ; CHECK-IR: "memprof"="cold" @@ -42,7 +42,7 @@ ; RUN: %clang -target x86_64-unknown-linux-gnu -O2 -o %t1.o -x ir %t.o -c -fthinlto-index=%t.o.thinlto.bc -save-temps=obj -; RUN: llvm-dis %t.s.0.preopt.bc -o - | FileCheck %s \ +; RUN: llvm-dis %t.s.3.import.bc -o - | FileCheck %s \ ; RUN: --implicit-check-not "!memprof" --implicit-check-not "!callsite" \ ; RUN: --implicit-check-not "memprof"="cold" diff --git a/clang/test/CodeGenCUDA/amdgpu-alias-undef-symbols.cu b/clang/test/CodeGenCUDA/amdgpu-alias-undef-symbols.cu index 9cb25730cbf89..d2ee39230d5a1 100644 --- a/clang/test/CodeGenCUDA/amdgpu-alias-undef-symbols.cu +++ b/clang/test/CodeGenCUDA/amdgpu-alias-undef-symbols.cu @@ -1,15 +1,14 @@ // REQUIRES: amdgpu-registered-target -// RUN: %clang -Xclang -no-opaque-pointers -target x86_64-unknown-linux-gnu --offload-arch=gfx906 --cuda-device-only -nogpulib -nogpuinc -x hip -emit-llvm -S -o - %s \ +// RUN: %clang -target x86_64-unknown-linux-gnu --offload-arch=gfx906 --cuda-device-only -nogpulib -nogpuinc -x hip -emit-llvm -S -o - %s \ // RUN: -fgpu-rdc -O3 -mllvm -amdgpu-early-inline-all=true -mllvm -amdgpu-function-calls=false | \ // RUN: FileCheck %s #include "Inputs/cuda.h" -// CHECK: %struct.B = type { i8 } struct B { - // CHECK: @_ZN1BC1Ei = hidden unnamed_addr alias void (%struct.B*, i32), void (%struct.B*, i32)* @_ZN1BC2Ei + // CHECK: @_ZN1BC1Ei = hidden unnamed_addr alias void (ptr, i32), ptr @_ZN1BC2Ei __device__ B(int x); }; diff --git a/clang/test/CodeGenCUDA/device-use-host-var.cu b/clang/test/CodeGenCUDA/device-use-host-var.cu index aeb9645660ac6..64de57e41b4b9 100644 --- a/clang/test/CodeGenCUDA/device-use-host-var.cu +++ b/clang/test/CodeGenCUDA/device-use-host-var.cu @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -no-opaque-pointers -std=c++14 -triple amdgcn-amd-amdhsa \ +// RUN: %clang_cc1 -std=c++14 -triple amdgcn-amd-amdhsa \ // RUN: -fcuda-is-device -emit-llvm -o - -x hip %s | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -std=c++14 -triple amdgcn-amd-amdhsa \ +// RUN: %clang_cc1 -std=c++14 -triple amdgcn-amd-amdhsa \ // RUN: -fcuda-is-device -emit-llvm -o - -x hip %s | FileCheck -check-prefix=NEG %s #include "Inputs/cuda.h" @@ -71,17 +71,17 @@ const int var_host_only = 7; // CHECK: store i32 1 // CHECK: store i32 2 // CHECK: store i32 3 -// CHECK: load i8, i8* getelementptr {{.*}} @_ZL13constexpr_str.const +// CHECK: load i8, ptr getelementptr {{.*}} @_ZL13constexpr_str.const // CHECK: store i32 4 // CHECK: store i32 5 // CHECK: store i32 6 -// CHECK: load i8, i8* getelementptr {{.*}} @_ZL9const_str -// CHECK: store i32* {{.*}}@_ZL13constexpr_var -// CHECK: store i32* getelementptr {{.*}} @_ZL16constexpr_struct -// CHECK: store i32* getelementptr {{.*}} @_ZL15constexpr_array -// CHECK: store i32* {{.*}}@_ZL9const_var -// CHECK: store i32* getelementptr {{.*}} @_ZL12const_struct -// CHECK: store i32* getelementptr {{.*}} @_ZL11const_array +// CHECK: load i8, ptr getelementptr {{.*}} @_ZL9const_str +// CHECK: store ptr {{.*}}@_ZL13constexpr_var +// CHECK: store ptr {{.*}} @_ZL16constexpr_struct +// CHECK: store ptr getelementptr {{.*}} @_ZL15constexpr_array +// CHECK: store ptr {{.*}}@_ZL9const_var +// CHECK: store ptr {{.*}} @_ZL12const_struct +// CHECK: store ptr getelementptr {{.*}} @_ZL11const_array __device__ void dev_fun(int *out, const int **out2) { *out = constexpr_var; *out = constexpr_struct.x; diff --git a/clang/test/CodeGenCUDA/managed-var.cu b/clang/test/CodeGenCUDA/managed-var.cu index 6915582e12127..5206acc62fe00 100644 --- a/clang/test/CodeGenCUDA/managed-var.cu +++ b/clang/test/CodeGenCUDA/managed-var.cu @@ -1,16 +1,16 @@ -// RUN: %clang_cc1 -no-opaque-pointers -triple amdgcn-amd-amdhsa -fcuda-is-device -std=c++11 \ +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fcuda-is-device -std=c++11 \ // RUN: -emit-llvm -o - -x hip %s | FileCheck \ // RUN: -check-prefixes=COMMON,DEV,NORDC-D %s -// RUN: %clang_cc1 -no-opaque-pointers -triple amdgcn-amd-amdhsa -fcuda-is-device -std=c++11 \ +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fcuda-is-device -std=c++11 \ // RUN: -emit-llvm -fgpu-rdc -cuid=abc -o - -x hip %s > %t.dev // RUN: cat %t.dev | FileCheck -check-prefixes=COMMON,DEV,RDC-D %s -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-gnu-linux -std=c++11 \ +// RUN: %clang_cc1 -triple x86_64-gnu-linux -std=c++11 \ // RUN: -emit-llvm -o - -x hip %s | FileCheck \ // RUN: -check-prefixes=COMMON,HOST,NORDC %s -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-gnu-linux -std=c++11 \ +// RUN: %clang_cc1 -triple x86_64-gnu-linux -std=c++11 \ // RUN: -emit-llvm -fgpu-rdc -cuid=abc -o - -x hip %s > %t.host // RUN: cat %t.host | FileCheck -check-prefixes=COMMON,HOST,RDC %s @@ -26,38 +26,38 @@ struct vec { }; // DEV-DAG: @x.managed = addrspace(1) externally_initialized global i32 1, align 4 -// DEV-DAG: @x = addrspace(1) externally_initialized global i32 addrspace(1)* null +// DEV-DAG: @x = addrspace(1) externally_initialized global ptr addrspace(1) null // NORDC-DAG: @x.managed = internal global i32 1 // RDC-DAG: @x.managed = global i32 1 -// NORDC-DAG: @x = internal externally_initialized global i32* null -// RDC-DAG: @x = externally_initialized global i32* null +// NORDC-DAG: @x = internal externally_initialized global ptr null +// RDC-DAG: @x = externally_initialized global ptr null // HOST-DAG: @[[DEVNAMEX:[0-9]+]] = {{.*}}c"x\00" __managed__ int x = 1; // DEV-DAG: @v.managed = addrspace(1) externally_initialized global [100 x %struct.vec] zeroinitializer, align 4 -// DEV-DAG: @v = addrspace(1) externally_initialized global [100 x %struct.vec] addrspace(1)* null +// DEV-DAG: @v = addrspace(1) externally_initialized global ptr addrspace(1) null __managed__ vec v[100]; // DEV-DAG: @v2.managed = addrspace(1) externally_initialized global <{ %struct.vec, [99 x %struct.vec] }> <{ %struct.vec { float 1.000000e+00, float 1.000000e+00, float 1.000000e+00 }, [99 x %struct.vec] zeroinitializer }>, align 4 -// DEV-DAG: @v2 = addrspace(1) externally_initialized global <{ %struct.vec, [99 x %struct.vec] }> addrspace(1)* null +// DEV-DAG: @v2 = addrspace(1) externally_initialized global ptr addrspace(1) null __managed__ vec v2[100] = {{1, 1, 1}}; // DEV-DAG: @ex.managed = external addrspace(1) global i32, align 4 -// DEV-DAG: @ex = external addrspace(1) externally_initialized global i32 addrspace(1)* +// DEV-DAG: @ex = external addrspace(1) externally_initialized global ptr addrspace(1) // HOST-DAG: @ex.managed = external global i32 -// HOST-DAG: @ex = external externally_initialized global i32* +// HOST-DAG: @ex = external externally_initialized global ptr extern __managed__ int ex; // NORDC-D-DAG: @_ZL2sx.managed = addrspace(1) externally_initialized global i32 1, align 4 -// NORDC-D-DAG: @_ZL2sx = addrspace(1) externally_initialized global i32 addrspace(1)* null +// NORDC-D-DAG: @_ZL2sx = addrspace(1) externally_initialized global ptr addrspace(1) null // RDC-D-DAG: @_ZL2sx.static.[[HASH:.*]].managed = addrspace(1) externally_initialized global i32 1, align 4 -// RDC-D-DAG: @_ZL2sx.static.[[HASH]] = addrspace(1) externally_initialized global i32 addrspace(1)* null +// RDC-D-DAG: @_ZL2sx.static.[[HASH]] = addrspace(1) externally_initialized global ptr addrspace(1) null // HOST-DAG: @_ZL2sx.managed = internal global i32 1 -// HOST-DAG: @_ZL2sx = internal externally_initialized global i32* null +// HOST-DAG: @_ZL2sx = internal externally_initialized global ptr null // NORDC-DAG: @[[DEVNAMESX:[0-9]+]] = {{.*}}c"_ZL2sx\00" // RDC-DAG: @[[DEVNAMESX:[0-9]+]] = {{.*}}c"_ZL2sx.static.[[HASH:.*]]\00" -// POSTFIX: @_ZL2sx.static.[[HASH:.*]] = addrspace(1) externally_initialized global i32 addrspace(1)* null +// POSTFIX: @_ZL2sx.static.[[HASH:.*]] = addrspace(1) externally_initialized global ptr addrspace(1) null // POSTFIX: @[[DEVNAMESX:[0-9]+]] = {{.*}}c"_ZL2sx.static.[[HASH]]\00" static __managed__ int sx = 1; @@ -81,70 +81,68 @@ int foo2() { } // COMMON-LABEL: define {{.*}}@_Z4loadv() -// DEV: %ld.managed = load i32 addrspace(1)*, i32 addrspace(1)* addrspace(1)* @x, align 4 -// DEV: %0 = addrspacecast i32 addrspace(1)* %ld.managed to i32* -// DEV: %1 = load i32, i32* %0, align 4 +// DEV: %ld.managed = load ptr addrspace(1), ptr addrspace(1) @x, align 4 +// DEV: %0 = addrspacecast ptr addrspace(1) %ld.managed to ptr +// DEV: %1 = load i32, ptr %0, align 4 // DEV: ret i32 %1 -// HOST: %ld.managed = load i32*, i32** @x, align 4 -// HOST: %0 = load i32, i32* %ld.managed, align 4 +// HOST: %ld.managed = load ptr, ptr @x, align 4 +// HOST: %0 = load i32, ptr %ld.managed, align 4 // HOST: ret i32 %0 __device__ __host__ int load() { return x; } // COMMON-LABEL: define {{.*}}@_Z5storev() -// DEV: %ld.managed = load i32 addrspace(1)*, i32 addrspace(1)* addrspace(1)* @x, align 4 -// DEV: %0 = addrspacecast i32 addrspace(1)* %ld.managed to i32* -// DEV: store i32 2, i32* %0, align 4 -// HOST: %ld.managed = load i32*, i32** @x, align 4 -// HOST: store i32 2, i32* %ld.managed, align 4 +// DEV: %ld.managed = load ptr addrspace(1), ptr addrspace(1) @x, align 4 +// DEV: %0 = addrspacecast ptr addrspace(1) %ld.managed to ptr +// DEV: store i32 2, ptr %0, align 4 +// HOST: %ld.managed = load ptr, ptr @x, align 4 +// HOST: store i32 2, ptr %ld.managed, align 4 __device__ __host__ void store() { x = 2; } // COMMON-LABEL: define {{.*}}@_Z10addr_takenv() -// DEV: %0 = addrspacecast i32 addrspace(1)* %ld.managed to i32* -// DEV: store i32* %0, i32** %p.ascast, align 8 -// DEV: %1 = load i32*, i32** %p.ascast, align 8 -// DEV: store i32 3, i32* %1, align 4 -// HOST: %ld.managed = load i32*, i32** @x, align 4 -// HOST: store i32* %ld.managed, i32** %p, align 8 -// HOST: %0 = load i32*, i32** %p, align 8 -// HOST: store i32 3, i32* %0, align 4 +// DEV: %0 = addrspacecast ptr addrspace(1) %ld.managed to ptr +// DEV: store ptr %0, ptr %p.ascast, align 8 +// DEV: %1 = load ptr, ptr %p.ascast, align 8 +// DEV: store i32 3, ptr %1, align 4 +// HOST: %ld.managed = load ptr, ptr @x, align 4 +// HOST: store ptr %ld.managed, ptr %p, align 8 +// HOST: %0 = load ptr, ptr %p, align 8 +// HOST: store i32 3, ptr %0, align 4 __device__ __host__ void addr_taken() { int *p = &x; *p = 3; } // HOST-LABEL: define {{.*}}@_Z5load2v() -// HOST: %ld.managed = load [100 x %struct.vec]*, [100 x %struct.vec]** @v, align 16 -// HOST: %0 = getelementptr inbounds [100 x %struct.vec], [100 x %struct.vec]* %ld.managed, i64 0, i64 1, i32 0 -// HOST: %1 = load float, float* %0, align 4 +// HOST: %ld.managed = load ptr, ptr @v, align 16 +// HOST: %0 = getelementptr inbounds [100 x %struct.vec], ptr %ld.managed, i64 0, i64 1 +// HOST: %1 = load float, ptr %0, align 4 // HOST: ret float %1 __device__ __host__ float load2() { return v[1].x; } // HOST-LABEL: define {{.*}}@_Z5load3v() -// HOST: %ld.managed = load <{ %struct.vec, [99 x %struct.vec] }>*, <{ %struct.vec, [99 x %struct.vec] }>** @v2, align 16 -// HOST: %0 = bitcast <{ %struct.vec, [99 x %struct.vec] }>* %ld.managed to [100 x %struct.vec]* -// HOST: %1 = getelementptr inbounds [100 x %struct.vec], [100 x %struct.vec]* %0, i64 0, i64 1, i32 1 -// HOST: %2 = load float, float* %1, align 4 -// HOST: ret float %2 +// HOST: %ld.managed = load ptr, ptr @v2, align 16 +// HOST: %0 = getelementptr inbounds [100 x %struct.vec], ptr %ld.managed, i64 0, i64 1, i32 1 +// HOST: %1 = load float, ptr %0, align 4 +// HOST: ret float %1 float load3() { return v2[1].y; } // HOST-LABEL: define {{.*}}@_Z11addr_taken2v() -// HOST: %ld.managed = load [100 x %struct.vec]*, [100 x %struct.vec]** @v, align 16 -// HOST: %0 = getelementptr inbounds [100 x %struct.vec], [100 x %struct.vec]* %ld.managed, i64 0, i64 1, i32 0 -// HOST: %1 = ptrtoint float* %0 to i64 -// HOST: %ld.managed1 = load <{ %struct.vec, [99 x %struct.vec] }>*, <{ %struct.vec, [99 x %struct.vec] }>** @v2, align 16 -// HOST: %2 = bitcast <{ %struct.vec, [99 x %struct.vec] }>* %ld.managed1 to [100 x %struct.vec]* -// HOST: %3 = getelementptr inbounds [100 x %struct.vec], [100 x %struct.vec]* %2, i64 0, i64 1, i32 1 -// HOST: %4 = ptrtoint float* %3 to i64 -// HOST: %5 = sub i64 %4, %1 -// HOST: %sub.ptr.div = sdiv exact i64 %5, 4 +// HOST: %ld.managed = load ptr, ptr @v, align 16 +// HOST: %0 = getelementptr inbounds [100 x %struct.vec], ptr %ld.managed, i64 0, i64 1 +// HOST: %1 = ptrtoint ptr %0 to i64 +// HOST: %ld.managed1 = load ptr, ptr @v2, align 16 +// HOST: %2 = getelementptr inbounds [100 x %struct.vec], ptr %ld.managed1, i64 0, i64 1, i32 1 +// HOST: %3 = ptrtoint ptr %2 to i64 +// HOST: %4 = sub i64 %3, %1 +// HOST: %sub.ptr.div = sdiv exact i64 %4, 4 // HOST: %conv = sitofp i64 %sub.ptr.div to float // HOST: ret float %conv float addr_taken2() { @@ -152,18 +150,18 @@ float addr_taken2() { } // COMMON-LABEL: define {{.*}}@_Z5load4v() -// DEV: %ld.managed = load i32 addrspace(1)*, i32 addrspace(1)* addrspace(1)* @ex, align 4 -// DEV: %0 = addrspacecast i32 addrspace(1)* %ld.managed to i32* -// DEV: %1 = load i32, i32* %0, align 4 +// DEV: %ld.managed = load ptr addrspace(1), ptr addrspace(1) @ex, align 4 +// DEV: %0 = addrspacecast ptr addrspace(1) %ld.managed to ptr +// DEV: %1 = load i32, ptr %0, align 4 // DEV: ret i32 %1 -// HOST: %ld.managed = load i32*, i32** @ex, align 4 -// HOST: %0 = load i32, i32* %ld.managed, align 4 +// HOST: %ld.managed = load ptr, ptr @ex, align 4 +// HOST: %0 = load i32, ptr %ld.managed, align 4 // HOST: ret i32 %0 __device__ __host__ int load4() { return ex; } -// HOST-DAG: __hipRegisterManagedVar({{.*}}@x {{.*}}@x.managed {{.*}}@[[DEVNAMEX]]{{.*}}, i64 4, i32 4) -// HOST-DAG: __hipRegisterManagedVar({{.*}}@_ZL2sx {{.*}}@_ZL2sx.managed {{.*}}@[[DEVNAMESX]] -// HOST-NOT: __hipRegisterManagedVar({{.*}}@ex {{.*}}@ex.managed -// HOST-DAG: declare void @__hipRegisterManagedVar(i8**, i8*, i8*, i8*, i64, i32) +// HOST-DAG: __hipRegisterManagedVar({{.*}}, ptr @x, ptr @x.managed, ptr @[[DEVNAMEX]], i64 4, i32 4) +// HOST-DAG: __hipRegisterManagedVar({{.*}}, ptr @_ZL2sx, ptr @_ZL2sx.managed, ptr @[[DEVNAMESX]] +// HOST-NOT: __hipRegisterManagedVar({{.*}}, ptr @ex, ptr @ex.managed +// HOST-DAG: declare void @__hipRegisterManagedVar(ptr, ptr, ptr, ptr, i64, i32) diff --git a/clang/test/CodeGenCUDA/static-device-var-no-rdc.cu b/clang/test/CodeGenCUDA/static-device-var-no-rdc.cu index 71e63caa79e47..80655c2d29604 100644 --- a/clang/test/CodeGenCUDA/static-device-var-no-rdc.cu +++ b/clang/test/CodeGenCUDA/static-device-var-no-rdc.cu @@ -1,18 +1,18 @@ // REQUIRES: x86-registered-target // REQUIRES: amdgpu-registered-target -// RUN: %clang_cc1 -no-opaque-pointers -triple amdgcn-amd-amdhsa -fcuda-is-device -std=c++11 \ +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fcuda-is-device -std=c++11 \ // RUN: -emit-llvm -o - -x hip %s | FileCheck -check-prefix=DEV %s -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-gnu-linux -std=c++11 \ +// RUN: %clang_cc1 -triple x86_64-gnu-linux -std=c++11 \ // RUN: -emit-llvm -o - -x hip %s | FileCheck -check-prefix=HOST %s // Negative tests. -// RUN: %clang_cc1 -no-opaque-pointers -triple amdgcn-amd-amdhsa -fcuda-is-device -std=c++11 \ +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fcuda-is-device -std=c++11 \ // RUN: -emit-llvm -o - -x hip %s | FileCheck -check-prefix=DEV-NEG %s -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-gnu-linux -std=c++11 \ +// RUN: %clang_cc1 -triple x86_64-gnu-linux -std=c++11 \ // RUN: -emit-llvm -o - -x hip %s | FileCheck -check-prefix=HOST-NEG %s #include "Inputs/cuda.h" @@ -124,9 +124,9 @@ void foo(const int **a) { decltype(u) tmp; } -// HOST-DAG: __hipRegisterVar({{.*}}@_ZL1x {{.*}}@[[DEVNAMEX]] -// HOST-DAG: __hipRegisterVar({{.*}}@_ZL1y {{.*}}@[[DEVNAMEY]] -// HOST-DAG: __hipRegisterVar({{.*}}@_ZL1w {{.*}}@[[DEVNAMEW]] +// HOST-DAG: __hipRegisterVar({{.*}}@_ZL1x, {{.*}}@[[DEVNAMEX]] +// HOST-DAG: __hipRegisterVar({{.*}}@_ZL1y, {{.*}}@[[DEVNAMEY]] +// HOST-DAG: __hipRegisterVar({{.*}}@_ZL1w, {{.*}}@[[DEVNAMEW]] // HOST-NEG-NOT: __hipRegisterVar({{.*}}@_ZL1u // HOST-NEG-NOT: __hipRegisterVar({{.*}}@_ZZ6kernelPiPPKiE1w // HOST-NEG-NOT: __hipRegisterVar({{.*}}@_ZZ6devfunPPKiE1p diff --git a/clang/test/CodeGenCUDA/surface.cu b/clang/test/CodeGenCUDA/surface.cu index 68cdbc63b11a9..4106673f3138a 100644 --- a/clang/test/CodeGenCUDA/surface.cu +++ b/clang/test/CodeGenCUDA/surface.cu @@ -1,9 +1,9 @@ // REQUIRES: x86-registered-target // REQUIRES: nvptx-registered-target -// RUN: %clang_cc1 -no-opaque-pointers -std=c++11 -fcuda-is-device -triple nvptx64-nvidia-cuda -emit-llvm -o - %s | FileCheck --check-prefix=DEVICE %s +// RUN: %clang_cc1 -std=c++11 -fcuda-is-device -triple nvptx64-nvidia-cuda -emit-llvm -o - %s | FileCheck --check-prefix=DEVICE %s // RUN: echo "GPU binary would be here" > %t -// RUN: %clang_cc1 -no-opaque-pointers -std=c++11 -triple x86_64-unknown-linux-gnu -target-sdk-version=8.0 -fcuda-include-gpubinary %t -emit-llvm -o - %s | FileCheck --check-prefix=HOST %s +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -target-sdk-version=8.0 -fcuda-include-gpubinary %t -emit-llvm -o - %s | FileCheck --check-prefix=HOST %s struct surfaceReference { int desc; @@ -28,7 +28,7 @@ surface surf; __attribute__((device)) int suld_2d_zero(surface, int, int) asm("llvm.nvvm.suld.2d.i32.zero"); // DEVICE-LABEL: i32 @_Z3fooii(i32 noundef %x, i32 noundef %y) -// DEVICE: call i64 @llvm.nvvm.texsurf.handle.internal.p1i64(i64 addrspace(1)* @surf) +// DEVICE: call i64 @llvm.nvvm.texsurf.handle.internal.p1(ptr addrspace(1) @surf) // DEVICE: call noundef i32 @llvm.nvvm.suld.2d.i32.zero(i64 %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}) __attribute__((device)) int foo(int x, int y) { return suld_2d_zero(surf, x, y); @@ -36,7 +36,7 @@ __attribute__((device)) int foo(int x, int y) { // HOST: define internal void @[[PREFIX:__cuda]]_register_globals // Texture references need registering with correct arguments. -// HOST: call void @[[PREFIX]]RegisterSurface(i8** %0, i8*{{.*}}({{.*}}@surf{{.*}}), i8*{{.*}}({{.*}}@0{{.*}}), i8*{{.*}}({{.*}}@0{{.*}}), i32 2, i32 0) +// HOST: call void @[[PREFIX]]RegisterSurface(ptr %0, ptr @surf, ptr @0, ptr @0, i32 2, i32 0) // They also need annotating in metadata. -// DEVICE: !0 = !{i64 addrspace(1)* @surf, !"surface", i32 1} +// DEVICE: !0 = !{ptr addrspace(1) @surf, !"surface", i32 1} diff --git a/clang/test/CodeGenCUDA/usual-deallocators.cu b/clang/test/CodeGenCUDA/usual-deallocators.cu index a958fa5ec2f86..b85a706813fc2 100644 --- a/clang/test/CodeGenCUDA/usual-deallocators.cu +++ b/clang/test/CodeGenCUDA/usual-deallocators.cu @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -no-opaque-pointers %s --std=c++11 -triple nvptx-unknown-unknown -fcuda-is-device \ +// RUN: %clang_cc1 %s --std=c++11 -triple nvptx-unknown-unknown -fcuda-is-device \ // RUN: -emit-llvm -o - | FileCheck %s --check-prefixes=COMMON,DEVICE -// RUN: %clang_cc1 -no-opaque-pointers %s --std=c++11 -triple nvptx-unknown-unknown \ +// RUN: %clang_cc1 %s --std=c++11 -triple nvptx-unknown-unknown \ // RUN: -emit-llvm -o - | FileCheck %s --check-prefixes=COMMON,HOST -// RUN: %clang_cc1 -no-opaque-pointers %s --std=c++17 -triple nvptx-unknown-unknown -fcuda-is-device \ +// RUN: %clang_cc1 %s --std=c++17 -triple nvptx-unknown-unknown -fcuda-is-device \ // RUN: -emit-llvm -o - | FileCheck %s --check-prefixes=COMMON,DEVICE -// RUN: %clang_cc1 -no-opaque-pointers %s --std=c++17 -triple nvptx-unknown-unknown \ +// RUN: %clang_cc1 %s --std=c++17 -triple nvptx-unknown-unknown \ // RUN: -emit-llvm -o - | FileCheck %s --check-prefixes=COMMON,HOST #include "Inputs/cuda.h" @@ -83,28 +83,28 @@ __host__ __device__ void tests_hd(void *t) { // COMMON: call void @_ZN4H1D1dlEPv test_hd(t); // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI4H1D2EvPv - // DEVICE: call void @_ZN4H1D2dlEPvj(i8* noundef {{.*}}, i32 noundef 1) - // HOST: call void @_ZN4H1D2dlEPv(i8* noundef {{.*}}) + // DEVICE: call void @_ZN4H1D2dlEPvj(ptr noundef {{.*}}, i32 noundef 1) + // HOST: call void @_ZN4H1D2dlEPv(ptr noundef {{.*}}) test_hd(t); // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI4H2D1EvPv - // DEVICE: call void @_ZN4H2D1dlEPv(i8* {{.*}}) - // HOST: call void @_ZN4H2D1dlEPvj(i8* noundef %3, i32 noundef 1) + // DEVICE: call void @_ZN4H2D1dlEPv(ptr {{.*}}) + // HOST: call void @_ZN4H2D1dlEPvj(ptr noundef {{.*}}, i32 noundef 1) test_hd(t); // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI4H2D2EvPv - // COMMON: call void @_ZN4H2D2dlEPvj(i8* noundef {{.*}}, i32 noundef 1) + // COMMON: call void @_ZN4H2D2dlEPvj(ptr noundef {{.*}}, i32 noundef 1) test_hd(t); // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI6H1D1D2EvPv - // COMMON: call void @_ZN6H1D1D2dlEPv(i8* noundef %3) + // COMMON: call void @_ZN6H1D1D2dlEPv(ptr noundef {{.*}}) test_hd(t); // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI6H1H2D1EvPv - // COMMON: call void @_ZN6H1H2D1dlEPv(i8* {{.*}}) + // COMMON: call void @_ZN6H1H2D1dlEPv(ptr {{.*}}) test_hd(t); // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI6H1H2D2EvPv - // DEVICE: call void @_ZN6H1H2D2dlEPvj(i8* noundef {{.*}}, i32 noundef 1) - // HOST: call void @_ZN6H1H2D2dlEPv(i8* noundef {{.*}}) + // DEVICE: call void @_ZN6H1H2D2dlEPvj(ptr noundef {{.*}}, i32 noundef 1) + // HOST: call void @_ZN6H1H2D2dlEPv(ptr noundef {{.*}}) test_hd(t); // COMMON-LABEL: define linkonce_odr void @_Z7test_hdI8H1H2D1D2EvPv - // COMMON: call void @_ZN8H1H2D1D2dlEPv(i8* {{.*}}) + // COMMON: call void @_ZN8H1H2D1D2dlEPv(ptr {{.*}}) test_hd(t); } @@ -113,39 +113,39 @@ __host__ __device__ void tests_hd(void *t) { // Make sure we've picked deallocator for the correct side of compilation. -// COMMON-LABEL: define linkonce_odr void @_ZN4H1D1dlEPv(i8* noundef %0) +// COMMON-LABEL: define linkonce_odr void @_ZN4H1D1dlEPv(ptr noundef %0) // DEVICE: call void @dev_fn() // HOST: call void @host_fn() -// DEVICE-LABEL: define linkonce_odr void @_ZN4H1D2dlEPvj(i8* noundef %0, i32 noundef %1) +// DEVICE-LABEL: define linkonce_odr void @_ZN4H1D2dlEPvj(ptr noundef %0, i32 noundef %1) // DEVICE: call void @dev_fn() -// HOST-LABEL: define linkonce_odr void @_ZN4H1D2dlEPv(i8* noundef %0) +// HOST-LABEL: define linkonce_odr void @_ZN4H1D2dlEPv(ptr noundef %0) // HOST: call void @host_fn() -// DEVICE-LABEL: define linkonce_odr void @_ZN4H2D1dlEPv(i8* noundef %0) +// DEVICE-LABEL: define linkonce_odr void @_ZN4H2D1dlEPv(ptr noundef %0) // DEVICE: call void @dev_fn() -// HOST-LABEL: define linkonce_odr void @_ZN4H2D1dlEPvj(i8* noundef %0, i32 noundef %1) +// HOST-LABEL: define linkonce_odr void @_ZN4H2D1dlEPvj(ptr noundef %0, i32 noundef %1) // HOST: call void @host_fn() -// COMMON-LABEL: define linkonce_odr void @_ZN4H2D2dlEPvj(i8* noundef %0, i32 noundef %1) +// COMMON-LABEL: define linkonce_odr void @_ZN4H2D2dlEPvj(ptr noundef %0, i32 noundef %1) // DEVICE: call void @dev_fn() // HOST: call void @host_fn() -// COMMON-LABEL: define linkonce_odr void @_ZN6H1D1D2dlEPv(i8* noundef %0) +// COMMON-LABEL: define linkonce_odr void @_ZN6H1D1D2dlEPv(ptr noundef %0) // DEVICE: call void @dev_fn() // HOST: call void @host_fn() -// COMMON-LABEL: define linkonce_odr void @_ZN6H1H2D1dlEPv(i8* noundef %0) +// COMMON-LABEL: define linkonce_odr void @_ZN6H1H2D1dlEPv(ptr noundef %0) // DEVICE: call void @dev_fn() // HOST: call void @host_fn() -// DEVICE-LABEL: define linkonce_odr void @_ZN6H1H2D2dlEPvj(i8* noundef %0, i32 noundef %1) +// DEVICE-LABEL: define linkonce_odr void @_ZN6H1H2D2dlEPvj(ptr noundef %0, i32 noundef %1) // DEVICE: call void @dev_fn() -// HOST-LABEL: define linkonce_odr void @_ZN6H1H2D2dlEPv(i8* noundef %0) +// HOST-LABEL: define linkonce_odr void @_ZN6H1H2D2dlEPv(ptr noundef %0) // HOST: call void @host_fn() -// COMMON-LABEL: define linkonce_odr void @_ZN8H1H2D1D2dlEPv(i8* noundef %0) +// COMMON-LABEL: define linkonce_odr void @_ZN8H1H2D1D2dlEPv(ptr noundef %0) // DEVICE: call void @dev_fn() // HOST: call void @host_fn() -// DEVICE: !0 = !{void (i32)* @_Z1fIiEvT_, !"kernel", i32 1} +// DEVICE: !0 = !{ptr @_Z1fIiEvT_, !"kernel", i32 1} diff --git a/clang/test/CodeGenCUDA/vtbl.cu b/clang/test/CodeGenCUDA/vtbl.cu index 65331ff168d10..4c3bb8436c49f 100644 --- a/clang/test/CodeGenCUDA/vtbl.cu +++ b/clang/test/CodeGenCUDA/vtbl.cu @@ -1,13 +1,12 @@ -// RUN: %clang_cc1 -no-opaque-pointers -fcuda-is-device -triple amdgcn-amd-amdhsa -target-cpu gfx906 \ +// RUN: %clang_cc1 -fcuda-is-device -triple amdgcn-amd-amdhsa -target-cpu gfx906 \ // RUN: -emit-llvm -o - %s | FileCheck %s #include "Inputs/cuda.h" -// CHECK-LABEL: define {{.*}}@_ZN1AC2Ev(%struct.A* noundef nonnull align 8 dereferenceable(8) %this) -// CHECK: store %struct.A* %this, %struct.A** %this.addr.ascast -// CHECK: %this1 = load %struct.A*, %struct.A** %this.addr.ascast -// CHECK: %[[VTFIELD:.*]] = bitcast %struct.A* %this1 to i32 (...)* addrspace(1)** -// CHECK: store i32 (...)* addrspace(1)* bitcast{{.*}} @_ZTV1A{{.*}}, i32 (...)* addrspace(1)** %[[VTFIELD]] +// CHECK-LABEL: define {{.*}}@_ZN1AC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %this) +// CHECK: store ptr %this, ptr %this.addr.ascast +// CHECK: %this1 = load ptr, ptr %this.addr.ascast +// CHECK: store ptr addrspace(1) {{.*}} @_ZTV1A{{.*}}, ptr %this1 struct A { __device__ virtual void vf() {} }; diff --git a/clang/test/CodeGenCXX/thinlto_public_type_test_distributed.ll b/clang/test/CodeGenCXX/thinlto_public_type_test_distributed.ll index 1d175962e3602..ce3447384adbe 100644 --- a/clang/test/CodeGenCXX/thinlto_public_type_test_distributed.ll +++ b/clang/test/CodeGenCXX/thinlto_public_type_test_distributed.ll @@ -11,7 +11,7 @@ ; RUN: %clang_cc1 -triple x86_64-grtev4-linux-gnu \ ; RUN: -emit-obj -fthinlto-index=%t.o.thinlto.bc \ ; RUN: -o %t.native.o -x ir %t.o --save-temps=obj -; RUN: llvm-dis %t.native.o.0.preopt.bc -o - | FileCheck %s --check-prefix=PUBLIC +; RUN: llvm-dis %t.native.o.3.import.bc -o - | FileCheck %s --check-prefix=PUBLIC ; RUN: llvm-lto2 run -thinlto-distributed-indexes %t.o --whole-program-visibility \ ; RUN: -o %t2.index \ @@ -20,7 +20,7 @@ ; RUN: %clang_cc1 -triple x86_64-grtev4-linux-gnu \ ; RUN: -emit-obj -fthinlto-index=%t.o.thinlto.bc \ ; RUN: -o %t.native.o -x ir %t.o --save-temps=obj -; RUN: llvm-dis %t.native.o.0.preopt.bc -o - | FileCheck %s --check-prefix=HIDDEN +; RUN: llvm-dis %t.native.o.3.import.bc -o - | FileCheck %s --check-prefix=HIDDEN ; PUBLIC-NOT: call {{.*}}@llvm.public.type.test ; PUBLIC-NOT: call {{.*}}@llvm.type.test diff --git a/clang/test/CodeGenCXX/warn-padded-packed.cpp b/clang/test/CodeGenCXX/warn-padded-packed.cpp index cf4890e40005d..c51a6c9443f6e 100644 --- a/clang/test/CodeGenCXX/warn-padded-packed.cpp +++ b/clang/test/CodeGenCXX/warn-padded-packed.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -triple=x86_64-none-none -Wpadded -Wpacked -verify %s -emit-llvm-only +// RUN: %clang_cc1 -triple=x86_64-none-none -Wpadded -Wpacked -verify=expected,top %s -emit-llvm-only +// RUN: %clang_cc1 -triple=x86_64-none-none -Wpadded -Wpacked -verify=expected,abi15 -fclang-abi-compat=15 %s -emit-llvm-only struct S1 { char c; @@ -154,7 +155,7 @@ struct S28 { char c1; short s1; char c2; - S28_non_pod p1; // expected-warning {{not packing field 'p1' as it is non-POD for the purposes of layout}} + S28_non_pod p1; // top-warning {{not packing field 'p1' as it is non-POD for the purposes of layout}} } __attribute__((packed)); struct S29_non_pod_align_1 { @@ -167,6 +168,16 @@ struct S29 { } __attribute__((packed)); // no warning static_assert(alignof(S29) == 1, ""); +struct S30 { +protected: + short s; +} __attribute__((packed)); // no warning +struct S30_use { // abi15-warning {{packed attribute is unnecessary for 'S30_use'}} + char c; + S30 u; +} __attribute__((packed)); +static_assert(sizeof(S30_use) == 3, ""); + // The warnings are emitted when the layout of the structs is computed, so we have to use them. void f(S1*, S2*, S3*, S4*, S5*, S6*, S7*, S8*, S9*, S10*, S11*, S12*, S13*, S14*, S15*, S16*, S17*, S18*, S19*, S20*, S21*, S22*, S23*, S24*, S25*, diff --git a/clang/test/CodeGenCoroutines/coro-params.cpp b/clang/test/CodeGenCoroutines/coro-params.cpp index 09b3b6d583738..c5a61a53cb46e 100644 --- a/clang/test/CodeGenCoroutines/coro-params.cpp +++ b/clang/test/CodeGenCoroutines/coro-params.cpp @@ -2,7 +2,7 @@ // Verifies that parameter copies are destroyed // Vefifies that parameter copies are used in the body of the coroutine // Verifies that parameter copies are used to construct the promise type, if that type has a matching constructor -// RUN: %clang_cc1 -no-opaque-pointers -std=c++20 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -disable-llvm-passes -fexceptions | FileCheck %s +// RUN: %clang_cc1 -std=c++20 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -disable-llvm-passes -fexceptions | FileCheck %s namespace std { template struct coroutine_traits; @@ -62,27 +62,25 @@ struct MoveAndCopy { void consume(int,int,int) noexcept; // TODO: Add support for CopyOnly params -// CHECK: define{{.*}} void @_Z1fi8MoveOnly11MoveAndCopy(i32 noundef %val, %struct.MoveOnly* noundef %[[MoParam:.+]], %struct.MoveAndCopy* noundef %[[McParam:.+]]) #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8* +// CHECK: define{{.*}} void @_Z1fi8MoveOnly11MoveAndCopy(i32 noundef %val, ptr noundef %[[MoParam:.+]], ptr noundef %[[McParam:.+]]) #0 personality ptr @__gxx_personality_v0 void f(int val, MoveOnly moParam, MoveAndCopy mcParam) { // CHECK: %[[MoCopy:.+]] = alloca %struct.MoveOnly, // CHECK: %[[McCopy:.+]] = alloca %struct.MoveAndCopy, - // CHECK: store i32 %val, i32* %[[ValAddr:.+]] - - // CHECK: call i8* @llvm.coro.begin( - // CHECK: call void @_ZN8MoveOnlyC1EOS_(%struct.MoveOnly* {{[^,]*}} %[[MoCopy]], %struct.MoveOnly* noundef nonnull align 4 dereferenceable(4) %[[MoParam]]) - // CHECK-NEXT: bitcast %struct.MoveAndCopy* %[[McCopy]] to i8* - // CHECK-NEXT: call void @llvm.lifetime.start.p0i8( - // CHECK-NEXT: call void @_ZN11MoveAndCopyC1EOS_(%struct.MoveAndCopy* {{[^,]*}} %[[McCopy]], %struct.MoveAndCopy* noundef nonnull align 4 dereferenceable(4) %[[McParam]]) # - // CHECK-NEXT: bitcast %"struct.std::coroutine_traits::promise_type"* %__promise to i8* - // CHECK-NEXT: call void @llvm.lifetime.start.p0i8( + // CHECK: store i32 %val, ptr %[[ValAddr:.+]] + + // CHECK: call ptr @llvm.coro.begin( + // CHECK: call void @_ZN8MoveOnlyC1EOS_(ptr {{[^,]*}} %[[MoCopy]], ptr noundef nonnull align 4 dereferenceable(4) %[[MoParam]]) + // CHECK-NEXT: call void @llvm.lifetime.start.p0( + // CHECK-NEXT: call void @_ZN11MoveAndCopyC1EOS_(ptr {{[^,]*}} %[[McCopy]], ptr noundef nonnull align 4 dereferenceable(4) %[[McParam]]) # + // CHECK-NEXT: call void @llvm.lifetime.start.p0( // CHECK-NEXT: invoke void @_ZNSt16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeC1Ev( // CHECK: call void @_ZN14suspend_always12await_resumeEv( - // CHECK: %[[IntParam:.+]] = load i32, i32* %{{.*}} - // CHECK: %[[MoGep:.+]] = getelementptr inbounds %struct.MoveOnly, %struct.MoveOnly* %[[MoCopy]], i32 0, i32 0 - // CHECK: %[[MoVal:.+]] = load i32, i32* %[[MoGep]] - // CHECK: %[[McGep:.+]] = getelementptr inbounds %struct.MoveAndCopy, %struct.MoveAndCopy* %[[McCopy]], i32 0, i32 0 - // CHECK: %[[McVal:.+]] = load i32, i32* %[[McGep]] + // CHECK: %[[IntParam:.+]] = load i32, ptr %{{.*}} + // CHECK: %[[MoGep:.+]] = getelementptr inbounds %struct.MoveOnly, ptr %[[MoCopy]], i32 0, i32 0 + // CHECK: %[[MoVal:.+]] = load i32, ptr %[[MoGep]] + // CHECK: %[[McGep:.+]] = getelementptr inbounds %struct.MoveAndCopy, ptr %[[McCopy]], i32 0, i32 0 + // CHECK: %[[McVal:.+]] = load i32, ptr %[[McGep]] // CHECK: call void @_Z7consumeiii(i32 noundef %[[IntParam]], i32 noundef %[[MoVal]], i32 noundef %[[McVal]]) consume(val, moParam.val, mcParam.val); @@ -93,39 +91,31 @@ void f(int val, MoveOnly moParam, MoveAndCopy mcParam) { // CHECK: call void @_ZN14suspend_always12await_resumeEv( // Destroy promise, then parameter copies: - // CHECK: call void @_ZNSt16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeD1Ev(%"struct.std::coroutine_traits::promise_type"* {{[^,]*}} %__promise) - // CHECK-NEXT: bitcast %"struct.std::coroutine_traits::promise_type"* %__promise to i8* - // CHECK-NEXT: call void @llvm.lifetime.end.p0i8( - // CHECK-NEXT: call void @_ZN11MoveAndCopyD1Ev(%struct.MoveAndCopy* {{[^,]*}} %[[McCopy]]) - // CHECK-NEXT: bitcast %struct.MoveAndCopy* %[[McCopy]] to i8* - // CHECK-NEXT: call void @llvm.lifetime.end.p0i8( - // CHECK-NEXT: call void @_ZN8MoveOnlyD1Ev(%struct.MoveOnly* {{[^,]*}} %[[MoCopy]] - // CHECK-NEXT: bitcast %struct.MoveOnly* %[[MoCopy]] to i8* - // CHECK-NEXT: call void @llvm.lifetime.end.p0i8( - // CHECK-NEXT: bitcast i32* %{{.+}} to i8* - // CHECK-NEXT: call void @llvm.lifetime.end.p0i8( - // CHECK-NEXT: call i8* @llvm.coro.free( + // CHECK: call void @_ZNSt16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeD1Ev(ptr {{[^,]*}} %__promise) + // CHECK-NEXT: call void @llvm.lifetime.end.p0( + // CHECK-NEXT: call void @_ZN11MoveAndCopyD1Ev(ptr {{[^,]*}} %[[McCopy]]) + // CHECK-NEXT: call void @llvm.lifetime.end.p0( + // CHECK-NEXT: call void @_ZN8MoveOnlyD1Ev(ptr {{[^,]*}} %[[MoCopy]] + // CHECK-NEXT: call void @llvm.lifetime.end.p0( + // CHECK-NEXT: call void @llvm.lifetime.end.p0( + // CHECK-NEXT: call ptr @llvm.coro.free( } -// CHECK-LABEL: void @_Z16dependent_paramsI1A1BEvT_T0_S3_(%struct.A* noundef %x, %struct.B* noundef %0, %struct.B* noundef %y) +// CHECK-LABEL: void @_Z16dependent_paramsI1A1BEvT_T0_S3_(ptr noundef %x, ptr noundef %0, ptr noundef %y) template void dependent_params(T x, U, U y) { // CHECK: %[[x_copy:.+]] = alloca %struct.A, // CHECK-NEXT: %[[unnamed_copy:.+]] = alloca %struct.B // CHECK-NEXT: %[[y_copy:.+]] = alloca %struct.B - // CHECK: call i8* @llvm.coro.begin - // CHECK-NEXT: bitcast %struct.A* %[[x_copy]] to i8* - // CHECK-NEXT: call void @llvm.lifetime.start.p0i8( - // CHECK-NEXT: call void @_ZN1AC1EOS_(%struct.A* {{[^,]*}} %[[x_copy]], %struct.A* noundef nonnull align 4 dereferenceable(512) %x) - // CHECK-NEXT: bitcast %struct.B* %[[unnamed_copy]] to i8* - // CHECK-NEXT: call void @llvm.lifetime.start.p0i8( - // CHECK-NEXT: call void @_ZN1BC1EOS_(%struct.B* {{[^,]*}} %[[unnamed_copy]], %struct.B* noundef nonnull align 4 dereferenceable(512) %0) - // CHECK-NEXT: bitcast %struct.B* %[[y_copy]] to i8* - // CHECK-NEXT: call void @llvm.lifetime.start.p0i8( - // CHECK-NEXT: call void @_ZN1BC1EOS_(%struct.B* {{[^,]*}} %[[y_copy]], %struct.B* noundef nonnull align 4 dereferenceable(512) %y) - // CHECK-NEXT: bitcast %"struct.std::coroutine_traits::promise_type"* %__promise to i8* - // CHECK-NEXT: call void @llvm.lifetime.start.p0i8( + // CHECK: call ptr @llvm.coro.begin + // CHECK-NEXT: call void @llvm.lifetime.start.p0( + // CHECK-NEXT: call void @_ZN1AC1EOS_(ptr {{[^,]*}} %[[x_copy]], ptr noundef nonnull align 4 dereferenceable(512) %x) + // CHECK-NEXT: call void @llvm.lifetime.start.p0( + // CHECK-NEXT: call void @_ZN1BC1EOS_(ptr {{[^,]*}} %[[unnamed_copy]], ptr noundef nonnull align 4 dereferenceable(512) %0) + // CHECK-NEXT: call void @llvm.lifetime.start.p0( + // CHECK-NEXT: call void @_ZN1BC1EOS_(ptr {{[^,]*}} %[[y_copy]], ptr noundef nonnull align 4 dereferenceable(512) %y) + // CHECK-NEXT: call void @llvm.lifetime.start.p0( // CHECK-NEXT: invoke void @_ZNSt16coroutine_traitsIJv1A1BS1_EE12promise_typeC1Ev( co_return; @@ -169,10 +159,10 @@ struct std::coroutine_traits::promise_type"* {{[^,]*}} %__promise, i32 noundef %[[INT]], float noundef %[[FLOAT]], double noundef %[[DOUBLE]]) + // CHECK: %[[INT:.+]] = load i32, ptr %5, align 4 + // CHECK: %[[FLOAT:.+]] = load float, ptr %6, align 4 + // CHECK: %[[DOUBLE:.+]] = load double, ptr %7, align 8 + // CHECK: invoke void @_ZNSt16coroutine_traitsIJv28promise_matching_constructorifdEE12promise_typeC1ES0_ifd(ptr {{[^,]*}} %__promise, i32 noundef %[[INT]], float noundef %[[FLOAT]], double noundef %[[DOUBLE]]) co_return; } @@ -195,8 +185,8 @@ struct some_class { method good_coroutine_calls_custom_constructor(float); }; -// CHECK-LABEL: define{{.*}} void @_ZN10some_class39good_coroutine_calls_custom_constructorEf(%struct.some_class* +// CHECK-LABEL: define{{.*}} void @_ZN10some_class39good_coroutine_calls_custom_constructorEf(ptr method some_class::good_coroutine_calls_custom_constructor(float) { - // CHECK: invoke void @_ZNSt16coroutine_traitsIJ6methodR10some_classfEE12promise_typeC1ES2_f(%"struct.std::coroutine_traits::promise_type"* {{[^,]*}} %__promise, %struct.some_class* noundef nonnull align 1 dereferenceable(1) %{{.+}}, float + // CHECK: invoke void @_ZNSt16coroutine_traitsIJ6methodR10some_classfEE12promise_typeC1ES2_f(ptr {{[^,]*}} %__promise, ptr noundef nonnull align 1 dereferenceable(1) %{{.+}}, float co_return; } diff --git a/clang/test/CodeGenHIP/hip-cumode.hip b/clang/test/CodeGenHIP/hip-cumode.hip new file mode 100644 index 0000000000000..1aa1ca7a1a7ee --- /dev/null +++ b/clang/test/CodeGenHIP/hip-cumode.hip @@ -0,0 +1,20 @@ +// REQUIRES: amdgpu-registered-target + +// RUN: %clang -S -o - --offload-arch=gfx906 --cuda-device-only -nogpuinc -nogpulib \ +// RUN: %s 2>&1 | FileCheck --check-prefix=NOWGP %s +// RUN: %clang -S -o - --offload-arch=gfx906 --cuda-device-only -nogpuinc -nogpulib -mcumode \ +// RUN: %s 2>&1 | FileCheck --check-prefix=NOWGP %s +// RUN: %clang -S -o - --offload-arch=gfx906 --cuda-device-only -nogpuinc -nogpulib -mno-cumode \ +// RUN: %s 2>&1 | FileCheck --check-prefixes=NOWGP,WARN-CUMODE %s +// RUN: %clang -S -o - --offload-arch=gfx1030 --cuda-device-only -nogpuinc -nogpulib \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-OFF %s +// RUN: %clang -S -o - --offload-arch=gfx1030 --cuda-device-only -nogpuinc -nogpulib -mcumode \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-ON %s +// RUN: %clang -S -o - --offload-arch=gfx1030 --cuda-device-only -nogpuinc -nogpulib -mno-cumode \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-OFF %s +// WARN-CUMODE: warning: ignoring '-mno-cumode' option as it is not currently supported for processor 'gfx906' [-Woption-ignored] +// NOWGP-NOT: .amdhsa_workgroup_processor_mode +// CUMODE-ON: .amdhsa_workgroup_processor_mode 0 +// CUMODE-OFF: .amdhsa_workgroup_processor_mode 1 + +__attribute__((global)) void kernel() {} diff --git a/clang/test/CodeGenHIP/maybe_undef-attr-verify.hip b/clang/test/CodeGenHIP/maybe_undef-attr-verify.hip index afa461f909529..b7ab32ac408f1 100644 --- a/clang/test/CodeGenHIP/maybe_undef-attr-verify.hip +++ b/clang/test/CodeGenHIP/maybe_undef-attr-verify.hip @@ -1,16 +1,16 @@ -// RUN: %clang_cc1 -no-opaque-pointers -triple amdgcn-amd-amdhsa -target-cpu gfx906 -x hip -fcuda-is-device -emit-llvm %s \ +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -target-cpu gfx906 -x hip -fcuda-is-device -emit-llvm %s \ // RUN: -o - | FileCheck %s // CHECK: define dso_local amdgpu_kernel void @_Z13shufflekernelv() // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP1:%.*]] = alloca i32, align 4, addrspace(5) // CHECK-NEXT: [[TMP2:%.*]] = alloca i32, align 4, addrspace(5) -// CHECK-NEXT: [[TMP3:%.*]] = addrspacecast i32 addrspace(5)* [[TMP1:%.*]] to i32* -// CHECK-NEXT: [[TMP4:%.*]] = addrspacecast i32 addrspace(5)* [[TMP2:%.*]] to i32* -// CHECK-NEXT: [[TMP5:%.*]] = load i32, i32* [[TMP3:%.*]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = addrspacecast ptr addrspace(5) [[TMP1:%.*]] to ptr +// CHECK-NEXT: [[TMP4:%.*]] = addrspacecast ptr addrspace(5) [[TMP2:%.*]] to ptr +// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[TMP3:%.*]], align 4 // CHECK-NEXT: [[TMP6:%.*]] = freeze i32 [[TMP5:%.*]] // CHECK-NEXT: %call = call noundef i32 @_Z11__shfl_synciii(i32 noundef [[TMP6:%.*]], i32 noundef 64, i32 noundef 0) #4 -// CHECK-NEXT: store i32 %call, i32* [[TMP4:%.*]], align 4 +// CHECK-NEXT: store i32 %call, ptr [[TMP4:%.*]], align 4 // CHECK-NEXT: ret void // CHECK: define linkonce_odr noundef i32 @_Z11__shfl_synciii(i32 noundef [[TMP1:%.*]], i32 noundef [[TMP2:%.*]], i32 noundef [[TMP3:%.*]]) diff --git a/clang/test/CodeGenOpenCL/amdgpu-alignment.cl b/clang/test/CodeGenOpenCL/amdgpu-alignment.cl index 16bd35bfeb4b8..0245dbed5c360 100644 --- a/clang/test/CodeGenOpenCL/amdgpu-alignment.cl +++ b/clang/test/CodeGenOpenCL/amdgpu-alignment.cl @@ -1,6 +1,6 @@ // REQUIRES: amdgpu-registered-target -// RUN: %clang_cc1 -no-opaque-pointers -triple amdgcn-unknown-unknown -S -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -triple amdgcn-unknown-unknown-opencl -S -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -S -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn-unknown-unknown-opencl -S -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s #pragma OPENCL EXTENSION cl_khr_fp64 : enable #pragma OPENCL EXTENSION cl_khr_fp16 : enable @@ -92,48 +92,48 @@ typedef double __attribute__((ext_vector_type(16))) double16; // CHECK-LABEL: @local_memory_alignment_global( -// CHECK: store volatile i8 0, i8 addrspace(3)* getelementptr inbounds ([4 x i8], [4 x i8] addrspace(3)* @local_memory_alignment_global.lds_i8, i64 0, i64 0), align 1 -// CHECK: store volatile <2 x i8> zeroinitializer, <2 x i8> addrspace(3)* getelementptr inbounds ([4 x <2 x i8>], [4 x <2 x i8>] addrspace(3)* @local_memory_alignment_global.lds_v2i8, i64 0, i64 0), align 2 -// CHECK: store volatile <4 x i8> , <4 x i8> addrspace(3)* bitcast ([4 x <3 x i8>] addrspace(3)* @local_memory_alignment_global.lds_v3i8 to <4 x i8> addrspace(3)*), align 4 -// CHECK: store volatile <4 x i8> zeroinitializer, <4 x i8> addrspace(3)* getelementptr inbounds ([4 x <4 x i8>], [4 x <4 x i8>] addrspace(3)* @local_memory_alignment_global.lds_v4i8, i64 0, i64 0), align 4 -// CHECK: store volatile <8 x i8> zeroinitializer, <8 x i8> addrspace(3)* getelementptr inbounds ([4 x <8 x i8>], [4 x <8 x i8>] addrspace(3)* @local_memory_alignment_global.lds_v8i8, i64 0, i64 0), align 8 -// CHECK: store volatile <16 x i8> zeroinitializer, <16 x i8> addrspace(3)* getelementptr inbounds ([4 x <16 x i8>], [4 x <16 x i8>] addrspace(3)* @local_memory_alignment_global.lds_v16i8, i64 0, i64 0), align 16 -// CHECK: store volatile i16 0, i16 addrspace(3)* getelementptr inbounds ([4 x i16], [4 x i16] addrspace(3)* @local_memory_alignment_global.lds_i16, i64 0, i64 0), align 2 -// CHECK: store volatile <2 x i16> zeroinitializer, <2 x i16> addrspace(3)* getelementptr inbounds ([4 x <2 x i16>], [4 x <2 x i16>] addrspace(3)* @local_memory_alignment_global.lds_v2i16, i64 0, i64 0), align 4 -// CHECK: store volatile <4 x i16> , <4 x i16> addrspace(3)* bitcast ([4 x <3 x i16>] addrspace(3)* @local_memory_alignment_global.lds_v3i16 to <4 x i16> addrspace(3)*), align 8 -// CHECK: store volatile <4 x i16> zeroinitializer, <4 x i16> addrspace(3)* getelementptr inbounds ([4 x <4 x i16>], [4 x <4 x i16>] addrspace(3)* @local_memory_alignment_global.lds_v4i16, i64 0, i64 0), align 8 -// CHECK: store volatile <8 x i16> zeroinitializer, <8 x i16> addrspace(3)* getelementptr inbounds ([4 x <8 x i16>], [4 x <8 x i16>] addrspace(3)* @local_memory_alignment_global.lds_v8i16, i64 0, i64 0), align 16 -// CHECK: store volatile <16 x i16> zeroinitializer, <16 x i16> addrspace(3)* getelementptr inbounds ([4 x <16 x i16>], [4 x <16 x i16>] addrspace(3)* @local_memory_alignment_global.lds_v16i16, i64 0, i64 0), align 32 -// CHECK: store volatile i32 0, i32 addrspace(3)* getelementptr inbounds ([4 x i32], [4 x i32] addrspace(3)* @local_memory_alignment_global.lds_i32, i64 0, i64 0), align 4 -// CHECK: store volatile <2 x i32> zeroinitializer, <2 x i32> addrspace(3)* getelementptr inbounds ([4 x <2 x i32>], [4 x <2 x i32>] addrspace(3)* @local_memory_alignment_global.lds_v2i32, i64 0, i64 0), align 8 -// CHECK: store volatile <4 x i32> , <4 x i32> addrspace(3)* bitcast ([4 x <3 x i32>] addrspace(3)* @local_memory_alignment_global.lds_v3i32 to <4 x i32> addrspace(3)*), align 16 -// CHECK: store volatile <4 x i32> zeroinitializer, <4 x i32> addrspace(3)* getelementptr inbounds ([4 x <4 x i32>], [4 x <4 x i32>] addrspace(3)* @local_memory_alignment_global.lds_v4i32, i64 0, i64 0), align 16 -// CHECK: store volatile <8 x i32> zeroinitializer, <8 x i32> addrspace(3)* getelementptr inbounds ([4 x <8 x i32>], [4 x <8 x i32>] addrspace(3)* @local_memory_alignment_global.lds_v8i32, i64 0, i64 0), align 32 -// CHECK: store volatile <16 x i32> zeroinitializer, <16 x i32> addrspace(3)* getelementptr inbounds ([4 x <16 x i32>], [4 x <16 x i32>] addrspace(3)* @local_memory_alignment_global.lds_v16i32, i64 0, i64 0), align 64 -// CHECK: store volatile i64 0, i64 addrspace(3)* getelementptr inbounds ([4 x i64], [4 x i64] addrspace(3)* @local_memory_alignment_global.lds_i64, i64 0, i64 0), align 8 -// CHECK: store volatile <2 x i64> zeroinitializer, <2 x i64> addrspace(3)* getelementptr inbounds ([4 x <2 x i64>], [4 x <2 x i64>] addrspace(3)* @local_memory_alignment_global.lds_v2i64, i64 0, i64 0), align 16 -// CHECK: store volatile <4 x i64> , <4 x i64> addrspace(3)* bitcast ([4 x <3 x i64>] addrspace(3)* @local_memory_alignment_global.lds_v3i64 to <4 x i64> addrspace(3)*), align 32 -// CHECK: store volatile <4 x i64> zeroinitializer, <4 x i64> addrspace(3)* getelementptr inbounds ([4 x <4 x i64>], [4 x <4 x i64>] addrspace(3)* @local_memory_alignment_global.lds_v4i64, i64 0, i64 0), align 32 -// CHECK: store volatile <8 x i64> zeroinitializer, <8 x i64> addrspace(3)* getelementptr inbounds ([4 x <8 x i64>], [4 x <8 x i64>] addrspace(3)* @local_memory_alignment_global.lds_v8i64, i64 0, i64 0), align 64 -// CHECK: store volatile <16 x i64> zeroinitializer, <16 x i64> addrspace(3)* getelementptr inbounds ([4 x <16 x i64>], [4 x <16 x i64>] addrspace(3)* @local_memory_alignment_global.lds_v16i64, i64 0, i64 0), align 128 -// CHECK: store volatile half 0xH0000, half addrspace(3)* getelementptr inbounds ([4 x half], [4 x half] addrspace(3)* @local_memory_alignment_global.lds_f16, i64 0, i64 0), align 2 -// CHECK: store volatile <2 x half> zeroinitializer, <2 x half> addrspace(3)* getelementptr inbounds ([4 x <2 x half>], [4 x <2 x half>] addrspace(3)* @local_memory_alignment_global.lds_v2f16, i64 0, i64 0), align 4 -// CHECK: store volatile <4 x half> , <4 x half> addrspace(3)* bitcast ([4 x <3 x half>] addrspace(3)* @local_memory_alignment_global.lds_v3f16 to <4 x half> addrspace(3)*), align 8 -// CHECK: store volatile <4 x half> zeroinitializer, <4 x half> addrspace(3)* getelementptr inbounds ([4 x <4 x half>], [4 x <4 x half>] addrspace(3)* @local_memory_alignment_global.lds_v4f16, i64 0, i64 0), align 8 -// CHECK: store volatile <8 x half> zeroinitializer, <8 x half> addrspace(3)* getelementptr inbounds ([4 x <8 x half>], [4 x <8 x half>] addrspace(3)* @local_memory_alignment_global.lds_v8f16, i64 0, i64 0), align 16 -// CHECK: store volatile <16 x half> zeroinitializer, <16 x half> addrspace(3)* getelementptr inbounds ([4 x <16 x half>], [4 x <16 x half>] addrspace(3)* @local_memory_alignment_global.lds_v16f16, i64 0, i64 0), align 32 -// CHECK: store volatile float 0.000000e+00, float addrspace(3)* getelementptr inbounds ([4 x float], [4 x float] addrspace(3)* @local_memory_alignment_global.lds_f32, i64 0, i64 0), align 4 -// CHECK: store volatile <2 x float> zeroinitializer, <2 x float> addrspace(3)* getelementptr inbounds ([4 x <2 x float>], [4 x <2 x float>] addrspace(3)* @local_memory_alignment_global.lds_v2f32, i64 0, i64 0), align 8 -// CHECK: store volatile <4 x float> , <4 x float> addrspace(3)* bitcast ([4 x <3 x float>] addrspace(3)* @local_memory_alignment_global.lds_v3f32 to <4 x float> addrspace(3)*), align 16 -// CHECK: store volatile <4 x float> zeroinitializer, <4 x float> addrspace(3)* getelementptr inbounds ([4 x <4 x float>], [4 x <4 x float>] addrspace(3)* @local_memory_alignment_global.lds_v4f32, i64 0, i64 0), align 16 -// CHECK: store volatile <8 x float> zeroinitializer, <8 x float> addrspace(3)* getelementptr inbounds ([4 x <8 x float>], [4 x <8 x float>] addrspace(3)* @local_memory_alignment_global.lds_v8f32, i64 0, i64 0), align 32 -// CHECK: store volatile <16 x float> zeroinitializer, <16 x float> addrspace(3)* getelementptr inbounds ([4 x <16 x float>], [4 x <16 x float>] addrspace(3)* @local_memory_alignment_global.lds_v16f32, i64 0, i64 0), align 64 -// CHECK: store volatile double 0.000000e+00, double addrspace(3)* getelementptr inbounds ([4 x double], [4 x double] addrspace(3)* @local_memory_alignment_global.lds_f64, i64 0, i64 0), align 8 -// CHECK: store volatile <2 x double> zeroinitializer, <2 x double> addrspace(3)* getelementptr inbounds ([4 x <2 x double>], [4 x <2 x double>] addrspace(3)* @local_memory_alignment_global.lds_v2f64, i64 0, i64 0), align 16 -// CHECK: store volatile <4 x double> , <4 x double> addrspace(3)* bitcast ([4 x <3 x double>] addrspace(3)* @local_memory_alignment_global.lds_v3f64 to <4 x double> addrspace(3)*), align 32 -// CHECK: store volatile <4 x double> zeroinitializer, <4 x double> addrspace(3)* getelementptr inbounds ([4 x <4 x double>], [4 x <4 x double>] addrspace(3)* @local_memory_alignment_global.lds_v4f64, i64 0, i64 0), align 32 -// CHECK: store volatile <8 x double> zeroinitializer, <8 x double> addrspace(3)* getelementptr inbounds ([4 x <8 x double>], [4 x <8 x double>] addrspace(3)* @local_memory_alignment_global.lds_v8f64, i64 0, i64 0), align 64 -// CHECK: store volatile <16 x double> zeroinitializer, <16 x double> addrspace(3)* getelementptr inbounds ([4 x <16 x double>], [4 x <16 x double>] addrspace(3)* @local_memory_alignment_global.lds_v16f64, i64 0, i64 0), align 128 +// CHECK: store volatile i8 0, ptr addrspace(3) @local_memory_alignment_global.lds_i8, align 1 +// CHECK: store volatile <2 x i8> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v2i8, align 2 +// CHECK: store volatile <4 x i8> , ptr addrspace(3) @local_memory_alignment_global.lds_v3i8, align 4 +// CHECK: store volatile <4 x i8> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v4i8, align 4 +// CHECK: store volatile <8 x i8> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v8i8, align 8 +// CHECK: store volatile <16 x i8> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v16i8, align 16 +// CHECK: store volatile i16 0, ptr addrspace(3) @local_memory_alignment_global.lds_i16, align 2 +// CHECK: store volatile <2 x i16> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v2i16, align 4 +// CHECK: store volatile <4 x i16> , ptr addrspace(3) @local_memory_alignment_global.lds_v3i16, align 8 +// CHECK: store volatile <4 x i16> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v4i16, align 8 +// CHECK: store volatile <8 x i16> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v8i16, align 16 +// 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 <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 +// CHECK: store volatile i64 0, ptr addrspace(3) @local_memory_alignment_global.lds_i64, align 8 +// CHECK: store volatile <2 x i64> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v2i64, align 16 +// CHECK: store volatile <4 x i64> , ptr addrspace(3) @local_memory_alignment_global.lds_v3i64, align 32 +// CHECK: store volatile <4 x i64> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v4i64, align 32 +// CHECK: store volatile <8 x i64> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v8i64, align 64 +// CHECK: store volatile <16 x i64> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v16i64, align 128 +// CHECK: store volatile half 0xH0000, ptr addrspace(3) @local_memory_alignment_global.lds_f16, align 2 +// CHECK: store volatile <2 x half> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v2f16, align 4 +// CHECK: store volatile <4 x half> , ptr addrspace(3) @local_memory_alignment_global.lds_v3f16, align 8 +// CHECK: store volatile <4 x half> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v4f16, align 8 +// CHECK: store volatile <8 x half> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v8f16, align 16 +// 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 <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 +// CHECK: store volatile double 0.000000e+00, ptr addrspace(3) @local_memory_alignment_global.lds_f64, align 8 +// CHECK: store volatile <2 x double> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v2f64, align 16 +// CHECK: store volatile <4 x double> , ptr addrspace(3) @local_memory_alignment_global.lds_v3f64, align 32 +// CHECK: store volatile <4 x double> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v4f64, align 32 +// CHECK: store volatile <8 x double> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v8f64, align 64 +// CHECK: store volatile <16 x double> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v16f64, align 128 kernel void local_memory_alignment_global() { volatile local char lds_i8[4]; @@ -379,48 +379,48 @@ kernel void local_memory_alignment_arg( // CHECK: %private_v8f64 = alloca [4 x <8 x double>], align 64, addrspace(5) // CHECK: %private_v16f64 = alloca [4 x <16 x double>], align 128, addrspace(5) -// CHECK: store volatile i8 0, i8 addrspace(5)* %arraydecay, align 1 -// CHECK: store volatile <2 x i8> zeroinitializer, <2 x i8> addrspace(5)* %arraydecay{{[0-9]+}}, align 2 -// CHECK: store volatile <4 x i8> , <4 x i8> addrspace(5)* %storetmp, align 4 -// CHECK: store volatile <4 x i8> zeroinitializer, <4 x i8> addrspace(5)* %arraydecay{{[0-9]+}}, align 4 -// CHECK: store volatile <8 x i8> zeroinitializer, <8 x i8> addrspace(5)* %arraydecay{{[0-9]+}}, align 8 -// CHECK: store volatile <16 x i8> zeroinitializer, <16 x i8> addrspace(5)* %arraydecay{{[0-9]+}}, align 16 -// CHECK: store volatile i16 0, i16 addrspace(5)* %arraydecay{{[0-9]+}}, align 2 -// CHECK: store volatile <2 x i16> zeroinitializer, <2 x i16> addrspace(5)* %arraydecay{{[0-9]+}}, align 4 -// CHECK: store volatile <4 x i16> , <4 x i16> addrspace(5)* %storetmp{{[0-9]+}}, align 8 -// CHECK: store volatile <4 x i16> zeroinitializer, <4 x i16> addrspace(5)* %arraydecay{{[0-9]+}}, align 8 -// CHECK: store volatile <8 x i16> zeroinitializer, <8 x i16> addrspace(5)* %arraydecay{{[0-9]+}}, align 16 -// CHECK: store volatile <16 x i16> zeroinitializer, <16 x i16> addrspace(5)* %arraydecay{{[0-9]+}}, align 32 -// CHECK: store volatile i32 0, i32 addrspace(5)* %arraydecay{{[0-9]+}}, align 4 -// CHECK: store volatile <2 x i32> zeroinitializer, <2 x i32> addrspace(5)* %arraydecay{{[0-9]+}}, align 8 -// CHECK: store volatile <4 x i32> , <4 x i32> addrspace(5)* %storetmp16, align 16 -// CHECK: store volatile <4 x i32> zeroinitializer, <4 x i32> addrspace(5)* %arraydecay{{[0-9]+}}, align 16 -// CHECK: store volatile <8 x i32> zeroinitializer, <8 x i32> addrspace(5)* %arraydecay{{[0-9]+}}, align 32 -// CHECK: store volatile <16 x i32> zeroinitializer, <16 x i32> addrspace(5)* %arraydecay{{[0-9]+}}, align 64 -// CHECK: store volatile i64 0, i64 addrspace(5)* %arraydecay{{[0-9]+}}, align 8 -// CHECK: store volatile <2 x i64> zeroinitializer, <2 x i64> addrspace(5)* %arraydecay{{[0-9]+}}, align 16 -// CHECK: store volatile <4 x i64> , <4 x i64> addrspace(5)* %storetmp23, align 32 -// CHECK: store volatile <4 x i64> zeroinitializer, <4 x i64> addrspace(5)* %arraydecay{{[0-9]+}}, align 32 -// CHECK: store volatile <8 x i64> zeroinitializer, <8 x i64> addrspace(5)* %arraydecay{{[0-9]+}}, align 64 -// CHECK: store volatile <16 x i64> zeroinitializer, <16 x i64> addrspace(5)* %arraydecay{{[0-9]+}}, align 128 -// CHECK: store volatile half 0xH0000, half addrspace(5)* %arraydecay{{[0-9]+}}, align 2 -// CHECK: store volatile <2 x half> zeroinitializer, <2 x half> addrspace(5)* %arraydecay{{[0-9]+}}, align 4 -// CHECK: store volatile <4 x half> , <4 x half> addrspace(5)* %storetmp{{[0-9]+}}, align 8 -// CHECK: store volatile <4 x half> zeroinitializer, <4 x half> addrspace(5)* %arraydecay{{[0-9]+}}, align 8 -// CHECK: store volatile <8 x half> zeroinitializer, <8 x half> addrspace(5)* %arraydecay{{[0-9]+}}, align 16 -// CHECK: store volatile <16 x half> zeroinitializer, <16 x half> addrspace(5)* %arraydecay{{[0-9]+}}, align 32 -// CHECK: store volatile float 0.000000e+00, float addrspace(5)* %arraydecay34, align 4 -// CHECK: store volatile <2 x float> zeroinitializer, <2 x float> addrspace(5)* %arraydecay{{[0-9]+}}, align 8 -// CHECK: store volatile <4 x float> , <4 x float> addrspace(5)* %storetmp{{[0-9]+}}, align 16 -// CHECK: store volatile <4 x float> zeroinitializer, <4 x float> addrspace(5)* %arraydecay{{[0-9]+}}, align 16 -// CHECK: store volatile <8 x float> zeroinitializer, <8 x float> addrspace(5)* %arraydecay{{[0-9]+}}, align 32 -// CHECK: store volatile <16 x float> zeroinitializer, <16 x float> addrspace(5)* %arraydecay{{[0-9]+}}, align 64 -// CHECK: store volatile double 0.000000e+00, double addrspace(5)* %arraydecay{{[0-9]+}}, align 8 -// CHECK: store volatile <2 x double> zeroinitializer, <2 x double> addrspace(5)* %arraydecay{{[0-9]+}}, align 16 -// CHECK: store volatile <4 x double> , <4 x double> addrspace(5)* %storetmp{{[0-9]+}}, align 32 -// CHECK: store volatile <4 x double> zeroinitializer, <4 x double> addrspace(5)* %arraydecay{{[0-9]+}}, align 32 -// CHECK: store volatile <8 x double> zeroinitializer, <8 x double> addrspace(5)* %arraydecay{{[0-9]+}}, align 64 -// CHECK: store volatile <16 x double> zeroinitializer, <16 x double> addrspace(5)* %arraydecay{{[0-9]+}}, align 128 +// CHECK: store volatile i8 0, ptr addrspace(5) %arraydecay, align 1 +// CHECK: store volatile <2 x i8> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 2 +// CHECK: store volatile <4 x i8> , ptr addrspace(5) %arraydecay{{[0-9]+}}, align 4 +// CHECK: store volatile <4 x i8> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 4 +// CHECK: store volatile <8 x i8> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 8 +// CHECK: store volatile <16 x i8> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 16 +// CHECK: store volatile i16 0, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 2 +// CHECK: store volatile <2 x i16> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 4 +// CHECK: store volatile <4 x i16> , ptr addrspace(5) %arraydecay{{[0-9]+}}, align 8 +// CHECK: store volatile <4 x i16> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 8 +// CHECK: store volatile <8 x i16> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 16 +// 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 <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 +// CHECK: store volatile i64 0, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 8 +// CHECK: store volatile <2 x i64> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 16 +// CHECK: store volatile <4 x i64> , ptr addrspace(5) %arraydecay{{[0-9]+}}, align 32 +// CHECK: store volatile <4 x i64> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 32 +// CHECK: store volatile <8 x i64> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 64 +// CHECK: store volatile <16 x i64> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 128 +// CHECK: store volatile half 0xH0000, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 2 +// CHECK: store volatile <2 x half> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 4 +// CHECK: store volatile <4 x half> , ptr addrspace(5) %arraydecay{{[0-9]+}}, align 8 +// CHECK: store volatile <4 x half> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 8 +// CHECK: store volatile <8 x half> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 16 +// 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 <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 +// CHECK: store volatile double 0.000000e+00, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 8 +// CHECK: store volatile <2 x double> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 16 +// CHECK: store volatile <4 x double> , ptr addrspace(5) %arraydecay{{[0-9]+}}, align 32 +// CHECK: store volatile <4 x double> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 32 +// CHECK: store volatile <8 x double> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 64 +// CHECK: store volatile <16 x double> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 128 kernel void private_memory_alignment_alloca() { volatile private char private_i8[4]; diff --git a/clang/test/CodeGenOpenCL/amdgpu-features.cl b/clang/test/CodeGenOpenCL/amdgpu-features.cl index e000239cd03fe..efa5759558cc5 100644 --- a/clang/test/CodeGenOpenCL/amdgpu-features.cl +++ b/clang/test/CodeGenOpenCL/amdgpu-features.cl @@ -30,6 +30,8 @@ // RUN: %clang_cc1 -triple amdgcn -target-cpu gfx90a -S -emit-llvm -o - %s | FileCheck --check-prefix=GFX90A %s // RUN: %clang_cc1 -triple amdgcn -target-cpu gfx90c -S -emit-llvm -o - %s | FileCheck --check-prefix=GFX90C %s // RUN: %clang_cc1 -triple amdgcn -target-cpu gfx940 -S -emit-llvm -o - %s | FileCheck --check-prefix=GFX940 %s +// RUN: %clang_cc1 -triple amdgcn -target-cpu gfx941 -S -emit-llvm -o - %s | FileCheck --check-prefix=GFX941 %s +// RUN: %clang_cc1 -triple amdgcn -target-cpu gfx942 -S -emit-llvm -o - %s | FileCheck --check-prefix=GFX942 %s // RUN: %clang_cc1 -triple amdgcn -target-cpu gfx1010 -S -emit-llvm -o - %s | FileCheck --check-prefix=GFX1010 %s // RUN: %clang_cc1 -triple amdgcn -target-cpu gfx1011 -S -emit-llvm -o - %s | FileCheck --check-prefix=GFX1011 %s // RUN: %clang_cc1 -triple amdgcn -target-cpu gfx1012 -S -emit-llvm -o - %s | FileCheck --check-prefix=GFX1012 %s @@ -75,6 +77,8 @@ // GFX90A: "target-features"="+16-bit-insts,+atomic-buffer-global-pk-add-f16-insts,+atomic-fadd-rtn-insts,+ci-insts,+dl-insts,+dot1-insts,+dot10-insts,+dot2-insts,+dot3-insts,+dot4-insts,+dot5-insts,+dot6-insts,+dot7-insts,+dpp,+gfx8-insts,+gfx9-insts,+gfx90a-insts,+mai-insts,+s-memrealtime,+s-memtime-inst,+wavefrontsize64" // GFX90C: "target-features"="+16-bit-insts,+ci-insts,+dpp,+gfx8-insts,+gfx9-insts,+s-memrealtime,+s-memtime-inst,+wavefrontsize64" // GFX940: "target-features"="+16-bit-insts,+atomic-buffer-global-pk-add-f16-insts,+atomic-ds-pk-add-16-insts,+atomic-fadd-rtn-insts,+atomic-flat-pk-add-16-insts,+atomic-global-pk-add-bf16-inst,+ci-insts,+dl-insts,+dot1-insts,+dot10-insts,+dot2-insts,+dot3-insts,+dot4-insts,+dot5-insts,+dot6-insts,+dot7-insts,+dpp,+fp8-insts,+gfx8-insts,+gfx9-insts,+gfx90a-insts,+gfx940-insts,+mai-insts,+s-memrealtime,+s-memtime-inst,+wavefrontsize64" +// GFX941: "target-features"="+16-bit-insts,+atomic-buffer-global-pk-add-f16-insts,+atomic-ds-pk-add-16-insts,+atomic-fadd-rtn-insts,+atomic-flat-pk-add-16-insts,+atomic-global-pk-add-bf16-inst,+ci-insts,+dl-insts,+dot1-insts,+dot10-insts,+dot2-insts,+dot3-insts,+dot4-insts,+dot5-insts,+dot6-insts,+dot7-insts,+dpp,+fp8-insts,+gfx8-insts,+gfx9-insts,+gfx90a-insts,+gfx940-insts,+mai-insts,+s-memrealtime,+s-memtime-inst,+wavefrontsize64" +// GFX942: "target-features"="+16-bit-insts,+atomic-buffer-global-pk-add-f16-insts,+atomic-ds-pk-add-16-insts,+atomic-fadd-rtn-insts,+atomic-flat-pk-add-16-insts,+atomic-global-pk-add-bf16-inst,+ci-insts,+dl-insts,+dot1-insts,+dot10-insts,+dot2-insts,+dot3-insts,+dot4-insts,+dot5-insts,+dot6-insts,+dot7-insts,+dpp,+fp8-insts,+gfx8-insts,+gfx9-insts,+gfx90a-insts,+gfx940-insts,+mai-insts,+s-memrealtime,+s-memtime-inst,+wavefrontsize64" // GFX1010: "target-features"="+16-bit-insts,+ci-insts,+dl-insts,+dpp,+gfx10-insts,+gfx8-insts,+gfx9-insts,+s-memrealtime,+s-memtime-inst,+wavefrontsize32" // GFX1011: "target-features"="+16-bit-insts,+ci-insts,+dl-insts,+dot1-insts,+dot10-insts,+dot2-insts,+dot5-insts,+dot6-insts,+dot7-insts,+dpp,+gfx10-insts,+gfx8-insts,+gfx9-insts,+s-memrealtime,+s-memtime-inst,+wavefrontsize32" // GFX1012: "target-features"="+16-bit-insts,+ci-insts,+dl-insts,+dot1-insts,+dot10-insts,+dot2-insts,+dot5-insts,+dot6-insts,+dot7-insts,+dpp,+gfx10-insts,+gfx8-insts,+gfx9-insts,+s-memrealtime,+s-memtime-inst,+wavefrontsize32" diff --git a/clang/test/CodeGenOpenCL/atomic-ops-libcall.cl b/clang/test/CodeGenOpenCL/atomic-ops-libcall.cl index 6dd790ba64981..2f020c2108212 100644 --- a/clang/test/CodeGenOpenCL/atomic-ops-libcall.cl +++ b/clang/test/CodeGenOpenCL/atomic-ops-libcall.cl @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -no-opaque-pointers < %s -cl-std=CL2.0 -triple spir64 -emit-llvm | FileCheck -check-prefix=SPIR %s -// RUN: %clang_cc1 -no-opaque-pointers < %s -cl-std=CL2.0 -triple armv5e-none-linux-gnueabi -emit-llvm | FileCheck -check-prefix=ARM %s +// RUN: %clang_cc1 < %s -cl-std=CL2.0 -triple spir64 -emit-llvm | FileCheck -check-prefix=SPIR %s +// RUN: %clang_cc1 < %s -cl-std=CL2.0 -triple armv5e-none-linux-gnueabi -emit-llvm | FileCheck -check-prefix=ARM %s typedef enum memory_order { memory_order_relaxed = __ATOMIC_RELAXED, memory_order_acquire = __ATOMIC_ACQUIRE, @@ -20,63 +20,63 @@ typedef enum memory_scope { void f(atomic_int *i, global atomic_int *gi, local atomic_int *li, private atomic_int *pi, atomic_uint *ui, int cmp, int order, int scope) { int x; - // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_load_4(i8 addrspace(4)* noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_load_4(i8* noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_load_4(ptr addrspace(4) noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_load_4(ptr noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_work_group); - // SPIR: call void @__opencl_atomic_store_4(i8 addrspace(4)* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: call void @__opencl_atomic_store_4(i8* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: call void @__opencl_atomic_store_4(ptr addrspace(4) noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // ARM: call void @__opencl_atomic_store_4(ptr noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) __opencl_atomic_store(i, 1, memory_order_seq_cst, memory_scope_work_group); - // SPIR: %[[GP:[0-9]+]] = addrspacecast i8 addrspace(1)* {{%[0-9]+}} to i8 addrspace(4)* - // SPIR: call void @__opencl_atomic_store_4(i8 addrspace(4)* noundef %[[GP]], i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: call void @__opencl_atomic_store_4(i8* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: %[[GP:[0-9]+]] = addrspacecast ptr addrspace(1) {{%[0-9]+}} to ptr addrspace(4) + // SPIR: call void @__opencl_atomic_store_4(ptr addrspace(4) noundef %[[GP]], i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // ARM: call void @__opencl_atomic_store_4(ptr noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) __opencl_atomic_store(gi, 1, memory_order_seq_cst, memory_scope_work_group); - // SPIR: %[[GP:[0-9]+]] = addrspacecast i8 addrspace(3)* {{%[0-9]+}} to i8 addrspace(4)* - // SPIR: call void @__opencl_atomic_store_4(i8 addrspace(4)* noundef %[[GP]], i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: call void @__opencl_atomic_store_4(i8* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: %[[GP:[0-9]+]] = addrspacecast ptr addrspace(3) {{%[0-9]+}} to ptr addrspace(4) + // SPIR: call void @__opencl_atomic_store_4(ptr addrspace(4) noundef %[[GP]], i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // ARM: call void @__opencl_atomic_store_4(ptr noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) __opencl_atomic_store(li, 1, memory_order_seq_cst, memory_scope_work_group); - // SPIR: %[[GP:[0-9]+]] = addrspacecast i8* {{%[0-9]+}} to i8 addrspace(4)* - // SPIR: call void @__opencl_atomic_store_4(i8 addrspace(4)* noundef %[[GP]], i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: call void @__opencl_atomic_store_4(i8* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: %[[GP:[0-9]+]] = addrspacecast ptr {{%[0-9]+}} to ptr addrspace(4) + // SPIR: call void @__opencl_atomic_store_4(ptr addrspace(4) noundef %[[GP]], i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // ARM: call void @__opencl_atomic_store_4(ptr noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) __opencl_atomic_store(pi, 1, memory_order_seq_cst, memory_scope_work_group); - // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_add_4(i8 addrspace(4)* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_add_4(i8* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_add_4(ptr addrspace(4) noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_add_4(ptr noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) x = __opencl_atomic_fetch_add(i, 3, memory_order_seq_cst, memory_scope_work_group); - // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_min_4(i8 addrspace(4)* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_min_4(i8* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_min_4(ptr addrspace(4) noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_min_4(ptr noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) x = __opencl_atomic_fetch_min(i, 3, memory_order_seq_cst, memory_scope_work_group); - // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_umin_4(i8 addrspace(4)* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_umin_4(i8* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_umin_4(ptr addrspace(4) noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_umin_4(ptr noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) x = __opencl_atomic_fetch_min(ui, 3, memory_order_seq_cst, memory_scope_work_group); - // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8 addrspace(4)* noundef {{%[0-9]+}}, i8 addrspace(4)* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 1) - // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8* noundef {{%[0-9]+}}, i8* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 1) + // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr addrspace(4) noundef {{%[0-9]+}}, ptr addrspace(4) noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 1) + // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr noundef {{%[0-9]+}}, ptr noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 1) x = __opencl_atomic_compare_exchange_strong(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); - // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8 addrspace(4)* noundef {{%[0-9]+}}, i8 addrspace(4)* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 1) - // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8* noundef {{%[0-9]+}}, i8* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 1) + // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr addrspace(4) noundef {{%[0-9]+}}, ptr addrspace(4) noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 1) + // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr noundef {{%[0-9]+}}, ptr noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 1) x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); - // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8 addrspace(4)* noundef {{%[0-9]+}}, i8 addrspace(4)* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 2) - // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8* noundef {{%[0-9]+}}, i8* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 2) + // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr addrspace(4) noundef {{%[0-9]+}}, ptr addrspace(4) noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 2) + // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr noundef {{%[0-9]+}}, ptr noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 2) x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_device); - // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8 addrspace(4)* noundef {{%[0-9]+}}, i8 addrspace(4)* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 3) - // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8* noundef {{%[0-9]+}}, i8* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 3) + // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr addrspace(4) noundef {{%[0-9]+}}, ptr addrspace(4) noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 3) + // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr noundef {{%[0-9]+}}, ptr noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 3) x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_all_svm_devices); #ifdef cl_khr_subgroups - // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8 addrspace(4)* noundef {{%[0-9]+}}, i8 addrspace(4)* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 4) + // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr addrspace(4) noundef {{%[0-9]+}}, ptr addrspace(4) noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 4) x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_sub_group); #endif - // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8 addrspace(4)* noundef {{%[0-9]+}}, i8 addrspace(4)* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}) - // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8* noundef {{%[0-9]+}}, i8* noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}) + // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr addrspace(4) noundef {{%[0-9]+}}, ptr addrspace(4) noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}) + // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr noundef {{%[0-9]+}}, ptr noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}) x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, order, order, scope); } diff --git a/clang/test/CodeGenOpenCL/atomic-ops.cl b/clang/test/CodeGenOpenCL/atomic-ops.cl index 383dfdf5f5357..5e2de38ac3d3e 100644 --- a/clang/test/CodeGenOpenCL/atomic-ops.cl +++ b/clang/test/CodeGenOpenCL/atomic-ops.cl @@ -1,9 +1,9 @@ -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=CL2.0 -emit-llvm -O0 -o - -triple=amdgcn-amd-amdhsa \ +// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -O0 -o - -triple=amdgcn-amd-amdhsa \ // RUN: | FileCheck %s // Also test serialization of atomic operations here, to avoid duplicating the test. -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=CL2.0 -emit-pch -O0 -o %t -triple=amdgcn-amd-amdhsa -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=CL2.0 -include-pch %t -O0 -triple=amdgcn-amd-amdhsa \ +// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-pch -O0 -o %t -triple=amdgcn-amd-amdhsa +// RUN: %clang_cc1 %s -cl-std=CL2.0 -include-pch %t -O0 -triple=amdgcn-amd-amdhsa \ // RUN: -emit-llvm -o - | FileCheck %s #ifndef ALREADY_INCLUDED @@ -37,58 +37,58 @@ atomic_int j; void fi1(atomic_int *i) { // CHECK-LABEL: @fi1 - // CHECK: load atomic i32, i32* %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 + // CHECK: load atomic i32, ptr %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 int x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_work_group); - // CHECK: load atomic i32, i32* %{{[.0-9A-Z_a-z]+}} syncscope("agent") seq_cst, align 4 + // CHECK: load atomic i32, ptr %{{[.0-9A-Z_a-z]+}} syncscope("agent") seq_cst, align 4 x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_device); - // CHECK: load atomic i32, i32* %{{[.0-9A-Z_a-z]+}} seq_cst, align 4 + // CHECK: load atomic i32, ptr %{{[.0-9A-Z_a-z]+}} seq_cst, align 4 x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_all_svm_devices); - // CHECK: load atomic i32, i32* %{{[.0-9A-Z_a-z]+}} syncscope("wavefront") seq_cst, align 4 + // CHECK: load atomic i32, ptr %{{[.0-9A-Z_a-z]+}} syncscope("wavefront") seq_cst, align 4 x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_sub_group); } void fi2(atomic_int *i) { // CHECK-LABEL: @fi2 - // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, i32* %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 + // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, ptr %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 __opencl_atomic_store(i, 1, memory_order_seq_cst, memory_scope_work_group); } void test_addr(global atomic_int *ig, private atomic_int *ip, local atomic_int *il) { // CHECK-LABEL: @test_addr - // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, i32 addrspace(1)* %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 + // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, ptr addrspace(1) %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 __opencl_atomic_store(ig, 1, memory_order_seq_cst, memory_scope_work_group); - // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, i32 addrspace(5)* %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 + // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, ptr addrspace(5) %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 __opencl_atomic_store(ip, 1, memory_order_seq_cst, memory_scope_work_group); - // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, i32 addrspace(3)* %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 + // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, ptr addrspace(3) %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 __opencl_atomic_store(il, 1, memory_order_seq_cst, memory_scope_work_group); } void fi3(atomic_int *i, atomic_uint *ui) { // CHECK-LABEL: @fi3 - // CHECK: atomicrmw and i32* %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 + // CHECK: atomicrmw and ptr %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 int x = __opencl_atomic_fetch_and(i, 1, memory_order_seq_cst, memory_scope_work_group); - // CHECK: atomicrmw min i32* %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 + // CHECK: atomicrmw min ptr %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 x = __opencl_atomic_fetch_min(i, 1, memory_order_seq_cst, memory_scope_work_group); - // CHECK: atomicrmw max i32* %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 + // CHECK: atomicrmw max ptr %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 x = __opencl_atomic_fetch_max(i, 1, memory_order_seq_cst, memory_scope_work_group); - // CHECK: atomicrmw umin i32* %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 + // CHECK: atomicrmw umin ptr %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 x = __opencl_atomic_fetch_min(ui, 1, memory_order_seq_cst, memory_scope_work_group); - // CHECK: atomicrmw umax i32* %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 + // CHECK: atomicrmw umax ptr %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4 x = __opencl_atomic_fetch_max(ui, 1, memory_order_seq_cst, memory_scope_work_group); } bool fi4(atomic_int *i) { // CHECK-LABEL: @fi4( - // CHECK: [[PAIR:%[.0-9A-Z_a-z]+]] = cmpxchg i32* [[PTR:%[.0-9A-Z_a-z]+]], i32 [[EXPECTED:%[.0-9A-Z_a-z]+]], i32 [[DESIRED:%[.0-9A-Z_a-z]+]] syncscope("workgroup-one-as") acquire acquire, align 4 + // CHECK: [[PAIR:%[.0-9A-Z_a-z]+]] = cmpxchg ptr [[PTR:%[.0-9A-Z_a-z]+]], i32 [[EXPECTED:%[.0-9A-Z_a-z]+]], i32 [[DESIRED:%[.0-9A-Z_a-z]+]] syncscope("workgroup-one-as") acquire acquire, align 4 // CHECK: [[OLD:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 0 // CHECK: [[CMP:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 1 // CHECK: br i1 [[CMP]], label %[[STORE_EXPECTED:[.0-9A-Z_a-z]+]], label %[[CONTINUE:[.0-9A-Z_a-z]+]] @@ -105,16 +105,16 @@ void fi5(atomic_int *i, int scope) { // CHECK-NEXT: i32 4, label %[[opencl_subgroup:.*]] // CHECK-NEXT: ] // CHECK: [[opencl_workgroup]]: - // CHECK: load atomic i32, i32* %{{.*}} syncscope("workgroup") seq_cst, align 4 + // CHECK: load atomic i32, ptr %{{.*}} syncscope("workgroup") seq_cst, align 4 // CHECK: br label %[[continue:.*]] // CHECK: [[opencl_device]]: - // CHECK: load atomic i32, i32* %{{.*}} syncscope("agent") seq_cst, align 4 + // CHECK: load atomic i32, ptr %{{.*}} syncscope("agent") seq_cst, align 4 // CHECK: br label %[[continue]] // CHECK: [[opencl_allsvmdevices]]: - // CHECK: load atomic i32, i32* %{{.*}} seq_cst, align 4 + // CHECK: load atomic i32, ptr %{{.*}} seq_cst, align 4 // CHECK: br label %[[continue]] // CHECK: [[opencl_subgroup]]: - // CHECK: load atomic i32, i32* %{{.*}} syncscope("wavefront") seq_cst, align 4 + // CHECK: load atomic i32, ptr %{{.*}} syncscope("wavefront") seq_cst, align 4 // CHECK: br label %[[continue]] // CHECK: [[continue]]: int x = __opencl_atomic_load(i, memory_order_seq_cst, scope); @@ -146,35 +146,35 @@ void fi6(atomic_int *i, int order, int scope) { // CHECK-NEXT: i32 4, label %[[SEQ_SUB:.*]] // CHECK-NEXT: ] // CHECK: [[MON_WG]]: - // CHECK: load atomic i32, i32* %{{.*}} syncscope("workgroup-one-as") monotonic, align 4 + // CHECK: load atomic i32, ptr %{{.*}} syncscope("workgroup-one-as") monotonic, align 4 // CHECK: [[MON_DEV]]: - // CHECK: load atomic i32, i32* %{{.*}} syncscope("agent-one-as") monotonic, align 4 + // CHECK: load atomic i32, ptr %{{.*}} syncscope("agent-one-as") monotonic, align 4 // CHECK: [[MON_ALL]]: - // CHECK: load atomic i32, i32* %{{.*}} monotonic, align 4 + // CHECK: load atomic i32, ptr %{{.*}} monotonic, align 4 // CHECK: [[MON_SUB]]: - // CHECK: load atomic i32, i32* %{{.*}} syncscope("wavefront-one-as") monotonic, align 4 + // CHECK: load atomic i32, ptr %{{.*}} syncscope("wavefront-one-as") monotonic, align 4 // CHECK: [[ACQ_WG]]: - // CHECK: load atomic i32, i32* %{{.*}} syncscope("workgroup-one-as") acquire, align 4 + // CHECK: load atomic i32, ptr %{{.*}} syncscope("workgroup-one-as") acquire, align 4 // CHECK: [[ACQ_DEV]]: - // CHECK: load atomic i32, i32* %{{.*}} syncscope("agent-one-as") acquire, align 4 + // CHECK: load atomic i32, ptr %{{.*}} syncscope("agent-one-as") acquire, align 4 // CHECK: [[ACQ_ALL]]: - // CHECK: load atomic i32, i32* %{{.*}} acquire, align 4 + // CHECK: load atomic i32, ptr %{{.*}} acquire, align 4 // CHECK: [[ACQ_SUB]]: - // CHECK: load atomic i32, i32* %{{.*}} syncscope("wavefront-one-as") acquire, align 4 + // CHECK: load atomic i32, ptr %{{.*}} syncscope("wavefront-one-as") acquire, align 4 // CHECK: [[SEQ_WG]]: - // CHECK: load atomic i32, i32* %{{.*}} syncscope("workgroup") seq_cst, align 4 + // CHECK: load atomic i32, ptr %{{.*}} syncscope("workgroup") seq_cst, align 4 // CHECK: [[SEQ_DEV]]: - // CHECK: load atomic i32, i32* %{{.*}} syncscope("agent") seq_cst, align 4 + // CHECK: load atomic i32, ptr %{{.*}} syncscope("agent") seq_cst, align 4 // CHECK: [[SEQ_ALL]]: - // CHECK: load atomic i32, i32* %{{.*}} seq_cst, align 4 + // CHECK: load atomic i32, ptr %{{.*}} seq_cst, align 4 // CHECK: [[SEQ_SUB]]: - // CHECK: load atomic i32, i32* %{{.*}} syncscope("wavefront") seq_cst, align 4 + // CHECK: load atomic i32, ptr %{{.*}} syncscope("wavefront") seq_cst, align 4 int x = __opencl_atomic_load(i, order, scope); } float ff1(global atomic_float *d) { // CHECK-LABEL: @ff1 - // CHECK: load atomic i32, i32 addrspace(1)* {{.*}} syncscope("workgroup-one-as") monotonic, align 4 + // CHECK: load atomic i32, ptr addrspace(1) {{.*}} syncscope("workgroup-one-as") monotonic, align 4 return __opencl_atomic_load(d, memory_order_relaxed, memory_scope_work_group); } @@ -186,19 +186,19 @@ void ff2(atomic_float *d) { float ff3(atomic_float *d) { // CHECK-LABEL: @ff3 - // CHECK: atomicrmw xchg i32* {{.*}} syncscope("workgroup") seq_cst, align 4 + // CHECK: atomicrmw xchg ptr {{.*}} syncscope("workgroup") seq_cst, align 4 return __opencl_atomic_exchange(d, 2, memory_order_seq_cst, memory_scope_work_group); } float ff4(global atomic_float *d, float a) { // CHECK-LABEL: @ff4 - // CHECK: atomicrmw fadd float addrspace(1)* {{.*}} syncscope("workgroup-one-as") monotonic + // CHECK: atomicrmw fadd ptr addrspace(1) {{.*}} syncscope("workgroup-one-as") monotonic return __opencl_atomic_fetch_add(d, a, memory_order_relaxed, memory_scope_work_group); } float ff5(global atomic_double *d, double a) { // CHECK-LABEL: @ff5 - // CHECK: atomicrmw fadd double addrspace(1)* {{.*}} syncscope("workgroup-one-as") monotonic + // CHECK: atomicrmw fadd ptr addrspace(1) {{.*}} syncscope("workgroup-one-as") monotonic return __opencl_atomic_fetch_add(d, a, memory_order_relaxed, memory_scope_work_group); } @@ -215,10 +215,10 @@ void atomic_init_foo() // CHECK-LABEL: @failureOrder void failureOrder(atomic_int *ptr, int *ptr2) { - // CHECK: cmpxchg i32* {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z_.]+}} syncscope("workgroup-one-as") acquire monotonic, align 4 + // CHECK: cmpxchg ptr {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z_.]+}} syncscope("workgroup-one-as") acquire monotonic, align 4 __opencl_atomic_compare_exchange_strong(ptr, ptr2, 43, memory_order_acquire, memory_order_relaxed, memory_scope_work_group); - // CHECK: cmpxchg weak i32* {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z_.]+}} syncscope("workgroup") seq_cst acquire, align 4 + // CHECK: cmpxchg weak ptr {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z_.]+}} syncscope("workgroup") seq_cst acquire, align 4 __opencl_atomic_compare_exchange_weak(ptr, ptr2, 43, memory_order_seq_cst, memory_order_acquire, memory_scope_work_group); } @@ -330,13 +330,13 @@ void generalFailureOrder(atomic_int *ptr, int *ptr2, int success, int fail) { int test_volatile(volatile atomic_int *i) { // CHECK-LABEL: @test_volatile - // CHECK: %[[i_addr:.*]] = alloca i32 + // CHECK: %[[i_addr:.*]] = alloca ptr // CHECK-NEXT: %[[atomicdst:.*]] = alloca i32 - // CHECK-NEXT: store i32* %i, i32* addrspace(5)* %[[i_addr]] - // CHECK-NEXT: %[[addr:.*]] = load i32*, i32* addrspace(5)* %[[i_addr]] - // CHECK-NEXT: %[[res:.*]] = load atomic volatile i32, i32* %[[addr]] syncscope("workgroup") seq_cst, align 4 - // CHECK-NEXT: store i32 %[[res]], i32 addrspace(5)* %[[atomicdst]] - // CHECK-NEXT: %[[retval:.*]] = load i32, i32 addrspace(5)* %[[atomicdst]] + // CHECK-NEXT: store ptr %i, ptr addrspace(5) %[[i_addr]] + // CHECK-NEXT: %[[addr:.*]] = load ptr, ptr addrspace(5) %[[i_addr]] + // CHECK-NEXT: %[[res:.*]] = load atomic volatile i32, ptr %[[addr]] syncscope("workgroup") seq_cst, align 4 + // CHECK-NEXT: store i32 %[[res]], ptr addrspace(5) %[[atomicdst]] + // CHECK-NEXT: %[[retval:.*]] = load i32, ptr addrspace(5) %[[atomicdst]] // CHECK-NEXT: ret i32 %[[retval]] return __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_work_group); } diff --git a/clang/test/CodeGenOpenCL/blocks.cl b/clang/test/CodeGenOpenCL/blocks.cl index c5bc5781d1a1b..227b7db9595c8 100644 --- a/clang/test/CodeGenOpenCL/blocks.cl +++ b/clang/test/CodeGenOpenCL/blocks.cl @@ -1,20 +1,18 @@ -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=CL2.0 -emit-llvm -o - -O0 -triple spir-unknown-unknown | FileCheck -check-prefixes=COMMON,SPIR %s -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=CL2.0 -emit-llvm -o - -O0 -triple amdgcn-amd-amdhsa | FileCheck -check-prefixes=COMMON,AMDGCN %s -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=CL2.0 -emit-llvm -o - -O0 -debug-info-kind=limited -triple spir-unknown-unknown | FileCheck -check-prefixes=CHECK-DEBUG %s -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=CL2.0 -emit-llvm -o - -O0 -debug-info-kind=limited -triple amdgcn-amd-amdhsa | FileCheck -check-prefixes=CHECK-DEBUG %s -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=CL3.0 -cl-ext=-all,+__opencl_c_device_enqueue,+__opencl_c_generic_address_space,+__opencl_c_program_scope_global_variables -emit-llvm -o - -O0 -triple spir-unknown-unknown | FileCheck -check-prefixes=COMMON,SPIR %s -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=CL3.0 -cl-ext=-all,+__opencl_c_device_enqueue,+__opencl_c_generic_address_space,+__opencl_c_program_scope_global_variables -emit-llvm -o - -O0 -triple amdgcn-amd-amdhsa | FileCheck -check-prefixes=COMMON,AMDGCN %s -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=CL3.0 -cl-ext=-all,+__opencl_c_device_enqueue,+__opencl_c_generic_address_space,+__opencl_c_program_scope_global_variables -emit-llvm -o - -O0 -debug-info-kind=limited -triple spir-unknown-unknown | FileCheck -check-prefixes=CHECK-DEBUG %s -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=CL3.0 -cl-ext=-all,+__opencl_c_device_enqueue,+__opencl_c_generic_address_space,+__opencl_c_program_scope_global_variables -emit-llvm -o - -O0 -debug-info-kind=limited -triple amdgcn-amd-amdhsa | FileCheck -check-prefixes=CHECK-DEBUG %s +// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -o - -O0 -triple spir-unknown-unknown | FileCheck -check-prefixes=COMMON,SPIR %s +// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -o - -O0 -triple amdgcn-amd-amdhsa | FileCheck -check-prefixes=COMMON,AMDGCN %s +// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -o - -O0 -debug-info-kind=limited -triple spir-unknown-unknown | FileCheck -check-prefixes=CHECK-DEBUG %s +// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -o - -O0 -debug-info-kind=limited -triple amdgcn-amd-amdhsa | FileCheck -check-prefixes=CHECK-DEBUG %s +// RUN: %clang_cc1 %s -cl-std=CL3.0 -cl-ext=-all,+__opencl_c_device_enqueue,+__opencl_c_generic_address_space,+__opencl_c_program_scope_global_variables -emit-llvm -o - -O0 -triple spir-unknown-unknown | FileCheck -check-prefixes=COMMON,SPIR %s +// RUN: %clang_cc1 %s -cl-std=CL3.0 -cl-ext=-all,+__opencl_c_device_enqueue,+__opencl_c_generic_address_space,+__opencl_c_program_scope_global_variables -emit-llvm -o - -O0 -triple amdgcn-amd-amdhsa | FileCheck -check-prefixes=COMMON,AMDGCN %s +// RUN: %clang_cc1 %s -cl-std=CL3.0 -cl-ext=-all,+__opencl_c_device_enqueue,+__opencl_c_generic_address_space,+__opencl_c_program_scope_global_variables -emit-llvm -o - -O0 -debug-info-kind=limited -triple spir-unknown-unknown | FileCheck -check-prefixes=CHECK-DEBUG %s +// RUN: %clang_cc1 %s -cl-std=CL3.0 -cl-ext=-all,+__opencl_c_device_enqueue,+__opencl_c_generic_address_space,+__opencl_c_program_scope_global_variables -emit-llvm -o - -O0 -debug-info-kind=limited -triple amdgcn-amd-amdhsa | FileCheck -check-prefixes=CHECK-DEBUG %s -// SPIR: %struct.__opencl_block_literal_generic = type { i32, i32, i8 addrspace(4)* } -// AMDGCN: %struct.__opencl_block_literal_generic = type { i32, i32, i8* } -// SPIR: @__block_literal_global = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 12, i32 4, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*, i8 addrspace(3)*)* @block_A_block_invoke to i8*) to i8 addrspace(4)*) } -// AMDGCN: @__block_literal_global = internal addrspace(1) constant { i32, i32, i8* } { i32 16, i32 8, i8* bitcast (void (i8*, i8 addrspace(3)*)* @block_A_block_invoke to i8*) } +// SPIR: @__block_literal_global = internal addrspace(1) constant { i32, i32, ptr addrspace(4) } { i32 12, i32 4, ptr addrspace(4) addrspacecast (ptr @block_A_block_invoke to ptr addrspace(4)) } +// AMDGCN: @__block_literal_global = internal addrspace(1) constant { i32, i32, ptr } { i32 16, i32 8, ptr @block_A_block_invoke } // COMMON-NOT: .str -// SPIR-LABEL: define internal {{.*}}void @block_A_block_invoke(i8 addrspace(4)* noundef %.block_descriptor, i8 addrspace(3)* noundef %a) -// AMDGCN-LABEL: define internal {{.*}}void @block_A_block_invoke(i8* noundef %.block_descriptor, i8 addrspace(3)* noundef %a) +// SPIR-LABEL: define internal {{.*}}void @block_A_block_invoke(ptr addrspace(4) noundef %.block_descriptor, ptr addrspace(3) noundef %a) +// AMDGCN-LABEL: define internal {{.*}}void @block_A_block_invoke(ptr noundef %.block_descriptor, ptr addrspace(3) noundef %a) void (^block_A)(local void *) = ^(local void *a) { return; }; @@ -26,36 +24,32 @@ void foo(){ // COMMON-NOT: %block.flags // COMMON-NOT: %block.reserved // COMMON-NOT: %block.descriptor - // SPIR: %[[block_size:.*]] = getelementptr inbounds <{ i32, i32, i8 addrspace(4)*, i32 }>, <{ i32, i32, i8 addrspace(4)*, i32 }>* %block, i32 0, i32 0 - // AMDGCN: %[[block_size:.*]] = getelementptr inbounds <{ i32, i32, i8*, i32 }>, <{ i32, i32, i8*, i32 }> addrspace(5)* %block, i32 0, i32 0 - // SPIR: store i32 16, i32* %[[block_size]] - // AMDGCN: store i32 20, i32 addrspace(5)* %[[block_size]] - // SPIR: %[[block_align:.*]] = getelementptr inbounds <{ i32, i32, i8 addrspace(4)*, i32 }>, <{ i32, i32, i8 addrspace(4)*, i32 }>* %block, i32 0, i32 1 - // AMDGCN: %[[block_align:.*]] = getelementptr inbounds <{ i32, i32, i8*, i32 }>, <{ i32, i32, i8*, i32 }> addrspace(5)* %block, i32 0, i32 1 - // SPIR: store i32 4, i32* %[[block_align]] - // AMDGCN: store i32 8, i32 addrspace(5)* %[[block_align]] - // SPIR: %[[block_invoke:.*]] = getelementptr inbounds <{ i32, i32, i8 addrspace(4)*, i32 }>, <{ i32, i32, i8 addrspace(4)*, i32 }>* %[[block:.*]], i32 0, i32 2 - // SPIR: store i8 addrspace(4)* addrspacecast (i8* bitcast (i32 (i8 addrspace(4)*)* @__foo_block_invoke to i8*) to i8 addrspace(4)*), i8 addrspace(4)** %[[block_invoke]] - // SPIR: %[[block_captured:.*]] = getelementptr inbounds <{ i32, i32, i8 addrspace(4)*, i32 }>, <{ i32, i32, i8 addrspace(4)*, i32 }>* %[[block]], i32 0, i32 3 - // SPIR: %[[i_value:.*]] = load i32, i32* %i - // SPIR: store i32 %[[i_value]], i32* %[[block_captured]], - // SPIR: %[[blk_ptr:.*]] = bitcast <{ i32, i32, i8 addrspace(4)*, i32 }>* %[[block]] to %struct.__opencl_block_literal_generic* - // SPIR: %[[blk_gen_ptr:.*]] = addrspacecast %struct.__opencl_block_literal_generic* %[[blk_ptr]] to %struct.__opencl_block_literal_generic addrspace(4)* - // SPIR: store %struct.__opencl_block_literal_generic addrspace(4)* %[[blk_gen_ptr]], %struct.__opencl_block_literal_generic addrspace(4)** %[[block_B:.*]], - // SPIR: %[[block_literal:.*]] = load %struct.__opencl_block_literal_generic addrspace(4)*, %struct.__opencl_block_literal_generic addrspace(4)** %[[block_B]] - // SPIR: %[[blk_gen_ptr:.*]] = bitcast %struct.__opencl_block_literal_generic addrspace(4)* %[[block_literal]] to i8 addrspace(4)* - // SPIR: call {{.*}}i32 @__foo_block_invoke(i8 addrspace(4)* noundef %[[blk_gen_ptr]]) - // AMDGCN: %[[block_invoke:.*]] = getelementptr inbounds <{ i32, i32, i8*, i32 }>, <{ i32, i32, i8*, i32 }> addrspace(5)* %[[block:.*]], i32 0, i32 2 - // AMDGCN: store i8* bitcast (i32 (i8*)* @__foo_block_invoke to i8*), i8* addrspace(5)* %[[block_invoke]] - // AMDGCN: %[[block_captured:.*]] = getelementptr inbounds <{ i32, i32, i8*, i32 }>, <{ i32, i32, i8*, i32 }> addrspace(5)* %[[block]], i32 0, i32 3 - // AMDGCN: %[[i_value:.*]] = load i32, i32 addrspace(5)* %i - // AMDGCN: store i32 %[[i_value]], i32 addrspace(5)* %[[block_captured]], - // AMDGCN: %[[blk_ptr:.*]] = bitcast <{ i32, i32, i8*, i32 }> addrspace(5)* %[[block]] to %struct.__opencl_block_literal_generic addrspace(5)* - // AMDGCN: %[[blk_gen_ptr:.*]] = addrspacecast %struct.__opencl_block_literal_generic addrspace(5)* %[[blk_ptr]] to %struct.__opencl_block_literal_generic* - // AMDGCN: store %struct.__opencl_block_literal_generic* %[[blk_gen_ptr]], %struct.__opencl_block_literal_generic* addrspace(5)* %[[block_B:.*]], - // AMDGCN: %[[block_literal:.*]] = load %struct.__opencl_block_literal_generic*, %struct.__opencl_block_literal_generic* addrspace(5)* %[[block_B]] - // AMDGCN: %[[blk_gen_ptr:.*]] = bitcast %struct.__opencl_block_literal_generic* %[[block_literal]] to i8* - // AMDGCN: call {{.*}}i32 @__foo_block_invoke(i8* noundef %[[blk_gen_ptr]]) + // SPIR: %[[block_size:.*]] = getelementptr inbounds <{ i32, i32, ptr addrspace(4), i32 }>, ptr %block, i32 0, i32 0 + // AMDGCN: %[[block_size:.*]] = getelementptr inbounds <{ i32, i32, ptr, i32 }>, ptr addrspace(5) %block, i32 0, i32 0 + // SPIR: store i32 16, ptr %[[block_size]] + // AMDGCN: store i32 20, ptr addrspace(5) %[[block_size]] + // SPIR: %[[block_align:.*]] = getelementptr inbounds <{ i32, i32, ptr addrspace(4), i32 }>, ptr %block, i32 0, i32 1 + // AMDGCN: %[[block_align:.*]] = getelementptr inbounds <{ i32, i32, ptr, i32 }>, ptr addrspace(5) %block, i32 0, i32 1 + // SPIR: store i32 4, ptr %[[block_align]] + // AMDGCN: store i32 8, ptr addrspace(5) %[[block_align]] + // SPIR: %[[block_invoke:.*]] = getelementptr inbounds <{ i32, i32, ptr addrspace(4), i32 }>, ptr %[[block:.*]], i32 0, i32 2 + // SPIR: store ptr addrspace(4) addrspacecast (ptr @__foo_block_invoke to ptr addrspace(4)), ptr %[[block_invoke]] + // SPIR: %[[block_captured:.*]] = getelementptr inbounds <{ i32, i32, ptr addrspace(4), i32 }>, ptr %[[block]], i32 0, i32 3 + // SPIR: %[[i_value:.*]] = load i32, ptr %i + // SPIR: store i32 %[[i_value]], ptr %[[block_captured]], + // SPIR: %[[blk_gen_ptr:.*]] = addrspacecast ptr %[[block]] to ptr addrspace(4) + // SPIR: store ptr addrspace(4) %[[blk_gen_ptr]], ptr %[[block_B:.*]], + // SPIR: %[[block_literal:.*]] = load ptr addrspace(4), ptr %[[block_B]] + // SPIR: call {{.*}}i32 @__foo_block_invoke(ptr addrspace(4) noundef %[[block_literal]]) + // AMDGCN: %[[block_invoke:.*]] = getelementptr inbounds <{ i32, i32, ptr, i32 }>, ptr addrspace(5) %[[block:.*]], i32 0, i32 2 + // AMDGCN: store ptr @__foo_block_invoke, ptr addrspace(5) %[[block_invoke]] + // AMDGCN: %[[block_captured:.*]] = getelementptr inbounds <{ i32, i32, ptr, i32 }>, ptr addrspace(5) %[[block]], i32 0, i32 3 + // AMDGCN: %[[i_value:.*]] = load i32, ptr addrspace(5) %i + // AMDGCN: store i32 %[[i_value]], ptr addrspace(5) %[[block_captured]], + // AMDGCN: %[[blk_gen_ptr:.*]] = addrspacecast ptr addrspace(5) %[[block]] to ptr + // AMDGCN: store ptr %[[blk_gen_ptr]], ptr addrspace(5) %[[block_B:.*]], + // AMDGCN: %[[block_literal:.*]] = load ptr, ptr addrspace(5) %[[block_B]] + // AMDGCN: call {{.*}}i32 @__foo_block_invoke(ptr noundef %[[block_literal]]) int (^ block_B)(void) = ^{ return i; @@ -63,14 +57,12 @@ void foo(){ block_B(); } -// SPIR-LABEL: define internal {{.*}}i32 @__foo_block_invoke(i8 addrspace(4)* noundef %.block_descriptor) -// SPIR: %[[block:.*]] = bitcast i8 addrspace(4)* %.block_descriptor to <{ i32, i32, i8 addrspace(4)*, i32 }> addrspace(4)* -// SPIR: %[[block_capture_addr:.*]] = getelementptr inbounds <{ i32, i32, i8 addrspace(4)*, i32 }>, <{ i32, i32, i8 addrspace(4)*, i32 }> addrspace(4)* %[[block]], i32 0, i32 3 -// SPIR: %[[block_capture:.*]] = load i32, i32 addrspace(4)* %[[block_capture_addr]] -// AMDGCN-LABEL: define internal {{.*}}i32 @__foo_block_invoke(i8* noundef %.block_descriptor) -// AMDGCN: %[[block:.*]] = bitcast i8* %.block_descriptor to <{ i32, i32, i8*, i32 }>* -// AMDGCN: %[[block_capture_addr:.*]] = getelementptr inbounds <{ i32, i32, i8*, i32 }>, <{ i32, i32, i8*, i32 }>* %[[block]], i32 0, i32 3 -// AMDGCN: %[[block_capture:.*]] = load i32, i32* %[[block_capture_addr]] +// SPIR-LABEL: define internal {{.*}}i32 @__foo_block_invoke(ptr addrspace(4) noundef %.block_descriptor) +// SPIR: %[[block_capture_addr:.*]] = getelementptr inbounds <{ i32, i32, ptr addrspace(4), i32 }>, ptr addrspace(4) %.block_descriptor, i32 0, i32 3 +// SPIR: %[[block_capture:.*]] = load i32, ptr addrspace(4) %[[block_capture_addr]] +// AMDGCN-LABEL: define internal {{.*}}i32 @__foo_block_invoke(ptr noundef %.block_descriptor) +// AMDGCN: %[[block_capture_addr:.*]] = getelementptr inbounds <{ i32, i32, ptr, i32 }>, ptr %.block_descriptor, i32 0, i32 3 +// AMDGCN: %[[block_capture:.*]] = load i32, ptr %[[block_capture_addr]] // COMMON-NOT: define{{.*}}@__foo_block_invoke_kernel diff --git a/clang/test/CodeGenOpenCL/builtins.cl b/clang/test/CodeGenOpenCL/builtins.cl index ae6033fa70d15..aa666c7b671b9 100644 --- a/clang/test/CodeGenOpenCL/builtins.cl +++ b/clang/test/CodeGenOpenCL/builtins.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -no-opaque-pointers %s -finclude-default-header -fdeclare-opencl-builtins -cl-std=clc++ -fblocks -O0 -emit-llvm -o - -triple "spir-unknown-unknown" | FileCheck %s +// RUN: %clang_cc1 %s -finclude-default-header -fdeclare-opencl-builtins -cl-std=clc++ -fblocks -O0 -emit-llvm -o - -triple "spir-unknown-unknown" | FileCheck %s void testBranchingOnEnqueueKernel(queue_t default_queue, unsigned flags, ndrange_t ndrange) { // Ensure `enqueue_kernel` can be branched upon. @@ -61,23 +61,20 @@ void testBranchingOnAddressSpaceCast(generic long* ptr) { if (to_global(ptr)) (void)0; - // CHECK: [[P:%[0-9]+]] = call spir_func [[GLOBAL_VOID:i8 addrspace\(1\)\*]] @__to_global([[GENERIC_VOID:i8 addrspace\(4\)\*]] {{%[0-9]+}}) - // CHECK-NEXT: [[Q:%[0-9]+]] = bitcast [[GLOBAL_VOID]] [[P]] to [[GLOBAL_i64:i64 addrspace\(1\)\*]] - // CHECK-NEXT: [[BOOL:%[a-z0-9]+]] = icmp ne [[GLOBAL_i64]] [[Q]], null + // CHECK: [[P:%[0-9]+]] = call spir_func [[GLOBAL_VOID:ptr addrspace\(1\)]] @__to_global([[GENERIC_VOID:ptr addrspace\(4\)]] {{%[0-9]+}}) + // CHECK-NEXT: [[BOOL:%[a-z0-9]+]] = icmp ne ptr addrspace(1) [[P]], null // CHECK-NEXT: br i1 [[BOOL]] if (to_local(ptr)) (void)0; - // CHECK: [[P:%[0-9]+]] = call spir_func [[LOCAL_VOID:i8 addrspace\(3\)\*]] @__to_local([[GENERIC_VOID]] {{%[0-9]+}}) - // CHECK-NEXT: [[Q:%[0-9]+]] = bitcast [[LOCAL_VOID]] [[P]] to [[LOCAL_i64:i64 addrspace\(3\)\*]] - // CHECK-NEXT: [[BOOL:%[a-z0-9]+]] = icmp ne [[LOCAL_i64]] [[Q]], null + // CHECK: [[P:%[0-9]+]] = call spir_func [[LOCAL_VOID:ptr addrspace\(3\)]] @__to_local([[GENERIC_VOID]] {{%[0-9]+}}) + // CHECK-NEXT: [[BOOL:%[a-z0-9]+]] = icmp ne ptr addrspace(3) [[P]], null // CHECK-NEXT: br i1 [[BOOL]] if (to_private(ptr)) (void)0; - // CHECK: [[P:%[0-9]+]] = call spir_func [[PRIVATE_VOID:i8\*]] @__to_private([[GENERIC_VOID]] {{%[0-9]+}}) - // CHECK-NEXT: [[Q:%[0-9]+]] = bitcast [[PRIVATE_VOID]] [[P]] to [[PRIVATE_i64:i64\*]] - // CHECK-NEXT: [[BOOL:%[a-z0-9]+]] = icmp ne [[PRIVATE_i64]] [[Q]], null + // CHECK: [[P:%[0-9]+]] = call spir_func [[PRIVATE_VOID:ptr]] @__to_private([[GENERIC_VOID]] {{%[0-9]+}}) + // CHECK-NEXT: [[BOOL:%[a-z0-9]+]] = icmp ne ptr [[P]], null // CHECK-NEXT: br i1 [[BOOL]] } diff --git a/clang/test/CodeGenOpenCL/cast_image.cl b/clang/test/CodeGenOpenCL/cast_image.cl index 51f46fa7712ed..0579dc2d651e5 100644 --- a/clang/test/CodeGenOpenCL/cast_image.cl +++ b/clang/test/CodeGenOpenCL/cast_image.cl @@ -1,17 +1,17 @@ -// RUN: %clang_cc1 -no-opaque-pointers -emit-llvm -o - -triple amdgcn--amdhsa %s | FileCheck --check-prefix=AMDGCN %s -// RUN: %clang_cc1 -no-opaque-pointers -emit-llvm -o - -triple x86_64-unknown-unknown %s | FileCheck --check-prefix=X86 %s +// RUN: %clang_cc1 -emit-llvm -o - -triple amdgcn--amdhsa %s | FileCheck --check-prefix=AMDGCN %s +// RUN: %clang_cc1 -emit-llvm -o - -triple x86_64-unknown-unknown %s | FileCheck --check-prefix=X86 %s #ifdef __AMDGCN__ constant int* convert(image2d_t img) { - // AMDGCN: bitcast %opencl.image2d_ro_t addrspace(4)* %img to i32 addrspace(4)* + // AMDGCN: ret ptr addrspace(4) %img return __builtin_astype(img, constant int*); } #else global int* convert(image2d_t img) { - // X86: bitcast %opencl.image2d_ro_t* %img to i32* + // X86: ret ptr %img return __builtin_astype(img, global int*); } diff --git a/clang/test/CodeGenOpenCL/const-str-array-decay.cl b/clang/test/CodeGenOpenCL/const-str-array-decay.cl index b32df75286e0d..0bffe92d6565d 100644 --- a/clang/test/CodeGenOpenCL/const-str-array-decay.cl +++ b/clang/test/CodeGenOpenCL/const-str-array-decay.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -no-opaque-pointers %s -emit-llvm -o - -ffake-address-space-map | FileCheck %s +// RUN: %clang_cc1 %s -emit-llvm -o - -ffake-address-space-map | FileCheck %s int test_func(constant char* foo); @@ -6,6 +6,5 @@ kernel void str_array_decy() { test_func("Test string literal"); } -// CHECK: i8 addrspace(2)* noundef getelementptr inbounds ([20 x i8], [20 x i8] addrspace(2)* +// CHECK: ptr addrspace(2) noundef // CHECK-NOT: addrspacecast - diff --git a/clang/test/CodeGenOpenCL/kernels-have-spir-cc-by-default.cl b/clang/test/CodeGenOpenCL/kernels-have-spir-cc-by-default.cl index 15220975322bc..f39589ada0a70 100644 --- a/clang/test/CodeGenOpenCL/kernels-have-spir-cc-by-default.cl +++ b/clang/test/CodeGenOpenCL/kernels-have-spir-cc-by-default.cl @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=CL1.2 -emit-llvm -triple x86_64-unknown-unknown -o - | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=CL1.2 -emit-llvm -triple amdgcn-unknown-unknown -o - | FileCheck -check-prefixes=AMDGCN %s +// RUN: %clang_cc1 %s -cl-std=CL1.2 -emit-llvm -triple x86_64-unknown-unknown -o - | FileCheck %s +// RUN: %clang_cc1 %s -cl-std=CL1.2 -emit-llvm -triple amdgcn-unknown-unknown -o - | FileCheck -check-prefixes=AMDGCN %s // Test that the kernels always use the SPIR calling convention // to have unambiguous mapping of arguments to feasibly implement // clSetKernelArg(). @@ -27,16 +27,16 @@ typedef struct test_struct { kernel void test_single(int_single input, global int* output) { // CHECK: spir_kernel // AMDGCN: define{{.*}} amdgpu_kernel void @test_single -// CHECK: struct.int_single* nocapture {{.*}} byval(%struct.int_single) -// CHECK: i32* nocapture noundef writeonly align 4 %output +// CHECK: ptr nocapture {{.*}} byval(%struct.int_single) +// CHECK: ptr nocapture noundef writeonly align 4 %output output[0] = input.a; } kernel void test_pair(int_pair input, global int* output) { // CHECK: spir_kernel // AMDGCN: define{{.*}} amdgpu_kernel void @test_pair -// CHECK: struct.int_pair* nocapture {{.*}} byval(%struct.int_pair) -// CHECK: i32* nocapture noundef writeonly align 4 %output +// CHECK: ptr nocapture {{.*}} byval(%struct.int_pair) +// CHECK: ptr nocapture noundef writeonly align 4 %output output[0] = (int)input.a; output[1] = (int)input.b; } @@ -44,8 +44,8 @@ kernel void test_pair(int_pair input, global int* output) { kernel void test_kernel(test_struct input, global int* output) { // CHECK: spir_kernel // AMDGCN: define{{.*}} amdgpu_kernel void @test_kernel -// CHECK: struct.test_struct* nocapture {{.*}} byval(%struct.test_struct) -// CHECK: i32* nocapture noundef writeonly align 4 %output +// CHECK: ptr nocapture {{.*}} byval(%struct.test_struct) +// CHECK: ptr nocapture noundef writeonly align 4 %output output[0] = input.elementA; output[1] = input.elementB; output[2] = (int)input.elementC; @@ -59,7 +59,7 @@ kernel void test_kernel(test_struct input, global int* output) { void test_function(int_pair input, global int* output) { // CHECK-NOT: spir_kernel // AMDGCN-NOT: define{{.*}} amdgpu_kernel void @test_function -// CHECK: i64 %input.coerce0, i64 %input.coerce1, i32* nocapture noundef writeonly %output +// CHECK: i64 %input.coerce0, i64 %input.coerce1, ptr nocapture noundef writeonly %output output[0] = (int)input.a; output[1] = (int)input.b; } diff --git a/clang/test/CodeGenOpenCL/no-half.cl b/clang/test/CodeGenOpenCL/no-half.cl index 6ca24a479f93c..f9ddd94012404 100644 --- a/clang/test/CodeGenOpenCL/no-half.cl +++ b/clang/test/CodeGenOpenCL/no-half.cl @@ -1,39 +1,39 @@ -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=cl2.0 -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=cl1.2 -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers %s -cl-std=cl1.1 -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s +// RUN: %clang_cc1 %s -cl-std=cl2.0 -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s +// RUN: %clang_cc1 %s -cl-std=cl1.2 -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s +// RUN: %clang_cc1 %s -cl-std=cl1.1 -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s #pragma OPENCL EXTENSION cl_khr_fp64:enable -// CHECK-LABEL: @test_store_float(float noundef %foo, half addrspace({{.}}){{.*}} %bar) +// CHECK-LABEL: @test_store_float(float noundef %foo, ptr addrspace({{.}}){{.*}} %bar) __kernel void test_store_float(float foo, __global half* bar) { __builtin_store_halff(foo, bar); // CHECK: [[HALF_VAL:%.*]] = fptrunc float %foo to half -// CHECK: store half [[HALF_VAL]], half addrspace({{.}})* %bar, align 2 +// CHECK: store half [[HALF_VAL]], ptr addrspace({{.}}) %bar, align 2 } -// CHECK-LABEL: @test_store_double(double noundef %foo, half addrspace({{.}}){{.*}} %bar) +// CHECK-LABEL: @test_store_double(double noundef %foo, ptr addrspace({{.}}){{.*}} %bar) __kernel void test_store_double(double foo, __global half* bar) { __builtin_store_half(foo, bar); // CHECK: [[HALF_VAL:%.*]] = fptrunc double %foo to half -// CHECK: store half [[HALF_VAL]], half addrspace({{.}})* %bar, align 2 +// CHECK: store half [[HALF_VAL]], ptr addrspace({{.}}) %bar, align 2 } -// CHECK-LABEL: @test_load_float(float addrspace({{.}}){{.*}} %foo, half addrspace({{.}}){{.*}} %bar) +// CHECK-LABEL: @test_load_float(ptr addrspace({{.}}){{.*}} %foo, ptr addrspace({{.}}){{.*}} %bar) __kernel void test_load_float(__global float* foo, __global half* bar) { foo[0] = __builtin_load_halff(bar); -// CHECK: [[HALF_VAL:%.*]] = load half, half addrspace({{.}})* %bar +// CHECK: [[HALF_VAL:%.*]] = load half, ptr addrspace({{.}}) %bar // CHECK: [[FULL_VAL:%.*]] = fpext half [[HALF_VAL]] to float -// CHECK: store float [[FULL_VAL]], float addrspace({{.}})* %foo +// CHECK: store float [[FULL_VAL]], ptr addrspace({{.}}) %foo } -// CHECK-LABEL: @test_load_double(double addrspace({{.}}){{.*}} %foo, half addrspace({{.}}){{.*}} %bar) +// CHECK-LABEL: @test_load_double(ptr addrspace({{.}}){{.*}} %foo, ptr addrspace({{.}}){{.*}} %bar) __kernel void test_load_double(__global double* foo, __global half* bar) { foo[0] = __builtin_load_half(bar); -// CHECK: [[HALF_VAL:%.*]] = load half, half addrspace({{.}})* %bar +// CHECK: [[HALF_VAL:%.*]] = load half, ptr addrspace({{.}}) %bar // CHECK: [[FULL_VAL:%.*]] = fpext half [[HALF_VAL]] to double -// CHECK: store double [[FULL_VAL]], double addrspace({{.}})* %foo +// CHECK: store double [[FULL_VAL]], ptr addrspace({{.}}) %foo } diff --git a/clang/test/CodeGenOpenCL/pipe_builtin.cl b/clang/test/CodeGenOpenCL/pipe_builtin.cl index 05cdcd1de30a7..c59f63bab6a45 100644 --- a/clang/test/CodeGenOpenCL/pipe_builtin.cl +++ b/clang/test/CodeGenOpenCL/pipe_builtin.cl @@ -1,73 +1,69 @@ -// RUN: %clang_cc1 -no-opaque-pointers -triple %itanium_abi_triple -emit-llvm -cl-ext=+cl_khr_subgroups -O0 -cl-std=clc++ -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -cl-ext=+cl_khr_subgroups -O0 -cl-std=clc++ -o - %s | FileCheck %s // FIXME: Add MS ABI manglings of OpenCL things and remove %itanium_abi_triple // above to support OpenCL in the MS C++ ABI. -// CHECK-DAG: %opencl.pipe_ro_t = type opaque -// CHECK-DAG: %opencl.pipe_wo_t = type opaque -// CHECK-DAG: %opencl.reserve_id_t = type opaque - #pragma OPENCL EXTENSION cl_khr_subgroups : enable void test1(read_only pipe int p, global int *ptr) { - // CHECK: call i32 @__read_pipe_2(%opencl.pipe_ro_t* %{{.*}}, i8* %{{.*}}, i32 4, i32 4) + // CHECK: call i32 @__read_pipe_2(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4) read_pipe(p, ptr); - // CHECK: call %opencl.reserve_id_t* @__reserve_read_pipe(%opencl.pipe_ro_t* %{{.*}}, i32 {{.*}}, i32 4, i32 4) + // CHECK: call ptr @__reserve_read_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4) reserve_id_t rid = reserve_read_pipe(p, 2); - // CHECK: call i32 @__read_pipe_4(%opencl.pipe_ro_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}, i32 {{.*}}, i8* %{{.*}}, i32 4, i32 4) + // CHECK: call i32 @__read_pipe_4(ptr %{{.*}}, ptr %{{.*}}, i32 {{.*}}, ptr %{{.*}}, i32 4, i32 4) read_pipe(p, rid, 2, ptr); - // CHECK: call void @__commit_read_pipe(%opencl.pipe_ro_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}, i32 4, i32 4) + // CHECK: call void @__commit_read_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4) commit_read_pipe(p, rid); } void test2(write_only pipe int p, global int *ptr) { - // CHECK: call i32 @__write_pipe_2(%opencl.pipe_wo_t* %{{.*}}, i8* %{{.*}}, i32 4, i32 4) + // CHECK: call i32 @__write_pipe_2(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4) write_pipe(p, ptr); - // CHECK: call %opencl.reserve_id_t* @__reserve_write_pipe(%opencl.pipe_wo_t* %{{.*}}, i32 {{.*}}, i32 4, i32 4) + // CHECK: call ptr @__reserve_write_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4) reserve_id_t rid = reserve_write_pipe(p, 2); - // CHECK: call i32 @__write_pipe_4(%opencl.pipe_wo_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}, i32 {{.*}}, i8* %{{.*}}, i32 4, i32 4) + // CHECK: call i32 @__write_pipe_4(ptr %{{.*}}, ptr %{{.*}}, i32 {{.*}}, ptr %{{.*}}, i32 4, i32 4) write_pipe(p, rid, 2, ptr); - // CHECK: call void @__commit_write_pipe(%opencl.pipe_wo_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}, i32 4, i32 4) + // CHECK: call void @__commit_write_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4) commit_write_pipe(p, rid); } void test3(read_only pipe int p, global int *ptr) { - // CHECK: call %opencl.reserve_id_t* @__work_group_reserve_read_pipe(%opencl.pipe_ro_t* %{{.*}}, i32 {{.*}}, i32 4, i32 4) + // CHECK: call ptr @__work_group_reserve_read_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4) reserve_id_t rid = work_group_reserve_read_pipe(p, 2); - // CHECK: call void @__work_group_commit_read_pipe(%opencl.pipe_ro_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}, i32 4, i32 4) + // CHECK: call void @__work_group_commit_read_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4) work_group_commit_read_pipe(p, rid); } void test4(write_only pipe int p, global int *ptr) { - // CHECK: call %opencl.reserve_id_t* @__work_group_reserve_write_pipe(%opencl.pipe_wo_t* %{{.*}}, i32 {{.*}}, i32 4, i32 4) + // CHECK: call ptr @__work_group_reserve_write_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4) reserve_id_t rid = work_group_reserve_write_pipe(p, 2); - // CHECK: call void @__work_group_commit_write_pipe(%opencl.pipe_wo_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}, i32 4, i32 4) + // CHECK: call void @__work_group_commit_write_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4) work_group_commit_write_pipe(p, rid); } void test5(read_only pipe int p, global int *ptr) { - // CHECK: call %opencl.reserve_id_t* @__sub_group_reserve_read_pipe(%opencl.pipe_ro_t* %{{.*}}, i32 {{.*}}, i32 4, i32 4) + // CHECK: call ptr @__sub_group_reserve_read_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4) reserve_id_t rid = sub_group_reserve_read_pipe(p, 2); - // CHECK: call void @__sub_group_commit_read_pipe(%opencl.pipe_ro_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}, i32 4, i32 4) + // CHECK: call void @__sub_group_commit_read_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4) sub_group_commit_read_pipe(p, rid); } void test6(write_only pipe int p, global int *ptr) { - // CHECK: call %opencl.reserve_id_t* @__sub_group_reserve_write_pipe(%opencl.pipe_wo_t* %{{.*}}, i32 {{.*}}, i32 4, i32 4) + // CHECK: call ptr @__sub_group_reserve_write_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4) reserve_id_t rid = sub_group_reserve_write_pipe(p, 2); - // CHECK: call void @__sub_group_commit_write_pipe(%opencl.pipe_wo_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}, i32 4, i32 4) + // CHECK: call void @__sub_group_commit_write_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4) sub_group_commit_write_pipe(p, rid); } void test7(read_only pipe int p, global int *ptr) { - // CHECK: call i32 @__get_pipe_num_packets_ro(%opencl.pipe_ro_t* %{{.*}}, i32 4, i32 4) + // CHECK: call i32 @__get_pipe_num_packets_ro(ptr %{{.*}}, i32 4, i32 4) *ptr = get_pipe_num_packets(p); - // CHECK: call i32 @__get_pipe_max_packets_ro(%opencl.pipe_ro_t* %{{.*}}, i32 4, i32 4) + // CHECK: call i32 @__get_pipe_max_packets_ro(ptr %{{.*}}, i32 4, i32 4) *ptr = get_pipe_max_packets(p); } void test8(write_only pipe int p, global int *ptr) { - // CHECK: call i32 @__get_pipe_num_packets_wo(%opencl.pipe_wo_t* %{{.*}}, i32 4, i32 4) + // CHECK: call i32 @__get_pipe_num_packets_wo(ptr %{{.*}}, i32 4, i32 4) *ptr = get_pipe_num_packets(p); - // CHECK: call i32 @__get_pipe_max_packets_wo(%opencl.pipe_wo_t* %{{.*}}, i32 4, i32 4) + // CHECK: call i32 @__get_pipe_max_packets_wo(ptr %{{.*}}, i32 4, i32 4) *ptr = get_pipe_max_packets(p); } diff --git a/clang/test/CodeGenOpenCL/pipe_types.cl b/clang/test/CodeGenOpenCL/pipe_types.cl index 702c0ede6f625..dc53ac0eef46d 100644 --- a/clang/test/CodeGenOpenCL/pipe_types.cl +++ b/clang/test/CodeGenOpenCL/pipe_types.cl @@ -1,39 +1,37 @@ -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-unknown-linux-gnu -emit-llvm -O0 -cl-std=CL2.0 -o - %s | FileCheck --check-prefixes=CHECK,CHECK-STRUCT %s -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-unknown-linux-gnu -emit-llvm -O0 -cl-std=CL3.0 -cl-ext=-all,+__opencl_c_pipes,+__opencl_c_generic_address_space,+__opencl_c_program_scope_global_variables -o - %s | FileCheck --check-prefixes=CHECK %s -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-unknown-linux-gnu -emit-llvm -O0 -cl-std=CL3.0 -cl-ext=-all,+__opencl_c_pipes,+__opencl_c_generic_address_space -o - %s | FileCheck --check-prefixes=CHECK %s -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-unknown-linux-gnu -emit-llvm -O0 -cl-std=clc++2021 -cl-ext=-all,+__opencl_c_pipes,+__opencl_c_generic_address_space,+__opencl_c_program_scope_global_variables -o - %s | FileCheck --check-prefixes=CHECK %s -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-unknown-linux-gnu -emit-llvm -O0 -cl-std=clc++2021 -cl-ext=-all,+__opencl_c_pipes,+__opencl_c_generic_address_space -o - %s | FileCheck --check-prefixes=CHECK %s - -// CHECK: %opencl.pipe_ro_t = type opaque -// CHECK: %opencl.pipe_wo_t = type opaque +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -O0 -cl-std=CL2.0 -o - %s | FileCheck --check-prefixes=CHECK,CHECK-STRUCT %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -O0 -cl-std=CL3.0 -cl-ext=-all,+__opencl_c_pipes,+__opencl_c_generic_address_space,+__opencl_c_program_scope_global_variables -o - %s | FileCheck --check-prefixes=CHECK %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -O0 -cl-std=CL3.0 -cl-ext=-all,+__opencl_c_pipes,+__opencl_c_generic_address_space -o - %s | FileCheck --check-prefixes=CHECK %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -O0 -cl-std=clc++2021 -cl-ext=-all,+__opencl_c_pipes,+__opencl_c_generic_address_space,+__opencl_c_program_scope_global_variables -o - %s | FileCheck --check-prefixes=CHECK %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -O0 -cl-std=clc++2021 -cl-ext=-all,+__opencl_c_pipes,+__opencl_c_generic_address_space -o - %s | FileCheck --check-prefixes=CHECK %s + typedef unsigned char __attribute__((ext_vector_type(3))) uchar3; typedef int __attribute__((ext_vector_type(4))) int4; void test1(read_only pipe int p) { -// CHECK: define{{.*}} void @{{.*}}test1{{.*}}(%opencl.pipe_ro_t* %p) +// CHECK: define{{.*}} void @{{.*}}test1{{.*}}(ptr %p) reserve_id_t rid; -// CHECK: %rid = alloca %opencl.reserve_id_t +// CHECK: %rid = alloca ptr } void test2(write_only pipe float p) { -// CHECK: define{{.*}} void @{{.*}}test2{{.*}}(%opencl.pipe_wo_t* %p) +// CHECK: define{{.*}} void @{{.*}}test2{{.*}}(ptr %p) } void test3(read_only pipe const int p) { -// CHECK: define{{.*}} void @{{.*}}test3{{.*}}(%opencl.pipe_ro_t* %p) +// CHECK: define{{.*}} void @{{.*}}test3{{.*}}(ptr %p) } void test4(read_only pipe uchar3 p) { -// CHECK: define{{.*}} void @{{.*}}test4{{.*}}(%opencl.pipe_ro_t* %p) +// CHECK: define{{.*}} void @{{.*}}test4{{.*}}(ptr %p) } void test5(read_only pipe int4 p) { -// CHECK: define{{.*}} void @{{.*}}test5{{.*}}(%opencl.pipe_ro_t* %p) +// CHECK: define{{.*}} void @{{.*}}test5{{.*}}(ptr %p) } typedef read_only pipe int MyPipe; kernel void test6(MyPipe p) { -// CHECK: define{{.*}} spir_kernel void @test6(%opencl.pipe_ro_t* %p) +// CHECK: define{{.*}} spir_kernel void @test6(ptr %p) } struct Person { @@ -46,7 +44,7 @@ void test_reserved_read_pipe(global struct Person *SDst, read_only pipe struct Person SPipe) { // CHECK-STRUCT: define{{.*}} void @test_reserved_read_pipe read_pipe (SPipe, SDst); - // CHECK-STRUCT: call i32 @__read_pipe_2(%opencl.pipe_ro_t* %{{.*}}, i8* %{{.*}}, i32 16, i32 8) + // CHECK-STRUCT: call i32 @__read_pipe_2(ptr %{{.*}}, ptr %{{.*}}, i32 16, i32 8) read_pipe (SPipe, SDst); - // CHECK-STRUCT: call i32 @__read_pipe_2(%opencl.pipe_ro_t* %{{.*}}, i8* %{{.*}}, i32 16, i32 8) + // CHECK-STRUCT: call i32 @__read_pipe_2(ptr %{{.*}}, ptr %{{.*}}, i32 16, i32 8) } diff --git a/clang/test/CodeGenOpenCL/to_addr_builtin.cl b/clang/test/CodeGenOpenCL/to_addr_builtin.cl index 2334dacfaa884..49b210ce84df1 100644 --- a/clang/test/CodeGenOpenCL/to_addr_builtin.cl +++ b/clang/test/CodeGenOpenCL/to_addr_builtin.cl @@ -1,8 +1,7 @@ -// RUN: %clang_cc1 -no-opaque-pointers -triple spir-unknown-unknown -emit-llvm -O0 -cl-std=clc++ -o - %s | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -triple spir-unknown-unknown -emit-llvm -O0 -cl-std=cl2.0 -o - %s | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -triple spir-unknown-unknown -emit-llvm -O0 -cl-std=cl3.0 -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm -O0 -cl-std=clc++ -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm -O0 -cl-std=cl2.0 -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm -O0 -cl-std=cl3.0 -o - %s | FileCheck %s -// CHECK: %[[A:.*]] = type { float, float, float } typedef struct { float x,y,z; } A; @@ -15,75 +14,75 @@ void test(void) { private int *priv; generic int *gen; - //CHECK: %[[ARG:.*]] = addrspacecast i32 addrspace(1)* %{{.*}} to i8 addrspace(4)* - //CHECK: %[[RET:.*]] = call spir_func i8 addrspace(1)* @__to_global(i8 addrspace(4)* %[[ARG]]) - //CHECK: %{{.*}} = bitcast i8 addrspace(1)* %[[RET]] to i32 addrspace(1)* + //CHECK: %[[ARG:.*]] = addrspacecast ptr addrspace(1) %{{.*}} to ptr addrspace(4) + //CHECK: %[[RET:.*]] = call spir_func ptr addrspace(1) @__to_global(ptr addrspace(4) %[[ARG]]) + //CHECK: store ptr addrspace(1) %[[RET]], ptr %glob glob = to_global(glob); - //CHECK: %[[ARG:.*]] = addrspacecast i32 addrspace(3)* %{{.*}} to i8 addrspace(4)* - //CHECK: %[[RET:.*]] = call spir_func i8 addrspace(1)* @__to_global(i8 addrspace(4)* %[[ARG]]) - //CHECK: %{{.*}} = bitcast i8 addrspace(1)* %[[RET]] to i32 addrspace(1)* + //CHECK: %[[ARG:.*]] = addrspacecast ptr addrspace(3) %{{.*}} to ptr addrspace(4) + //CHECK: %[[RET:.*]] = call spir_func ptr addrspace(1) @__to_global(ptr addrspace(4) %[[ARG]]) + //CHECK: store ptr addrspace(1) %[[RET]], ptr %glob glob = to_global(loc); - //CHECK: %[[ARG:.*]] = addrspacecast i32* %{{.*}} to i8 addrspace(4)* - //CHECK: %[[RET:.*]] = call spir_func i8 addrspace(1)* @__to_global(i8 addrspace(4)* %[[ARG]]) - //CHECK: %{{.*}} = bitcast i8 addrspace(1)* %[[RET]] to i32 addrspace(1)* + //CHECK: %[[ARG:.*]] = addrspacecast ptr %{{.*}} to ptr addrspace(4) + //CHECK: %[[RET:.*]] = call spir_func ptr addrspace(1) @__to_global(ptr addrspace(4) %[[ARG]]) + //CHECK: store ptr addrspace(1) %[[RET]], ptr %glob glob = to_global(priv); - //CHECK: %[[ARG:.*]] = bitcast i32 addrspace(4)* %{{.*}} to i8 addrspace(4)* - //CHECK: %[[RET:.*]] = call spir_func i8 addrspace(1)* @__to_global(i8 addrspace(4)* %[[ARG]]) - //CHECK: %{{.*}} = bitcast i8 addrspace(1)* %[[RET]] to i32 addrspace(1)* + //CHECK: %[[ARG:.*]] = load ptr addrspace(4), ptr %gen + //CHECK: %[[RET:.*]] = call spir_func ptr addrspace(1) @__to_global(ptr addrspace(4) %[[ARG]]) + //CHECK: store ptr addrspace(1) %[[RET]], ptr %glob glob = to_global(gen); - //CHECK: %[[ARG:.*]] = addrspacecast i32 addrspace(1)* %{{.*}} to i8 addrspace(4)* - //CHECK: %[[RET:.*]] = call spir_func i8 addrspace(3)* @__to_local(i8 addrspace(4)* %[[ARG]]) - //CHECK: %{{.*}} = bitcast i8 addrspace(3)* %[[RET]] to i32 addrspace(3)* + //CHECK: %[[ARG:.*]] = addrspacecast ptr addrspace(1) %{{.*}} to ptr addrspace(4) + //CHECK: %[[RET:.*]] = call spir_func ptr addrspace(3) @__to_local(ptr addrspace(4) %[[ARG]]) + //CHECK: store ptr addrspace(3) %[[RET]], ptr %loc loc = to_local(glob); - //CHECK: %[[ARG:.*]] = addrspacecast i32 addrspace(3)* %{{.*}} to i8 addrspace(4)* - //CHECK: %[[RET:.*]] = call spir_func i8 addrspace(3)* @__to_local(i8 addrspace(4)* %[[ARG]]) - //CHECK: %{{.*}} = bitcast i8 addrspace(3)* %[[RET]] to i32 addrspace(3)* + //CHECK: %[[ARG:.*]] = addrspacecast ptr addrspace(3) %{{.*}} to ptr addrspace(4) + //CHECK: %[[RET:.*]] = call spir_func ptr addrspace(3) @__to_local(ptr addrspace(4) %[[ARG]]) + //CHECK: store ptr addrspace(3) %[[RET]], ptr %loc loc = to_local(loc); - //CHECK: %[[ARG:.*]] = addrspacecast i32* %{{.*}} to i8 addrspace(4)* - //CHECK: %[[RET:.*]] = call spir_func i8 addrspace(3)* @__to_local(i8 addrspace(4)* %[[ARG]]) - //CHECK: %{{.*}} = bitcast i8 addrspace(3)* %[[RET]] to i32 addrspace(3)* + //CHECK: %[[ARG:.*]] = addrspacecast ptr %{{.*}} to ptr addrspace(4) + //CHECK: %[[RET:.*]] = call spir_func ptr addrspace(3) @__to_local(ptr addrspace(4) %[[ARG]]) + //CHECK: store ptr addrspace(3) %[[RET]], ptr %loc loc = to_local(priv); - //CHECK: %[[ARG:.*]] = bitcast i32 addrspace(4)* %{{.*}} to i8 addrspace(4)* - //CHECK: %[[RET:.*]] = call spir_func i8 addrspace(3)* @__to_local(i8 addrspace(4)* %[[ARG]]) - //CHECK: %{{.*}} = bitcast i8 addrspace(3)* %[[RET]] to i32 addrspace(3)* + //CHECK: %[[ARG:.*]] = load ptr addrspace(4), ptr %gen + //CHECK: %[[RET:.*]] = call spir_func ptr addrspace(3) @__to_local(ptr addrspace(4) %[[ARG]]) + //CHECK: store ptr addrspace(3) %[[RET]], ptr %loc loc = to_local(gen); - //CHECK: %[[ARG:.*]] = addrspacecast i32 addrspace(1)* %{{.*}} to i8 addrspace(4)* - //CHECK: %[[RET:.*]] = call spir_func i8* @__to_private(i8 addrspace(4)* %[[ARG]]) - //CHECK: %{{.*}} = bitcast i8* %[[RET]] to i32* + //CHECK: %[[ARG:.*]] = addrspacecast ptr addrspace(1) %{{.*}} to ptr addrspace(4) + //CHECK: %[[RET:.*]] = call spir_func ptr @__to_private(ptr addrspace(4) %[[ARG]]) + //CHECK: store ptr %[[RET]], ptr %priv priv = to_private(glob); - //CHECK: %[[ARG:.*]] = addrspacecast i32 addrspace(3)* %{{.*}} to i8 addrspace(4)* - //CHECK: %[[RET:.*]] = call spir_func i8* @__to_private(i8 addrspace(4)* %[[ARG]]) - //CHECK: %{{.*}} = bitcast i8* %[[RET]] to i32* + //CHECK: %[[ARG:.*]] = addrspacecast ptr addrspace(3) %{{.*}} to ptr addrspace(4) + //CHECK: %[[RET:.*]] = call spir_func ptr @__to_private(ptr addrspace(4) %[[ARG]]) + //CHECK: store ptr %[[RET]], ptr %priv priv = to_private(loc); - //CHECK: %[[ARG:.*]] = addrspacecast i32* %{{.*}} to i8 addrspace(4)* - //CHECK: %[[RET:.*]] = call spir_func i8* @__to_private(i8 addrspace(4)* %[[ARG]]) - //CHECK: %{{.*}} = bitcast i8* %[[RET]] to i32* + //CHECK: %[[ARG:.*]] = addrspacecast ptr %{{.*}} to ptr addrspace(4) + //CHECK: %[[RET:.*]] = call spir_func ptr @__to_private(ptr addrspace(4) %[[ARG]]) + //CHECK: store ptr %[[RET]], ptr %priv priv = to_private(priv); - //CHECK: %[[ARG:.*]] = bitcast i32 addrspace(4)* %{{.*}} to i8 addrspace(4)* - //CHECK: %[[RET:.*]] = call spir_func i8* @__to_private(i8 addrspace(4)* %[[ARG]]) - //CHECK: %{{.*}} = bitcast i8* %[[RET]] to i32* + //CHECK: %[[ARG:.*]] = load ptr addrspace(4), ptr %gen + //CHECK: %[[RET:.*]] = call spir_func ptr @__to_private(ptr addrspace(4) %[[ARG]]) + //CHECK: store ptr %[[RET]], ptr %priv priv = to_private(gen); - //CHECK: %[[ARG:.*]] = addrspacecast %[[A]]* %{{.*}} to i8 addrspace(4)* - //CHECK: %[[RET:.*]] = call spir_func i8 addrspace(1)* @__to_global(i8 addrspace(4)* %[[ARG]]) - //CHECK: %{{.*}} = bitcast i8 addrspace(1)* %[[RET]] to %[[A]] addrspace(1)* + //CHECK: %[[ARG:.*]] = addrspacecast ptr %{{.*}} to ptr addrspace(4) + //CHECK: %[[RET:.*]] = call spir_func ptr addrspace(1) @__to_global(ptr addrspace(4) %[[ARG]]) + //CHECK: store ptr addrspace(1) %[[RET]], ptr %gA PA pA; GA gA = to_global(pA); //CHECK-NOT: addrspacecast //CHECK-NOT: bitcast - //CHECK: call spir_func i8 addrspace(1)* @__to_global(i8 addrspace(4)* %{{.*}}) + //CHECK: call spir_func ptr addrspace(1) @__to_global(ptr addrspace(4) %{{.*}}) //CHECK-NOT: addrspacecast //CHECK-NOT: bitcast generic void *gen_v; diff --git a/clang/test/CodeGenSYCL/field-annotate-addr-space.cpp b/clang/test/CodeGenSYCL/field-annotate-addr-space.cpp index 15319c68abac5..764bed19e3103 100644 --- a/clang/test/CodeGenSYCL/field-annotate-addr-space.cpp +++ b/clang/test/CodeGenSYCL/field-annotate-addr-space.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -no-opaque-pointers -triple spir64 -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple spir64 -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s // CHECK: [[ANNOT:.+]] = private unnamed_addr addrspace(1) constant {{.*}}c"my_annotation\00" @@ -11,9 +11,8 @@ struct HasField { __attribute__((sycl_device)) void foo(int *b) { struct HasField f; - // CHECK: %[[A:.+]] = getelementptr inbounds %struct{{.*}}.HasField, %struct{{.*}}.HasField addrspace(4)* %{{.+}} - // CHECK: %[[BITCAST:.+]] = bitcast i32 addrspace(4)* addrspace(4)* %[[A]] to i8 addrspace(4)* - // CHECK: %[[CALL:.+]] = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8.p1i8(i8 addrspace(4)* %[[BITCAST]], i8 addrspace(1)* getelementptr inbounds ([14 x i8], [14 x i8] addrspace(1)* [[ANNOT]] - // CHECK: bitcast i8 addrspace(4)* %[[CALL]] to i32 addrspace(4)* addrspace(4)* + // CHECK: %[[A:.+]] = getelementptr inbounds %struct.HasField, ptr addrspace(4) %{{.+}} + // CHECK: %[[CALL:.+]] = call ptr addrspace(4) @llvm.ptr.annotation.p4.p1(ptr addrspace(4) %[[A]], ptr addrspace(1) [[ANNOT]] + // CHECK: store ptr addrspace(4) %{{[0-9]+}}, ptr addrspace(4) %[[CALL]] f.a = b; } diff --git a/clang/test/CodeGenSYCL/unique_stable_name.cpp b/clang/test/CodeGenSYCL/unique_stable_name.cpp index ec0a5a8cf9baa..3ab7e3b8f2e7a 100644 --- a/clang/test/CodeGenSYCL/unique_stable_name.cpp +++ b/clang/test/CodeGenSYCL/unique_stable_name.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-linux-pc -fsycl-is-host -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux-pc -fsycl-is-host -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s // CHECK: @[[LAMBDA_KERNEL3:[^\w]+]] = private unnamed_addr constant [[LAMBDA_K3_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ4mainEUlPZ4mainEUlvE_E_\00" // CHECK: @[[INT1:[^\w]+]] = private unnamed_addr constant [[INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSi\00" // CHECK: @[[STRING:[^\w]+]] = private unnamed_addr constant [[STRING_SIZE:\[[0-9]+ x i8\]]] c"_ZTSAppL_ZZ4mainE1jE_i\00", @@ -77,48 +77,48 @@ void not_kernel_single_task(KernelType kernelFunc) { int main() { not_kernel_single_task(func); - // CHECK: call void @_Z22not_kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_(i8* ()* noundef @_Z4funcI4DerpEDTu33__builtin_sycl_unique_stable_nameDtsrT_3strEEEv) + // CHECK: call void @_Z22not_kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_(ptr noundef @_Z4funcI4DerpEDTu33__builtin_sycl_unique_stable_nameDtsrT_3strEEEv) auto l1 = []() { return 1; }; auto l2 = [](decltype(l1) *l = nullptr) { return 2; }; kernel_single_task(l2); puts(__builtin_sycl_unique_stable_name(decltype(l2))); // CHECK: call void @_Z18kernel_single_taskIZ4mainEUlPZ4mainEUlvE_E_S2_EvT0_ - // CHECK: call void @puts(i8* noundef getelementptr inbounds ([[LAMBDA_K3_SIZE]], [[LAMBDA_K3_SIZE]]* @[[LAMBDA_KERNEL3]], i32 0, i32 0)) + // CHECK: call void @puts(ptr noundef @[[LAMBDA_KERNEL3]]) constexpr const char str[] = "lalala"; static_assert(__builtin_strcmp(__builtin_sycl_unique_stable_name(decltype(str)), "_ZTSA7_Kc\0") == 0, "unexpected mangling"); int i = 0; puts(__builtin_sycl_unique_stable_name(decltype(i++))); - // CHECK: call void @puts(i8* noundef getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]]* @[[INT1]], i32 0, i32 0)) + // CHECK: call void @puts(ptr noundef @[[INT1]]) // FIXME: Ensure that j is incremented because VLAs are terrible. int j = 55; puts(__builtin_sycl_unique_stable_name(int[++j])); - // CHECK: call void @puts(i8* noundef getelementptr inbounds ([[STRING_SIZE]], [[STRING_SIZE]]* @[[STRING]], i32 0, i32 0)) + // CHECK: call void @puts(ptr noundef @[[STRING]]) // CHECK: define internal void @_Z22not_kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_ - // CHECK: declare noundef i8* @_Z4funcI4DerpEDTu33__builtin_sycl_unique_stable_nameDtsrT_3strEEEv + // CHECK: declare noundef ptr @_Z4funcI4DerpEDTu33__builtin_sycl_unique_stable_nameDtsrT_3strEEEv // CHECK: define internal void @_Z18kernel_single_taskIZ4mainEUlPZ4mainEUlvE_E_S2_EvT0_ // CHECK: define internal void @_Z18kernel_single_taskIZ4mainEUlvE0_S0_EvT0_ unnamed_kernel_single_task( []() { puts(__builtin_sycl_unique_stable_name(int)); - // CHECK: call void @puts(i8* noundef getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]]* @[[INT2]], i32 0, i32 0)) + // CHECK: call void @puts(ptr noundef @[[INT2]]) auto x = []() {}; puts(__builtin_sycl_unique_stable_name(decltype(x))); - // CHECK: call void @puts(i8* noundef getelementptr inbounds ([[LAMBDA_X_SIZE]], [[LAMBDA_X_SIZE]]* @[[LAMBDA_X]], i32 0, i32 0)) + // CHECK: call void @puts(ptr noundef @[[LAMBDA_X]]) DEF_IN_MACRO(); - // CHECK: call void @puts(i8* noundef getelementptr inbounds ([[MACRO_SIZE]], [[MACRO_SIZE]]* @[[MACRO_X]], i32 0, i32 0)) - // CHECK: call void @puts(i8* noundef getelementptr inbounds ([[MACRO_SIZE]], [[MACRO_SIZE]]* @[[MACRO_Y]], i32 0, i32 0)) + // CHECK: call void @puts(ptr noundef @[[MACRO_X]]) + // CHECK: call void @puts(ptr noundef @[[MACRO_Y]]) MACRO_CALLS_MACRO(); - // CHECK: call void @puts(i8* noundef getelementptr inbounds ([[MACRO_MACRO_SIZE]], [[MACRO_MACRO_SIZE]]* @[[MACRO_MACRO_X]], i32 0, i32 0)) - // CHECK: call void @puts(i8* noundef getelementptr inbounds ([[MACRO_MACRO_SIZE]], [[MACRO_MACRO_SIZE]]* @[[MACRO_MACRO_Y]], i32 0, i32 0)) + // CHECK: call void @puts(ptr noundef @[[MACRO_MACRO_X]]) + // CHECK: call void @puts(ptr noundef @[[MACRO_MACRO_Y]]) template_param(); // CHECK: call void @_Z14template_paramIiEvv @@ -148,22 +148,22 @@ int main() { } // CHECK: define linkonce_odr void @_Z14template_paramIiEvv -// CHECK: call void @puts(i8* noundef getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]]* @[[INT3]], i32 0, i32 0)) +// CHECK: call void @puts(ptr noundef @[[INT3]]) // CHECK: define internal void @_Z14template_paramIZZ4mainENKUlvE0_clEvEUlvE_Evv -// CHECK: call void @puts(i8* noundef getelementptr inbounds ([[LAMBDA_SIZE]], [[LAMBDA_SIZE]]* @[[LAMBDA]], i32 0, i32 0)) +// CHECK: call void @puts(ptr noundef @[[LAMBDA]]) // CHECK: define linkonce_odr void @_Z28lambda_in_dependent_functionIiEvv -// CHECK: call void @puts(i8* noundef getelementptr inbounds ([[DEP_INT_SIZE]], [[DEP_INT_SIZE]]* @[[LAMBDA_IN_DEP_INT]], i32 0, i32 0)) +// CHECK: call void @puts(ptr noundef @[[LAMBDA_IN_DEP_INT]]) // CHECK: define internal void @_Z28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_Evv -// CHECK: call void @puts(i8* noundef getelementptr inbounds ([[DEP_LAMBDA_SIZE]], [[DEP_LAMBDA_SIZE]]* @[[LAMBDA_IN_DEP_X]], i32 0, i32 0)) +// CHECK: call void @puts(ptr noundef @[[LAMBDA_IN_DEP_X]]) // CHECK: define linkonce_odr void @_Z13lambda_no_depIidEvT_T0_(i32 noundef %a, double noundef %b) -// CHECK: call void @puts(i8* noundef getelementptr inbounds ([[NO_DEP_LAMBDA_SIZE]], [[NO_DEP_LAMBDA_SIZE]]* @[[LAMBDA_NO_DEP]], i32 0, i32 0)) +// CHECK: call void @puts(ptr noundef @[[LAMBDA_NO_DEP]]) // CHECK: define internal void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_Evv -// CHECK: call void @puts(i8* noundef getelementptr inbounds ([[DEP_LAMBDA1_SIZE]], [[DEP_LAMBDA1_SIZE]]* @[[LAMBDA_TWO_DEP]], i32 0, i32 0)) +// CHECK: call void @puts(ptr noundef @[[LAMBDA_TWO_DEP]]) // CHECK: define internal void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_Evv -// CHECK: call void @puts(i8* noundef getelementptr inbounds ([[DEP_LAMBDA2_SIZE]], [[DEP_LAMBDA2_SIZE]]* @[[LAMBDA_TWO_DEP2]], i32 0, i32 0)) +// CHECK: call void @puts(ptr noundef @[[LAMBDA_TWO_DEP2]]) diff --git a/clang/test/Driver/aix-ld.c b/clang/test/Driver/aix-ld.c index eb2910db239ff..d5c595495976a 100644 --- a/clang/test/Driver/aix-ld.c +++ b/clang/test/Driver/aix-ld.c @@ -1096,3 +1096,27 @@ // CHECK-RELOCATABLE-NOT: "[[SYSROOT]]/usr/lib{{/|\\\\}}crti.o" // CHECK-RELOCATABLE-NOT: "-l{{.*}}" // CHECK-RELOCATABLE-NOT: "-L{{.*}}" + +// Check powerpc-ibm-aix7.1.0.0. -K is a passthrough linker option. +// RUN: %clang %s 2>&1 -### \ +// RUN: --target=powerpc-ibm-aix7.1.0.0 \ +// RUN: --sysroot %S/Inputs/aix_ppc_tree \ +// RUN: --unwindlib=libunwind \ +// RUN: -K \ +// RUN: | FileCheck --check-prefixes=CHECK-K %s +// CHECK-K: "-cc1" "-triple" "powerpc-ibm-aix7.1.0.0" +// CHECK-K: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK-K: "{{.*}}ld{{(.exe)?}}" +// CHECK-K: "[[SYSROOT]]/usr/lib{{/|\\\\}}crt0.o" +// CHECK-K: "[[SYSROOT]]/usr/lib{{/|\\\\}}crti.o" +// CHECK-K: "-K" + +// Check powerpc-ibm-aix7.1.0.0. -K unused when not linking. +// RUN: %clang %s 2>&1 -### \ +// RUN: --target=powerpc-ibm-aix7.1.0.0 \ +// RUN: --sysroot %S/Inputs/aix_ppc_tree \ +// RUN: --unwindlib=libunwind \ +// RUN: -K \ +// RUN: -c \ +// RUN: | FileCheck --check-prefixes=CHECK-K-UNUSED %s +// CHECK-K-UNUSED: clang: warning: -K: 'linker' input unused [-Wunused-command-line-argument] diff --git a/clang/test/Driver/amdgpu-macros.cl b/clang/test/Driver/amdgpu-macros.cl index 4fa782aa20495..1a481fcdbcca0 100644 --- a/clang/test/Driver/amdgpu-macros.cl +++ b/clang/test/Driver/amdgpu-macros.cl @@ -109,6 +109,8 @@ // RUN: %clang -E -dM -target amdgcn -mcpu=gfx90a %s 2>&1 | FileCheck --check-prefixes=ARCH-GCN,FAST_FMAF %s -DWAVEFRONT_SIZE=64 -DCPU=gfx90a -DFAMILY=GFX9 // RUN: %clang -E -dM -target amdgcn -mcpu=gfx90c %s 2>&1 | FileCheck --check-prefixes=ARCH-GCN,FAST_FMAF %s -DWAVEFRONT_SIZE=64 -DCPU=gfx90c -DFAMILY=GFX9 // RUN: %clang -E -dM -target amdgcn -mcpu=gfx940 %s 2>&1 | FileCheck --check-prefixes=ARCH-GCN,FAST_FMAF %s -DWAVEFRONT_SIZE=64 -DCPU=gfx940 -DFAMILY=GFX9 +// RUN: %clang -E -dM -target amdgcn -mcpu=gfx941 %s 2>&1 | FileCheck --check-prefixes=ARCH-GCN,FAST_FMAF %s -DWAVEFRONT_SIZE=64 -DCPU=gfx941 -DFAMILY=GFX9 +// RUN: %clang -E -dM -target amdgcn -mcpu=gfx942 %s 2>&1 | FileCheck --check-prefixes=ARCH-GCN,FAST_FMAF %s -DWAVEFRONT_SIZE=64 -DCPU=gfx942 -DFAMILY=GFX9 // RUN: %clang -E -dM -target amdgcn -mcpu=gfx1010 %s 2>&1 | FileCheck --check-prefixes=ARCH-GCN,FAST_FMAF %s -DWAVEFRONT_SIZE=32 -DCPU=gfx1010 -DFAMILY=GFX10 // RUN: %clang -E -dM -target amdgcn -mcpu=gfx1011 %s 2>&1 | FileCheck --check-prefixes=ARCH-GCN,FAST_FMAF %s -DWAVEFRONT_SIZE=32 -DCPU=gfx1011 -DFAMILY=GFX10 // RUN: %clang -E -dM -target amdgcn -mcpu=gfx1012 %s 2>&1 | FileCheck --check-prefixes=ARCH-GCN,FAST_FMAF %s -DWAVEFRONT_SIZE=32 -DCPU=gfx1012 -DFAMILY=GFX10 @@ -156,3 +158,19 @@ // RUN: -mwavefrontsize64 %s 2>&1 | FileCheck --check-prefix=WAVE64 %s // WAVE64-DAG: #define __AMDGCN_WAVEFRONT_SIZE 64 // WAVE32-DAG: #define __AMDGCN_WAVEFRONT_SIZE 32 + +// RUN: %clang -E -dM -target amdgcn -mcpu=gfx906 \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-ON %s +// RUN: %clang -E -dM -target amdgcn -mcpu=gfx906 -mcumode \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-ON %s +// RUN: %clang -E -dM -target amdgcn -mcpu=gfx906 -mno-cumode \ +// RUN: %s 2>&1 | FileCheck --check-prefixes=CUMODE-ON,WARN-CUMODE %s +// RUN: %clang -E -dM -target amdgcn -mcpu=gfx1030 \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-OFF %s +// RUN: %clang -E -dM -target amdgcn -mcpu=gfx1030 -mcumode \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-ON %s +// RUN: %clang -E -dM -target amdgcn -mcpu=gfx1030 -mno-cumode \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-OFF %s +// WARN-CUMODE-DAG: warning: ignoring '-mno-cumode' option as it is not currently supported for processor 'gfx906' [-Woption-ignored] +// CUMODE-ON-DAG: #define __AMDGCN_CUMODE__ 1 +// CUMODE-OFF-DAG: #define __AMDGCN_CUMODE__ 0 diff --git a/clang/test/Driver/amdgpu-mcpu.cl b/clang/test/Driver/amdgpu-mcpu.cl index dfc7ab24927fc..57e4dd4d9d042 100644 --- a/clang/test/Driver/amdgpu-mcpu.cl +++ b/clang/test/Driver/amdgpu-mcpu.cl @@ -93,6 +93,8 @@ // RUN: %clang -### -target amdgcn -mcpu=gfx90a %s 2>&1 | FileCheck --check-prefix=GFX90A %s // RUN: %clang -### -target amdgcn -mcpu=gfx90c %s 2>&1 | FileCheck --check-prefix=GFX90C %s // RUN: %clang -### -target amdgcn -mcpu=gfx940 %s 2>&1 | FileCheck --check-prefix=GFX940 %s +// RUN: %clang -### -target amdgcn -mcpu=gfx941 %s 2>&1 | FileCheck --check-prefix=GFX941 %s +// RUN: %clang -### -target amdgcn -mcpu=gfx942 %s 2>&1 | FileCheck --check-prefix=GFX942 %s // RUN: %clang -### -target amdgcn -mcpu=gfx1010 %s 2>&1 | FileCheck --check-prefix=GFX1010 %s // RUN: %clang -### -target amdgcn -mcpu=gfx1011 %s 2>&1 | FileCheck --check-prefix=GFX1011 %s // RUN: %clang -### -target amdgcn -mcpu=gfx1012 %s 2>&1 | FileCheck --check-prefix=GFX1012 %s @@ -133,6 +135,8 @@ // GFX90A: "-target-cpu" "gfx90a" // GFX90C: "-target-cpu" "gfx90c" // GFX940: "-target-cpu" "gfx940" +// GFX941: "-target-cpu" "gfx941" +// GFX942: "-target-cpu" "gfx942" // GFX1010: "-target-cpu" "gfx1010" // GFX1011: "-target-cpu" "gfx1011" // GFX1012: "-target-cpu" "gfx1012" diff --git a/clang/test/Driver/amdgpu-toolchain.c b/clang/test/Driver/amdgpu-toolchain.c index b8b6667333d81..288dbbedd49d5 100644 --- a/clang/test/Driver/amdgpu-toolchain.c +++ b/clang/test/Driver/amdgpu-toolchain.c @@ -11,6 +11,6 @@ // DWARF_VER: "-dwarf-version=5" // RUN: %clang -### --target=amdgcn-amd-amdhsa -mcpu=gfx906 -nogpulib \ -// RUN: -flto -fconvergent-functions %s 2>&1 | FileCheck -check-prefix=LTO %s +// RUN: -L. -flto -fconvergent-functions %s 2>&1 | FileCheck -check-prefix=LTO %s // LTO: clang{{.*}} "-flto=full"{{.*}}"-fconvergent-functions" -// LTO: ld.lld{{.*}}-plugin-opt=mcpu=gfx906 +// LTO: ld.lld{{.*}}"-L."{{.*}}"-plugin-opt=mcpu=gfx906" diff --git a/clang/test/Driver/check-time-trace-sections.cpp b/clang/test/Driver/check-time-trace-sections.cpp deleted file mode 100644 index 2dbe2037550a5..0000000000000 --- a/clang/test/Driver/check-time-trace-sections.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// RUN: %clangxx -S -ftime-trace -ftime-trace-granularity=0 -o %T/check-time-trace-sections %s -// RUN: cat %T/check-time-trace-sections.json | %python %S/check-time-trace-sections.py - -template -void foo(T) {} -void bar() { foo(0); } diff --git a/clang/test/Driver/check-time-trace.cpp b/clang/test/Driver/check-time-trace.cpp deleted file mode 100644 index 32940500db1bc..0000000000000 --- a/clang/test/Driver/check-time-trace.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// RUN: %clangxx -S -ftime-trace -ftime-trace-granularity=0 -o %T/check-time-trace %s -// RUN: cat %T/check-time-trace.json \ -// RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \ -// RUN: | FileCheck %s -// RUN: %clangxx -S -ftime-trace=%T/new-name.json -ftime-trace-granularity=0 -o %T/check-time-trace %s -// RUN: cat %T/new-name.json \ -// RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \ -// RUN: | FileCheck %s -// RUN: rm -rf %T/output1 && mkdir %T/output1 -// RUN: %clangxx -S -ftime-trace=%T/output1 -ftime-trace-granularity=0 -o %T/check-time-trace %s -// RUN: cat %T/output1/check-time-trace.json \ -// RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \ -// RUN: | FileCheck %s -// RUN: rm -rf %T/output2 && mkdir %T/output2 -// RUN: %clangxx -S -ftime-trace=%T/output2/ -ftime-trace-granularity=0 -o %T/check-time-trace %s -// RUN: cat %T/output2/check-time-trace.json \ -// RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \ -// RUN: | FileCheck %s - -// CHECK: "beginningOfTime": {{[0-9]{16},}} -// CHECK-NEXT: "traceEvents": [ -// CHECK: "args": -// CHECK: "detail": -// CHECK: "dur": -// CHECK: "name": -// CHECK-NEXT: "ph": -// CHECK-NEXT: "pid": -// CHECK-NEXT: "tid": -// CHECK-NEXT: "ts": -// CHECK: "name": "{{clang|llvm}}{{.*}}" -// CHECK: "name": "process_name" -// CHECK: "name": "thread_name" - -template -struct Struct { - T Num; -}; - -int main() { - Struct S; - - return 0; -} diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c index b32b44ab31648..12d7023bd61b1 100644 --- a/clang/test/Driver/cl-options.c +++ b/clang/test/Driver/cl-options.c @@ -604,7 +604,7 @@ // STDCXX20: -std=c++20 // RUN: %clang_cl -fmsc-version=1900 -TP -std:c++latest -### -- %s 2>&1 | FileCheck -check-prefix=STDCXXLATEST %s -// STDCXXLATEST: -std=c++23 +// STDCXXLATEST: -std=c++26 // RUN: env CL="/Gy" %clang_cl -### -- %s 2>&1 | FileCheck -check-prefix=ENV-CL %s // ENV-CL: "-ffunction-sections" diff --git a/clang/test/Driver/frame-pointer-elim.c b/clang/test/Driver/frame-pointer-elim.c index 761b2ae713f83..71aca66c46ba7 100644 --- a/clang/test/Driver/frame-pointer-elim.c +++ b/clang/test/Driver/frame-pointer-elim.c @@ -106,6 +106,12 @@ // RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s // RUN: %clang -### -target ve-unknown-linux-gnu -S %s 2>&1 | \ // RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: %clang -### --target=aarch64-linux-android -S %s 2>&1 | \ +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: %clang -### --target=aarch64-linux-android -S -O2 %s 2>&1 | \ +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: %clang -### --target=aarch64-linux-android -S -Os %s 2>&1 | \ +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s // RUN: %clang -### -target powerpc64 -S %s 2>&1 | \ // RUN: FileCheck --check-prefix=KEEP-ALL %s @@ -153,6 +159,9 @@ // RUN: FileCheck --check-prefix=KEEP-ALL %s // RUN: %clang -### -target armv7a-linux-androideabi- -mthumb -mbig-endian -O1 -S %s 2>&1 | \ // RUN: FileCheck --check-prefix=KEEP-ALL %s - +// RUN: %clang -### --target=riscv64-linux-android -O1 -S %s 2>&1 | \ +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: %clang -### --target=riscv64-linux-android -mbig-endian -O1 -S %s 2>&1 | \ +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s void f0() {} void f1() { f0(); } diff --git a/clang/test/Driver/frame-pointer.c b/clang/test/Driver/frame-pointer.c index a007fda5aaf6e..2b4287bf447ca 100644 --- a/clang/test/Driver/frame-pointer.c +++ b/clang/test/Driver/frame-pointer.c @@ -57,6 +57,10 @@ // RUN: %clang --target=riscv64-unknown-linux-gnu -### -S -O3 %s 2>&1 | FileCheck -check-prefix=CHECK3-64 %s // RUN: %clang --target=riscv64-unknown-linux-gnu -### -S -Os %s 2>&1 | FileCheck -check-prefix=CHECKs-64 %s +// RUN: %clang --target=riscv64-linux-android -### -S -O0 %s 2>&1 | FileCheck -check-prefix=CHECK-ANDROID-64 %s +// RUN: %clang --target=riscv64-linux-android -### -S -O1 %s 2>&1 | FileCheck -check-prefix=CHECK-ANDROID-64 %s +// RUN: %clang --target=riscv64-linux-android -### -S -Os %s 2>&1 | FileCheck -check-prefix=CHECK-ANDROID-64 %s + // RUN: %clang --target=loongarch32 -### -S -O0 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK0-32 %s // RUN: %clang --target=loongarch32 -### -S -O1 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK1-32 %s // RUN: %clang --target=loongarch32 -### -S -O2 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK2-32 %s @@ -81,3 +85,5 @@ // CHECK3-64-NOT: -mframe-pointer=all // CHECKs-64-NOT: -mframe-pointer=all // CHECK-MACHO-64: -mframe-pointer=all + +// CHECK-ANDROID-64: -mframe-pointer=non-leaf diff --git a/clang/test/Driver/ftime-trace-sections.cpp b/clang/test/Driver/ftime-trace-sections.cpp new file mode 100644 index 0000000000000..0c16052bc0c3a --- /dev/null +++ b/clang/test/Driver/ftime-trace-sections.cpp @@ -0,0 +1,7 @@ +// RUN: rm -rf %t && mkdir %t && cd %t +// RUN: %clangxx -S -ftime-trace -ftime-trace-granularity=0 -o out %s +// RUN: %python %S/ftime-trace-sections.py < out.json + +template +void foo(T) {} +void bar() { foo(0); } diff --git a/clang/test/Driver/check-time-trace-sections.py b/clang/test/Driver/ftime-trace-sections.py similarity index 100% rename from clang/test/Driver/check-time-trace-sections.py rename to clang/test/Driver/ftime-trace-sections.py diff --git a/clang/test/Driver/ftime-trace.cpp b/clang/test/Driver/ftime-trace.cpp new file mode 100644 index 0000000000000..5fe63de915a71 --- /dev/null +++ b/clang/test/Driver/ftime-trace.cpp @@ -0,0 +1,74 @@ +// RUN: rm -rf %t && mkdir -p %t && cd %t +// RUN: %clangxx -S -no-canonical-prefixes -ftime-trace -ftime-trace-granularity=0 -o out %s +// RUN: cat out.json \ +// RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \ +// RUN: | FileCheck %s +// RUN: %clangxx -S -no-canonical-prefixes -ftime-trace=new-name.json -ftime-trace-granularity=0 -o out %s +// RUN: cat new-name.json \ +// RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \ +// RUN: | FileCheck %s +// RUN: mkdir dir1 dir2 +// RUN: %clangxx -S -no-canonical-prefixes -ftime-trace=dir1 -ftime-trace-granularity=0 -o out %s +// RUN: cat dir1/out.json \ +// RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \ +// RUN: | FileCheck %s +// RUN: %clangxx -S -no-canonical-prefixes -ftime-trace=dir2/ -ftime-trace-granularity=0 -o out %s +// RUN: cat dir2/out.json \ +// RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \ +// RUN: | FileCheck %s + +// CHECK: "beginningOfTime": {{[0-9]{16},}} +// CHECK-NEXT: "traceEvents": [ +// CHECK: "args": +// CHECK: "detail": +// CHECK: "dur": +// CHECK: "name": +// CHECK-NEXT: "ph": +// CHECK-NEXT: "pid": +// CHECK-NEXT: "tid": +// CHECK-NEXT: "ts": +// CHECK: "name": "{{clang|llvm}}{{.*}}" +// CHECK: "name": "process_name" +// CHECK: "name": "thread_name" + +// RUN: mkdir d e f && cp %s d/a.cpp && touch d/b.c + +/// TODO: Support -fno-integrated-as. +// RUN: %clang -### -c -ftime-trace -ftime-trace-granularity=0 -fintegrated-as d/a.cpp -o e/a.o 2>&1 | FileCheck %s --check-prefix=COMPILE1 +// COMPILE1: -cc1{{.*}} "-ftime-trace=e/a.json" "-ftime-trace-granularity=0" + +// RUN: %clang -### -c -ftime-trace -ftime-trace-granularity=0 d/a.cpp d/b.c -dumpdir f/ 2>&1 | FileCheck %s --check-prefix=COMPILE2 +// COMPILE2: -cc1{{.*}} "-ftime-trace=f/a.json" "-ftime-trace-granularity=0" +// COMPILE2: -cc1{{.*}} "-ftime-trace=f/b.json" "-ftime-trace-granularity=0" + +/// -o specifies the link output. Create ${output}-${basename}.json. +// RUN: %clang -### -ftime-trace -ftime-trace-granularity=0 d/a.cpp d/b.c -o e/x 2>&1 | FileCheck %s --check-prefix=LINK1 +// LINK1: -cc1{{.*}} "-ftime-trace=e/x-a.json" "-ftime-trace-granularity=0" +// LINK1: -cc1{{.*}} "-ftime-trace=e/x-b.json" "-ftime-trace-granularity=0" + +/// -dumpdir is f/g, not ending with a path separator. We create f/g${basename}.json. +// RUN: %clang -### -ftime-trace -ftime-trace-granularity=0 d/a.cpp d/b.c -o e/x -dumpdir f/g 2>&1 | FileCheck %s --check-prefix=LINK2 +// LINK2: -cc1{{.*}} "-ftime-trace=f/ga.json" "-ftime-trace-granularity=0" +// LINK2: -cc1{{.*}} "-ftime-trace=f/gb.json" "-ftime-trace-granularity=0" + +// RUN: %clang -### -ftime-trace=e -ftime-trace-granularity=0 d/a.cpp d/b.c -o f/x -dumpdir f/ 2>&1 | FileCheck %s --check-prefix=LINK3 +// LINK3: -cc1{{.*}} "-ftime-trace=e{{/|\\\\}}a-{{[^.]*}}.json" "-ftime-trace-granularity=0" +// LINK3: -cc1{{.*}} "-ftime-trace=e{{/|\\\\}}b-{{[^.]*}}.json" "-ftime-trace-granularity=0" + +// RUN: %clang -### -ftime-trace -ftime-trace=e -ftime-trace-granularity=1 -xassembler d/a.cpp 2>&1 | \ +// RUN: FileCheck %s --check-prefix=UNUSED +// UNUSED: warning: argument unused during compilation: '-ftime-trace' +// UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace=e' +// UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace-granularity=1' +// UNUSED-NOT: warning: + +template +struct Struct { + T Num; +}; + +int main() { + Struct S; + + return 0; +} diff --git a/clang/test/Driver/hip-gsplit-dwarf-options.hip b/clang/test/Driver/hip-gsplit-dwarf-options.hip index e9f87872da869..cfd5c5020e663 100644 --- a/clang/test/Driver/hip-gsplit-dwarf-options.hip +++ b/clang/test/Driver/hip-gsplit-dwarf-options.hip @@ -13,13 +13,17 @@ // RUN: %clang -### --target=x86_64-unknown-linux-gnu \ // RUN: --offload-arch=gfx906:xnack+ %s -nogpulib -nogpuinc \ // RUN: --offload-arch=gfx900 \ -// RUN: -ggdb -gsplit-dwarf 2>&1 | FileCheck %s +// RUN: -ggdb -gsplit-dwarf 2>&1 | FileCheck %s --check-prefix=LINK // RUN: %clang -### --target=x86_64-unknown-linux-gnu \ // RUN: -fgpu-rdc --offload-arch=gfx906:xnack+ %s -nogpulib -nogpuinc \ // RUN: --offload-arch=gfx900 \ -// RUN: -ggdb -gsplit-dwarf 2>&1 | FileCheck %s +// RUN: -ggdb -gsplit-dwarf 2>&1 | FileCheck %s --check-prefix=LINK // CHECK-DAG: {{".*clang.*".* "-target-cpu" "gfx906".* "-split-dwarf-output" "hip-gsplit-dwarf-options_gfx906:xnack\+.dwo"}} // CHECK-DAG: {{".*clang.*".* "-target-cpu" "gfx900".* "-split-dwarf-output" "hip-gsplit-dwarf-options_gfx900.dwo"}} // CHECK-DAG: {{".*clang.*".* "-target-cpu" "x86-64".* "-split-dwarf-output" "hip-gsplit-dwarf-options.dwo"}} + +// LINK-DAG: {{".*clang.*".* "-target-cpu" "gfx906".* "-split-dwarf-output" "a-hip-gsplit-dwarf-options_gfx906:xnack\+.dwo"}} +// LINK-DAG: {{".*clang.*".* "-target-cpu" "gfx900".* "-split-dwarf-output" "a-hip-gsplit-dwarf-options_gfx900.dwo"}} +// LINK-DAG: {{".*clang.*".* "-target-cpu" "x86-64".* "-split-dwarf-output" "a-hip-gsplit-dwarf-options.dwo"}} diff --git a/clang/test/Driver/hip-macros.hip b/clang/test/Driver/hip-macros.hip index 49a83b1414342..f32ee0e64a23c 100644 --- a/clang/test/Driver/hip-macros.hip +++ b/clang/test/Driver/hip-macros.hip @@ -19,3 +19,26 @@ // RUN: -mwavefrontsize64 %s 2>&1 | FileCheck --check-prefixes=WAVE64 %s // WAVE64-DAG: #define __AMDGCN_WAVEFRONT_SIZE 64 // WAVE32-DAG: #define __AMDGCN_WAVEFRONT_SIZE 32 + +// RUN: %clang -E -dM --offload-arch=gfx906 --cuda-device-only -nogpuinc -nogpulib \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-ON %s +// RUN: %clang -E -dM --offload-arch=gfx906 --cuda-device-only -nogpuinc -nogpulib -mcumode \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-ON %s +// RUN: %clang -E -dM --offload-arch=gfx906 --cuda-device-only -nogpuinc -nogpulib -mno-cumode \ +// RUN: %s 2>&1 | FileCheck --check-prefixes=CUMODE-ON,WARN-CUMODE %s +// RUN: %clang -E -dM --offload-arch=gfx1030 --cuda-device-only -nogpuinc -nogpulib \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-OFF %s +// RUN: %clang -E -dM --offload-arch=gfx1030 --cuda-device-only -nogpuinc -nogpulib -mcumode \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-ON %s +// RUN: %clang -E -dM --offload-arch=gfx1030 --cuda-device-only -nogpuinc -nogpulib -mno-cumode \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-OFF %s + +// Check no duplicate warnings. +// RUN: %clang -E -dM --offload-arch=gfx906 --cuda-device-only -nogpuinc -nogpulib -mcumode \ +// RUN: -mno-cumode -mno-cumode \ +// RUN: %s 2>&1 | FileCheck --check-prefixes=CUMODE-ON,WARN-CUMODE %s + +// WARN-CUMODE-DAG: warning: ignoring '-mno-cumode' option as it is not currently supported for processor 'gfx906' [-Woption-ignored] +// WARN-CUMODE-NOT: warning: ignoring '-mno-cumode' option as it is not currently supported for processor 'gfx906' [-Woption-ignored] +// CUMODE-ON-DAG: #define __AMDGCN_CUMODE__ 1 +// CUMODE-OFF-DAG: #define __AMDGCN_CUMODE__ 0 diff --git a/clang/test/Driver/ppc-roptr.c b/clang/test/Driver/ppc-roptr.c new file mode 100644 index 0000000000000..0ab740da9e04a --- /dev/null +++ b/clang/test/Driver/ppc-roptr.c @@ -0,0 +1,46 @@ +// RUN: %clang -### --target=powerpc-ibm-aix-xcoff -mxcoff-roptr %s 2>&1 | \ +// RUN: FileCheck %s --check-prefixes=ROPTR,LINK +// RUN: %clang -### --target=powerpc-ibm-aix-xcoff -c -mxcoff-roptr %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=ROPTR +// RUN: %clang -### --target=powerpc-ibm-aix-xcoff -mxcoff-roptr -mno-xcoff-roptr %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=NO_ROPTR + +// RUN: %clang -### --target=powerpc64-ibm-aix-xcoff -mxcoff-roptr %s 2>&1 | \ +// RUN: FileCheck %s --check-prefixes=ROPTR,LINK +// RUN: %clang -### --target=powerpc64-ibm-aix-xcoff -S -mxcoff-roptr %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=ROPTR +// RUN: %clang -### --target=powerpc-ibm-aix-xcoff %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=NO_ROPTR +// RUN: %clang -### --target=powerpc64-ibm-aix-xcoff -mxcoff-roptr -flto %s 2>&1 | \ +// RUN: FileCheck %s --check-prefixes=ROPTR,LINK,LTO_ROPTR +// RUN: touch %t.o +// RUN: %clang -### --target=powerpc64-ibm-aix-xcoff -mxcoff-roptr %t.o 2>&1 | \ +// RUN: FileCheck %s --check-prefix=LINK + +// RUN: %clang -### --target=powerpc64le-unknown-linux-gnu -mxcoff-roptr \ +// RUN: %s 2>&1 | FileCheck %s --check-prefix=TARGET_ROPTR_ERR +// RUN: %clang -### --target=powerpc64le-unknown-linux-gnu -mno-xcoff-roptr \ +// RUN: %s 2>&1 | FileCheck %s --check-prefix=TARGET_NOROPTR_ERR +// RUN: touch %t.o +// RUN: %clang -### --target=powerpc64-ibm-aix-xcoff -mxcoff-roptr -shared \ +// RUN: %t.o 2>&1 | FileCheck %s --check-prefix=SHARED_ERR +// RUN: %clang -### --target=powerpc64le-unknown-linux-gnu -mxcoff-roptr -flto \ +// RUN: %t.o 2>&1 | FileCheck %s --check-prefix=TARGET_ROPTR_ERR +// RUN: %clang -### --target=powerpc64-ibm-aix-xcoff -mxcoff-roptr -flto -fno-data-sections \ +// RUN: %t.o 2>&1 | FileCheck %s --check-prefix=DATA_SECTION_ERR +// RUN: %clang -### --target=powerpc64-ibm-aix-xcoff -mno-xcoff-roptr -flto -fno-data-sections \ +// RUN: %t.o 2>&1 | FileCheck %s --check-prefix=NO_DATA_SECTION_ERR +// RUN: %clang -### --target=powerpc64le-unknown-linux-gnu -mno-xcoff-roptr -flto \ +// RUN: %t.o 2>&1 | FileCheck %s --check-prefix=TARGET_NOROPTR_ERR + +// ROPTR: "-mxcoff-roptr" +// LINK: "-bforceimprw" +// LTO_ROPTR: "-bplugin_opt:-mxcoff-roptr" +// NO_ROPTR-NOT: "-mxcoff-roptr" +// NO_ROPTR-NOT: "-bforceimprw" + +// DATA_SECTION_ERR: error: -mxcoff-roptr is supported only with -fdata-sections +// NO_DATA_SECTION_ERR-NOT: error: -mxcoff-roptr is supported only with -fdata-sections +// TARGET_ROPTR_ERR: error: unsupported option '-mxcoff-roptr' for target 'powerpc64le-unknown-linux-gnu' +// TARGET_NOROPTR_ERR: error: unsupported option '-mno-xcoff-roptr' for target 'powerpc64le-unknown-linux-gnu' +// SHARED_ERR: error: -mxcoff-roptr is not supported with -shared diff --git a/clang/test/Driver/split-debug.c b/clang/test/Driver/split-debug.c index 94db20b554046..e45d2e19bb81e 100644 --- a/clang/test/Driver/split-debug.c +++ b/clang/test/Driver/split-debug.c @@ -9,6 +9,7 @@ // INLINE: "-fsplit-dwarf-inlining" // NOINLINE-NOT: "-fsplit-dwarf-inlining" +// SPLIT-NOT: "-dumpdir" // SPLIT: "-debug-info-kind=constructor" // SPLIT-SAME: "-ggnu-pubnames" // SPLIT-SAME: "-split-dwarf-file" "split-debug.dwo" "-split-dwarf-output" "split-debug.dwo" @@ -54,8 +55,29 @@ // SINGLE_WITH_FILENAME: "-split-dwarf-file" "{{.*}}foo.o" // SINGLE_WITH_FILENAME-NOT: "-split-dwarf-output" -/// Without -c, clang performs linking as well. The output is unchanged. -// RUN: %clang -### -target x86_64-unknown-linux-gnu -gsplit-dwarf -g %s -o ignore.d 2>&1 | FileCheck %s --check-prefix=SPLIT +/// If linking is the final phase, the .dwo filename is derived from -o (if specified) or "a". +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -gsplit-dwarf -g %s -o obj/out 2>&1 | FileCheck %s --check-prefix=SPLIT_LINK +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -gsplit-dwarf -g %s 2>&1 | FileCheck %s --check-prefix=SPLIT_LINK_A + +// SPLIT_LINK: "-dumpdir" "obj/out-" +// SPLIT_LINK: "-debug-info-kind=constructor" +// SPLIT_LINK-SAME: "-split-dwarf-file" "obj/out-split-debug.dwo" "-split-dwarf-output" "obj/out-split-debug.dwo" +// SPLIT_LINK_A: "-dumpdir" "a-" +// SPLIT_LINK_A-SAME: "-split-dwarf-file" "a-split-debug.dwo" "-split-dwarf-output" "a-split-debug.dwo" + +/// GCC special cases /dev/null (HOST_BIT_BUCKET) but not other special files like /dev/zero. +/// We don't apply special rules at all. +// RUN: %if !system-windows %{ %clang -### --target=x86_64-unknown-linux-gnu -gsplit-dwarf -g %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=SPLIT_LINK_NULL %} + +// SPLIT_LINK_NULL: "-dumpdir" "/dev/null-" +// SPLIT_LINK_NULL-SAME: "-split-dwarf-output" "/dev/null-split-debug.dwo" + +/// If -dumpdir is specified, use its value to derive the .dwo filename. +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -gsplit-dwarf -g %s -o obj/out -dumpdir pf/x -c 2>&1 | FileCheck %s --check-prefix=DUMPDIR +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -gsplit-dwarf -g %s -o obj/out -dumpdir pf/x 2>&1 | FileCheck %s --check-prefix=DUMPDIR + +// DUMPDIR: "-dumpdir" "pf/x" +// DUMPDIR-SAME: "-split-dwarf-output" "pf/xsplit-debug.dwo" /// -fsplit-dwarf-inlining // RUN: %clang -### -c -target x86_64 -gsplit-dwarf=split -g -fsplit-dwarf-inlining %s 2>&1 | FileCheck %s --check-prefixes=INLINE,SPLIT diff --git a/clang/test/Driver/unknown-std.cpp b/clang/test/Driver/unknown-std.cpp index 1490e9e3a1164..e918c087095ef 100644 --- a/clang/test/Driver/unknown-std.cpp +++ b/clang/test/Driver/unknown-std.cpp @@ -19,6 +19,8 @@ // CHECK-NEXT: note: use 'gnu++20' for 'ISO C++ 2020 DIS with GNU extensions' standard // CHECK-NEXT: note: use 'c++23' for 'ISO C++ 2023 DIS' standard // CHECK-NEXT: note: use 'gnu++23' for 'ISO C++ 2023 DIS with GNU extensions' standard +// CHECK-NEXT: note: use 'c++2c' or 'c++26' for 'Working draft for C++2c' standard +// CHECK-NEXT: note: use 'gnu++2c' or 'gnu++26' for 'Working draft for C++2c with GNU extensions' standard // CUDA-NEXT: note: use 'cuda' for 'NVIDIA CUDA(tm)' standard // Make sure that no other output is present. diff --git a/clang/test/Driver/unsupported-target-K.c b/clang/test/Driver/unsupported-target-K.c new file mode 100644 index 0000000000000..8b9a6f529c326 --- /dev/null +++ b/clang/test/Driver/unsupported-target-K.c @@ -0,0 +1,8 @@ +// Check powerpc64-unknown-linux-gnu. -K not supported. +// RUN: %clang %s 2>&1 -### \ +// RUN: --target=powerpc64-unknown-linux-gnu \ +// RUN: --sysroot %S/Inputs/aix_ppc_tree \ +// RUN: --unwindlib=libunwind \ +// RUN: -K \ +// RUN: | FileCheck --check-prefixes=CHECK-K-SUPPORT %s +// CHECK-K-SUPPORT: clang: error: unsupported option '-K' for target 'powerpc64-unknown-linux-gnu' diff --git a/clang/test/Index/Core/index-source.cpp b/clang/test/Index/Core/index-source.cpp index 781343e008fa6..8f9fbc4c8d29c 100644 --- a/clang/test/Index/Core/index-source.cpp +++ b/clang/test/Index/Core/index-source.cpp @@ -405,7 +405,7 @@ template | Ref,RelCont | rel: 1 // CHECK-NEXT: RelCont | TemplateDefaultValues | c:@ST>3#T#NI#t>1#T@TemplateDefaultValues int x = Record::C, -// CHECK: [[@LINE-1]]:26 | static-property/C++ | C | c:@S@Record@C | __ZN6Record1CE | Ref,Read,RelCont | rel: 1 +// CHECK: [[@LINE-1]]:26 | static-property/C++ | C | c:@S@Record@C | __ZN6Record1CE | Ref,RelCont | rel: 1 // CHECK-NEXT: RelCont | TemplateDefaultValues | c:@ST>3#T#NI#t>1#T@TemplateDefaultValues // CHECK: [[@LINE-3]]:18 | struct/C++ | Record | c:@S@Record | | Ref,RelCont | rel: 1 template class Collection = ns2::ACollectionDecl> diff --git a/clang/test/Layout/aix-Wpacked-expecting-diagnostics.cpp b/clang/test/Layout/aix-Wpacked-expecting-diagnostics.cpp index 37982fcb74b96..1576b8561cb56 100644 --- a/clang/test/Layout/aix-Wpacked-expecting-diagnostics.cpp +++ b/clang/test/Layout/aix-Wpacked-expecting-diagnostics.cpp @@ -6,6 +6,8 @@ // RUN: -fdump-record-layouts -fsyntax-only -verify -x c++ < %s | \ // RUN: FileCheck %s +// expected-no-diagnostics + struct A { double d; }; @@ -14,7 +16,7 @@ struct B { char x[8]; }; -struct [[gnu::packed]] C : B, A { // expected-warning{{packed attribute is unnecessary for 'C'}} +struct [[gnu::packed]] C : B, A { char x alignas(4)[8]; }; diff --git a/clang/test/Misc/target-invalid-cpu-note.c b/clang/test/Misc/target-invalid-cpu-note.c index ddc639dc60a80..598a12fac33fd 100644 --- a/clang/test/Misc/target-invalid-cpu-note.c +++ b/clang/test/Misc/target-invalid-cpu-note.c @@ -29,7 +29,7 @@ // RUN: not %clang_cc1 -triple nvptx--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix NVPTX // NVPTX: error: unknown target CPU 'not-a-cpu' -// NVPTX-NEXT: note: valid target CPU values are: sm_20, sm_21, sm_30, sm_32, sm_35, sm_37, sm_50, sm_52, sm_53, sm_60, sm_61, sm_62, sm_70, sm_72, sm_75, sm_80, sm_86, sm_87, sm_89, sm_90, gfx600, gfx601, gfx602, gfx700, gfx701, gfx702, gfx703, gfx704, gfx705, gfx801, gfx802, gfx803, gfx805, gfx810, gfx900, gfx902, gfx904, gfx906, gfx908, gfx909, gfx90a, gfx90c, gfx940, gfx1010, gfx1011, gfx1012, gfx1013, gfx1030, gfx1031, gfx1032, gfx1033, gfx1034, gfx1035, gfx1036, gfx1100, gfx1101, gfx1102, gfx1103{{$}} +// NVPTX-NEXT: note: valid target CPU values are: sm_20, sm_21, sm_30, sm_32, sm_35, sm_37, sm_50, sm_52, sm_53, sm_60, sm_61, sm_62, sm_70, sm_72, sm_75, sm_80, sm_86, sm_87, sm_89, sm_90, gfx600, gfx601, gfx602, gfx700, gfx701, gfx702, gfx703, gfx704, gfx705, gfx801, gfx802, gfx803, gfx805, gfx810, gfx900, gfx902, gfx904, gfx906, gfx908, gfx909, gfx90a, gfx90c, gfx940, gfx941, gfx942, gfx1010, gfx1011, gfx1012, gfx1013, gfx1030, gfx1031, gfx1032, gfx1033, gfx1034, gfx1035, gfx1036, gfx1100, gfx1101, gfx1102, gfx1103{{$}} // RUN: not %clang_cc1 -triple r600--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix R600 // R600: error: unknown target CPU 'not-a-cpu' @@ -37,7 +37,7 @@ // RUN: not %clang_cc1 -triple amdgcn--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix AMDGCN // AMDGCN: error: unknown target CPU 'not-a-cpu' -// AMDGCN-NEXT: note: valid target CPU values are: gfx600, tahiti, gfx601, pitcairn, verde, gfx602, hainan, oland, gfx700, kaveri, gfx701, hawaii, gfx702, gfx703, kabini, mullins, gfx704, bonaire, gfx705, gfx801, carrizo, gfx802, iceland, tonga, gfx803, fiji, polaris10, polaris11, gfx805, tongapro, gfx810, stoney, gfx900, gfx902, gfx904, gfx906, gfx908, gfx909, gfx90a, gfx90c, gfx940, gfx1010, gfx1011, gfx1012, gfx1013, gfx1030, gfx1031, gfx1032, gfx1033, gfx1034, gfx1035, gfx1036, gfx1100, gfx1101, gfx1102, gfx1103{{$}} +// AMDGCN-NEXT: note: valid target CPU values are: gfx600, tahiti, gfx601, pitcairn, verde, gfx602, hainan, oland, gfx700, kaveri, gfx701, hawaii, gfx702, gfx703, kabini, mullins, gfx704, bonaire, gfx705, gfx801, carrizo, gfx802, iceland, tonga, gfx803, fiji, polaris10, polaris11, gfx805, tongapro, gfx810, stoney, gfx900, gfx902, gfx904, gfx906, gfx908, gfx909, gfx90a, gfx90c, gfx940, gfx941, gfx942, gfx1010, gfx1011, gfx1012, gfx1013, gfx1030, gfx1031, gfx1032, gfx1033, gfx1034, gfx1035, gfx1036, gfx1100, gfx1101, gfx1102, gfx1103{{$}} // RUN: not %clang_cc1 -triple wasm64--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix WEBASM // WEBASM: error: unknown target CPU 'not-a-cpu' diff --git a/clang/test/Modules/match_initializer_list.cpp b/clang/test/Modules/match_initializer_list.cpp new file mode 100644 index 0000000000000..31e2b015a9d05 --- /dev/null +++ b/clang/test/Modules/match_initializer_list.cpp @@ -0,0 +1,19 @@ +// RUN: rm -rf %t +// +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t \ +// RUN: -I %S/Inputs/initializer_list \ +// RUN: -fmodule-map-file=%S/Inputs/initializer_list/direct.modulemap \ +// RUN: %s -verify + +// expected-no-diagnostics + +class C { + public: + virtual ~C() {} +}; + +#include "Inputs/initializer_list/direct.h" + +void takesInitList(std::initializer_list); + +void passesInitList() { takesInitList({0}); } diff --git a/clang/test/Modules/named-modules-adl-3.cppm b/clang/test/Modules/named-modules-adl-3.cppm new file mode 100644 index 0000000000000..2fc2962c926b1 --- /dev/null +++ b/clang/test/Modules/named-modules-adl-3.cppm @@ -0,0 +1,64 @@ +// 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 -fmodule-file=a=%t/a.pcm -emit-module-interface \ +// RUN: -o %t/b.pcm +// RUN: %clang_cc1 -std=c++20 %t/c.cppm -fmodule-file=a=%t/a.pcm -fmodule-file=b=%t/b.pcm \ +// RUN: -fsyntax-only -verify +// +// RUN: %clang_cc1 -std=c++20 -DEXPORT_OPERATOR %t/a.cppm -emit-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 -DEXPORT_OPERATOR %t/b.cppm -fmodule-file=a=%t/a.pcm \ +// RUN: -emit-module-interface -o %t/b.pcm +// RUN: %clang_cc1 -std=c++20 -DEXPORT_OPERATOR %t/c.cppm -fmodule-file=a=%t/a.pcm \ +// RUN: -fmodule-file=b=%t/b.pcm -fsyntax-only -verify + +//--- foo.h +namespace n { + +struct s { }; + +void operator+(s, int) {} + +} // namespace n + +//--- a.cppm +module; +#include "foo.h" +export module a; +export namespace n { + using n::s; +#ifdef EXPORT_OPERATOR + using n::operator+; +#endif +} + +//--- b.cppm +export module b; +export import a; + +export template +void b(T x) { + n::s() + x; +} + +//--- c.cppm +#ifdef EXPORT_OPERATOR +// expected-no-diagnostics +#endif +export module c; +import b; + +void c(int x) { +#ifndef EXPORT_OPERATOR + // expected-error@b.cppm:6 {{invalid operands to binary expression ('n::s' and 'int')}} + // expected-note@+2 {{in instantiation of function template specialization 'b' requested here}} +#endif + b(0); + +#ifndef EXPORT_OPERATOR + // expected-error@+2 {{invalid operands to binary expression ('n::s' and 'int')}} +#endif + n::s() + x; +} diff --git a/clang/test/Modules/pr61892.cppm b/clang/test/Modules/pr61892.cppm new file mode 100644 index 0000000000000..99d02f36b2b54 --- /dev/null +++ b/clang/test/Modules/pr61892.cppm @@ -0,0 +1,65 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple \ +// RUN: -emit-module-interface %t/a.cppm -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple \ +// RUN: %t/b.cpp -fmodule-file=a=%t/a.pcm -disable-llvm-passes \ +// RUN: -emit-llvm -o - | FileCheck %t/b.cpp +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple \ +// RUN: %t/c.cpp -fmodule-file=a=%t/a.pcm -disable-llvm-passes \ +// RUN: -emit-llvm -o - | FileCheck %t/c.cpp + +//--- a.cppm +export module a; + +struct integer { + explicit operator int() const { + return 0; + } +}; + +export template +int a = static_cast(integer()); + +struct s { + ~s(); + operator int() const; +}; + +export template +auto d = s(); + +int aa() { + return a + d; +} + +int dynamic_func(); +export inline int dynamic_var = dynamic_func(); + +//--- b.cpp +import a; + +void b() {} + +// CHECK-NOT: @_ZW1a1dIvE = +// CHECK-NOT: @_ZGVW1a1dIvE = +// CHECK-NOT: @_ZW1a11dynamic_var = +// CHECK-NOT: @_ZGVW1a11dynamic_var = +// CHECK-NOT: @_ZW1a1aIvE = +// CHECK-NOT: @_ZGVW1a1aIvE = + +//--- c.cpp +import a; +int c() { + return a + d + dynamic_var; +} + +// The used variables are generated normally +// CHECK-DAG: @_ZW1a1aIvE = +// CHECK-DAG: @_ZW1a1dIvE = +// CHECK-DAG: @_ZW1a11dynamic_var = linkonce_odr +// CHECK-DAG: @_ZGVW1a1aIvE = +// CHECk-DAG: @_ZGVW1a1dIvE = +// CHECK-DAG: @_ZGVW1a11dynamic_var = linkonce_odr diff --git a/clang/test/Modules/pr62158.cppm b/clang/test/Modules/pr62158.cppm new file mode 100644 index 0000000000000..7a0761df77158 --- /dev/null +++ b/clang/test/Modules/pr62158.cppm @@ -0,0 +1,46 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/lib.cppm -o %t/lib.pcm +// RUN: %clang_cc1 -std=c++20 %t/main.cpp -fmodule-file=lib=%t/lib.pcm \ +// RUN: -verify -fsyntax-only + +//--- header.h +namespace lib::inline __1 { +template +inline constexpr bool test = false; +template +constexpr bool func() { + return false; +} +inline constexpr bool non_templ = true; +} // namespace lib + +//--- lib.cppm +module; +#include "header.h" +export module lib; + +export namespace lib { + using lib::test; + using lib::func; + using lib::non_templ; +} // namespace lib + +//--- main.cpp +// expected-no-diagnostics +import lib; + +struct foo {}; + +template <> +inline constexpr bool lib::test = true; + +template <> +constexpr bool lib::func() { + return true; +} + +static_assert(lib::test); +static_assert(lib::func()); diff --git a/clang/test/Modules/pr62589.cppm b/clang/test/Modules/pr62589.cppm new file mode 100644 index 0000000000000..4164c3405ac0e --- /dev/null +++ b/clang/test/Modules/pr62589.cppm @@ -0,0 +1,79 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++23 -emit-module-interface %t/a.cppm -o %t/a.pcm +// RUN: %clang_cc1 -std=c++23 %t/b.cpp -fmodule-file=a=%t/a.pcm -fsyntax-only -verify + +//--- foo.h +class TypeA {}; + +template +concept __comparable = requires (_Tp &&__t, _Up &&__u) { + __t == __u; +}; + +namespace ranges { +namespace __end { + template + concept __member_end = + requires(_Tp&& __t) { + { __t.end() } -> __comparable; + }; + + struct __fn { + template + requires __member_end<_Tp> + constexpr auto operator()(_Tp&& __t) const + { + return true; + } + + void operator()(auto&&) const = delete; + }; +} + +inline namespace __cpo { + inline constexpr auto end = __end::__fn{}; +} +} + +template +concept range = requires(_Tp& __t) { + ranges::end(__t); +}; + +template +class a { +public: + a(T*) {} + TypeA end() { return {}; } +}; + +template +class a_view { +public: + template + a_view(a) {} +}; +template +a_view(_Range) -> a_view; + +constexpr bool operator==(TypeA, TypeA) { + return true; +} + +//--- a.cppm +module; +#include "foo.h" +export module a; +export using ::a; +export using ::a_view; + +//--- b.cpp +// expected-no-diagnostics +import a; +void use() { + auto _ = a{"char"}; + auto __ = a_view{_}; +} diff --git a/clang/test/Modules/pr62705.cppm b/clang/test/Modules/pr62705.cppm new file mode 100644 index 0000000000000..a09bdf2563e84 --- /dev/null +++ b/clang/test/Modules/pr62705.cppm @@ -0,0 +1,48 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 %t/a.cppm -std=c++20 -triple %itanium_abi_triple \ +// RUN: -emit-module-interface -o %t/a.pcm +// RUN: %clang_cc1 %t/b.cppm -std=c++20 -triple %itanium_abi_triple \ +// RUN: -emit-module-interface -o %t/b.pcm \ +// RUN: -fmodule-file=a=%t/a.pcm +// RUN: %clang_cc1 %t/b.pcm -std=c++20 -triple %itanium_abi_triple \ +// RUN: -emit-llvm -o - | FileCheck %t/b.cppm + +//--- foo.h +namespace n { + +template +struct s0 { + static int m; +}; + +template +struct s1 { + using type = s0; +}; + +} + +template +void require(n::s1) { +} + +//--- a.cppm +module; + +#include "foo.h" + +export module a; + +//--- b.cppm +module; + +#include "foo.h" + +export module b; +import a; + +// Check the LLVM IR of module 'b' get generated correctly. +// CHECK: define{{.*}}@_ZGIW1b diff --git a/clang/test/Modules/predefined.cpp b/clang/test/Modules/predefined.cpp new file mode 100644 index 0000000000000..fbe0c4e23ca59 --- /dev/null +++ b/clang/test/Modules/predefined.cpp @@ -0,0 +1,27 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cd %t + +// RUN: %clang_cc1 -x c++ -std=c++20 -emit-module-interface a.h -o a.pcm -fms-extensions -verify +// RUN: %clang_cc1 -std=c++20 a.cpp -fmodule-file=A=a.pcm -fms-extensions -fsyntax-only -verify + +//--- a.h + +// expected-no-diagnostics + +export module A; + +export template +void f() { + char a[] = __func__; +} + +//--- a.cpp + +// expected-warning@a.h:8 {{initializing an array from a '__func__' predefined identifier is a Microsoft extension}} + +import A; + +void g() { + f(); // expected-note {{in instantiation of function template specialization 'f' requested here}} +} diff --git a/clang/test/OpenMP/atomic_capture_codegen.cpp b/clang/test/OpenMP/atomic_capture_codegen.cpp index 95509df9ba935..a5eca0197a8a0 100644 --- a/clang/test/OpenMP/atomic_capture_codegen.cpp +++ b/clang/test/OpenMP/atomic_capture_codegen.cpp @@ -1,19 +1,19 @@ -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-50 %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-50 %s -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp-simd -x c -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp-simd -x c -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -fopenmp-version=51 -x c -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -fopenmp-version=51 -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -fopenmp-version=51 -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -fopenmp-version=51 -x c -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=51 -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=51 -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp-simd -fopenmp-version=51 -x c -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -fopenmp-version=51 -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -fopenmp-version=51 -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp-simd -fopenmp-version=51 -x c -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=51 -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=51 -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s // SIMD-ONLY0-NOT: {{__kmpc|__tgt}} // expected-no-diagnostics #ifndef HEADER @@ -91,268 +91,256 @@ float2 float2x; register int rix __asm__("esp"); int main(void) { -// CHECK: [[PREV:%.+]] = atomicrmw add i8* @{{.+}}, i8 1 monotonic, align 1 -// CHECK: store i8 [[PREV]], i8* @{{.+}}, +// CHECK: [[PREV:%.+]] = atomicrmw add ptr @{{.+}}, i8 1 monotonic, align 1 +// CHECK: store i8 [[PREV]], ptr @{{.+}}, #pragma omp atomic capture bv = bx++; -// CHECK: atomicrmw add i8* @{{.+}}, i8 1 monotonic, align 1 +// CHECK: atomicrmw add ptr @{{.+}}, i8 1 monotonic, align 1 // CHECK: add nsw i32 %{{.+}}, 1 -// CHECK: store i8 %{{.+}}, i8* @{{.+}}, +// CHECK: store i8 %{{.+}}, ptr @{{.+}}, #pragma omp atomic capture cv = ++cx; -// CHECK: [[PREV:%.+]] = atomicrmw sub i8* @{{.+}}, i8 1 monotonic, align 1 -// CHECK: store i8 [[PREV]], i8* @{{.+}}, +// CHECK: [[PREV:%.+]] = atomicrmw sub ptr @{{.+}}, i8 1 monotonic, align 1 +// CHECK: store i8 [[PREV]], ptr @{{.+}}, #pragma omp atomic capture ucv = ucx--; -// CHECK: atomicrmw sub i16* @{{.+}}, i16 1 monotonic, align 2 +// CHECK: atomicrmw sub ptr @{{.+}}, i16 1 monotonic, align 2 // CHECK: sub nsw i32 %{{.+}}, 1 -// CHECK: store i16 %{{.+}}, i16* @{{.+}}, +// CHECK: store i16 %{{.+}}, ptr @{{.+}}, #pragma omp atomic capture sv = --sx; -// CHECK: [[USV:%.+]] = load i16, i16* @{{.+}}, +// CHECK: [[USV:%.+]] = load i16, ptr @{{.+}}, // CHECK: [[EXPR:%.+]] = zext i16 [[USV]] to i32 -// CHECK: [[X:%.+]] = load atomic i16, i16* [[X_ADDR:@.+]] monotonic, align 2 +// CHECK: [[X:%.+]] = load atomic i16, ptr [[X_ADDR:@.+]] monotonic, align 2 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i16 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[CONV:%.+]] = zext i16 [[EXPECTED]] to i32 // CHECK: [[ADD:%.+]] = add nsw i32 [[CONV]], [[EXPR]] // CHECK: [[DESIRED_CALC:%.+]] = trunc i32 [[ADD]] to i16 -// CHECK: store i16 [[DESIRED_CALC]], i16* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i16, i16* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i16* [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic, align 2 +// CHECK: store i16 [[DESIRED_CALC]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i16, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic, align 2 // CHECK: [[OLD_X]] = extractvalue { i16, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i16, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i16 [[DESIRED_CALC]], i16* @{{.+}}, +// CHECK: store i16 [[DESIRED_CALC]], ptr @{{.+}}, #pragma omp atomic capture sv = usx += usv; -// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}}, -// CHECK: [[X:%.+]] = load atomic i32, i32* [[X_ADDR:@.+]] monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load i32, ptr @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i32, ptr [[X_ADDR:@.+]] monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[DESIRED_CALC:%.+]] = mul nsw i32 [[EXPECTED]], [[EXPR]] -// CHECK: store i32 [[DESIRED_CALC]], i32* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i32, i32* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i32* [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 +// CHECK: store i32 [[DESIRED_CALC]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i32, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 // CHECK: [[OLD_X]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i32 [[DESIRED_CALC]], i32* @{{.+}}, +// CHECK: store i32 [[DESIRED_CALC]], ptr @{{.+}}, #pragma omp atomic capture uiv = ix *= iv; -// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}}, -// CHECK: [[PREV:%.+]] = atomicrmw sub i32* @{{.+}}, i32 [[EXPR]] monotonic, align 4 -// CHECK: store i32 [[PREV]], i32* @{{.+}}, +// CHECK: [[EXPR:%.+]] = load i32, ptr @{{.+}}, +// CHECK: [[PREV:%.+]] = atomicrmw sub ptr @{{.+}}, i32 [[EXPR]] monotonic, align 4 +// CHECK: store i32 [[PREV]], ptr @{{.+}}, #pragma omp atomic capture {iv = uix; uix -= uiv;} -// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}}, -// CHECK: [[X:%.+]] = load atomic i32, i32* [[X_ADDR:@.+]] monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load i32, ptr @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i32, ptr [[X_ADDR:@.+]] monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[DESIRED_CALC:%.+]] = shl i32 [[EXPECTED]], [[EXPR]] -// CHECK: store i32 [[DESIRED_CALC]], i32* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i32, i32* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i32* [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 +// CHECK: store i32 [[DESIRED_CALC]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i32, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 // CHECK: [[OLD_X]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i32 [[DESIRED_CALC]], i32* @{{.+}}, +// CHECK: store i32 [[DESIRED_CALC]], ptr @{{.+}}, #pragma omp atomic capture {ix <<= iv; uiv = ix;} -// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}}, -// CHECK: [[X:%.+]] = load atomic i32, i32* [[X_ADDR:@.+]] monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load i32, ptr @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i32, ptr [[X_ADDR:@.+]] monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[DESIRED_CALC:%.+]] = lshr i32 [[EXPECTED]], [[EXPR]] -// CHECK: store i32 [[DESIRED_CALC]], i32* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i32, i32* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i32* [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 +// CHECK: store i32 [[DESIRED_CALC]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i32, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 // CHECK: [[OLD_X]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i32 [[DESIRED_CALC]], i32* @{{.+}}, +// CHECK: store i32 [[DESIRED_CALC]], ptr @{{.+}}, #pragma omp atomic capture iv = uix >>= uiv; -// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, -// CHECK: [[X:%.+]] = load atomic i64, i64* [[X_ADDR:@.+]] monotonic, align 8 +// CHECK: [[EXPR:%.+]] = load i64, ptr @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i64, ptr [[X_ADDR:@.+]] monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[DESIRED:%.+]] = sdiv i64 [[EXPECTED]], [[EXPR]] -// CHECK: store i64 [[DESIRED]], i64* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i64* [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: store i64 [[DESIRED]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i64, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 // CHECK: [[OLD_X]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i64 [[EXPECTED]], i64* @{{.+}}, +// CHECK: store i64 [[EXPECTED]], ptr @{{.+}}, #pragma omp atomic capture {ulv = lx; lx /= lv;} -// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, -// CHECK: [[OLD:%.+]] = atomicrmw and i64* @{{.+}}, i64 [[EXPR]] monotonic, align 8 +// CHECK: [[EXPR:%.+]] = load i64, ptr @{{.+}}, +// CHECK: [[OLD:%.+]] = atomicrmw and ptr @{{.+}}, i64 [[EXPR]] monotonic, align 8 // CHECK: [[DESIRED:%.+]] = and i64 [[OLD]], [[EXPR]] -// CHECK: store i64 [[DESIRED]], i64* @{{.+}}, +// CHECK: store i64 [[DESIRED]], ptr @{{.+}}, #pragma omp atomic capture {ulx &= ulv; lv = ulx;} -// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, -// CHECK: [[OLD:%.+]] = atomicrmw xor i64* @{{.+}}, i64 [[EXPR]] monotonic, align 8 +// CHECK: [[EXPR:%.+]] = load i64, ptr @{{.+}}, +// CHECK: [[OLD:%.+]] = atomicrmw xor ptr @{{.+}}, i64 [[EXPR]] monotonic, align 8 // CHECK: [[DESIRED:%.+]] = xor i64 [[OLD]], [[EXPR]] -// CHECK: store i64 [[DESIRED]], i64* @{{.+}}, +// CHECK: store i64 [[DESIRED]], ptr @{{.+}}, #pragma omp atomic capture ullv = llx ^= llv; -// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, -// CHECK: [[OLD:%.+]] = atomicrmw or i64* @{{.+}}, i64 [[EXPR]] monotonic, align 8 +// CHECK: [[EXPR:%.+]] = load i64, ptr @{{.+}}, +// CHECK: [[OLD:%.+]] = atomicrmw or ptr @{{.+}}, i64 [[EXPR]] monotonic, align 8 // CHECK: [[DESIRED:%.+]] = or i64 [[OLD]], [[EXPR]] -// CHECK: store i64 [[DESIRED]], i64* @{{.+}}, +// CHECK: store i64 [[DESIRED]], ptr @{{.+}}, #pragma omp atomic capture llv = ullx |= ullv; -// CHECK: [[EXPR:%.+]] = load float, float* @{{.+}}, -// CHECK: [[OLD:%.+]] = atomicrmw fadd float* @{{.+}}, float [[EXPR]] monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load float, ptr @{{.+}}, +// CHECK: [[OLD:%.+]] = atomicrmw fadd ptr @{{.+}}, float [[EXPR]] monotonic, align 4 // CHECK: [[ADD:%.+]] = fadd float [[OLD]], [[EXPR]] // CHECK: [[CAST:%.+]] = fpext float [[ADD]] to double -// CHECK: store double [[CAST]], double* @{{.+}}, +// CHECK: store double [[CAST]], ptr @{{.+}}, #pragma omp atomic capture dv = fx = fx + fv; -// CHECK: [[EXPR:%.+]] = load double, double* @{{.+}}, -// CHECK: [[X:%.+]] = load atomic i64, i64* bitcast (double* [[X_ADDR:@.+]] to i64*) monotonic, align 8 +// CHECK: [[EXPR:%.+]] = load double, ptr @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i64, ptr [[X_ADDR:@.+]] monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] -// CHECK: [[TEMP_I:%.+]] = bitcast double* [[TEMP:%.+]] to i64* // CHECK: [[OLD:%.+]] = bitcast i64 [[EXPECTED]] to double // CHECK: [[SUB:%.+]] = fsub double [[EXPR]], [[OLD]] -// CHECK: store double [[SUB]], double* [[TEMP]], -// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP_I]], -// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (double* [[X_ADDR]] to i64*), i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: store double [[SUB]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i64, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 // CHECK: [[OLD_X:%.+]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] // CHECK: [[CAST:%.+]] = fptrunc double [[OLD]] to float -// CHECK: store float [[CAST]], float* @{{.+}}, +// CHECK: store float [[CAST]], ptr @{{.+}}, #pragma omp atomic capture {fv = dx; dx = dv - dx;} -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}, -// CHECK: [[X:%.+]] = load atomic i128, i128* bitcast (x86_fp80* [[X_ADDR:@.+]] to i128*) monotonic, align 16 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i128, ptr [[X_ADDR:@.+]] monotonic, align 16 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i128 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i128* -// CHECK: store i128 [[EXPECTED]], i128* [[BITCAST]] -// CHECK: [[BITCAST1:%.+]] = bitcast x86_fp80* [[TEMP1:%.+]] to i128* -// CHECK: store i128 [[EXPECTED]], i128* [[BITCAST1]] -// CHECK: [[OLD:%.+]] = load x86_fp80, x86_fp80* [[TEMP1]] +// CHECK: store i128 [[EXPECTED]], ptr [[TEMP:%.+]] +// CHECK: store i128 [[EXPECTED]], ptr [[TEMP1:%.+]] +// CHECK: [[OLD:%.+]] = load x86_fp80, ptr [[TEMP1]] // CHECK: [[MUL:%.+]] = fmul x86_fp80 [[OLD]], [[EXPR]] -// CHECK: store x86_fp80 [[MUL]], x86_fp80* [[TEMP]] -// CHECK: [[DESIRED:%.+]] = load i128, i128* [[BITCAST]] -// CHECK: [[RES:%.+]] = cmpxchg i128* bitcast (x86_fp80* [[X_ADDR]] to i128*), i128 [[EXPECTED]], i128 [[DESIRED]] monotonic monotonic, align 16 +// CHECK: store x86_fp80 [[MUL]], ptr [[TEMP]] +// CHECK: [[DESIRED:%.+]] = load i128, ptr [[TEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i128 [[EXPECTED]], i128 [[DESIRED]] monotonic monotonic, align 16 // CHECK: [[OLD_X:%.+]] = extractvalue { i128, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i128, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] // CHECK: [[CAST:%.+]] = fptrunc x86_fp80 [[MUL]] to double -// CHECK: store double [[CAST]], double* @{{.+}}, +// CHECK: store double [[CAST]], ptr @{{.+}}, #pragma omp atomic capture {ldx = ldx * ldv; dv = ldx;} -// CHECK: [[EXPR_RE:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 0) -// CHECK: [[EXPR_IM:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 1) -// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* [[X_ADDR:@.+]] to i8*), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[EXPR_RE:%.+]] = load i32, ptr @{{.+}} +// CHECK: [[EXPR_IM:%.+]] = load i32, ptr getelementptr inbounds ({ i32, i32 }, ptr @{{.+}}, i32 0, i32 1) +// CHECK: call void @__atomic_load(i64 noundef 8, ptr noundef [[X_ADDR:@.+]], ptr noundef [[EXPECTED_ADDR:%.+]], i32 noundef 0) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 0 -// CHECK: [[LD_RE:%.+]] = load i32, i32* [[LD_RE_ADDR]] -// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 1 -// CHECK: [[LD_IM:%.+]] = load i32, i32* [[LD_IM_ADDR]] +// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[LD_RE:%.+]] = load i32, ptr [[LD_RE_ADDR]] +// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[LD_IM:%.+]] = load i32, ptr [[LD_IM_ADDR]] // -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR]], i32 0, i32 1 -// CHECK: store i32 [[NEW_RE:%.+]], i32* [[X_RE_ADDR]] -// CHECK: store i32 [[NEW_IM:%.+]], i32* [[X_IM_ADDR]] -// CHECK: [[EXPECTED:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR]] to i8* -// CHECK: [[DESIRED:%.+]] = bitcast { i32, i32 }* [[DESIRED_ADDR]] to i8* -// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* [[X_ADDR]] to i8*), i8* noundef [[EXPECTED]], i8* noundef [[DESIRED]], i32 noundef 0, i32 noundef 0) +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store i32 [[NEW_RE:%.+]], ptr [[X_RE_ADDR]] +// CHECK: store i32 [[NEW_IM:%.+]], ptr [[X_IM_ADDR]] +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, ptr noundef [[X_ADDR]], ptr noundef [[EXPECTED_ADDR]], ptr noundef [[DESIRED_ADDR]], i32 noundef 0, i32 noundef 0) // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] // CHECK: [[RE_CAST:%.+]] = sitofp i32 [[NEW_RE]] to float // CHECK: [[IM_CAST:%.+]] = sitofp i32 [[NEW_IM]] to float -// CHECK: store float [[RE_CAST]], float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 0), -// CHECK: store float [[IM_CAST]], float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 1), +// CHECK: store float [[RE_CAST]], ptr @{{.+}}, +// CHECK: store float [[IM_CAST]], ptr getelementptr inbounds ({ float, float }, ptr @{{.+}}, i32 0, i32 1), #pragma omp atomic capture cfv = cix = civ / cix; -// CHECK: [[EXPR_RE:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 0) -// CHECK: [[EXPR_IM:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 1) -// CHECK: [[BITCAST:%.+]] = bitcast { float, float }* [[EXPECTED_ADDR:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 8, i8* noundef bitcast ({ float, float }* [[X_ADDR:@.+]] to i8*), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[EXPR_RE:%.+]] = load float, ptr @{{.+}} +// CHECK: [[EXPR_IM:%.+]] = load float, ptr getelementptr inbounds ({ float, float }, ptr @{{.+}}, i32 0, i32 1) +// CHECK: call void @__atomic_load(i64 noundef 8, ptr noundef [[X_ADDR:@.+]], ptr noundef [[EXPECTED_ADDR:%.+]], i32 noundef 0) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[EXPECTED_ADDR]], i32 0, i32 0 -// CHECK: [[X_RE_OLD:%.+]] = load float, float* [[X_RE_ADDR]] -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[EXPECTED_ADDR]], i32 0, i32 1 -// CHECK: [[X_IM_OLD:%.+]] = load float, float* [[X_IM_ADDR]] +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, ptr [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[X_RE_OLD:%.+]] = load float, ptr [[X_RE_ADDR]] +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, ptr [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[X_IM_OLD:%.+]] = load float, ptr [[X_IM_ADDR]] // -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[DESIRED_ADDR]], i32 0, i32 1 -// CHECK: store float [[NEW_RE:%.+]], float* [[X_RE_ADDR]] -// CHECK: store float [[NEW_IM:%.+]], float* [[X_IM_ADDR]] -// CHECK: [[EXPECTED:%.+]] = bitcast { float, float }* [[EXPECTED_ADDR]] to i8* -// CHECK: [[DESIRED:%.+]] = bitcast { float, float }* [[DESIRED_ADDR]] to i8* -// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, i8* noundef bitcast ({ float, float }* [[X_ADDR]] to i8*), i8* noundef [[EXPECTED]], i8* noundef [[DESIRED]], i32 noundef 0, i32 noundef 0) +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, ptr [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, ptr [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store float [[NEW_RE:%.+]], ptr [[X_RE_ADDR]] +// CHECK: store float [[NEW_IM:%.+]], ptr [[X_IM_ADDR]] +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, ptr noundef [[X_ADDR]], ptr noundef [[EXPECTED_ADDR]], ptr noundef [[DESIRED_ADDR]], i32 noundef 0, i32 noundef 0) // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] // CHECK: [[RE_CAST:%.+]] = fptosi float [[X_RE_OLD]] to i32 // CHECK: [[IM_CAST:%.+]] = fptosi float [[X_IM_OLD]] to i32 -// CHECK: store i32 [[RE_CAST]], i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 0), -// CHECK: store i32 [[IM_CAST]], i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 1), +// CHECK: store i32 [[RE_CAST]], ptr @{{.+}}, +// CHECK: store i32 [[IM_CAST]], ptr getelementptr inbounds ({ i32, i32 }, ptr @{{.+}}, i32 0, i32 1), #pragma omp atomic capture {civ = cfx; cfx = cfv + cfx;} -// CHECK: [[EXPR_RE:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 0) -// CHECK: [[EXPR_IM:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 1) -// CHECK: [[BITCAST:%.+]] = bitcast { double, double }* [[EXPECTED_ADDR:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 16, i8* noundef bitcast ({ double, double }* [[X_ADDR:@.+]] to i8*), i8* noundef [[BITCAST]], i32 noundef 5) +// CHECK: [[EXPR_RE:%.+]] = load double, ptr @{{.+}} +// CHECK: [[EXPR_IM:%.+]] = load double, ptr getelementptr inbounds ({ double, double }, ptr @{{.+}}, i32 0, i32 1) +// CHECK: call void @__atomic_load(i64 noundef 16, ptr noundef [[X_ADDR:@.+]], ptr noundef [[EXPECTED_ADDR:%.+]], i32 noundef 5) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[EXPECTED_ADDR]], i32 0, i32 0 -// CHECK: [[X_RE:%.+]] = load double, double* [[X_RE_ADDR]] -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[EXPECTED_ADDR]], i32 0, i32 1 -// CHECK: [[X_IM:%.+]] = load double, double* [[X_IM_ADDR]] +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, ptr [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[X_RE:%.+]] = load double, ptr [[X_RE_ADDR]] +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, ptr [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[X_IM:%.+]] = load double, ptr [[X_IM_ADDR]] // -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[DESIRED_ADDR]], i32 0, i32 1 -// CHECK: store double [[NEW_RE:%.+]], double* [[X_RE_ADDR]] -// CHECK: store double [[NEW_IM:%.+]], double* [[X_IM_ADDR]] -// CHECK: [[EXPECTED:%.+]] = bitcast { double, double }* [[EXPECTED_ADDR]] to i8* -// CHECK: [[DESIRED:%.+]] = bitcast { double, double }* [[DESIRED_ADDR]] to i8* -// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 16, i8* noundef bitcast ({ double, double }* [[X_ADDR]] to i8*), i8* noundef [[EXPECTED]], i8* noundef [[DESIRED]], i32 noundef 5, i32 noundef 5) +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, ptr [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, ptr [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store double [[NEW_RE:%.+]], ptr [[X_RE_ADDR]] +// CHECK: store double [[NEW_IM:%.+]], ptr [[X_IM_ADDR]] +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 16, ptr noundef [[X_ADDR]], ptr noundef [[EXPECTED_ADDR]], ptr noundef [[DESIRED_ADDR]], i32 noundef 5, i32 noundef 5) // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] // CHECK: [[RE_CAST:%.+]] = fptrunc double [[NEW_RE]] to float // CHECK: [[IM_CAST:%.+]] = fptrunc double [[NEW_IM]] to float -// CHECK: store float [[RE_CAST]], float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 0), -// CHECK: store float [[IM_CAST]], float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 1), +// CHECK: store float [[RE_CAST]], ptr @{{.+}}, +// CHECK: store float [[IM_CAST]], ptr getelementptr inbounds ({ float, float }, ptr @{{.+}}, i32 0, i32 1), // CHECK-50: call{{.*}} @__kmpc_flush( #pragma omp atomic capture seq_cst {cdx = cdx - cdv; cfv = cdx;} -// CHECK: [[BV:%.+]] = load i8, i8* @{{.+}} +// CHECK: [[BV:%.+]] = load i8, ptr @{{.+}} // CHECK: [[BOOL:%.+]] = trunc i8 [[BV]] to i1 // CHECK: [[EXPR:%.+]] = zext i1 [[BOOL]] to i64 -// CHECK: [[OLD:%.+]] = atomicrmw and i64* @{{.+}}, i64 [[EXPR]] monotonic, align 8 +// CHECK: [[OLD:%.+]] = atomicrmw and ptr @{{.+}}, i64 [[EXPR]] monotonic, align 8 // CHECK: [[DESIRED:%.+]] = and i64 [[OLD]], [[EXPR]] -// CHECK: store i64 [[DESIRED]], i64* @{{.+}}, +// CHECK: store i64 [[DESIRED]], ptr @{{.+}}, #pragma omp atomic capture ulv = ulx = ulx & bv; -// CHECK: [[CV:%.+]] = load i8, i8* @{{.+}}, align 1 +// CHECK: [[CV:%.+]] = load i8, ptr @{{.+}}, align 1 // CHECK: [[EXPR:%.+]] = sext i8 [[CV]] to i32 -// CHECK: [[X:%.+]] = load atomic i8, i8* [[BX_ADDR:@.+]] monotonic, align 1 +// CHECK: [[X:%.+]] = load atomic i8, ptr [[BX_ADDR:@.+]] monotonic, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i8 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] @@ -361,194 +349,184 @@ int main(void) { // CHECK: [[AND:%.+]] = and i32 [[EXPR]], [[X_RVAL]] // CHECK: [[CAST:%.+]] = icmp ne i32 [[AND]], 0 // CHECK: [[NEW:%.+]] = zext i1 [[CAST]] to i8 -// CHECK: store i8 [[NEW]], i8* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i8, i8* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i8* [[BX_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic, align 1 +// CHECK: store i8 [[NEW]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i8, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[BX_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic, align 1 // CHECK: [[OLD:%.+]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] // CHECK: [[OLD_I8:%.+]] = zext i1 [[OLD_BOOL]] to i8 -// CHECK: store i8 [[OLD_I8]], i8* @{{.+}}, +// CHECK: store i8 [[OLD_I8]], ptr @{{.+}}, #pragma omp atomic capture {bv = bx; bx = cv & bx;} -// CHECK: [[UCV:%.+]] = load i8, i8* @{{.+}}, +// CHECK: [[UCV:%.+]] = load i8, ptr @{{.+}}, // CHECK: [[EXPR:%.+]] = zext i8 [[UCV]] to i32 -// CHECK: [[X:%.+]] = load atomic i8, i8* [[CX_ADDR:@.+]] seq_cst, align 1 +// CHECK: [[X:%.+]] = load atomic i8, ptr [[CX_ADDR:@.+]] seq_cst, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i8 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[X_RVAL:%.+]] = sext i8 [[EXPECTED]] to i32 // CHECK: [[ASHR:%.+]] = ashr i32 [[X_RVAL]], [[EXPR]] // CHECK: [[NEW:%.+]] = trunc i32 [[ASHR]] to i8 -// CHECK: store i8 [[NEW]], i8* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i8, i8* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i8* [[CX_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] seq_cst seq_cst, align 1 +// CHECK: store i8 [[NEW]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i8, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[CX_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] seq_cst seq_cst, align 1 // CHECK: [[OLD_X:%.+]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i8 [[NEW]], i8* @{{.+}}, +// CHECK: store i8 [[NEW]], ptr @{{.+}}, // CHECK-50: call{{.*}} @__kmpc_flush( #pragma omp atomic capture, seq_cst {cx = cx >> ucv; cv = cx;} -// CHECK: [[SV:%.+]] = load i16, i16* @{{.+}}, +// CHECK: [[SV:%.+]] = load i16, ptr @{{.+}}, // CHECK: [[EXPR:%.+]] = sext i16 [[SV]] to i32 -// CHECK: [[X:%.+]] = load atomic i64, i64* [[ULX_ADDR:@.+]] monotonic, align 8 +// CHECK: [[X:%.+]] = load atomic i64, ptr [[ULX_ADDR:@.+]] monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[X_RVAL:%.+]] = trunc i64 [[EXPECTED]] to i32 // CHECK: [[SHL:%.+]] = shl i32 [[EXPR]], [[X_RVAL]] // CHECK: [[NEW:%.+]] = sext i32 [[SHL]] to i64 -// CHECK: store i64 [[NEW]], i64* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i64* [[ULX_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: store i64 [[NEW]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i64, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[ULX_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 // CHECK: [[OLD_X:%.+]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i64 [[NEW]], i64* @{{.+}}, +// CHECK: store i64 [[NEW]], ptr @{{.+}}, #pragma omp atomic capture ulv = ulx = sv << ulx; -// CHECK: [[USV:%.+]] = load i16, i16* @{{.+}}, +// CHECK: [[USV:%.+]] = load i16, ptr @{{.+}}, // CHECK: [[EXPR:%.+]] = zext i16 [[USV]] to i64 -// CHECK: [[X:%.+]] = load atomic i64, i64* [[LX_ADDR:@.+]] monotonic, align 8 +// CHECK: [[X:%.+]] = load atomic i64, ptr [[LX_ADDR:@.+]] monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[DESIRED:%.+]] = srem i64 [[EXPECTED]], [[EXPR]] -// CHECK: store i64 [[DESIRED]], i64* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i64* [[LX_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: store i64 [[DESIRED]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i64, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[LX_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 // CHECK: [[OLD_X:%.+]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i64 [[EXPECTED]], i64* @{{.+}}, +// CHECK: store i64 [[EXPECTED]], ptr @{{.+}}, #pragma omp atomic capture {lv = lx; lx = lx % usv;} -// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}} -// CHECK: [[OLD:%.+]] = atomicrmw or i32* @{{.+}}, i32 [[EXPR]] seq_cst, align 4 +// CHECK: [[EXPR:%.+]] = load i32, ptr @{{.+}} +// CHECK: [[OLD:%.+]] = atomicrmw or ptr @{{.+}}, i32 [[EXPR]] seq_cst, align 4 // CHECK: [[DESIRED:%.+]] = or i32 [[EXPR]], [[OLD]] -// CHECK: store i32 [[DESIRED]], i32* @{{.+}}, +// CHECK: store i32 [[DESIRED]], ptr @{{.+}}, // CHECK-50: call{{.*}} @__kmpc_flush( #pragma omp atomic seq_cst, capture {uix = iv | uix; uiv = uix;} -// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}} -// CHECK: [[OLD:%.+]] = atomicrmw and i32* @{{.+}}, i32 [[EXPR]] monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load i32, ptr @{{.+}} +// CHECK: [[OLD:%.+]] = atomicrmw and ptr @{{.+}}, i32 [[EXPR]] monotonic, align 4 // CHECK: [[DESIRED:%.+]] = and i32 [[OLD]], [[EXPR]] -// CHECK: store i32 [[DESIRED]], i32* @{{.+}}, +// CHECK: store i32 [[DESIRED]], ptr @{{.+}}, #pragma omp atomic capture iv = ix = ix & uiv; -// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, -// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* [[X_ADDR:@.+]] to i8*), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[EXPR:%.+]] = load i64, ptr @{{.+}}, +// CHECK: call void @__atomic_load(i64 noundef 8, ptr noundef [[X_ADDR:@.+]], ptr noundef [[EXPECTED_ADDR:%.+]], i32 noundef 0) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 0 -// CHECK: [[OLD_RE:%.+]] = load i32, i32* [[X_RE_ADDR]] -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 1 -// CHECK: [[OLD_IM:%.+]] = load i32, i32* [[X_IM_ADDR]] +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[OLD_RE:%.+]] = load i32, ptr [[X_RE_ADDR]] +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[OLD_IM:%.+]] = load i32, ptr [[X_IM_ADDR]] // -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR]], i32 0, i32 1 -// CHECK: store i32 %{{.+}}, i32* [[X_RE_ADDR]] -// CHECK: store i32 %{{.+}}, i32* [[X_IM_ADDR]] -// CHECK: [[EXPECTED:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR]] to i8* -// CHECK: [[DESIRED:%.+]] = bitcast { i32, i32 }* [[DESIRED_ADDR]] to i8* -// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* [[X_ADDR]] to i8*), i8* noundef [[EXPECTED]], i8* noundef [[DESIRED]], i32 noundef 0, i32 noundef 0) +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store i32 %{{.+}}, ptr [[X_RE_ADDR]] +// CHECK: store i32 %{{.+}}, ptr [[X_IM_ADDR]] +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, ptr noundef [[X_ADDR]], ptr noundef [[EXPECTED_ADDR]], ptr noundef [[DESIRED_ADDR]], i32 noundef 0, i32 noundef 0) // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i32 [[OLD_RE]], i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 0), -// CHECK: store i32 [[OLD_IM]], i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 1), +// CHECK: store i32 [[OLD_RE]], ptr @{{.+}}, +// CHECK: store i32 [[OLD_IM]], ptr getelementptr inbounds ({ i32, i32 }, ptr @{{.+}}, i32 0, i32 1), #pragma omp atomic capture {civ = cix; cix = lv + cix;} -// CHECK: [[ULV:%.+]] = load i64, i64* @{{.+}}, +// CHECK: [[ULV:%.+]] = load i64, ptr @{{.+}}, // CHECK: [[EXPR:%.+]] = uitofp i64 [[ULV]] to float -// CHECK: [[X:%.+]] = load atomic i32, i32* bitcast (float* [[X_ADDR:@.+]] to i32*) monotonic, align 4 +// CHECK: [[X:%.+]] = load atomic i32, ptr [[X_ADDR:@.+]] monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] -// CHECK: [[TEMP_I:%.+]] = bitcast float* [[TEMP:%.+]] to i32* // CHECK: [[OLD:%.+]] = bitcast i32 [[EXPECTED]] to float // CHECK: [[MUL:%.+]] = fmul float [[OLD]], [[EXPR]] -// CHECK: store float [[MUL]], float* [[TEMP]], -// CHECK: [[DESIRED:%.+]] = load i32, i32* [[TEMP_I]], -// CHECK: [[RES:%.+]] = cmpxchg i32* bitcast (float* [[X_ADDR]] to i32*), i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 +// CHECK: store float [[MUL]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i32, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 // CHECK: [[OLD_X:%.+]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store float [[MUL]], float* @{{.+}}, +// CHECK: store float [[MUL]], ptr @{{.+}}, #pragma omp atomic capture {fx = fx * ulv; fv = fx;} -// CHECK: [[LLV:%.+]] = load i64, i64* @{{.+}}, +// CHECK: [[LLV:%.+]] = load i64, ptr @{{.+}}, // CHECK: [[EXPR:%.+]] = sitofp i64 [[LLV]] to double -// CHECK: [[X:%.+]] = load atomic i64, i64* bitcast (double* [[X_ADDR:@.+]] to i64*) monotonic, align 8 +// CHECK: [[X:%.+]] = load atomic i64, ptr [[X_ADDR:@.+]] monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] -// CHECK: [[TEMP_I:%.+]] = bitcast double* [[TEMP:%.+]] to i64* // CHECK: [[OLD:%.+]] = bitcast i64 [[EXPECTED]] to double // CHECK: [[DIV:%.+]] = fdiv double [[OLD]], [[EXPR]] -// CHECK: store double [[DIV]], double* [[TEMP]], -// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP_I]], -// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (double* [[X_ADDR]] to i64*), i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: store double [[DIV]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i64, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 // CHECK: [[OLD_X:%.+]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store double [[DIV]], double* @{{.+}}, +// CHECK: store double [[DIV]], ptr @{{.+}}, #pragma omp atomic capture dv = dx /= llv; -// CHECK: [[ULLV:%.+]] = load i64, i64* @{{.+}}, +// CHECK: [[ULLV:%.+]] = load i64, ptr @{{.+}}, // CHECK: [[EXPR:%.+]] = uitofp i64 [[ULLV]] to x86_fp80 -// CHECK: [[X:%.+]] = load atomic i128, i128* bitcast (x86_fp80* [[X_ADDR:@.+]] to i128*) monotonic, align 16 +// CHECK: [[X:%.+]] = load atomic i128, ptr [[X_ADDR:@.+]] monotonic, align 16 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i128 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] -// CHECK: [[TEMP_I1:%.+]] = bitcast x86_fp80* [[TEMP1:%.+]] to i128* -// CHECK: store i128 [[EXPECTED]], i128* [[TEMP_I1]], -// CHECK: [[TEMP_I:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i128* -// CHECK: store i128 [[EXPECTED]], i128* [[TEMP_I]], -// CHECK: [[OLD:%.+]] = load x86_fp80, x86_fp80* [[TEMP]], +// CHECK: store i128 [[EXPECTED]], ptr [[TEMP1:%.+]], +// CHECK: store i128 [[EXPECTED]], ptr [[TEMP:%.+]], +// CHECK: [[OLD:%.+]] = load x86_fp80, ptr [[TEMP]], // CHECK: [[SUB:%.+]] = fsub x86_fp80 [[OLD]], [[EXPR]] -// CHECK: store x86_fp80 [[SUB]], x86_fp80* [[TEMP1]] -// CHECK: [[DESIRED:%.+]] = load i128, i128* [[TEMP_I1]] -// CHECK: [[RES:%.+]] = cmpxchg i128* bitcast (x86_fp80* [[X_ADDR]] to i128*), i128 [[EXPECTED]], i128 [[DESIRED]] monotonic monotonic, align 16 +// CHECK: store x86_fp80 [[SUB]], ptr [[TEMP1]] +// CHECK: [[DESIRED:%.+]] = load i128, ptr [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i128 [[EXPECTED]], i128 [[DESIRED]] monotonic monotonic, align 16 // CHECK: [[OLD_X:%.+]] = extractvalue { i128, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i128, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store x86_fp80 [[OLD]], x86_fp80* @{{.+}}, +// CHECK: store x86_fp80 [[OLD]], ptr @{{.+}}, #pragma omp atomic capture {ldv = ldx; ldx -= ullv;} -// CHECK: [[EXPR:%.+]] = load float, float* @{{.+}}, -// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* [[X_ADDR:@.+]] to i8*), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[EXPR:%.+]] = load float, ptr @{{.+}}, +// CHECK: call void @__atomic_load(i64 noundef 8, ptr noundef [[X_ADDR:@.+]], ptr noundef [[EXPECTED_ADDR:%.+]], i32 noundef 0) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 0 -// CHECK: [[X_RE:%.+]] = load i32, i32* [[X_RE_ADDR]] -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 1 -// CHECK: [[X_IM:%.+]] = load i32, i32* [[X_IM_ADDR]] +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[X_RE:%.+]] = load i32, ptr [[X_RE_ADDR]] +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[X_IM:%.+]] = load i32, ptr [[X_IM_ADDR]] // -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR]], i32 0, i32 1 -// CHECK: store i32 [[NEW_RE:%.+]], i32* [[X_RE_ADDR]] -// CHECK: store i32 [[NEW_IM:%.+]], i32* [[X_IM_ADDR]] -// CHECK: [[EXPECTED:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR]] to i8* -// CHECK: [[DESIRED:%.+]] = bitcast { i32, i32 }* [[DESIRED_ADDR]] to i8* -// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* [[X_ADDR]] to i8*), i8* noundef [[EXPECTED]], i8* noundef [[DESIRED]], i32 noundef 0, i32 noundef 0) +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store i32 [[NEW_RE:%.+]], ptr [[X_RE_ADDR]] +// CHECK: store i32 [[NEW_IM:%.+]], ptr [[X_IM_ADDR]] +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, ptr noundef [[X_ADDR]], ptr noundef [[EXPECTED_ADDR]], ptr noundef [[DESIRED_ADDR]], i32 noundef 0, i32 noundef 0) // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i32 [[NEW_RE]], i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 0), -// CHECK: store i32 [[NEW_IM]], i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 1), +// CHECK: store i32 [[NEW_RE]], ptr @{{.+}}, +// CHECK: store i32 [[NEW_IM]], ptr getelementptr inbounds ({ i32, i32 }, ptr @{{.+}}, i32 0, i32 1), #pragma omp atomic capture {cix = fv / cix; civ = cix;} -// CHECK: [[EXPR:%.+]] = load double, double* @{{.+}}, -// CHECK: [[X:%.+]] = load atomic i16, i16* [[X_ADDR:@.+]] monotonic, align 2 +// CHECK: [[EXPR:%.+]] = load double, ptr @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i16, ptr [[X_ADDR:@.+]] monotonic, align 2 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i16 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] @@ -556,18 +534,18 @@ int main(void) { // CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CONV]] to double // CHECK: [[ADD:%.+]] = fadd double [[X_RVAL]], [[EXPR]] // CHECK: [[NEW:%.+]] = fptosi double [[ADD]] to i16 -// CHECK: store i16 [[NEW]], i16* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i16, i16* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i16* [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic, align 2 +// CHECK: store i16 [[NEW]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i16, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic, align 2 // CHECK: [[OLD_X]] = extractvalue { i16, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i16, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i16 [[NEW]], i16* @{{.+}}, +// CHECK: store i16 [[NEW]], ptr @{{.+}}, #pragma omp atomic capture sv = sx = sx + dv; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}, -// CHECK: [[XI8:%.+]] = load atomic i8, i8* [[X_ADDR:@.+]] monotonic, align 1 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}}, +// CHECK: [[XI8:%.+]] = load atomic i8, ptr [[X_ADDR:@.+]] monotonic, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i8 [ [[XI8]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] @@ -577,20 +555,20 @@ int main(void) { // CHECK: [[MUL:%.+]] = fmul x86_fp80 [[EXPR]], [[X_RVAL]] // CHECK: [[BOOL_DESIRED:%.+]] = fcmp une x86_fp80 [[MUL]], 0xK00000000000000000000 // CHECK: [[DESIRED:%.+]] = zext i1 [[BOOL_DESIRED]] to i8 -// CHECK: store i8 [[DESIRED]], i8* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i8, i8* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i8* [[X_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic, align 1 +// CHECK: store i8 [[DESIRED]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i8, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic, align 1 // CHECK: [[OLD_X:%.+]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] // CHECK: [[EXPECTED_I8:%.+]] = zext i1 [[BOOL_EXPECTED]] to i8 -// CHECK: store i8 [[EXPECTED_I8]], i8* @{{.+}}, +// CHECK: store i8 [[EXPECTED_I8]], ptr @{{.+}}, #pragma omp atomic capture {bv = bx; bx = ldv * bx;} -// CHECK: [[EXPR_RE:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* [[CIV_ADDR:@.+]], i32 0, i32 0), -// CHECK: [[EXPR_IM:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* [[CIV_ADDR]], i32 0, i32 1), -// CHECK: [[XI8:%.+]] = load atomic i8, i8* [[X_ADDR:@.+]] monotonic, align 1 +// CHECK: [[EXPR_RE:%.+]] = load i32, ptr [[CIV_ADDR:@.+]], +// CHECK: [[EXPR_IM:%.+]] = load i32, ptr getelementptr inbounds ({ i32, i32 }, ptr [[CIV_ADDR]], i32 0, i32 1), +// CHECK: [[XI8:%.+]] = load atomic i8, ptr [[X_ADDR:@.+]] monotonic, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i8 [ [[XI8]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] @@ -602,195 +580,187 @@ int main(void) { // CHECK: icmp ne i32 [[SUB_IM]], 0 // CHECK: [[BOOL_DESIRED:%.+]] = or i1 // CHECK: [[DESIRED:%.+]] = zext i1 [[BOOL_DESIRED]] to i8 -// CHECK: store i8 [[DESIRED]], i8* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i8, i8* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i8* [[X_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic, align 1 +// CHECK: store i8 [[DESIRED]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i8, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic, align 1 // CHECK: [[OLD_X:%.+]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] // CHECK: [[DESIRED_I8:%.+]] = zext i1 [[BOOL_DESIRED]] to i8 -// CHECK: store i8 [[DESIRED_I8]], i8* @{{.+}}, +// CHECK: store i8 [[DESIRED_I8]], ptr @{{.+}}, #pragma omp atomic capture {bx = civ - bx; bv = bx;} -// CHECK: [[IDX:%.+]] = load i16, i16* @{{.+}} -// CHECK: load i8, i8* +// CHECK: [[IDX:%.+]] = load i16, ptr @{{.+}} +// CHECK: load i8, ptr // CHECK: [[VEC_ITEM_VAL:%.+]] = zext i1 %{{.+}} to i32 -// CHECK: [[I128VAL:%.+]] = load atomic i128, i128* bitcast (<4 x i32>* [[DEST:@.+]] to i128*) monotonic, align 16 +// CHECK: [[I128VAL:%.+]] = load atomic i128, ptr [[DEST:@.+]] monotonic, align 16 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_I128:%.+]] = phi i128 [ [[I128VAL]], %{{.+}} ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: [[TEMP_I:%.+]] = bitcast <4 x i32>* [[TEMP:%.+]] to i128* -// CHECK: store i128 [[OLD_I128]], i128* [[TEMP_I]], +// CHECK: store i128 [[OLD_I128]], ptr [[TEMP:%.+]], // CHECK: [[LD:%.+]] = bitcast i128 [[OLD_I128]] to <4 x i32> -// CHECK: store <4 x i32> [[LD]], <4 x i32>* [[TEMP1:%.+]], -// CHECK: [[VEC_VAL:%.+]] = load <4 x i32>, <4 x i32>* [[TEMP1]] +// CHECK: store <4 x i32> [[LD]], ptr [[TEMP1:%.+]], +// CHECK: [[VEC_VAL:%.+]] = load <4 x i32>, ptr [[TEMP1]] // CHECK: [[ITEM:%.+]] = extractelement <4 x i32> [[VEC_VAL]], i16 [[IDX]] // CHECK: [[OR:%.+]] = or i32 [[ITEM]], [[VEC_ITEM_VAL]] -// CHECK: [[VEC_VAL:%.+]] = load <4 x i32>, <4 x i32>* [[TEMP]] +// CHECK: [[VEC_VAL:%.+]] = load <4 x i32>, ptr [[TEMP]] // CHECK: [[NEW_VEC_VAL:%.+]] = insertelement <4 x i32> [[VEC_VAL]], i32 [[OR]], i16 [[IDX]] -// CHECK: store <4 x i32> [[NEW_VEC_VAL]], <4 x i32>* [[TEMP]] -// CHECK: [[NEW_I128:%.+]] = load i128, i128* [[TEMP_I]], -// CHECK: [[RES:%.+]] = cmpxchg i128* bitcast (<4 x i32>* [[DEST]] to i128*), i128 [[OLD_I128]], i128 [[NEW_I128]] monotonic monotonic, align 16 +// CHECK: store <4 x i32> [[NEW_VEC_VAL]], ptr [[TEMP]] +// CHECK: [[NEW_I128:%.+]] = load i128, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[DEST]], i128 [[OLD_I128]], i128 [[NEW_I128]] monotonic monotonic, align 16 // CHECK: [[FAILED_OLD_VAL:%.+]] = extractvalue { i128, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i128, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i32 [[OR]], i32* @{{.+}}, +// CHECK: store i32 [[OR]], ptr @{{.+}}, #pragma omp atomic capture {int4x[sv] |= bv; iv = int4x[sv];} -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.BitFields* @{{.+}} to i8*), i64 4) to i32*) monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, ptr getelementptr (i8, ptr @{{.+}}, i64 4) monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP1:%.+]], -// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP:%.+]], -// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]], +// CHECK: store i32 [[OLD_BF_VALUE]], ptr [[TEMP1:%.+]], +// CHECK: store i32 [[OLD_BF_VALUE]], ptr [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i32, ptr [[TEMP]], // CHECK: [[A_SHL:%.+]] = shl i32 [[A_LD]], 1 // CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_SHL]], 1 // CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80 // CHECK: [[SUB:%.+]] = fsub x86_fp80 [[X_RVAL]], [[EXPR]] // CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[SUB]] to i32 -// CHECK: [[NEW_VAL:%.+]] = load i32, i32* [[TEMP1]], +// CHECK: [[NEW_VAL:%.+]] = load i32, ptr [[TEMP1]], // CHECK: [[BF_VALUE:%.+]] = and i32 [[CONV]], 2147483647 // CHECK: [[BF_CLEAR:%.+]] = and i32 [[NEW_VAL]], -2147483648 // CHECK: [[BF_SET:%.+]] = or i32 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i32 [[BF_SET]], i32* [[TEMP1]], -// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[TEMP1]], -// CHECK: [[RES:%.+]] = cmpxchg i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.BitFields* @{{.+}} to i8*), i64 4) to i32*), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 +// CHECK: store i32 [[BF_SET]], ptr [[TEMP1]], +// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, ptr [[TEMP1]], +// CHECK: [[RES:%.+]] = cmpxchg ptr getelementptr (i8, ptr @{{.+}}, i64 4), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i32 [[CONV]], i32* @{{.+}}, +// CHECK: store i32 [[CONV]], ptr @{{.+}}, #pragma omp atomic capture iv = bfx.a = bfx.a - ldv; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[BITCAST:%.+]] = bitcast i32* [[LDTEMP:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 4, i8* noundef getelementptr (i8, i8* bitcast (%struct.BitFields_packed* @{{.+}} to i8*), i64 4), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: call void @__atomic_load(i64 noundef 4, ptr noundef getelementptr (i8, ptr @{{.+}}, i64 4), ptr noundef [[LDTEMP:%.+]], i32 noundef 0) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[OLD:%.+]] = load i32, i32* [[LDTEMP]], -// CHECK: store i32 [[OLD]], i32* [[TEMP1:%.+]], -// CHECK: [[OLD:%.+]] = load i32, i32* [[LDTEMP]], -// CHECK: store i32 [[OLD]], i32* [[TEMP:%.+]], -// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]], +// CHECK: [[OLD:%.+]] = load i32, ptr [[LDTEMP]], +// CHECK: store i32 [[OLD]], ptr [[TEMP1:%.+]], +// CHECK: [[OLD:%.+]] = load i32, ptr [[LDTEMP]], +// CHECK: store i32 [[OLD]], ptr [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i32, ptr [[TEMP]], // CHECK: [[A_SHL:%.+]] = shl i32 [[A_LD]], 1 // CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_SHL]], 1 // CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80 // CHECK: [[MUL:%.+]] = fmul x86_fp80 [[X_RVAL]], [[EXPR]] // CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[MUL]] to i32 -// CHECK: [[NEW_VAL:%.+]] = load i32, i32* [[TEMP1]], +// CHECK: [[NEW_VAL:%.+]] = load i32, ptr [[TEMP1]], // CHECK: [[BF_VALUE:%.+]] = and i32 [[CONV]], 2147483647 // CHECK: [[BF_CLEAR:%.+]] = and i32 [[NEW_VAL]], -2147483648 // CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i32 %{{.+}}, i32* [[TEMP1]] -// CHECK: [[BITCAST_TEMP_OLD_BF_ADDR:%.+]] = bitcast i32* [[LDTEMP]] to i8* -// CHECK: [[BITCAST_TEMP_NEW_BF_ADDR:%.+]] = bitcast i32* [[TEMP1]] to i8* -// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 4, i8* noundef getelementptr (i8, i8* bitcast (%struct.BitFields_packed* @{{.+}} to i8*), i64 4), i8* noundef [[BITCAST_TEMP_OLD_BF_ADDR]], i8* noundef [[BITCAST_TEMP_NEW_BF_ADDR]], i32 noundef 0, i32 noundef 0) +// CHECK: store i32 %{{.+}}, ptr [[TEMP1]] +// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 4, ptr noundef getelementptr (i8, ptr @{{.+}}, i64 4), ptr noundef [[LDTEMP]], ptr noundef [[TEMP1]], i32 noundef 0, i32 noundef 0) // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i32 [[A_ASHR]], i32* @{{.+}}, +// CHECK: store i32 [[A_ASHR]], ptr @{{.+}}, #pragma omp atomic capture {iv = bfx_packed.a; bfx_packed.a *= ldv;} -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* getelementptr inbounds (%struct.BitFields2, %struct.BitFields2* @{{.+}}, i32 0, i32 0) monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, ptr @{{.+}} monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP1:%.+]], -// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP:%.+]], -// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]], +// CHECK: store i32 [[OLD_BF_VALUE]], ptr [[TEMP1:%.+]], +// CHECK: store i32 [[OLD_BF_VALUE]], ptr [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i32, ptr [[TEMP]], // CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_LD]], 31 // CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80 // CHECK: [[SUB:%.+]] = fsub x86_fp80 [[X_RVAL]], [[EXPR]] // CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[SUB]] to i32 -// CHECK: [[NEW_VAL:%.+]] = load i32, i32* [[TEMP1]], +// CHECK: [[NEW_VAL:%.+]] = load i32, ptr [[TEMP1]], // CHECK: [[BF_AND:%.+]] = and i32 [[CONV]], 1 // CHECK: [[BF_VALUE:%.+]] = shl i32 [[BF_AND]], 31 // CHECK: [[BF_CLEAR:%.+]] = and i32 [[NEW_VAL]], 2147483647 // CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i32 %{{.+}}, i32* [[TEMP1]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[TEMP1]] -// CHECK: [[RES:%.+]] = cmpxchg i32* getelementptr inbounds (%struct.BitFields2, %struct.BitFields2* @{{.+}}, i32 0, i32 0), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 +// CHECK: store i32 %{{.+}}, ptr [[TEMP1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, ptr [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr @{{.+}}, i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i32 [[CONV]], i32* @{{.+}}, +// CHECK: store i32 [[CONV]], ptr @{{.+}}, #pragma omp atomic capture {bfx2.a -= ldv; iv = bfx2.a;} -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr (i8, i8* bitcast (%struct.BitFields2_packed* @{{.+}} to i8*), i64 3) monotonic, align 1 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, ptr getelementptr (i8, ptr @{{.+}}, i64 3) monotonic, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST_NEW:%.+]] = bitcast i32* %{{.+}} to i8* -// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST_NEW]], -// CHECK: [[BITCAST:%.+]] = bitcast i32* %{{.+}} to i8* -// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST]], -// CHECK: [[A_LD:%.+]] = load i8, i8* [[BITCAST]], +// CHECK: store i8 [[OLD_BF_VALUE]], ptr [[BITCAST_NEW:%.+]], +// CHECK: store i8 [[OLD_BF_VALUE]], ptr [[BITCAST:%.+]], +// CHECK: [[A_LD:%.+]] = load i8, ptr [[BITCAST]], // CHECK: [[A_ASHR:%.+]] = ashr i8 [[A_LD]], 7 // CHECK: [[CAST:%.+]] = sext i8 [[A_ASHR]] to i32 // CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CAST]] to x86_fp80 // CHECK: [[DIV:%.+]] = fdiv x86_fp80 [[EXPR]], [[X_RVAL]] // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[DIV]] to i32 // CHECK: [[TRUNC:%.+]] = trunc i32 [[NEW_VAL]] to i8 -// CHECK: [[BF_LD:%.+]] = load i8, i8* [[BITCAST_NEW]], +// CHECK: [[BF_LD:%.+]] = load i8, ptr [[BITCAST_NEW]], // CHECK: [[BF_AND:%.+]] = and i8 [[TRUNC]], 1 // CHECK: [[BF_VALUE:%.+]] = shl i8 [[BF_AND]], 7 // CHECK: [[BF_CLEAR:%.+]] = and i8 %{{.+}}, 127 // CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i8 %{{.+}}, i8* [[BITCAST_NEW]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[BITCAST_NEW]] -// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr (i8, i8* bitcast (%struct.BitFields2_packed* @{{.+}} to i8*), i64 3), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 +// CHECK: store i8 %{{.+}}, ptr [[BITCAST_NEW]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, ptr [[BITCAST_NEW]] +// CHECK: [[RES:%.+]] = cmpxchg ptr getelementptr (i8, ptr @{{.+}}, i64 3), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i32 [[NEW_VAL]], i32* @{{.+}}, +// CHECK: store i32 [[NEW_VAL]], ptr @{{.+}}, #pragma omp atomic capture iv = bfx2_packed.a = ldv / bfx2_packed.a; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* getelementptr inbounds (%struct.BitFields3, %struct.BitFields3* @{{.+}}, i32 0, i32 0) monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, ptr @{{.+}} monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP1:%.+]], -// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP:%.+]], -// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]], +// CHECK: store i32 [[OLD_BF_VALUE]], ptr [[TEMP1:%.+]], +// CHECK: store i32 [[OLD_BF_VALUE]], ptr [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i32, ptr [[TEMP]], // CHECK: [[A_SHL:%.+]] = shl i32 [[A_LD]], 7 // CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_SHL]], 18 // CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80 // CHECK: [[DIV:%.+]] = fdiv x86_fp80 [[X_RVAL]], [[EXPR]] // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[DIV]] to i32 -// CHECK: [[BF_LD:%.+]] = load i32, i32* [[TEMP1]], +// CHECK: [[BF_LD:%.+]] = load i32, ptr [[TEMP1]], // CHECK: [[BF_AND:%.+]] = and i32 [[NEW_VAL]], 16383 // CHECK: [[BF_VALUE:%.+]] = shl i32 [[BF_AND]], 11 // CHECK: [[BF_CLEAR:%.+]] = and i32 %{{.+}}, -33552385 // CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i32 %{{.+}}, i32* [[TEMP1]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[TEMP1]] -// CHECK: [[RES:%.+]] = cmpxchg i32* getelementptr inbounds (%struct.BitFields3, %struct.BitFields3* @{{.+}}, i32 0, i32 0), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 +// CHECK: store i32 %{{.+}}, ptr [[TEMP1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, ptr [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr @{{.+}}, i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i32 [[A_ASHR]], i32* @{{.+}}, +// CHECK: store i32 [[A_ASHR]], ptr @{{.+}}, #pragma omp atomic capture {iv = bfx3.a; bfx3.a /= ldv;} -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[LDTEMP:%.+]] = bitcast i32* %{{.+}} to i24* -// CHECK: [[BITCAST:%.+]] = bitcast i24* [[LDTEMP]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 3, i8* noundef getelementptr (i8, i8* bitcast (%struct.BitFields3_packed* @{{.+}} to i8*), i64 1), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: call void @__atomic_load(i64 noundef 3, ptr noundef getelementptr (i8, ptr @{{.+}}, i64 1), ptr noundef [[LDTEMP:%.+]], i32 noundef 0) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[OLD:%.+]] = load i24, i24* [[LDTEMP]], -// CHECK: store i24 [[OLD]], i24* [[BITCAST2:%.+]], -// CHECK: [[OLD:%.+]] = load i24, i24* [[LDTEMP]], -// CHECK: store i24 [[OLD]], i24* [[BITCAST1:%.+]], -// CHECK: [[A_LD:%.+]] = load i24, i24* [[BITCAST1]], +// CHECK: [[OLD:%.+]] = load i24, ptr [[LDTEMP]], +// CHECK: store i24 [[OLD]], ptr [[BITCAST2:%.+]], +// CHECK: [[OLD:%.+]] = load i24, ptr [[LDTEMP]], +// CHECK: store i24 [[OLD]], ptr [[BITCAST1:%.+]], +// CHECK: [[A_LD:%.+]] = load i24, ptr [[BITCAST1]], // CHECK: [[A_SHL:%.+]] = shl i24 [[A_LD]], 7 // CHECK: [[A_ASHR:%.+]] = ashr i24 [[A_SHL]], 10 // CHECK: [[CAST:%.+]] = sext i24 [[A_ASHR]] to i32 @@ -798,28 +768,26 @@ int main(void) { // CHECK: [[ADD:%.+]] = fadd x86_fp80 [[X_RVAL]], [[EXPR]] // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[ADD]] to i32 // CHECK: [[TRUNC:%.+]] = trunc i32 [[NEW_VAL]] to i24 -// CHECK: [[BF_LD:%.+]] = load i24, i24* [[BITCAST2]], +// CHECK: [[BF_LD:%.+]] = load i24, ptr [[BITCAST2]], // CHECK: [[BF_AND:%.+]] = and i24 [[TRUNC]], 16383 // CHECK: [[BF_VALUE:%.+]] = shl i24 [[BF_AND]], 3 // CHECK: [[BF_CLEAR:%.+]] = and i24 [[BF_LD]], -131065 // CHECK: or i24 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i24 %{{.+}}, i24* [[BITCAST2]] -// CHECK: [[BITCAST_TEMP_OLD_BF_ADDR:%.+]] = bitcast i24* [[LDTEMP]] to i8* -// CHECK: [[BITCAST_TEMP_NEW_BF_ADDR:%.+]] = bitcast i24* [[BITCAST2]] to i8* -// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 3, i8* noundef getelementptr (i8, i8* bitcast (%struct.BitFields3_packed* @{{.+}} to i8*), i64 1), i8* noundef [[BITCAST_TEMP_OLD_BF_ADDR]], i8* noundef [[BITCAST_TEMP_NEW_BF_ADDR]], i32 noundef 0, i32 noundef 0) +// CHECK: store i24 %{{.+}}, ptr [[BITCAST2]] +// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 3, ptr noundef getelementptr (i8, ptr @{{.+}}, i64 1), ptr noundef [[LDTEMP]], ptr noundef [[BITCAST2]], i32 noundef 0, i32 noundef 0) // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i32 [[NEW_VAL]], i32* @{{.+}}, +// CHECK: store i32 [[NEW_VAL]], ptr @{{.+}}, #pragma omp atomic capture {bfx3_packed.a += ldv; iv = bfx3_packed.a;} -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, i64* bitcast (%struct.BitFields4* @{{.+}} to i64*) monotonic, align 8 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, ptr @{{.+}} monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i64 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: store i64 [[OLD_BF_VALUE]], i64* [[TEMP1:%.+]], -// CHECK: store i64 [[OLD_BF_VALUE]], i64* [[TEMP:%.+]], -// CHECK: [[A_LD:%.+]] = load i64, i64* [[TEMP]], +// CHECK: store i64 [[OLD_BF_VALUE]], ptr [[TEMP1:%.+]], +// CHECK: store i64 [[OLD_BF_VALUE]], ptr [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i64, ptr [[TEMP]], // CHECK: [[A_SHL:%.+]] = shl i64 [[A_LD]], 47 // CHECK: [[A_ASHR:%.+]] = ashr i64 [[A_SHL:%.+]], 63 // CHECK: [[A_CAST:%.+]] = trunc i64 [[A_ASHR:%.+]] to i32 @@ -827,31 +795,29 @@ int main(void) { // CHECK: [[MUL:%.+]] = fmul x86_fp80 [[X_RVAL]], [[EXPR]] // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[MUL]] to i32 // CHECK: [[ZEXT:%.+]] = zext i32 [[NEW_VAL]] to i64 -// CHECK: [[BF_LD:%.+]] = load i64, i64* [[TEMP1]], +// CHECK: [[BF_LD:%.+]] = load i64, ptr [[TEMP1]], // CHECK: [[BF_AND:%.+]] = and i64 [[ZEXT]], 1 // CHECK: [[BF_VALUE:%.+]] = shl i64 [[BF_AND]], 16 // CHECK: [[BF_CLEAR:%.+]] = and i64 [[BF_LD]], -65537 // CHECK: or i64 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i64 %{{.+}}, i64* [[TEMP1]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, i64* [[TEMP1]] -// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (%struct.BitFields4* @{{.+}} to i64*), i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] monotonic monotonic, align 8 +// CHECK: store i64 %{{.+}}, ptr [[TEMP1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, ptr [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr @{{.+}}, i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] monotonic monotonic, align 8 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i32 [[NEW_VAL]], i32* @{{.+}}, +// CHECK: store i32 [[NEW_VAL]], ptr @{{.+}}, #pragma omp atomic relaxed capture iv = bfx4.a = bfx4.a * ldv; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2) monotonic, align 1 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, ptr getelementptr (i8, ptr @{{.+}}, i64 2) monotonic, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %{{.+}} ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST1:%.+]] = bitcast i32* %{{.+}} to i8* -// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST1]], -// CHECK: [[BITCAST:%.+]] = bitcast i32* %{{.+}} to i8* -// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST]], -// CHECK: [[A_LD:%.+]] = load i8, i8* [[BITCAST]], +// CHECK: store i8 [[OLD_BF_VALUE]], ptr [[BITCAST1:%.+]], +// CHECK: store i8 [[OLD_BF_VALUE]], ptr [[BITCAST:%.+]], +// CHECK: [[A_LD:%.+]] = load i8, ptr [[BITCAST]], // CHECK: [[A_SHL:%.+]] = shl i8 [[A_LD]], 7 // CHECK: [[A_ASHR:%.+]] = ashr i8 [[A_SHL:%.+]], 7 // CHECK: [[CAST:%.+]] = sext i8 [[A_ASHR:%.+]] to i32 @@ -859,120 +825,117 @@ int main(void) { // CHECK: [[SUB: %.+]] = fsub x86_fp80 [[CONV]], [[EXPR]] // CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[SUB:%.+]] to i32 // CHECK: [[NEW_VAL:%.+]] = trunc i32 [[CONV]] to i8 -// CHECK: [[BF_LD:%.+]] = load i8, i8* [[BITCAST1]], +// CHECK: [[BF_LD:%.+]] = load i8, ptr [[BITCAST1]], // CHECK: [[BF_VALUE:%.+]] = and i8 [[NEW_VAL]], 1 // CHECK: [[BF_CLEAR:%.+]] = and i8 [[BF_LD]], -2 // CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i8 %{{.+}}, i8* [[BITCAST1]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[BITCAST1]] -// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 +// CHECK: store i8 %{{.+}}, ptr [[BITCAST1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, ptr [[BITCAST1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr getelementptr (i8, ptr @{{.+}}, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store i32 [[CAST]], i32* @{{.+}}, +// CHECK: store i32 [[CAST]], ptr @{{.+}}, #pragma omp atomic capture relaxed {iv = bfx4_packed.a; bfx4_packed.a -= ldv;} -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, i64* bitcast (%struct.BitFields4* @{{.+}} to i64*) monotonic, align 8 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, ptr @{{.+}} monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i64 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: store i64 [[OLD_BF_VALUE]], i64* [[TEMP1:%.+]], -// CHECK: store i64 [[OLD_BF_VALUE]], i64* [[TEMP:%.+]], -// CHECK: [[A_LD:%.+]] = load i64, i64* [[TEMP]], +// CHECK: store i64 [[OLD_BF_VALUE]], ptr [[TEMP1:%.+]], +// CHECK: store i64 [[OLD_BF_VALUE]], ptr [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i64, ptr [[TEMP]], // CHECK: [[A_SHL:%.+]] = shl i64 [[A_LD]], 40 // CHECK: [[A_ASHR:%.+]] = ashr i64 [[A_SHL:%.+]], 57 // CHECK: [[CONV:%.+]] = sitofp i64 [[A_ASHR]] to x86_fp80 // CHECK: [[DIV:%.+]] = fdiv x86_fp80 [[CONV]], [[EXPR]] // CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[DIV]] to i64 -// CHECK: [[BF_LD:%.+]] = load i64, i64* [[TEMP1]], +// CHECK: [[BF_LD:%.+]] = load i64, ptr [[TEMP1]], // CHECK: [[BF_AND:%.+]] = and i64 [[CONV]], 127 // CHECK: [[BF_VALUE:%.+]] = shl i64 [[BF_AND:%.+]], 17 // CHECK: [[BF_CLEAR:%.+]] = and i64 [[BF_LD]], -16646145 // CHECK: [[VAL:%.+]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i64 [[VAL]], i64* [[TEMP1]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, i64* [[TEMP1]] -// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (%struct.BitFields4* @{{.+}} to i64*), i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] release monotonic, align 8 +// CHECK: store i64 [[VAL]], ptr [[TEMP1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, ptr [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr @{{.+}}, i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] release monotonic, align 8 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] // CHECK: [[NEW_VAL:%.+]] = trunc i64 [[CONV]] to i32 -// CHECK: store i32 [[NEW_VAL]], i32* @{{.+}}, +// CHECK: store i32 [[NEW_VAL]], ptr @{{.+}}, // CHECK-50: call{{.*}} @__kmpc_flush( #pragma omp atomic capture release {bfx4.b /= ldv; iv = bfx4.b;} -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2) acquire, align 1 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, ptr getelementptr (i8, ptr @{{.+}}, i64 2) acquire, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST1:%.+]] = bitcast i64* %{{.+}} to i8* -// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST1]], -// CHECK: [[BITCAST:%.+]] = bitcast i64* %{{.+}} to i8* -// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST]], -// CHECK: [[A_LD:%.+]] = load i8, i8* [[BITCAST]], +// CHECK: store i8 [[OLD_BF_VALUE]], ptr [[BITCAST1:%.+]], +// CHECK: store i8 [[OLD_BF_VALUE]], ptr [[BITCAST:%.+]], +// CHECK: [[A_LD:%.+]] = load i8, ptr [[BITCAST]], // CHECK: [[A_ASHR:%.+]] = ashr i8 [[A_LD]], 1 // CHECK: [[CAST:%.+]] = sext i8 [[A_ASHR]] to i64 // CHECK: [[CONV:%.+]] = sitofp i64 [[CAST]] to x86_fp80 // CHECK: [[ADD:%.+]] = fadd x86_fp80 [[CONV]], [[EXPR]] // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[ADD]] to i64 // CHECK: [[TRUNC:%.+]] = trunc i64 [[NEW_VAL]] to i8 -// CHECK: [[BF_LD:%.+]] = load i8, i8* [[BITCAST1]], +// CHECK: [[BF_LD:%.+]] = load i8, ptr [[BITCAST1]], // CHECK: [[BF_AND:%.+]] = and i8 [[TRUNC]], 127 // CHECK: [[BF_VALUE:%.+]] = shl i8 [[BF_AND]], 1 // CHECK: [[BF_CLEAR:%.+]] = and i8 [[BF_LD]], 1 // CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i8 %{{.+}}, i8* [[BITCAST1]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[BITCAST1]] -// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] acquire acquire, align 1 +// CHECK: store i8 %{{.+}}, ptr [[BITCAST1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, ptr [[BITCAST1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr getelementptr (i8, ptr @{{.+}}, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] acquire acquire, align 1 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] // CHECK: [[NEW_VAL_I32:%.+]] = trunc i64 [[NEW_VAL]] to i32 -// CHECK: store i32 [[NEW_VAL_I32]], i32* @{{.+}}, +// CHECK: store i32 [[NEW_VAL_I32]], ptr @{{.+}}, // CHECK-50: call{{.*}} @__kmpc_flush( #pragma omp atomic capture acquire iv = bfx4_packed.b += ldv; -// CHECK: load i64, i64* +// CHECK: load i64, ptr // CHECK: [[EXPR:%.+]] = uitofp i64 %{{.+}} to float -// CHECK: [[I64VAL:%.+]] = load atomic i64, i64* bitcast (<2 x float>* [[DEST:@.+]] to i64*) acquire, align 8 +// CHECK: [[I64VAL:%.+]] = load atomic i64, ptr [[DEST:@.+]] acquire, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_I64:%.+]] = phi i64 [ [[I64VAL]], %{{.+}} ], [ [[FAILED_I64_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST:%.+]] = bitcast <2 x float>* [[LDTEMP1:%.+]] to i64* -// CHECK: store i64 [[OLD_I64]], i64* [[BITCAST]], +// CHECK: store i64 [[OLD_I64]], ptr [[LDTEMP1:%.+]], // CHECK: [[OLD_VEC_VAL:%.+]] = bitcast i64 [[OLD_I64]] to <2 x float> -// CHECK: store <2 x float> [[OLD_VEC_VAL]], <2 x float>* [[LDTEMP:%.+]], -// CHECK: [[VEC_VAL:%.+]] = load <2 x float>, <2 x float>* [[LDTEMP]] +// CHECK: store <2 x float> [[OLD_VEC_VAL]], ptr [[LDTEMP:%.+]], +// CHECK: [[VEC_VAL:%.+]] = load <2 x float>, ptr [[LDTEMP]] // CHECK: [[X:%.+]] = extractelement <2 x float> [[VEC_VAL]], i64 0 // CHECK: [[VEC_ITEM_VAL:%.+]] = fsub float [[EXPR]], [[X]] -// CHECK: [[VEC_VAL:%.+]] = load <2 x float>, <2 x float>* [[LDTEMP1]], +// CHECK: [[VEC_VAL:%.+]] = load <2 x float>, ptr [[LDTEMP1]], // CHECK: [[NEW_VEC_VAL:%.+]] = insertelement <2 x float> [[VEC_VAL]], float [[VEC_ITEM_VAL]], i64 0 -// CHECK: store <2 x float> [[NEW_VEC_VAL]], <2 x float>* [[LDTEMP1]] -// CHECK: [[NEW_I64:%.+]] = load i64, i64* [[BITCAST]] -// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (<2 x float>* [[DEST]] to i64*), i64 [[OLD_I64]], i64 [[NEW_I64]] acq_rel acquire, align 8 +// CHECK: store <2 x float> [[NEW_VEC_VAL]], ptr [[LDTEMP1]] +// CHECK: [[NEW_I64:%.+]] = load i64, ptr [[LDTEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr [[DEST]], i64 [[OLD_I64]], i64 [[NEW_I64]] acq_rel acquire, align 8 // CHECK: [[FAILED_I64_OLD_VAL:%.+]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] -// CHECK: store float [[X]], float* @{{.+}}, +// CHECK: store float [[X]], ptr @{{.+}}, // CHECK-50: call{{.*}} @__kmpc_flush( #pragma omp atomic capture acq_rel {fv = float2x.x; float2x.x = ulv - float2x.x;} -// CHECK: [[EXPR:%.+]] = load double, double* @{{.+}}, +// CHECK: [[EXPR:%.+]] = load double, ptr @{{.+}}, // CHECK: [[OLD_VAL:%.+]] = call i32 @llvm.read_register.i32([[REG:metadata ![0-9]+]]) // CHECK: [[X_RVAL:%.+]] = sitofp i32 [[OLD_VAL]] to double // CHECK: [[DIV:%.+]] = fdiv double [[EXPR]], [[X_RVAL]] // CHECK: [[NEW_VAL:%.+]] = fptosi double [[DIV]] to i32 // CHECK: call void @llvm.write_register.i32([[REG]], i32 [[NEW_VAL]]) -// CHECK: store i32 [[NEW_VAL]], i32* @{{.+}}, +// CHECK: store i32 [[NEW_VAL]], ptr @{{.+}}, // CHECK-50: call{{.*}} @__kmpc_flush( #pragma omp atomic capture seq_cst {rix = dv / rix; iv = rix;} -// CHECK: [[OLD_VAL:%.+]] = atomicrmw xchg i32* @{{.+}}, i32 5 monotonic, align 4 +// CHECK: [[OLD_VAL:%.+]] = atomicrmw xchg ptr @{{.+}}, i32 5 monotonic, align 4 // CHECK: call void @llvm.write_register.i32([[REG]], i32 [[OLD_VAL]]) #pragma omp atomic capture {rix = ix; ix = 5;} diff --git a/clang/test/OpenMP/atomic_read_codegen.c b/clang/test/OpenMP/atomic_read_codegen.c index a6608eade1433..b60e1686d4dab 100644 --- a/clang/test/OpenMP/atomic_read_codegen.c +++ b/clang/test/OpenMP/atomic_read_codegen.c @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp-simd -x c -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp-simd -x c -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s // SIMD-ONLY0-NOT: {{__kmpc|__tgt}} // expected-no-diagnostics // REQUIRES: x86-registered-target @@ -84,64 +84,63 @@ register int rix __asm__("esp"); // CHECK-LABEL: @main( int main(void) { -// CHECK: load atomic i8, i8* {{.*}} monotonic, align 1 +// CHECK: load atomic i8, ptr {{.*}} monotonic, align 1 // CHECK: store i8 #pragma omp atomic read bv = bx; -// CHECK: load atomic i8, i8* {{.*}} monotonic, align 1 +// CHECK: load atomic i8, ptr {{.*}} monotonic, align 1 // CHECK: store i8 #pragma omp atomic read cv = cx; -// CHECK: load atomic i8, i8* {{.*}} monotonic, align 1 +// CHECK: load atomic i8, ptr {{.*}} monotonic, align 1 // CHECK: store i8 #pragma omp atomic read ucv = ucx; -// CHECK: load atomic i16, i16* {{.*}} monotonic, align 2 +// CHECK: load atomic i16, ptr {{.*}} monotonic, align 2 // CHECK: store i16 #pragma omp atomic read sv = sx; -// CHECK: load atomic i16, i16* {{.*}} monotonic, align 2 +// CHECK: load atomic i16, ptr {{.*}} monotonic, align 2 // CHECK: store i16 #pragma omp atomic read usv = usx; -// CHECK: load atomic i32, i32* {{.*}} monotonic, align 4 +// CHECK: load atomic i32, ptr {{.*}} monotonic, align 4 // CHECK: store i32 #pragma omp atomic read iv = ix; -// CHECK: load atomic i32, i32* {{.*}} monotonic, align 4 +// CHECK: load atomic i32, ptr {{.*}} monotonic, align 4 // CHECK: store i32 #pragma omp atomic read uiv = uix; -// CHECK: load atomic i64, i64* {{.*}} monotonic, align 8 +// CHECK: load atomic i64, ptr {{.*}} monotonic, align 8 // CHECK: store i64 #pragma omp atomic read lv = lx; -// CHECK: load atomic i64, i64* {{.*}} monotonic, align 8 +// CHECK: load atomic i64, ptr {{.*}} monotonic, align 8 // CHECK: store i64 #pragma omp atomic read ulv = ulx; -// CHECK: load atomic i64, i64* {{.*}} monotonic, align 8 +// CHECK: load atomic i64, ptr {{.*}} monotonic, align 8 // CHECK: store i64 #pragma omp atomic read llv = llx; -// CHECK: load atomic i64, i64* {{.*}} monotonic, align 8 +// CHECK: load atomic i64, ptr {{.*}} monotonic, align 8 // CHECK: store i64 #pragma omp atomic read ullv = ullx; -// CHECK: load atomic i32, i32* bitcast (float* {{.*}} monotonic, align 4 +// CHECK: load atomic i32, ptr {{.*}} monotonic, align 4 // CHECK: bitcast i32 {{.*}} to float // CHECK: store float #pragma omp atomic read fv = fx; -// CHECK: load atomic i64, i64* bitcast (double* {{.*}} monotonic, align 8 +// CHECK: load atomic i64, ptr {{.*}} monotonic, align 8 // CHECK: bitcast i64 {{.*}} to double // CHECK: store double #pragma omp atomic read dv = dx; -// CHECK: [[LD:%.+]] = load atomic i128, i128* bitcast (x86_fp80* {{.*}} monotonic, align 16 -// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[LDTEMP:%.*]] to i128* -// CHECK: store i128 [[LD]], i128* [[BITCAST]] -// CHECK: [[LD:%.+]] = load x86_fp80, x86_fp80* [[LDTEMP]] +// CHECK: [[LD:%.+]] = load atomic i128, ptr {{.*}} monotonic, align 16 +// CHECK: store i128 [[LD]], ptr [[LDTEMP:%.+]] +// CHECK: [[LD:%.+]] = load x86_fp80, ptr [[LDTEMP]] // CHECK: store x86_fp80 [[LD]] #pragma omp atomic read ldv = ldx; @@ -161,33 +160,33 @@ int main(void) { // CHECK: store double #pragma omp atomic seq_cst read cdv = cdx; -// CHECK: load atomic i64, i64* {{.*}} monotonic, align 8 +// CHECK: load atomic i64, ptr {{.*}} monotonic, align 8 // CHECK: store i8 #pragma omp atomic read bv = ulx; -// CHECK: load atomic i8, i8* {{.*}} monotonic, align 1 +// CHECK: load atomic i8, ptr {{.*}} monotonic, align 1 // CHECK: store i8 #pragma omp atomic read cv = bx; -// CHECK: load atomic i8, i8* {{.*}} seq_cst, align 1 +// CHECK: load atomic i8, ptr {{.*}} seq_cst, align 1 // CHECK: call{{.*}} @__kmpc_flush( // CHECK: store i8 #pragma omp atomic read seq_cst ucv = cx; -// CHECK: load atomic i64, i64* {{.*}} monotonic, align 8 +// CHECK: load atomic i64, ptr {{.*}} monotonic, align 8 // CHECK: store i16 #pragma omp atomic read sv = ulx; -// CHECK: load atomic i64, i64* {{.*}} monotonic, align 8 +// CHECK: load atomic i64, ptr {{.*}} monotonic, align 8 // CHECK: store i16 #pragma omp atomic read usv = lx; -// CHECK: load atomic i32, i32* {{.*}} seq_cst, align 4 +// CHECK: load atomic i32, ptr {{.*}} seq_cst, align 4 // CHECK: call{{.*}} @__kmpc_flush( // CHECK: store i32 #pragma omp atomic seq_cst, read iv = uix; -// CHECK: load atomic i32, i32* {{.*}} monotonic, align 4 +// CHECK: load atomic i32, ptr {{.*}} monotonic, align 4 // CHECK: store i32 #pragma omp atomic read uiv = ix; @@ -195,15 +194,15 @@ int main(void) { // CHECK: store i64 #pragma omp atomic read lv = cix; -// CHECK: load atomic i32, i32* {{.*}} monotonic, align 4 +// CHECK: load atomic i32, ptr {{.*}} monotonic, align 4 // CHECK: store i64 #pragma omp atomic read ulv = fx; -// CHECK: load atomic i64, i64* {{.*}} monotonic, align 8 +// CHECK: load atomic i64, ptr {{.*}} monotonic, align 8 // CHECK: store i64 #pragma omp atomic read llv = dx; -// CHECK: load atomic i128, i128* {{.*}} monotonic, align 16 +// CHECK: load atomic i128, ptr {{.*}} monotonic, align 16 // CHECK: store i64 #pragma omp atomic read ullv = ldx; @@ -211,123 +210,119 @@ int main(void) { // CHECK: store float #pragma omp atomic read fv = cix; -// CHECK: load atomic i16, i16* {{.*}} monotonic, align 2 +// CHECK: load atomic i16, ptr {{.*}} monotonic, align 2 // CHECK: store double #pragma omp atomic read dv = sx; -// CHECK: load atomic i8, i8* {{.*}} monotonic, align 1 +// CHECK: load atomic i8, ptr {{.*}} monotonic, align 1 // CHECK: store x86_fp80 #pragma omp atomic read ldv = bx; -// CHECK: load atomic i8, i8* {{.*}} monotonic, align 1 +// CHECK: load atomic i8, ptr {{.*}} monotonic, align 1 // CHECK: store i32 // CHECK: store i32 #pragma omp atomic read civ = bx; -// CHECK: load atomic i16, i16* {{.*}} monotonic, align 2 +// CHECK: load atomic i16, ptr {{.*}} monotonic, align 2 // CHECK: store float // CHECK: store float #pragma omp atomic read cfv = usx; -// CHECK: load atomic i64, i64* {{.*}} monotonic, align 8 +// CHECK: load atomic i64, ptr {{.*}} monotonic, align 8 // CHECK: store double // CHECK: store double #pragma omp atomic read cdv = llx; -// CHECK: [[I128VAL:%.+]] = load atomic i128, i128* bitcast (<4 x i32>* @{{.+}} to i128*) monotonic, align 16 -// CHECK: [[I128PTR:%.+]] = bitcast <4 x i32>* [[LDTEMP:%.+]] to i128* -// CHECK: store i128 [[I128VAL]], i128* [[I128PTR]] -// CHECK: [[LD:%.+]] = load <4 x i32>, <4 x i32>* [[LDTEMP]] +// CHECK: [[I128VAL:%.+]] = load atomic i128, ptr @{{.+}} monotonic, align 16 +// CHECK: store i128 [[I128VAL]], ptr [[LDTEMP:%.+]] +// CHECK: [[LD:%.+]] = load <4 x i32>, ptr [[LDTEMP]] // CHECK: extractelement <4 x i32> [[LD]] // CHECK: store i8 #pragma omp atomic read bv = int4x[0]; -// CHECK: [[LD:%.+]] = load atomic i32, i32* bitcast (i8* getelementptr (i8, i8* bitcast (%{{.+}}* @{{.+}} to i8*), i64 4) to i32*) monotonic, align 4 -// CHECK: store i32 [[LD]], i32* [[LDTEMP:%.+]] -// CHECK: [[LD:%.+]] = load i32, i32* [[LDTEMP]] +// CHECK: [[LD:%.+]] = load atomic i32, ptr getelementptr (i8, ptr @{{.+}}, i64 4) monotonic, align 4 +// CHECK: store i32 [[LD]], ptr [[LDTEMP:%.+]] +// CHECK: [[LD:%.+]] = load i32, ptr [[LDTEMP]] // CHECK: [[SHL:%.+]] = shl i32 [[LD]], 1 // CHECK: ashr i32 [[SHL]], 1 // CHECK: store x86_fp80 #pragma omp atomic read ldv = bfx.a; -// CHECK: [[LDTEMP_VOID_PTR:%.+]] = bitcast i32* [[LDTEMP:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 4, i8* noundef getelementptr (i8, i8* bitcast (%struct.BitFields_packed* @bfx_packed to i8*), i64 4), i8* noundef [[LDTEMP_VOID_PTR]], i32 noundef 0) -// CHECK: [[LD:%.+]] = load i32, i32* [[LDTEMP]] +// CHECK: call void @__atomic_load(i64 noundef 4, ptr noundef getelementptr (i8, ptr @bfx_packed, i64 4), ptr noundef [[LDTEMP:%.+]], i32 noundef 0) +// CHECK: [[LD:%.+]] = load i32, ptr [[LDTEMP]] // CHECK: [[SHL:%.+]] = shl i32 [[LD]], 1 // CHECK: ashr i32 [[SHL]], 1 // CHECK: store x86_fp80 #pragma omp atomic read ldv = bfx_packed.a; -// CHECK: [[LD:%.+]] = load atomic i32, i32* getelementptr inbounds (%struct.BitFields2, %struct.BitFields2* @bfx2, i32 0, i32 0) monotonic, align 4 -// CHECK: store i32 [[LD]], i32* [[LDTEMP:%.+]] -// CHECK: [[LD:%.+]] = load i32, i32* [[LDTEMP]] +// CHECK: [[LD:%.+]] = load atomic i32, ptr @bfx2 monotonic, align 4 +// CHECK: store i32 [[LD]], ptr [[LDTEMP:%.+]] +// CHECK: [[LD:%.+]] = load i32, ptr [[LDTEMP]] // CHECK: ashr i32 [[LD]], 31 // CHECK: store x86_fp80 #pragma omp atomic read ldv = bfx2.a; -// CHECK: [[LD:%.+]] = load atomic i8, i8* getelementptr (i8, i8* bitcast (%struct.BitFields2_packed* @bfx2_packed to i8*), i64 3) monotonic, align 1 -// CHECK: store i8 [[LD]], i8* [[LDTEMP:%.+]] -// CHECK: [[LD:%.+]] = load i8, i8* [[LDTEMP]] +// CHECK: [[LD:%.+]] = load atomic i8, ptr getelementptr (i8, ptr @bfx2_packed, i64 3) monotonic, align 1 +// CHECK: store i8 [[LD]], ptr [[LDTEMP:%.+]] +// CHECK: [[LD:%.+]] = load i8, ptr [[LDTEMP]] // CHECK: ashr i8 [[LD]], 7 // CHECK: store x86_fp80 #pragma omp atomic read ldv = bfx2_packed.a; -// CHECK: [[LD:%.+]] = load atomic i32, i32* getelementptr inbounds (%struct.BitFields3, %struct.BitFields3* @bfx3, i32 0, i32 0) monotonic, align 4 -// CHECK: store i32 [[LD]], i32* [[LDTEMP:%.+]] -// CHECK: [[LD:%.+]] = load i32, i32* [[LDTEMP]] +// CHECK: [[LD:%.+]] = load atomic i32, ptr @bfx3 monotonic, align 4 +// CHECK: store i32 [[LD]], ptr [[LDTEMP:%.+]] +// CHECK: [[LD:%.+]] = load i32, ptr [[LDTEMP]] // CHECK: [[SHL:%.+]] = shl i32 [[LD]], 7 // CHECK: ashr i32 [[SHL]], 18 // CHECK: store x86_fp80 #pragma omp atomic read ldv = bfx3.a; -// CHECK: [[LDTEMP_VOID_PTR:%.+]] = bitcast i24* [[LDTEMP:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 3, i8* noundef getelementptr (i8, i8* bitcast (%struct.BitFields3_packed* @bfx3_packed to i8*), i64 1), i8* noundef [[LDTEMP_VOID_PTR]], i32 noundef 0) -// CHECK: [[LD:%.+]] = load i24, i24* [[LDTEMP]] +// CHECK: call void @__atomic_load(i64 noundef 3, ptr noundef getelementptr (i8, ptr @bfx3_packed, i64 1), ptr noundef [[LDTEMP:%.+]], i32 noundef 0) +// CHECK: [[LD:%.+]] = load i24, ptr [[LDTEMP]] // CHECK: [[SHL:%.+]] = shl i24 [[LD]], 7 // CHECK: [[ASHR:%.+]] = ashr i24 [[SHL]], 10 // CHECK: sext i24 [[ASHR]] to i32 // CHECK: store x86_fp80 #pragma omp atomic read ldv = bfx3_packed.a; -// CHECK: [[LD:%.+]] = load atomic i64, i64* bitcast (%struct.BitFields4* @bfx4 to i64*) monotonic, align 8 -// CHECK: store i64 [[LD]], i64* [[LDTEMP:%.+]] -// CHECK: [[LD:%.+]] = load i64, i64* [[LDTEMP]] +// CHECK: [[LD:%.+]] = load atomic i64, ptr @bfx4 monotonic, align 8 +// CHECK: store i64 [[LD]], ptr [[LDTEMP:%.+]] +// CHECK: [[LD:%.+]] = load i64, ptr [[LDTEMP]] // CHECK: [[SHL:%.+]] = shl i64 [[LD]], 47 // CHECK: [[ASHR:%.+]] = ashr i64 [[SHL]], 63 // CHECK: trunc i64 [[ASHR]] to i32 // CHECK: store x86_fp80 #pragma omp atomic read ldv = bfx4.a; -// CHECK: [[LD:%.+]] = load atomic i8, i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @bfx4_packed, i32 0, i32 0, i64 2) monotonic, align 1 -// CHECK: store i8 [[LD]], i8* [[LDTEMP:%.+]] -// CHECK: [[LD:%.+]] = load i8, i8* [[LDTEMP]] +// CHECK: [[LD:%.+]] = load atomic i8, ptr getelementptr (i8, ptr @bfx4_packed, i64 2) monotonic, align 1 +// CHECK: store i8 [[LD]], ptr [[LDTEMP:%.+]] +// CHECK: [[LD:%.+]] = load i8, ptr [[LDTEMP]] // CHECK: [[SHL:%.+]] = shl i8 [[LD]], 7 // CHECK: [[ASHR:%.+]] = ashr i8 [[SHL]], 7 // CHECK: sext i8 [[ASHR]] to i32 // CHECK: store x86_fp80 #pragma omp atomic relaxed read ldv = bfx4_packed.a; -// CHECK: [[LD:%.+]] = load atomic i64, i64* bitcast (%struct.BitFields4* @bfx4 to i64*) monotonic, align 8 -// CHECK: store i64 [[LD]], i64* [[LDTEMP:%.+]] -// CHECK: [[LD:%.+]] = load i64, i64* [[LDTEMP]] +// CHECK: [[LD:%.+]] = load atomic i64, ptr @bfx4 monotonic, align 8 +// CHECK: store i64 [[LD]], ptr [[LDTEMP:%.+]] +// CHECK: [[LD:%.+]] = load i64, ptr [[LDTEMP]] // CHECK: [[SHL:%.+]] = shl i64 [[LD]], 40 // CHECK: [[ASHR:%.+]] = ashr i64 [[SHL]], 57 // CHECK: store x86_fp80 #pragma omp atomic read relaxed ldv = bfx4.b; -// CHECK: [[LD:%.+]] = load atomic i8, i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @bfx4_packed, i32 0, i32 0, i64 2) acquire, align 1 -// CHECK: store i8 [[LD]], i8* [[LDTEMP:%.+]] -// CHECK: [[LD:%.+]] = load i8, i8* [[LDTEMP]] +// CHECK: [[LD:%.+]] = load atomic i8, ptr getelementptr (i8, ptr @bfx4_packed, i64 2) acquire, align 1 +// CHECK: store i8 [[LD]], ptr [[LDTEMP:%.+]] +// CHECK: [[LD:%.+]] = load i8, ptr [[LDTEMP]] // CHECK: [[ASHR:%.+]] = ashr i8 [[LD]], 1 // CHECK: sext i8 [[ASHR]] to i64 // CHECK: call{{.*}} @__kmpc_flush( // CHECK: store x86_fp80 #pragma omp atomic read acquire ldv = bfx4_packed.b; -// CHECK: [[LD:%.+]] = load atomic i64, i64* bitcast (<2 x float>* @{{.+}} to i64*) monotonic, align 8 -// CHECK: [[BITCAST:%.+]] = bitcast <2 x float>* [[LDTEMP:%.+]] to i64* -// CHECK: store i64 [[LD]], i64* [[BITCAST]] -// CHECK: [[LD:%.+]] = load <2 x float>, <2 x float>* [[LDTEMP]] +// CHECK: [[LD:%.+]] = load atomic i64, ptr @{{.+}} monotonic, align 8 +// CHECK: store i64 [[LD]], ptr [[LDTEMP:%.+]] +// CHECK: [[LD:%.+]] = load <2 x float>, ptr [[LDTEMP]] // CHECK: extractelement <2 x float> [[LD]] // CHECK: store i64 #pragma omp atomic read diff --git a/clang/test/OpenMP/atomic_update_codegen.cpp b/clang/test/OpenMP/atomic_update_codegen.cpp index 4cc301bee337d..31160b4176469 100644 --- a/clang/test/OpenMP/atomic_update_codegen.cpp +++ b/clang/test/OpenMP/atomic_update_codegen.cpp @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp-simd -x c -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp-simd -x c -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s // SIMD-ONLY0-NOT: {{__kmpc|__tgt}} // expected-no-diagnostics #ifndef HEADER @@ -82,232 +82,220 @@ float2 float2x; register int rix __asm__("esp"); int main(void) { -// CHECK: atomicrmw fadd double* @{{.+}}, double 1.000000e+00 monotonic, align 8 +// CHECK: atomicrmw fadd ptr @{{.+}}, double 1.000000e+00 monotonic, align 8 #pragma omp atomic ++dv; -// CHECK: atomicrmw add i8* @{{.+}}, i8 1 monotonic, align 1 +// CHECK: atomicrmw add ptr @{{.+}}, i8 1 monotonic, align 1 #pragma omp atomic bx++; -// CHECK: atomicrmw add i8* @{{.+}}, i8 1 monotonic, align 1 +// CHECK: atomicrmw add ptr @{{.+}}, i8 1 monotonic, align 1 #pragma omp atomic update ++cx; -// CHECK: atomicrmw sub i8* @{{.+}}, i8 1 monotonic, align 1 +// CHECK: atomicrmw sub ptr @{{.+}}, i8 1 monotonic, align 1 #pragma omp atomic ucx--; -// CHECK: atomicrmw sub i16* @{{.+}}, i16 1 monotonic, align 2 +// CHECK: atomicrmw sub ptr @{{.+}}, i16 1 monotonic, align 2 #pragma omp atomic update --sx; -// CHECK: [[USV:%.+]] = load i16, i16* @{{.+}}, +// CHECK: [[USV:%.+]] = load i16, ptr @{{.+}}, // CHECK: [[EXPR:%.+]] = zext i16 [[USV]] to i32 -// CHECK: [[X:%.+]] = load atomic i16, i16* [[X_ADDR:@.+]] monotonic, align 2 +// CHECK: [[X:%.+]] = load atomic i16, ptr [[X_ADDR:@.+]] monotonic, align 2 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i16 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[CONV:%.+]] = zext i16 [[EXPECTED]] to i32 // CHECK: [[ADD:%.+]] = add nsw i32 [[CONV]], [[EXPR]] // CHECK: [[DESIRED:%.+]] = trunc i32 [[ADD]] to i16 -// CHECK: store i16 [[DESIRED]], i16* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i16, i16* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i16* [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic, align 2 +// CHECK: store i16 [[DESIRED]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i16, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic, align 2 // CHECK: [[OLD_X]] = extractvalue { i16, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i16, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic usx += usv; -// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}}, -// CHECK: [[X:%.+]] = load atomic i32, i32* [[X_ADDR:@.+]] monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load i32, ptr @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i32, ptr [[X_ADDR:@.+]] monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[DESIRED:%.+]] = mul nsw i32 [[EXPECTED]], [[EXPR]] -// CHECK: store i32 [[DESIRED]], i32* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i32, i32* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i32* [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 +// CHECK: store i32 [[DESIRED]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i32, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 // CHECK: [[OLD_X]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic update ix *= iv; -// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}}, -// CHECK: atomicrmw sub i32* @{{.+}}, i32 [[EXPR]] monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load i32, ptr @{{.+}}, +// CHECK: atomicrmw sub ptr @{{.+}}, i32 [[EXPR]] monotonic, align 4 #pragma omp atomic uix -= uiv; -// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}}, -// CHECK: [[X:%.+]] = load atomic i32, i32* [[X_ADDR:@.+]] monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load i32, ptr @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i32, ptr [[X_ADDR:@.+]] monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[DESIRED:%.+]] = shl i32 [[EXPECTED]], [[EXPR]] -// CHECK: store i32 [[DESIRED]], i32* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i32, i32* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i32* [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 +// CHECK: store i32 [[DESIRED]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i32, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 // CHECK: [[OLD_X]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic update ix <<= iv; -// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}}, -// CHECK: [[X:%.+]] = load atomic i32, i32* [[X_ADDR:@.+]] monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load i32, ptr @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i32, ptr [[X_ADDR:@.+]] monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[DESIRED:%.+]] = lshr i32 [[EXPECTED]], [[EXPR]] -// CHECK: store i32 [[DESIRED]], i32* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i32, i32* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i32* [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 +// CHECK: store i32 [[DESIRED]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i32, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 // CHECK: [[OLD_X]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic uix >>= uiv; -// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, -// CHECK: [[X:%.+]] = load atomic i64, i64* [[X_ADDR:@.+]] monotonic, align 8 +// CHECK: [[EXPR:%.+]] = load i64, ptr @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i64, ptr [[X_ADDR:@.+]] monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[DESIRED:%.+]] = sdiv i64 [[EXPECTED]], [[EXPR]] -// CHECK: store i64 [[DESIRED]], i64* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i64* [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: store i64 [[DESIRED]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i64, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 // CHECK: [[OLD_X]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic update lx /= lv; -// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, -// CHECK: atomicrmw and i64* @{{.+}}, i64 [[EXPR]] monotonic, align 8 +// CHECK: [[EXPR:%.+]] = load i64, ptr @{{.+}}, +// CHECK: atomicrmw and ptr @{{.+}}, i64 [[EXPR]] monotonic, align 8 #pragma omp atomic ulx &= ulv; -// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, -// CHECK: atomicrmw xor i64* @{{.+}}, i64 [[EXPR]] monotonic, align 8 +// CHECK: [[EXPR:%.+]] = load i64, ptr @{{.+}}, +// CHECK: atomicrmw xor ptr @{{.+}}, i64 [[EXPR]] monotonic, align 8 #pragma omp atomic update llx ^= llv; -// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, -// CHECK: atomicrmw or i64* @{{.+}}, i64 [[EXPR]] monotonic, align 8 +// CHECK: [[EXPR:%.+]] = load i64, ptr @{{.+}}, +// CHECK: atomicrmw or ptr @{{.+}}, i64 [[EXPR]] monotonic, align 8 #pragma omp atomic ullx |= ullv; -// CHECK: [[EXPR:%.+]] = load float, float* @{{.+}}, -// CHECK: atomicrmw fadd float* @{{.+}}, float [[EXPR]] monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load float, ptr @{{.+}}, +// CHECK: atomicrmw fadd ptr @{{.+}}, float [[EXPR]] monotonic, align 4 #pragma omp atomic update fx = fx + fv; -// CHECK: [[EXPR:%.+]] = load double, double* @{{.+}}, -// CHECK: [[OLD:%.+]] = load atomic i64, i64* bitcast (double* [[X_ADDR:@.+]] to i64*) monotonic, align 8 +// CHECK: [[EXPR:%.+]] = load double, ptr @{{.+}}, +// CHECK: [[OLD:%.+]] = load atomic i64, ptr [[X_ADDR:@.+]] monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i64 [ [[OLD]], %{{.+}} ], [ [[PREV:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST:%.+]] = bitcast double* [[TEMP:%.+]] to i64* // CHECK: [[OLD:%.+]] = bitcast i64 [[EXPECTED]] to double // CHECK: [[SUB:%.+]] = fsub double [[EXPR]], [[OLD]] -// CHECK: store double [[SUB]], double* [[TEMP]], -// CHECK: [[DESIRED:%.+]] = load i64, i64* [[BITCAST]], -// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (double* [[X_ADDR]] to i64*), i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: store double [[SUB]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i64, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 // CHECK: [[PREV:%.+]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic dx = dv - dx; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}, -// CHECK: [[OLD:%.+]] = load atomic i128, i128* bitcast (x86_fp80* [[X_ADDR:@.+]] to i128*) monotonic, align 16 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}}, +// CHECK: [[OLD:%.+]] = load atomic i128, ptr [[X_ADDR:@.+]] monotonic, align 16 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i128 [ [[OLD]], %{{.+}} ], [ [[PREV:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i128* -// CHECK: store i128 [[EXPECTED]], i128* [[BITCAST]], -// CHECK: [[BITCAST1:%.+]] = bitcast x86_fp80* [[TEMP1:%.+]] to i128* -// CHECK: store i128 [[EXPECTED]], i128* [[BITCAST1]], -// CHECK: [[OLD:%.+]] = load x86_fp80, x86_fp80* [[TEMP1]] +// CHECK: store i128 [[EXPECTED]], ptr [[TEMP:%.+]], +// CHECK: store i128 [[EXPECTED]], ptr [[TEMP1:%.+]], +// CHECK: [[OLD:%.+]] = load x86_fp80, ptr [[TEMP1]] // CHECK: [[MUL:%.+]] = fmul x86_fp80 [[OLD]], [[EXPR]] -// CHECK: store x86_fp80 [[MUL]], x86_fp80* [[TEMP]] -// CHECK: [[DESIRED:%.+]] = load i128, i128* [[BITCAST]] -// CHECK: [[RES:%.+]] = cmpxchg i128* bitcast (x86_fp80* [[X_ADDR]] to i128*), i128 [[EXPECTED]], i128 [[DESIRED]] monotonic monotonic, align 16 +// CHECK: store x86_fp80 [[MUL]], ptr [[TEMP]] +// CHECK: [[DESIRED:%.+]] = load i128, ptr [[TEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i128 [[EXPECTED]], i128 [[DESIRED]] monotonic monotonic, align 16 // CHECK: [[PREV:%.+]] = extractvalue { i128, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i128, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic update ldx = ldx * ldv; -// CHECK: [[EXPR_RE:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 0) -// CHECK: [[EXPR_IM:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 1) -// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* [[X_ADDR:@.+]] to i8*), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[EXPR_RE:%.+]] = load i32, ptr @{{.+}} +// CHECK: [[EXPR_IM:%.+]] = load i32, ptr getelementptr inbounds ({ i32, i32 }, ptr @{{.+}}, i32 0, i32 1) +// CHECK: call void @__atomic_load(i64 noundef 8, ptr noundef [[X_ADDR:@.+]], ptr noundef [[EXPECTED_ADDR:%.+]], i32 noundef 0) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 0 -// CHECK: [[X_RE:%.+]] = load i32, i32* [[X_RE_ADDR]] -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 1 -// CHECK: [[X_IM:%.+]] = load i32, i32* [[X_IM_ADDR]] +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[X_RE:%.+]] = load i32, ptr [[X_RE_ADDR]] +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[X_IM:%.+]] = load i32, ptr [[X_IM_ADDR]] // -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR]], i32 0, i32 1 -// CHECK: store i32 %{{.+}}, i32* [[X_RE_ADDR]] -// CHECK: store i32 %{{.+}}, i32* [[X_IM_ADDR]] -// CHECK: [[EXPECTED:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR]] to i8* -// CHECK: [[DESIRED:%.+]] = bitcast { i32, i32 }* [[DESIRED_ADDR]] to i8* -// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* [[X_ADDR]] to i8*), i8* noundef [[EXPECTED]], i8* noundef [[DESIRED]], i32 noundef 0, i32 noundef 0) +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store i32 %{{.+}}, ptr [[X_RE_ADDR]] +// CHECK: store i32 %{{.+}}, ptr [[X_IM_ADDR]] +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, ptr noundef [[X_ADDR]], ptr noundef [[EXPECTED_ADDR]], ptr noundef [[DESIRED_ADDR]], i32 noundef 0, i32 noundef 0) // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic cix = civ / cix; -// CHECK: [[EXPR_RE:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 0) -// CHECK: [[EXPR_IM:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 1) -// CHECK: [[BITCAST:%.+]] = bitcast { float, float }* [[EXPECTED_ADDR:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 8, i8* noundef bitcast ({ float, float }* [[X_ADDR:@.+]] to i8*), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[EXPR_RE:%.+]] = load float, ptr @{{.+}} +// CHECK: [[EXPR_IM:%.+]] = load float, ptr getelementptr inbounds ({ float, float }, ptr @{{.+}}, i32 0, i32 1) +// CHECK: call void @__atomic_load(i64 noundef 8, ptr noundef [[X_ADDR:@.+]], ptr noundef [[EXPECTED_ADDR:%.+]], i32 noundef 0) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[EXPECTED_ADDR]], i32 0, i32 0 -// CHECK: [[X_RE:%.+]] = load float, float* [[X_RE_ADDR]] -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[EXPECTED_ADDR]], i32 0, i32 1 -// CHECK: [[X_IM:%.+]] = load float, float* [[X_IM_ADDR]] +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, ptr [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[X_RE:%.+]] = load float, ptr [[X_RE_ADDR]] +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, ptr [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[X_IM:%.+]] = load float, ptr [[X_IM_ADDR]] // -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[DESIRED_ADDR]], i32 0, i32 1 -// CHECK: store float %{{.+}}, float* [[X_RE_ADDR]] -// CHECK: store float %{{.+}}, float* [[X_IM_ADDR]] -// CHECK: [[EXPECTED:%.+]] = bitcast { float, float }* [[EXPECTED_ADDR]] to i8* -// CHECK: [[DESIRED:%.+]] = bitcast { float, float }* [[DESIRED_ADDR]] to i8* -// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, i8* noundef bitcast ({ float, float }* [[X_ADDR]] to i8*), i8* noundef [[EXPECTED]], i8* noundef [[DESIRED]], i32 noundef 0, i32 noundef 0) +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, ptr [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, ptr [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store float %{{.+}}, ptr [[X_RE_ADDR]] +// CHECK: store float %{{.+}}, ptr [[X_IM_ADDR]] +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, ptr noundef [[X_ADDR]], ptr noundef [[EXPECTED_ADDR]], ptr noundef [[DESIRED_ADDR]], i32 noundef 0, i32 noundef 0) // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic update cfx = cfv + cfx; -// CHECK: [[EXPR_RE:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 0) -// CHECK: [[EXPR_IM:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 1) -// CHECK: [[BITCAST:%.+]] = bitcast { double, double }* [[EXPECTED_ADDR:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 16, i8* noundef bitcast ({ double, double }* [[X_ADDR:@.+]] to i8*), i8* noundef [[BITCAST]], i32 noundef 5) +// CHECK: [[EXPR_RE:%.+]] = load double, ptr @{{.+}} +// CHECK: [[EXPR_IM:%.+]] = load double, ptr getelementptr inbounds ({ double, double }, ptr @{{.+}}, i32 0, i32 1) +// CHECK: call void @__atomic_load(i64 noundef 16, ptr noundef [[X_ADDR:@.+]], ptr noundef [[EXPECTED_ADDR:%.+]], i32 noundef 5) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[EXPECTED_ADDR]], i32 0, i32 0 -// CHECK: [[X_RE:%.+]] = load double, double* [[X_RE_ADDR]] -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[EXPECTED_ADDR]], i32 0, i32 1 -// CHECK: [[X_IM:%.+]] = load double, double* [[X_IM_ADDR]] +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, ptr [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[X_RE:%.+]] = load double, ptr [[X_RE_ADDR]] +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, ptr [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[X_IM:%.+]] = load double, ptr [[X_IM_ADDR]] // -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[DESIRED_ADDR]], i32 0, i32 1 -// CHECK: store double %{{.+}}, double* [[X_RE_ADDR]] -// CHECK: store double %{{.+}}, double* [[X_IM_ADDR]] -// CHECK: [[EXPECTED:%.+]] = bitcast { double, double }* [[EXPECTED_ADDR]] to i8* -// CHECK: [[DESIRED:%.+]] = bitcast { double, double }* [[DESIRED_ADDR]] to i8* -// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 16, i8* noundef bitcast ({ double, double }* [[X_ADDR]] to i8*), i8* noundef [[EXPECTED]], i8* noundef [[DESIRED]], i32 noundef 5, i32 noundef 5) +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, ptr [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, ptr [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store double %{{.+}}, ptr [[X_RE_ADDR]] +// CHECK: store double %{{.+}}, ptr [[X_IM_ADDR]] +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 16, ptr noundef [[X_ADDR]], ptr noundef [[EXPECTED_ADDR]], ptr noundef [[DESIRED_ADDR]], i32 noundef 5, i32 noundef 5) // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] // CHECK: call{{.*}} @__kmpc_flush( #pragma omp atomic seq_cst cdx = cdx - cdv; -// CHECK: [[BV:%.+]] = load i8, i8* @{{.+}} +// CHECK: [[BV:%.+]] = load i8, ptr @{{.+}} // CHECK: [[BOOL:%.+]] = trunc i8 [[BV]] to i1 // CHECK: [[EXPR:%.+]] = zext i1 [[BOOL]] to i64 -// CHECK: atomicrmw and i64* @{{.+}}, i64 [[EXPR]] monotonic, align 8 +// CHECK: atomicrmw and ptr @{{.+}}, i64 [[EXPR]] monotonic, align 8 #pragma omp atomic update ulx = ulx & bv; -// CHECK: [[CV:%.+]] = load i8, i8* @{{.+}}, align 1 +// CHECK: [[CV:%.+]] = load i8, ptr @{{.+}}, align 1 // CHECK: [[EXPR:%.+]] = sext i8 [[CV]] to i32 -// CHECK: [[BX:%.+]] = load atomic i8, i8* [[BX_ADDR:@.+]] monotonic, align 1 +// CHECK: [[BX:%.+]] = load atomic i8, ptr [[BX_ADDR:@.+]] monotonic, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i8 [ [[BX]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] @@ -316,27 +304,27 @@ int main(void) { // CHECK: [[AND:%.+]] = and i32 [[EXPR]], [[X_RVAL]] // CHECK: [[CAST:%.+]] = icmp ne i32 [[AND]], 0 // CHECK: [[DESIRED:%.+]] = zext i1 [[CAST]] to i8 -// CHECK: store i8 [[DESIRED]], i8* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i8, i8* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i8* [[BX_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic, align 1 +// CHECK: store i8 [[DESIRED]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i8, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[BX_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic, align 1 // CHECK: [[OLD_X:%.+]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic bx = cv & bx; -// CHECK: [[UCV:%.+]] = load i8, i8* @{{.+}}, +// CHECK: [[UCV:%.+]] = load i8, ptr @{{.+}}, // CHECK: [[EXPR:%.+]] = zext i8 [[UCV]] to i32 -// CHECK: [[X:%.+]] = load atomic i8, i8* [[CX_ADDR:@.+]] seq_cst, align 1 +// CHECK: [[X:%.+]] = load atomic i8, ptr [[CX_ADDR:@.+]] seq_cst, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i8 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[X_RVAL:%.+]] = sext i8 [[EXPECTED]] to i32 // CHECK: [[ASHR:%.+]] = ashr i32 [[X_RVAL]], [[EXPR]] // CHECK: [[DESIRED:%.+]] = trunc i32 [[ASHR]] to i8 -// CHECK: store i8 [[DESIRED]], i8* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i8, i8* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i8* [[CX_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] seq_cst seq_cst, align 1 +// CHECK: store i8 [[DESIRED]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i8, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[CX_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] seq_cst seq_cst, align 1 // CHECK: [[OLD_X:%.+]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] @@ -344,149 +332,139 @@ int main(void) { // CHECK: call{{.*}} @__kmpc_flush( #pragma omp atomic update, seq_cst cx = cx >> ucv; -// CHECK: [[SV:%.+]] = load i16, i16* @{{.+}}, +// CHECK: [[SV:%.+]] = load i16, ptr @{{.+}}, // CHECK: [[EXPR:%.+]] = sext i16 [[SV]] to i32 -// CHECK: [[X:%.+]] = load atomic i64, i64* [[ULX_ADDR:@.+]] monotonic, align 8 +// CHECK: [[X:%.+]] = load atomic i64, ptr [[ULX_ADDR:@.+]] monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[X_RVAL:%.+]] = trunc i64 [[EXPECTED]] to i32 // CHECK: [[SHL:%.+]] = shl i32 [[EXPR]], [[X_RVAL]] // CHECK: [[DESIRED:%.+]] = sext i32 [[SHL]] to i64 -// CHECK: store i64 [[DESIRED]], i64* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i64* [[ULX_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: store i64 [[DESIRED]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i64, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[ULX_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 // CHECK: [[OLD_X:%.+]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic update ulx = sv << ulx; -// CHECK: [[USV:%.+]] = load i16, i16* @{{.+}}, +// CHECK: [[USV:%.+]] = load i16, ptr @{{.+}}, // CHECK: [[EXPR:%.+]] = zext i16 [[USV]] to i64 -// CHECK: [[X:%.+]] = load atomic i64, i64* [[LX_ADDR:@.+]] monotonic, align 8 +// CHECK: [[X:%.+]] = load atomic i64, ptr [[LX_ADDR:@.+]] monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[DESIRED:%.+]] = srem i64 [[EXPECTED]], [[EXPR]] -// CHECK: store i64 [[DESIRED]], i64* [[TEMP:%.+]], -// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP]], -// CHECK: [[RES:%.+]] = cmpxchg i64* [[LX_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: store i64 [[DESIRED]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i64, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[LX_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 // CHECK: [[OLD_X:%.+]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic lx = lx % usv; -// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}} -// CHECK: atomicrmw or i32* @{{.+}}, i32 [[EXPR]] seq_cst, align 4 +// CHECK: [[EXPR:%.+]] = load i32, ptr @{{.+}} +// CHECK: atomicrmw or ptr @{{.+}}, i32 [[EXPR]] seq_cst, align 4 // CHECK: call{{.*}} @__kmpc_flush( #pragma omp atomic seq_cst, update uix = iv | uix; -// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}} -// CHECK: atomicrmw and i32* @{{.+}}, i32 [[EXPR]] monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load i32, ptr @{{.+}} +// CHECK: atomicrmw and ptr @{{.+}}, i32 [[EXPR]] monotonic, align 4 #pragma omp atomic ix = ix & uiv; -// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, -// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* [[X_ADDR:@.+]] to i8*), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[EXPR:%.+]] = load i64, ptr @{{.+}}, +// CHECK: call void @__atomic_load(i64 noundef 8, ptr noundef [[X_ADDR:@.+]], ptr noundef [[EXPECTED_ADDR:%.+]], i32 noundef 0) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 0 -// CHECK: [[X_RE:%.+]] = load i32, i32* [[X_RE_ADDR]] -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 1 -// CHECK: [[X_IM:%.+]] = load i32, i32* [[X_IM_ADDR]] +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[X_RE:%.+]] = load i32, ptr [[X_RE_ADDR]] +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[X_IM:%.+]] = load i32, ptr [[X_IM_ADDR]] // -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR]], i32 0, i32 1 -// CHECK: store i32 %{{.+}}, i32* [[X_RE_ADDR]] -// CHECK: store i32 %{{.+}}, i32* [[X_IM_ADDR]] -// CHECK: [[EXPECTED:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR]] to i8* -// CHECK: [[DESIRED:%.+]] = bitcast { i32, i32 }* [[DESIRED_ADDR]] to i8* -// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* [[X_ADDR]] to i8*), i8* noundef [[EXPECTED]], i8* noundef [[DESIRED]], i32 noundef 0, i32 noundef 0) +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store i32 %{{.+}}, ptr [[X_RE_ADDR]] +// CHECK: store i32 %{{.+}}, ptr [[X_IM_ADDR]] +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, ptr noundef [[X_ADDR]], ptr noundef [[EXPECTED_ADDR]], ptr noundef [[DESIRED_ADDR]], i32 noundef 0, i32 noundef 0) // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic update cix = lv + cix; -// CHECK: [[ULV:%.+]] = load i64, i64* @{{.+}}, +// CHECK: [[ULV:%.+]] = load i64, ptr @{{.+}}, // CHECK: [[EXPR:%.+]] = uitofp i64 [[ULV]] to float -// CHECK: [[OLD:%.+]] = load atomic i32, i32* bitcast (float* [[X_ADDR:@.+]] to i32*) monotonic, align 4 +// CHECK: [[OLD:%.+]] = load atomic i32, ptr [[X_ADDR:@.+]] monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i32 [ [[OLD]], %{{.+}} ], [ [[PREV:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST:%.+]] = bitcast float* [[TEMP:%.+]] to i32* // CHECK: [[OLD:%.+]] = bitcast i32 [[EXPECTED]] to float // CHECK: [[MUL:%.+]] = fmul float [[OLD]], [[EXPR]] -// CHECK: store float [[MUL]], float* [[TEMP]], -// CHECK: [[DESIRED:%.+]] = load i32, i32* [[BITCAST]], -// CHECK: [[RES:%.+]] = cmpxchg i32* bitcast (float* [[X_ADDR]] to i32*), i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 +// CHECK: store float [[MUL]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i32, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 // CHECK: [[PREV:%.+]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic fx = fx * ulv; -// CHECK: [[LLV:%.+]] = load i64, i64* @{{.+}}, +// CHECK: [[LLV:%.+]] = load i64, ptr @{{.+}}, // CHECK: [[EXPR:%.+]] = sitofp i64 [[LLV]] to double -// CHECK: [[OLD:%.+]] = load atomic i64, i64* bitcast (double* [[X_ADDR:@.+]] to i64*) monotonic, align 8 +// CHECK: [[OLD:%.+]] = load atomic i64, ptr [[X_ADDR:@.+]] monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i64 [ [[OLD]], %{{.+}} ], [ [[PREV:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST:%.+]] = bitcast double* [[TEMP:%.+]] to i64* // CHECK: [[OLD:%.+]] = bitcast i64 [[EXPECTED]] to double // CHECK: [[DIV:%.+]] = fdiv double [[OLD]], [[EXPR]] -// CHECK: store double [[DIV]], double* [[TEMP]], -// CHECK: [[DESIRED:%.+]] = load i64, i64* [[BITCAST]], -// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (double* [[X_ADDR]] to i64*), i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: store double [[DIV]], ptr [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i64, ptr [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 // CHECK: [[PREV:%.+]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic update dx /= llv; -// CHECK: [[ULLV:%.+]] = load i64, i64* @{{.+}}, +// CHECK: [[ULLV:%.+]] = load i64, ptr @{{.+}}, // CHECK: [[EXPR:%.+]] = uitofp i64 [[ULLV]] to x86_fp80 -// CHECK: [[OLD:%.+]] = load atomic i128, i128* bitcast (x86_fp80* [[X_ADDR:@.+]] to i128*) monotonic, align 16 +// CHECK: [[OLD:%.+]] = load atomic i128, ptr [[X_ADDR:@.+]] monotonic, align 16 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i128 [ [[OLD]], %{{.+}} ], [ [[PREV:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST1:%.+]] = bitcast x86_fp80* [[TEMP1:%.+]] to i128* -// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i128* -// CHECK: store i128 [[EXPECTED]], i128* [[BITCAST]] -// CHECK: [[OLD:%.+]] = load x86_fp80, x86_fp80* [[TEMP]] +// CHECK: store i128 [[EXPECTED]], ptr [[TEMP1:%.+]] +// CHECK: [[OLD:%.+]] = load x86_fp80, ptr [[TEMP:%.+]] // CHECK: [[SUB:%.+]] = fsub x86_fp80 [[OLD]], [[EXPR]] -// CHECK: store x86_fp80 [[SUB]], x86_fp80* [[TEMP1]] -// CHECK: [[DESIRED:%.+]] = load i128, i128* [[BITCAST1]] -// CHECK: [[RES:%.+]] = cmpxchg i128* bitcast (x86_fp80* [[X_ADDR]] to i128*), i128 [[EXPECTED]], i128 [[DESIRED]] monotonic monotonic, align 16 +// CHECK: store x86_fp80 [[SUB]], ptr [[TEMP1]] +// CHECK: [[DESIRED:%.+]] = load i128, ptr [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i128 [[EXPECTED]], i128 [[DESIRED]] monotonic monotonic, align 16 // CHECK: [[PREV:%.+]] = extractvalue { i128, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i128, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic ldx -= ullv; -// CHECK: [[EXPR:%.+]] = load float, float* @{{.+}}, -// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* [[X_ADDR:@.+]] to i8*), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[EXPR:%.+]] = load float, ptr @{{.+}}, +// CHECK: call void @__atomic_load(i64 noundef 8, ptr noundef [[X_ADDR:@.+]], ptr noundef [[EXPECTED_ADDR:%.+]], i32 noundef 0) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 0 -// CHECK: [[X_RE:%.+]] = load i32, i32* [[X_RE_ADDR]] -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 1 -// CHECK: [[X_IM:%.+]] = load i32, i32* [[X_IM_ADDR]] +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[X_RE:%.+]] = load i32, ptr [[X_RE_ADDR]] +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[X_IM:%.+]] = load i32, ptr [[X_IM_ADDR]] // -// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 -// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR]], i32 0, i32 1 -// CHECK: store i32 %{{.+}}, i32* [[X_RE_ADDR]] -// CHECK: store i32 %{{.+}}, i32* [[X_IM_ADDR]] -// CHECK: [[EXPECTED:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR]] to i8* -// CHECK: [[DESIRED:%.+]] = bitcast { i32, i32 }* [[DESIRED_ADDR]] to i8* -// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* [[X_ADDR]] to i8*), i8* noundef [[EXPECTED]], i8* noundef [[DESIRED]], i32 noundef 0, i32 noundef 0) +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store i32 %{{.+}}, ptr [[X_RE_ADDR]] +// CHECK: store i32 %{{.+}}, ptr [[X_IM_ADDR]] +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 8, ptr noundef [[X_ADDR]], ptr noundef [[EXPECTED_ADDR]], ptr noundef [[DESIRED_ADDR]], i32 noundef 0, i32 noundef 0) // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic update cix = fv / cix; -// CHECK: [[EXPR:%.+]] = load double, double* @{{.+}}, -// CHECK: [[X:%.+]] = load atomic i16, i16* [[X_ADDR:@.+]] monotonic, align 2 +// CHECK: [[EXPR:%.+]] = load double, ptr @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i16, ptr [[X_ADDR:@.+]] monotonic, align 2 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i16 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] @@ -494,17 +472,17 @@ int main(void) { // CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CONV]] to double // CHECK: [[ADD:%.+]] = fadd double [[X_RVAL]], [[EXPR]] // CHECK: [[DESIRED:%.+]] = fptosi double [[ADD]] to i16 -// CHECK: store i16 [[DESIRED]], i16* [[TEMP:%.+]] -// CHECK: [[DESIRED:%.+]] = load i16, i16* [[TEMP]] -// CHECK: [[RES:%.+]] = cmpxchg i16* [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic, align 2 +// CHECK: store i16 [[DESIRED]], ptr [[TEMP:%.+]] +// CHECK: [[DESIRED:%.+]] = load i16, ptr [[TEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic, align 2 // CHECK: [[OLD_X]] = extractvalue { i16, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i16, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic sx = sx + dv; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}, -// CHECK: [[XI8:%.+]] = load atomic i8, i8* [[X_ADDR:@.+]] monotonic, align 1 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}}, +// CHECK: [[XI8:%.+]] = load atomic i8, ptr [[X_ADDR:@.+]] monotonic, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i8 [ [[XI8]], %{{.+}} ], [ [[OLD_XI8:%.+]], %[[CONT]] ] @@ -514,9 +492,9 @@ int main(void) { // CHECK: [[MUL:%.+]] = fmul x86_fp80 [[EXPR]], [[X_RVAL]] // CHECK: [[BOOL_DESIRED:%.+]] = fcmp une x86_fp80 [[MUL]], 0xK00000000000000000000 // CHECK: [[DESIRED:%.+]] = zext i1 [[BOOL_DESIRED]] to i8 -// CHECK: store i8 [[DESIRED]], i8* [[TEMP:%.+]] -// CHECK: [[DESIRED:%.+]] = load i8, i8* [[TEMP]] -// CHECK: [[RES:%.+]] = cmpxchg i8* [[X_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] release monotonic, align 1 +// CHECK: store i8 [[DESIRED]], ptr [[TEMP:%.+]] +// CHECK: [[DESIRED:%.+]] = load i8, ptr [[TEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] release monotonic, align 1 // CHECK: [[OLD_XI8:%.+]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] @@ -524,9 +502,9 @@ int main(void) { // CHECK: call{{.*}} @__kmpc_flush( #pragma omp atomic update release bx = ldv * bx; -// CHECK: [[EXPR_RE:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* [[CIV_ADDR:@.+]], i32 0, i32 0), -// CHECK: [[EXPR_IM:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* [[CIV_ADDR]], i32 0, i32 1), -// CHECK: [[XI8:%.+]] = load atomic i8, i8* [[X_ADDR:@.+]] monotonic, align 1 +// CHECK: [[EXPR_RE:%.+]] = load i32, ptr [[CIV_ADDR:@.+]], +// CHECK: [[EXPR_IM:%.+]] = load i32, ptr getelementptr inbounds ({ i32, i32 }, ptr [[CIV_ADDR]], i32 0, i32 1), +// CHECK: [[XI8:%.+]] = load atomic i8, ptr [[X_ADDR:@.+]] monotonic, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i8 [ [[XI8]], %{{.+}} ], [ [[OLD_XI8:%.+]], %[[CONT]] ] @@ -538,187 +516,179 @@ int main(void) { // CHECK: icmp ne i32 [[SUB_IM]], 0 // CHECK: [[BOOL_DESIRED:%.+]] = or i1 // CHECK: [[DESIRED:%.+]] = zext i1 [[BOOL_DESIRED]] to i8 -// CHECK: store i8 [[DESIRED]], i8* [[TEMP:%.+]] -// CHECK: [[DESIRED:%.+]] = load i8, i8* [[TEMP]] -// CHECK: [[RES:%.+]] = cmpxchg i8* [[X_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic, align 1 +// CHECK: store i8 [[DESIRED]], ptr [[TEMP:%.+]] +// CHECK: [[DESIRED:%.+]] = load i8, ptr [[TEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr [[X_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic, align 1 // CHECK: [[OLD_XI8:%.+]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic bx = civ - bx; -// CHECK: [[IDX:%.+]] = load i16, i16* @{{.+}} -// CHECK: load i8, i8* +// CHECK: [[IDX:%.+]] = load i16, ptr @{{.+}} +// CHECK: load i8, ptr // CHECK: [[VEC_ITEM_VAL:%.+]] = zext i1 %{{.+}} to i32 -// CHECK: [[I128VAL:%.+]] = load atomic i128, i128* bitcast (<4 x i32>* [[DEST:@.+]] to i128*) monotonic, align 16 +// CHECK: [[I128VAL:%.+]] = load atomic i128, ptr [[DEST:@.+]] monotonic, align 16 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_I128:%.+]] = phi i128 [ [[I128VAL]], %{{.+}} ], [ [[FAILED_I128_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST:%.+]] = bitcast <4 x i32>* [[TEMP:%.+]] to i128* -// CHECK: store i128 [[OLD_I128]], i128* [[BITCAST]], +// CHECK: store i128 [[OLD_I128]], ptr [[TEMP:%.+]], // CHECK: [[OLD_VEC_VAL:%.+]] = bitcast i128 [[OLD_I128]] to <4 x i32> -// CHECK: store <4 x i32> [[OLD_VEC_VAL]], <4 x i32>* [[LDTEMP:%.+]], -// CHECK: [[VEC_VAL:%.+]] = load <4 x i32>, <4 x i32>* [[LDTEMP]] +// CHECK: store <4 x i32> [[OLD_VEC_VAL]], ptr [[LDTEMP:%.+]], +// CHECK: [[VEC_VAL:%.+]] = load <4 x i32>, ptr [[LDTEMP]] // CHECK: [[ITEM:%.+]] = extractelement <4 x i32> [[VEC_VAL]], i16 [[IDX]] // CHECK: [[OR:%.+]] = or i32 [[ITEM]], [[VEC_ITEM_VAL]] -// CHECK: [[VEC_VAL:%.+]] = load <4 x i32>, <4 x i32>* [[TEMP]] +// CHECK: [[VEC_VAL:%.+]] = load <4 x i32>, ptr [[TEMP]] // CHECK: [[NEW_VEC_VAL:%.+]] = insertelement <4 x i32> [[VEC_VAL]], i32 [[OR]], i16 [[IDX]] -// CHECK: store <4 x i32> [[NEW_VEC_VAL]], <4 x i32>* [[TEMP]] -// CHECK: [[NEW_I128:%.+]] = load i128, i128* [[BITCAST]] -// CHECK: [[RES:%.+]] = cmpxchg i128* bitcast (<4 x i32>* [[DEST]] to i128*), i128 [[OLD_I128]], i128 [[NEW_I128]] monotonic monotonic, align 16 +// CHECK: store <4 x i32> [[NEW_VEC_VAL]], ptr [[TEMP]] +// CHECK: [[NEW_I128:%.+]] = load i128, ptr [[TEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr [[DEST]], i128 [[OLD_I128]], i128 [[NEW_I128]] monotonic monotonic, align 16 // CHECK: [[FAILED_I128_OLD_VAL:%.+]] = extractvalue { i128, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i128, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic update int4x[sv] |= bv; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.BitFields* @{{.+}} to i8*), i64 4) to i32*) monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, ptr getelementptr (i8, ptr @{{.+}}, i64 4) monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP1:%.+]], -// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP:%.+]], -// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]], +// CHECK: store i32 [[OLD_BF_VALUE]], ptr [[TEMP1:%.+]], +// CHECK: store i32 [[OLD_BF_VALUE]], ptr [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i32, ptr [[TEMP]], // CHECK: [[A_SHL:%.+]] = shl i32 [[A_LD]], 1 // CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_SHL]], 1 // CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80 // CHECK: [[SUB:%.+]] = fsub x86_fp80 [[X_RVAL]], [[EXPR]] // CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[SUB]] to i32 -// CHECK: [[NEW_VAL:%.+]] = load i32, i32* [[TEMP1]], +// CHECK: [[NEW_VAL:%.+]] = load i32, ptr [[TEMP1]], // CHECK: [[BF_VALUE:%.+]] = and i32 [[CONV]], 2147483647 // CHECK: [[BF_CLEAR:%.+]] = and i32 [[NEW_VAL]], -2147483648 // CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i32 %{{.+}}, i32* [[TEMP1]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[TEMP1]] -// CHECK: [[RES:%.+]] = cmpxchg i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.BitFields* @{{.+}} to i8*), i64 4) to i32*), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 +// CHECK: store i32 %{{.+}}, ptr [[TEMP1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, ptr [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr getelementptr (i8, ptr @{{.+}}, i64 4), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic bfx.a = bfx.a - ldv; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[BITCAST:%.+]] = bitcast i32* [[LDTEMP:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 4, i8* noundef getelementptr (i8, i8* bitcast (%struct.BitFields_packed* @{{.+}} to i8*), i64 4), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: call void @__atomic_load(i64 noundef 4, ptr noundef getelementptr (i8, ptr @{{.+}}, i64 4), ptr noundef [[LDTEMP:%.+]], i32 noundef 0) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[PREV_VALUE:%.+]] = load i32, i32* [[LDTEMP]] -// CHECK: store i32 [[PREV_VALUE]], i32* [[TEMP1:%.+]], -// CHECK: [[PREV_VALUE:%.+]] = load i32, i32* [[LDTEMP]] -// CHECK: store i32 [[PREV_VALUE]], i32* [[TEMP:%.+]], -// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]], +// CHECK: [[PREV_VALUE:%.+]] = load i32, ptr [[LDTEMP]] +// CHECK: store i32 [[PREV_VALUE]], ptr [[TEMP1:%.+]], +// CHECK: [[PREV_VALUE:%.+]] = load i32, ptr [[LDTEMP]] +// CHECK: store i32 [[PREV_VALUE]], ptr [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i32, ptr [[TEMP]], // CHECK: [[A_SHL:%.+]] = shl i32 [[A_LD]], 1 // CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_SHL]], 1 // CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80 // CHECK: [[MUL:%.+]] = fmul x86_fp80 [[X_RVAL]], [[EXPR]] // CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[MUL]] to i32 -// CHECK: [[NEW_VAL:%.+]] = load i32, i32* [[TEMP1]], +// CHECK: [[NEW_VAL:%.+]] = load i32, ptr [[TEMP1]], // CHECK: [[BF_VALUE:%.+]] = and i32 [[CONV]], 2147483647 // CHECK: [[BF_CLEAR:%.+]] = and i32 [[NEW_VAL]], -2147483648 // CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i32 %{{.+}}, i32* [[TEMP1]] -// CHECK: [[BITCAST_TEMP_OLD_BF_ADDR:%.+]] = bitcast i32* [[LDTEMP]] to i8* -// CHECK: [[BITCAST_TEMP_NEW_BF_ADDR:%.+]] = bitcast i32* [[TEMP1]] to i8* -// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 4, i8* noundef getelementptr (i8, i8* bitcast (%struct.BitFields_packed* @{{.+}} to i8*), i64 4), i8* noundef [[BITCAST_TEMP_OLD_BF_ADDR]], i8* noundef [[BITCAST_TEMP_NEW_BF_ADDR]], i32 noundef 0, i32 noundef 0) +// CHECK: store i32 %{{.+}}, ptr [[TEMP1]] +// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 4, ptr noundef getelementptr (i8, ptr @{{.+}}, i64 4), ptr noundef [[LDTEMP]], ptr noundef [[TEMP1]], i32 noundef 0, i32 noundef 0) // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic update bfx_packed.a *= ldv; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* getelementptr inbounds (%struct.BitFields2, %struct.BitFields2* @{{.+}}, i32 0, i32 0) monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, ptr @{{.+}} monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP1:%.+]], -// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP:%.+]], -// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]], +// CHECK: store i32 [[OLD_BF_VALUE]], ptr [[TEMP1:%.+]], +// CHECK: store i32 [[OLD_BF_VALUE]], ptr [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i32, ptr [[TEMP]], // CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_LD]], 31 // CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80 // CHECK: [[SUB:%.+]] = fsub x86_fp80 [[X_RVAL]], [[EXPR]] // CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[SUB]] to i32 -// CHECK: [[NEW_VAL:%.+]] = load i32, i32* [[TEMP1]], +// CHECK: [[NEW_VAL:%.+]] = load i32, ptr [[TEMP1]], // CHECK: [[BF_AND:%.+]] = and i32 [[CONV]], 1 // CHECK: [[BF_VALUE:%.+]] = shl i32 [[BF_AND]], 31 // CHECK: [[BF_CLEAR:%.+]] = and i32 [[NEW_VAL]], 2147483647 // CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i32 %{{.+}}, i32* [[TEMP1]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[TEMP1]] -// CHECK: [[RES:%.+]] = cmpxchg i32* getelementptr inbounds (%struct.BitFields2, %struct.BitFields2* @{{.+}}, i32 0, i32 0), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 +// CHECK: store i32 %{{.+}}, ptr [[TEMP1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, ptr [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr @{{.+}}, i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic bfx2.a -= ldv; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr (i8, i8* bitcast (%struct.BitFields2_packed* @{{.+}} to i8*), i64 3) monotonic, align 1 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, ptr getelementptr (i8, ptr @{{.+}}, i64 3) monotonic, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST1:%.+]] = bitcast i32* %{{.+}} to i8* -// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST1]], -// CHECK: [[BITCAST:%.+]] = bitcast i32* %{{.+}} to i8* -// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST]], -// CHECK: [[A_LD:%.+]] = load i8, i8* [[BITCAST]], +// CHECK: store i8 [[OLD_BF_VALUE]], ptr [[BITCAST1:%.+]], +// CHECK: store i8 [[OLD_BF_VALUE]], ptr [[BITCAST:%.+]], +// CHECK: [[A_LD:%.+]] = load i8, ptr [[BITCAST]], // CHECK: [[A_ASHR:%.+]] = ashr i8 [[A_LD]], 7 // CHECK: [[CAST:%.+]] = sext i8 [[A_ASHR]] to i32 // CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CAST]] to x86_fp80 // CHECK: [[DIV:%.+]] = fdiv x86_fp80 [[EXPR]], [[X_RVAL]] // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[DIV]] to i32 // CHECK: [[TRUNC:%.+]] = trunc i32 [[NEW_VAL]] to i8 -// CHECK: [[BF_LD:%.+]] = load i8, i8* [[BITCAST1]], +// CHECK: [[BF_LD:%.+]] = load i8, ptr [[BITCAST1]], // CHECK: [[BF_AND:%.+]] = and i8 [[TRUNC]], 1 // CHECK: [[BF_VALUE:%.+]] = shl i8 [[BF_AND]], 7 // CHECK: [[BF_CLEAR:%.+]] = and i8 %{{.+}}, 127 // CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i8 %{{.+}}, i8* [[BITCAST1]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[BITCAST1]] -// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr (i8, i8* bitcast (%struct.BitFields2_packed* @{{.+}} to i8*), i64 3), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 +// CHECK: store i8 %{{.+}}, ptr [[BITCAST1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, ptr [[BITCAST1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr getelementptr (i8, ptr @{{.+}}, i64 3), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic update bfx2_packed.a = ldv / bfx2_packed.a; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* getelementptr inbounds (%struct.BitFields3, %struct.BitFields3* @{{.+}}, i32 0, i32 0) monotonic, align 4 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, ptr @{{.+}} monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP1:%.+]], -// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP:%.+]], -// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]], +// CHECK: store i32 [[OLD_BF_VALUE]], ptr [[TEMP1:%.+]], +// CHECK: store i32 [[OLD_BF_VALUE]], ptr [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i32, ptr [[TEMP]], // CHECK: [[A_SHL:%.+]] = shl i32 [[A_LD]], 7 // CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_SHL]], 18 // CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80 // CHECK: [[DIV:%.+]] = fdiv x86_fp80 [[X_RVAL]], [[EXPR]] // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[DIV]] to i32 -// CHECK: [[BF_LD:%.+]] = load i32, i32* [[TEMP1]], +// CHECK: [[BF_LD:%.+]] = load i32, ptr [[TEMP1]], // CHECK: [[BF_AND:%.+]] = and i32 [[NEW_VAL]], 16383 // CHECK: [[BF_VALUE:%.+]] = shl i32 [[BF_AND]], 11 // CHECK: [[BF_CLEAR:%.+]] = and i32 %{{.+}}, -33552385 // CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i32 %{{.+}}, i32* [[TEMP1]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[TEMP1]] -// CHECK: [[RES:%.+]] = cmpxchg i32* getelementptr inbounds (%struct.BitFields3, %struct.BitFields3* @{{.+}}, i32 0, i32 0), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 +// CHECK: store i32 %{{.+}}, ptr [[TEMP1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, ptr [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr @{{.+}}, i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic bfx3.a /= ldv; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[LDTEMP:%.+]] = bitcast i32* %{{.+}} to i24* -// CHECK: [[BITCAST:%.+]] = bitcast i24* %{{.+}} to i8* -// CHECK: call void @__atomic_load(i64 noundef 3, i8* noundef getelementptr (i8, i8* bitcast (%struct.BitFields3_packed* @{{.+}} to i8*), i64 1), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: call void @__atomic_load(i64 noundef 3, ptr noundef getelementptr (i8, ptr @{{.+}}, i64 1), ptr noundef [[BITCAST:%.+]], i32 noundef 0) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[PREV_VALUE:%.+]] = load i24, i24* [[LDTEMP]] -// CHECK: store i24 [[PREV_VALUE]], i24* [[TEMP1:%.+]], -// CHECK: [[PREV_VALUE:%.+]] = load i24, i24* [[LDTEMP]] -// CHECK: store i24 [[PREV_VALUE]], i24* [[TEMP:%.+]], -// CHECK: [[A_LD:%.+]] = load i24, i24* [[TEMP]], +// CHECK: [[PREV_VALUE:%.+]] = load i24, ptr [[LDTEMP:%.+]], +// CHECK: store i24 [[PREV_VALUE]], ptr [[TEMP1:%.+]], +// CHECK: [[PREV_VALUE:%.+]] = load i24, ptr [[LDTEMP]] +// CHECK: store i24 [[PREV_VALUE]], ptr [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i24, ptr [[TEMP]], // CHECK: [[A_SHL:%.+]] = shl i24 [[A_LD]], 7 // CHECK: [[A_ASHR:%.+]] = ashr i24 [[A_SHL]], 10 // CHECK: [[CAST:%.+]] = sext i24 [[A_ASHR]] to i32 @@ -726,27 +696,25 @@ int main(void) { // CHECK: [[ADD:%.+]] = fadd x86_fp80 [[X_RVAL]], [[EXPR]] // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[ADD]] to i32 // CHECK: [[TRUNC:%.+]] = trunc i32 [[NEW_VAL]] to i24 -// CHECK: [[BF_LD:%.+]] = load i24, i24* [[TEMP1]], +// CHECK: [[BF_LD:%.+]] = load i24, ptr [[TEMP1]], // CHECK: [[BF_AND:%.+]] = and i24 [[TRUNC]], 16383 // CHECK: [[BF_VALUE:%.+]] = shl i24 [[BF_AND]], 3 // CHECK: [[BF_CLEAR:%.+]] = and i24 [[BF_LD]], -131065 // CHECK: or i24 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i24 %{{.+}}, i24* [[TEMP1]] -// CHECK: [[BITCAST_TEMP_OLD_BF_ADDR:%.+]] = bitcast i24* [[LDTEMP]] to i8* -// CHECK: [[BITCAST_TEMP_NEW_BF_ADDR:%.+]] = bitcast i24* [[TEMP1]] to i8* -// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 3, i8* noundef getelementptr (i8, i8* bitcast (%struct.BitFields3_packed* @{{.+}} to i8*), i64 1), i8* noundef [[BITCAST_TEMP_OLD_BF_ADDR]], i8* noundef [[BITCAST_TEMP_NEW_BF_ADDR]], i32 noundef 0, i32 noundef 0) +// CHECK: store i24 %{{.+}}, ptr [[TEMP1]] +// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 3, ptr noundef getelementptr (i8, ptr @{{.+}}, i64 1), ptr noundef [[LDTEMP]], ptr noundef [[TEMP1]], i32 noundef 0, i32 noundef 0) // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic update bfx3_packed.a += ldv; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, i64* bitcast (%struct.BitFields4* @{{.+}} to i64*) monotonic, align 8 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, ptr @{{.+}} monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i64 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: store i64 [[OLD_BF_VALUE]], i64* [[TEMP1:%.+]], -// CHECK: store i64 [[OLD_BF_VALUE]], i64* [[TEMP:%.+]], -// CHECK: [[A_LD:%.+]] = load i64, i64* [[TEMP]], +// CHECK: store i64 [[OLD_BF_VALUE]], ptr [[TEMP1:%.+]], +// CHECK: store i64 [[OLD_BF_VALUE]], ptr [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i64, ptr [[TEMP]], // CHECK: [[A_SHL:%.+]] = shl i64 [[A_LD]], 47 // CHECK: [[A_ASHR:%.+]] = ashr i64 [[A_SHL:%.+]], 63 // CHECK: [[A_CAST:%.+]] = trunc i64 [[A_ASHR:%.+]] to i32 @@ -754,30 +722,28 @@ int main(void) { // CHECK: [[MUL:%.+]] = fmul x86_fp80 [[X_RVAL]], [[EXPR]] // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[MUL]] to i32 // CHECK: [[ZEXT:%.+]] = zext i32 [[NEW_VAL]] to i64 -// CHECK: [[BF_LD:%.+]] = load i64, i64* [[TEMP1]], +// CHECK: [[BF_LD:%.+]] = load i64, ptr [[TEMP1]], // CHECK: [[BF_AND:%.+]] = and i64 [[ZEXT]], 1 // CHECK: [[BF_VALUE:%.+]] = shl i64 [[BF_AND]], 16 // CHECK: [[BF_CLEAR:%.+]] = and i64 [[BF_LD]], -65537 // CHECK: or i64 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i64 %{{.+}}, i64* [[TEMP1]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, i64* [[TEMP1]] -// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (%struct.BitFields4* @{{.+}} to i64*), i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] monotonic monotonic, align 8 +// CHECK: store i64 %{{.+}}, ptr [[TEMP1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, ptr [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr @{{.+}}, i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] monotonic monotonic, align 8 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic bfx4.a = bfx4.a * ldv; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2) monotonic, align 1 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, ptr getelementptr (i8, ptr @{{.+}}, i64 2) monotonic, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %{{.+}} ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST1:%.+]] = bitcast i32* %{{.+}} to i8* -// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST1]], -// CHECK: [[BITCAST:%.+]] = bitcast i32* %{{.+}} to i8* -// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST]], -// CHECK: [[A_LD:%.+]] = load i8, i8* [[BITCAST]], +// CHECK: store i8 [[OLD_BF_VALUE]], ptr [[BITCAST1:%.+]], +// CHECK: store i8 [[OLD_BF_VALUE]], ptr [[BITCAST:%.+]], +// CHECK: [[A_LD:%.+]] = load i8, ptr [[BITCAST]], // CHECK: [[A_SHL:%.+]] = shl i8 [[A_LD]], 7 // CHECK: [[A_ASHR:%.+]] = ashr i8 [[A_SHL:%.+]], 7 // CHECK: [[CAST:%.+]] = sext i8 [[A_ASHR:%.+]] to i32 @@ -785,101 +751,98 @@ int main(void) { // CHECK: [[SUB: %.+]] = fsub x86_fp80 [[CONV]], [[EXPR]] // CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[SUB:%.+]] to i32 // CHECK: [[NEW_VAL:%.+]] = trunc i32 [[CONV]] to i8 -// CHECK: [[BF_LD:%.+]] = load i8, i8* [[BITCAST1]], +// CHECK: [[BF_LD:%.+]] = load i8, ptr [[BITCAST1]], // CHECK: [[BF_VALUE:%.+]] = and i8 [[NEW_VAL]], 1 // CHECK: [[BF_CLEAR:%.+]] = and i8 [[BF_LD]], -2 // CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i8 %{{.+}}, i8* [[BITCAST1]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[BITCAST1]] -// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 +// CHECK: store i8 %{{.+}}, ptr [[BITCAST1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, ptr [[BITCAST1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr getelementptr (i8, ptr @{{.+}}, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic relaxed update bfx4_packed.a -= ldv; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, i64* bitcast (%struct.BitFields4* @{{.+}} to i64*) monotonic, align 8 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, ptr @{{.+}} monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i64 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: store i64 [[OLD_BF_VALUE]], i64* [[TEMP1:%.+]], -// CHECK: store i64 [[OLD_BF_VALUE]], i64* [[TEMP:%.+]], -// CHECK: [[A_LD:%.+]] = load i64, i64* [[TEMP]], +// CHECK: store i64 [[OLD_BF_VALUE]], ptr [[TEMP1:%.+]], +// CHECK: store i64 [[OLD_BF_VALUE]], ptr [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i64, ptr [[TEMP]], // CHECK: [[A_SHL:%.+]] = shl i64 [[A_LD]], 40 // CHECK: [[A_ASHR:%.+]] = ashr i64 [[A_SHL:%.+]], 57 // CHECK: [[CONV:%.+]] = sitofp i64 [[A_ASHR]] to x86_fp80 // CHECK: [[DIV:%.+]] = fdiv x86_fp80 [[CONV]], [[EXPR]] // CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[DIV]] to i64 -// CHECK: [[BF_LD:%.+]] = load i64, i64* [[TEMP1]], +// CHECK: [[BF_LD:%.+]] = load i64, ptr [[TEMP1]], // CHECK: [[BF_AND:%.+]] = and i64 [[CONV]], 127 // CHECK: [[BF_VALUE:%.+]] = shl i64 [[BF_AND:%.+]], 17 // CHECK: [[BF_CLEAR:%.+]] = and i64 [[BF_LD]], -16646145 // CHECK: [[VAL:%.+]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i64 [[VAL]], i64* [[TEMP1]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, i64* [[TEMP1]] -// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (%struct.BitFields4* @{{.+}} to i64*), i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] monotonic monotonic, align 8 +// CHECK: store i64 [[VAL]], ptr [[TEMP1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, ptr [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr @{{.+}}, i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] monotonic monotonic, align 8 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic bfx4.b /= ldv; -// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} -// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2) monotonic, align 1 +// CHECK: [[EXPR:%.+]] = load x86_fp80, ptr @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, ptr getelementptr (i8, ptr @{{.+}}, i64 2) monotonic, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST1:%.+]] = bitcast i64* %{{.+}} to i8* -// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST1]], -// CHECK: [[BITCAST:%.+]] = bitcast i64* %{{.+}} to i8* -// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST]], -// CHECK: [[A_LD:%.+]] = load i8, i8* [[BITCAST]], +// CHECK: store i8 [[OLD_BF_VALUE]], ptr [[BITCAST1:%.+]], +// CHECK: store i8 [[OLD_BF_VALUE]], ptr [[BITCAST:%.+]], +// CHECK: [[A_LD:%.+]] = load i8, ptr [[BITCAST]], // CHECK: [[A_ASHR:%.+]] = ashr i8 [[A_LD]], 1 // CHECK: [[CAST:%.+]] = sext i8 [[A_ASHR]] to i64 // CHECK: [[CONV:%.+]] = sitofp i64 [[CAST]] to x86_fp80 // CHECK: [[ADD:%.+]] = fadd x86_fp80 [[CONV]], [[EXPR]] // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[ADD]] to i64 // CHECK: [[TRUNC:%.+]] = trunc i64 [[NEW_VAL]] to i8 -// CHECK: [[BF_LD:%.+]] = load i8, i8* [[BITCAST1]], +// CHECK: [[BF_LD:%.+]] = load i8, ptr [[BITCAST1]], // CHECK: [[BF_AND:%.+]] = and i8 [[TRUNC]], 127 // CHECK: [[BF_VALUE:%.+]] = shl i8 [[BF_AND]], 1 // CHECK: [[BF_CLEAR:%.+]] = and i8 [[BF_LD]], 1 // CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i8 %{{.+}}, i8* [[BITCAST1]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[BITCAST1]] -// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 +// CHECK: store i8 %{{.+}}, ptr [[BITCAST1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, ptr [[BITCAST1]] +// CHECK: [[RES:%.+]] = cmpxchg ptr getelementptr (i8, ptr @{{.+}}, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic update relaxed bfx4_packed.b += ldv; -// CHECK: load i64, i64* +// CHECK: load i64, ptr // CHECK: [[EXPR:%.+]] = uitofp i64 %{{.+}} to float -// CHECK: [[I64VAL:%.+]] = load atomic i64, i64* bitcast (<2 x float>* [[DEST:@.+]] to i64*) monotonic, align 8 +// CHECK: [[I64VAL:%.+]] = load atomic i64, ptr [[DEST:@.+]] monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_I64:%.+]] = phi i64 [ [[I64VAL]], %{{.+}} ], [ [[FAILED_I64_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST:%.+]] = bitcast <2 x float>* [[TEMP:%.+]] to i64* -// CHECK: store i64 [[OLD_I64]], i64* [[BITCAST]], +// CHECK: store i64 [[OLD_I64]], ptr [[TEMP:%.+]], // CHECK: [[OLD_VEC_VAL:%.+]] = bitcast i64 [[OLD_I64]] to <2 x float> -// CHECK: store <2 x float> [[OLD_VEC_VAL]], <2 x float>* [[LDTEMP:%.+]], -// CHECK: [[VEC_VAL:%.+]] = load <2 x float>, <2 x float>* [[LDTEMP]] +// CHECK: store <2 x float> [[OLD_VEC_VAL]], ptr [[LDTEMP:%.+]], +// CHECK: [[VEC_VAL:%.+]] = load <2 x float>, ptr [[LDTEMP]] // CHECK: [[X:%.+]] = extractelement <2 x float> [[VEC_VAL]], i64 0 // CHECK: [[VEC_ITEM_VAL:%.+]] = fsub float [[EXPR]], [[X]] -// CHECK: [[VEC_VAL:%.+]] = load <2 x float>, <2 x float>* [[TEMP]], +// CHECK: [[VEC_VAL:%.+]] = load <2 x float>, ptr [[TEMP]], // CHECK: [[NEW_VEC_VAL:%.+]] = insertelement <2 x float> [[VEC_VAL]], float [[VEC_ITEM_VAL]], i64 0 -// CHECK: store <2 x float> [[NEW_VEC_VAL]], <2 x float>* [[TEMP]] -// CHECK: [[NEW_I64:%.+]] = load i64, i64* [[BITCAST]] -// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (<2 x float>* [[DEST]] to i64*), i64 [[OLD_I64]], i64 [[NEW_I64]] monotonic monotonic, align 8 +// CHECK: store <2 x float> [[NEW_VEC_VAL]], ptr [[TEMP]] +// CHECK: [[NEW_I64:%.+]] = load i64, ptr [[TEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr [[DEST]], i64 [[OLD_I64]], i64 [[NEW_I64]] monotonic monotonic, align 8 // CHECK: [[FAILED_I64_OLD_VAL:%.+]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic relaxed float2x.x = ulv - float2x.x; -// CHECK: [[EXPR:%.+]] = load double, double* @{{.+}}, +// CHECK: [[EXPR:%.+]] = load double, ptr @{{.+}}, // CHECK: [[OLD_VAL:%.+]] = call i32 @llvm.read_register.i32([[REG:metadata ![0-9]+]]) // CHECK: [[X_RVAL:%.+]] = sitofp i32 [[OLD_VAL]] to double // CHECK: [[DIV:%.+]] = fdiv double [[EXPR]], [[X_RVAL]] diff --git a/clang/test/OpenMP/atomic_write_codegen.c b/clang/test/OpenMP/atomic_write_codegen.c index 9e4da013950b5..24dfbf9c0e8fc 100644 --- a/clang/test/OpenMP/atomic_write_codegen.c +++ b/clang/test/OpenMP/atomic_write_codegen.c @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp-simd -x c -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp-simd -x c -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s // SIMD-ONLY0-NOT: {{__kmpc|__tgt}} // expected-no-diagnostics // REQUIRES: x86-registered-target @@ -83,256 +83,243 @@ float2 float2x; register int rix __asm__("esp"); int main(void) { -// CHECK: store atomic i32 1, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @civ, i32 0, i32 1) monotonic, align 4 +// CHECK: store atomic i32 1, ptr getelementptr inbounds ({ i32, i32 }, ptr @civ, i32 0, i32 1) monotonic, align 4 #pragma omp atomic write __imag(civ) = 1; -// CHECK: load i8, i8* +// CHECK: load i8, ptr // CHECK: store atomic i8 {{.*}} monotonic, align 1 #pragma omp atomic write bx = bv; -// CHECK: load i8, i8* +// CHECK: load i8, ptr // CHECK: store atomic i8 {{.*}} release, align 1 #pragma omp atomic write release cx = cv; -// CHECK: load i8, i8* +// CHECK: load i8, ptr // CHECK: store atomic i8 {{.*}} monotonic, align 1 #pragma omp atomic write ucx = ucv; -// CHECK: load i16, i16* +// CHECK: load i16, ptr // CHECK: store atomic i16 {{.*}} monotonic, align 2 #pragma omp atomic write sx = sv; -// CHECK: load i16, i16* +// CHECK: load i16, ptr // CHECK: store atomic i16 {{.*}} monotonic, align 2 #pragma omp atomic write usx = usv; -// CHECK: load i32, i32* +// CHECK: load i32, ptr // CHECK: store atomic i32 {{.*}} monotonic, align 4 #pragma omp atomic write ix = iv; -// CHECK: load i32, i32* +// CHECK: load i32, ptr // CHECK: store atomic i32 {{.*}} monotonic, align 4 #pragma omp atomic write uix = uiv; -// CHECK: load i64, i64* +// CHECK: load i64, ptr // CHECK: store atomic i64 {{.*}} monotonic, align 8 #pragma omp atomic write lx = lv; -// CHECK: load i64, i64* +// CHECK: load i64, ptr // CHECK: store atomic i64 {{.*}} monotonic, align 8 #pragma omp atomic write ulx = ulv; -// CHECK: load i64, i64* +// CHECK: load i64, ptr // CHECK: store atomic i64 {{.*}} monotonic, align 8 #pragma omp atomic write llx = llv; -// CHECK: load i64, i64* +// CHECK: load i64, ptr // CHECK: store atomic i64 {{.*}} monotonic, align 8 #pragma omp atomic write ullx = ullv; -// CHECK: load float, float* +// CHECK: load float, ptr // CHECK: bitcast float {{.*}} to i32 -// CHECK: store atomic i32 {{.*}}, i32* bitcast (float* {{.*}} monotonic, align 4 +// CHECK: store atomic i32 {{.*}}, ptr {{.*}} monotonic, align 4 #pragma omp atomic write fx = fv; -// CHECK: load double, double* +// CHECK: load double, ptr // CHECK: bitcast double {{.*}} to i64 -// CHECK: store atomic i64 {{.*}}, i64* bitcast (double* {{.*}} monotonic, align 8 +// CHECK: store atomic i64 {{.*}}, ptr {{.*}} monotonic, align 8 #pragma omp atomic write dx = dv; -// CHECK: [[LD:%.+]] = load x86_fp80, x86_fp80* -// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[LDTEMP:%.*]] to i8* -// CHECK: call void @llvm.memset.p0i8.i64(i8* align 16 [[BITCAST]], i8 0, i64 16, i1 false) -// CHECK: store x86_fp80 [[LD]], x86_fp80* [[LDTEMP]] -// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[LDTEMP:%.*]] to i128* -// CHECK: [[LD:%.+]] = load i128, i128* [[BITCAST]] -// CHECK: store atomic i128 [[LD]], i128* bitcast (x86_fp80* {{.*}} monotonic, align 16 +// CHECK: [[LD:%.+]] = load x86_fp80, ptr +// CHECK: call void @llvm.memset.p0.i64(ptr align 16 [[LDTEMP:%.*]], i8 0, i64 16, i1 false) +// CHECK: store x86_fp80 [[LD]], ptr [[LDTEMP]] +// CHECK: [[LD:%.+]] = load i128, ptr [[LDTEMP:%.*]] +// CHECK: store atomic i128 [[LD]], ptr {{.*}} monotonic, align 16 #pragma omp atomic write ldx = ldv; -// CHECK: [[REAL_VAL:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.*}}, i32 0, i32 0) -// CHECK: [[IMG_VAL:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.*}}, i32 0, i32 1) -// CHECK: [[TEMP_REAL_REF:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP:%.+]], i32 0, i32 0 -// CHECK: [[TEMP_IMG_REF:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1 -// CHECK: store i32 [[REAL_VAL]], i32* [[TEMP_REAL_REF]] -// CHECK: store i32 [[IMG_VAL]], i32* [[TEMP_IMG_REF]] -// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP]] to i8* -// CHECK: call void @__atomic_store(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* @{{.*}} to i8*), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[REAL_VAL:%.+]] = load i32, ptr @{{.*}} +// CHECK: [[IMG_VAL:%.+]] = load i32, ptr getelementptr inbounds ({ i32, i32 }, ptr @{{.*}}, i32 0, i32 1) +// CHECK: [[TEMP_REAL_REF:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[TEMP:%.+]], i32 0, i32 0 +// CHECK: [[TEMP_IMG_REF:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[TEMP]], i32 0, i32 1 +// CHECK: store i32 [[REAL_VAL]], ptr [[TEMP_REAL_REF]] +// CHECK: store i32 [[IMG_VAL]], ptr [[TEMP_IMG_REF]] +// CHECK: call void @__atomic_store(i64 noundef 8, ptr noundef @{{.*}}, ptr noundef [[TEMP]], i32 noundef 0) #pragma omp atomic write cix = civ; -// CHECK: [[REAL_VAL:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.*}}, i32 0, i32 0) -// CHECK: [[IMG_VAL:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.*}}, i32 0, i32 1) -// CHECK: [[TEMP_REAL_REF:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP:%.+]], i32 0, i32 0 -// CHECK: [[TEMP_IMG_REF:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP]], i32 0, i32 1 -// CHECK: store float [[REAL_VAL]], float* [[TEMP_REAL_REF]] -// CHECK: store float [[IMG_VAL]], float* [[TEMP_IMG_REF]] -// CHECK: [[BITCAST:%.+]] = bitcast { float, float }* [[TEMP]] to i8* -// CHECK: call void @__atomic_store(i64 noundef 8, i8* noundef bitcast ({ float, float }* @{{.*}} to i8*), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[REAL_VAL:%.+]] = load float, ptr @{{.*}} +// CHECK: [[IMG_VAL:%.+]] = load float, ptr getelementptr inbounds ({ float, float }, ptr @{{.*}}, i32 0, i32 1) +// CHECK: [[TEMP_REAL_REF:%.+]] = getelementptr inbounds { float, float }, ptr [[TEMP:%.+]], i32 0, i32 0 +// CHECK: [[TEMP_IMG_REF:%.+]] = getelementptr inbounds { float, float }, ptr [[TEMP]], i32 0, i32 1 +// CHECK: store float [[REAL_VAL]], ptr [[TEMP_REAL_REF]] +// CHECK: store float [[IMG_VAL]], ptr [[TEMP_IMG_REF]] +// CHECK: call void @__atomic_store(i64 noundef 8, ptr noundef @{{.*}}, ptr noundef [[TEMP]], i32 noundef 0) #pragma omp atomic write cfx = cfv; -// CHECK: [[REAL_VAL:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.*}}, i32 0, i32 0) -// CHECK: [[IMG_VAL:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.*}}, i32 0, i32 1) -// CHECK: [[TEMP_REAL_REF:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[TEMP:%.+]], i32 0, i32 0 -// CHECK: [[TEMP_IMG_REF:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[TEMP]], i32 0, i32 1 -// CHECK: store double [[REAL_VAL]], double* [[TEMP_REAL_REF]] -// CHECK: store double [[IMG_VAL]], double* [[TEMP_IMG_REF]] -// CHECK: [[BITCAST:%.+]] = bitcast { double, double }* [[TEMP]] to i8* -// CHECK: call void @__atomic_store(i64 noundef 16, i8* noundef bitcast ({ double, double }* @{{.*}} to i8*), i8* noundef [[BITCAST]], i32 noundef 5) +// CHECK: [[REAL_VAL:%.+]] = load double, ptr @{{.*}} +// CHECK: [[IMG_VAL:%.+]] = load double, ptr getelementptr inbounds ({ double, double }, ptr @{{.*}}, i32 0, i32 1) +// CHECK: [[TEMP_REAL_REF:%.+]] = getelementptr inbounds { double, double }, ptr [[TEMP:%.+]], i32 0, i32 0 +// CHECK: [[TEMP_IMG_REF:%.+]] = getelementptr inbounds { double, double }, ptr [[TEMP]], i32 0, i32 1 +// CHECK: store double [[REAL_VAL]], ptr [[TEMP_REAL_REF]] +// CHECK: store double [[IMG_VAL]], ptr [[TEMP_IMG_REF]] +// CHECK: call void @__atomic_store(i64 noundef 16, ptr noundef @{{.*}}, ptr noundef [[TEMP]], i32 noundef 5) // CHECK: call{{.*}} @__kmpc_flush( #pragma omp atomic seq_cst write cdx = cdv; -// CHECK: load i8, i8* +// CHECK: load i8, ptr // CHECK: store atomic i64 {{.*}} monotonic, align 8 #pragma omp atomic write ulx = bv; -// CHECK: load i8, i8* +// CHECK: load i8, ptr // CHECK: store atomic i8 {{.*}} monotonic, align 1 #pragma omp atomic write bx = cv; -// CHECK: load i8, i8* +// CHECK: load i8, ptr // CHECK: store atomic i8 {{.*}} seq_cst, align 1 // CHECK: call{{.*}} @__kmpc_flush( #pragma omp atomic write, seq_cst cx = ucv; -// CHECK: load i16, i16* +// CHECK: load i16, ptr // CHECK: store atomic i64 {{.*}} monotonic, align 8 #pragma omp atomic write ulx = sv; -// CHECK: load i16, i16* +// CHECK: load i16, ptr // CHECK: store atomic i64 {{.*}} monotonic, align 8 #pragma omp atomic write lx = usv; -// CHECK: load i32, i32* +// CHECK: load i32, ptr // CHECK: store atomic i32 {{.*}} seq_cst, align 4 // CHECK: call{{.*}} @__kmpc_flush( #pragma omp atomic seq_cst, write uix = iv; -// CHECK: load i32, i32* +// CHECK: load i32, ptr // CHECK: store atomic i32 {{.*}} monotonic, align 4 #pragma omp atomic write ix = uiv; -// CHECK: load i64, i64* +// CHECK: load i64, ptr // CHECK: [[VAL:%.+]] = trunc i64 %{{.*}} to i32 -// CHECK: [[TEMP_REAL_REF:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP:%.+]], i32 0, i32 0 -// CHECK: [[TEMP_IMG_REF:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1 -// CHECK: store i32 [[VAL]], i32* [[TEMP_REAL_REF]] -// CHECK: store i32 0, i32* [[TEMP_IMG_REF]] -// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP]] to i8* -// CHECK: call void @__atomic_store(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* @{{.+}} to i8*), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[TEMP_REAL_REF:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[TEMP:%.+]], i32 0, i32 0 +// CHECK: [[TEMP_IMG_REF:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[TEMP]], i32 0, i32 1 +// CHECK: store i32 [[VAL]], ptr [[TEMP_REAL_REF]] +// CHECK: store i32 0, ptr [[TEMP_IMG_REF]] +// CHECK: call void @__atomic_store(i64 noundef 8, ptr noundef @{{.+}}, ptr noundef [[TEMP]], i32 noundef 0) #pragma omp atomic write cix = lv; -// CHECK: load i64, i64* -// CHECK: store atomic i32 %{{.+}}, i32* bitcast (float* {{.*}} monotonic, align 4 +// CHECK: load i64, ptr +// CHECK: store atomic i32 %{{.+}}, ptr {{.*}} monotonic, align 4 #pragma omp atomic write fx = ulv; -// CHECK: load i64, i64* -// CHECK: store atomic i64 %{{.+}}, i64* bitcast (double* {{.*}} monotonic, align 8 +// CHECK: load i64, ptr +// CHECK: store atomic i64 %{{.+}}, ptr {{.*}} monotonic, align 8 #pragma omp atomic write dx = llv; -// CHECK: load i64, i64* +// CHECK: load i64, ptr // CHECK: [[VAL:%.+]] = uitofp i64 %{{.+}} to x86_fp80 -// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i8* -// CHECK: call void @llvm.memset.p0i8.i64(i8* align 16 [[BITCAST]], i8 0, i64 16, i1 false) -// CHECK: store x86_fp80 [[VAL]], x86_fp80* [[TEMP]] -// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP]] to i128* -// CHECK: [[VAL:%.+]] = load i128, i128* [[BITCAST]] -// CHECK: store atomic i128 [[VAL]], i128* bitcast (x86_fp80* {{.*}} monotonic, align 16 +// CHECK: call void @llvm.memset.p0.i64(ptr align 16 [[TEMP:%.+]], i8 0, i64 16, i1 false) +// CHECK: store x86_fp80 [[VAL]], ptr [[TEMP]] +// CHECK: [[VAL:%.+]] = load i128, ptr [[TEMP]] +// CHECK: store atomic i128 [[VAL]], ptr {{.*}} monotonic, align 16 #pragma omp atomic write ldx = ullv; -// CHECK: load float, float* +// CHECK: load float, ptr // CHECK: [[VAL:%.+]] = fptosi float %{{.*}} to i32 -// CHECK: [[TEMP_REAL_REF:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP:%.+]], i32 0, i32 0 -// CHECK: [[TEMP_IMG_REF:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1 -// CHECK: store i32 [[VAL]], i32* [[TEMP_REAL_REF]] -// CHECK: store i32 0, i32* [[TEMP_IMG_REF]] -// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP]] to i8* -// CHECK: call void @__atomic_store(i64 noundef 8, i8* noundef bitcast ({ i32, i32 }* @{{.+}} to i8*), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: [[TEMP_REAL_REF:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[TEMP:%.+]], i32 0, i32 0 +// CHECK: [[TEMP_IMG_REF:%.+]] = getelementptr inbounds { i32, i32 }, ptr [[TEMP]], i32 0, i32 1 +// CHECK: store i32 [[VAL]], ptr [[TEMP_REAL_REF]] +// CHECK: store i32 0, ptr [[TEMP_IMG_REF]] +// CHECK: call void @__atomic_store(i64 noundef 8, ptr noundef @{{.+}}, ptr noundef [[TEMP]], i32 noundef 0) #pragma omp atomic write cix = fv; -// CHECK: load double, double* +// CHECK: load double, ptr // CHECK: store atomic i16 {{.*}} monotonic, align 2 #pragma omp atomic write sx = dv; -// CHECK: load x86_fp80, x86_fp80* +// CHECK: load x86_fp80, ptr // CHECK: store atomic i8 {{.*}} monotonic, align 1 #pragma omp atomic write bx = ldv; -// CHECK: load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 0) -// CHECK: load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 1) +// CHECK: load i32, ptr @{{.+}} +// CHECK: load i32, ptr getelementptr inbounds ({ i32, i32 }, ptr @{{.+}}, i32 0, i32 1) // CHECK: icmp ne i32 %{{.+}}, 0 // CHECK: icmp ne i32 %{{.+}}, 0 // CHECK: or i1 // CHECK: store atomic i8 {{.*}} monotonic, align 1 #pragma omp atomic write bx = civ; -// CHECK: load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.*}}, i32 0, i32 0) +// CHECK: load float, ptr @{{.*}} // CHECK: store atomic i16 {{.*}} monotonic, align 2 #pragma omp atomic write usx = cfv; -// CHECK: load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 0) +// CHECK: load double, ptr @{{.+}} // CHECK: store atomic i64 {{.*}} monotonic, align 8 #pragma omp atomic write llx = cdv; -// CHECK-DAG: [[IDX:%.+]] = load i16, i16* @{{.+}} -// CHECK-DAG: load i8, i8* +// CHECK-DAG: [[IDX:%.+]] = load i16, ptr @{{.+}} +// CHECK-DAG: load i8, ptr // CHECK-DAG: [[VEC_ITEM_VAL:%.+]] = zext i1 %{{.+}} to i32 -// CHECK: [[I128VAL:%.+]] = load atomic i128, i128* bitcast (<4 x i32>* [[DEST:@.+]] to i128*) monotonic, align 16 +// CHECK: [[I128VAL:%.+]] = load atomic i128, ptr [[DEST:@.+]] monotonic, align 16 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_I128:%.+]] = phi i128 [ [[I128VAL]], %{{.+}} ], [ [[FAILED_I128_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST:%.+]] = bitcast <4 x i32>* [[LDTEMP:%.+]] to i128* -// CHECK: store i128 [[OLD_I128]], i128* [[BITCAST]], -// CHECK: [[VEC_VAL:%.+]] = load <4 x i32>, <4 x i32>* [[LDTEMP]] +// CHECK: store i128 [[OLD_I128]], ptr [[LDTEMP:%.+]], +// CHECK: [[VEC_VAL:%.+]] = load <4 x i32>, ptr [[LDTEMP]] // CHECK: [[NEW_VEC_VAL:%.+]] = insertelement <4 x i32> [[VEC_VAL]], i32 [[VEC_ITEM_VAL]], i16 [[IDX]] -// CHECK: store <4 x i32> [[NEW_VEC_VAL]], <4 x i32>* [[LDTEMP]] -// CHECK: [[NEW_I128:%.+]] = load i128, i128* [[BITCAST]] -// CHECK: [[RES:%.+]] = cmpxchg i128* bitcast (<4 x i32>* [[DEST]] to i128*), i128 [[OLD_I128]], i128 [[NEW_I128]] monotonic monotonic, align 16 +// CHECK: store <4 x i32> [[NEW_VEC_VAL]], ptr [[LDTEMP]] +// CHECK: [[NEW_I128:%.+]] = load i128, ptr [[LDTEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr [[DEST]], i128 [[OLD_I128]], i128 [[NEW_I128]] monotonic monotonic, align 16 // CHECK: [[FAILED_I128_OLD_VAL:%.+]] = extractvalue { i128, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i128, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic write int4x[sv] = bv; -// CHECK: load x86_fp80, x86_fp80* @{{.+}} +// CHECK: load x86_fp80, ptr @{{.+}} // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 %{{.+}} to i32 -// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.BitFields* @{{.+}} to i8*), i64 4) to i32*) monotonic, align 4 +// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, ptr getelementptr (i8, ptr @{{.+}}, i64 4) monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] // CHECK: [[BF_VALUE:%.+]] = and i32 [[NEW_VAL]], 2147483647 // CHECK: [[BF_CLEAR:%.+]] = and i32 %{{.+}}, -2147483648 // CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i32 %{{.+}}, i32* [[LDTEMP:%.+]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[LDTEMP]] -// CHECK: [[RES:%.+]] = cmpxchg i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.BitFields* @{{.+}} to i8*), i64 4) to i32*), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 +// CHECK: store i32 %{{.+}}, ptr [[LDTEMP:%.+]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, ptr [[LDTEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr getelementptr (i8, ptr @{{.+}}, i64 4), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic write bfx.a = ldv; -// CHECK: load x86_fp80, x86_fp80* @{{.+}} +// CHECK: load x86_fp80, ptr @{{.+}} // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 %{{.+}} to i32 -// CHECK: [[BITCAST:%.+]] = bitcast i32* [[LDTEMP:%.+]] to i8* -// CHECK: call void @__atomic_load(i64 noundef 4, i8* noundef getelementptr (i8, i8* bitcast (%struct.BitFields_packed* @{{.+}} to i8*), i64 4), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: call void @__atomic_load(i64 noundef 4, ptr noundef getelementptr (i8, ptr @{{.+}}, i64 4), ptr noundef [[LDTEMP:%.+]], i32 noundef 0) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[OLD_BF_VALUE:%.+]] = load i32, i32* [[LDTEMP]], -// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[LDTEMP1:%.+]], -// CHECK: [[OLD_BF_VALUE:%.+]] = load i32, i32* [[LDTEMP1]], +// CHECK: [[OLD_BF_VALUE:%.+]] = load i32, ptr [[LDTEMP]], +// CHECK: store i32 [[OLD_BF_VALUE]], ptr [[LDTEMP1:%.+]], +// CHECK: [[OLD_BF_VALUE:%.+]] = load i32, ptr [[LDTEMP1]], // CHECK: [[BF_VALUE:%.+]] = and i32 [[NEW_VAL]], 2147483647 // CHECK: [[BF_CLEAR:%.+]] = and i32 [[OLD_BF_VALUE]], -2147483648 // CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i32 %{{.+}}, i32* [[LDTEMP1]] -// CHECK: [[BITCAST_TEMP_OLD_BF_ADDR:%.+]] = bitcast i32* [[LDTEMP]] to i8* -// CHECK: [[BITCAST_TEMP_NEW_BF_ADDR:%.+]] = bitcast i32* [[LDTEMP1]] to i8* -// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 4, i8* noundef getelementptr (i8, i8* bitcast (%struct.BitFields_packed* @{{.+}} to i8*), i64 4), i8* noundef [[BITCAST_TEMP_OLD_BF_ADDR]], i8* noundef [[BITCAST_TEMP_NEW_BF_ADDR]], i32 noundef 0, i32 noundef 0) +// CHECK: store i32 %{{.+}}, ptr [[LDTEMP1]] +// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 4, ptr noundef getelementptr (i8, ptr @{{.+}}, i64 4), ptr noundef [[LDTEMP]], ptr noundef [[LDTEMP1]], i32 noundef 0, i32 noundef 0) // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic write bfx_packed.a = ldv; -// CHECK: load x86_fp80, x86_fp80* @{{.+}} +// CHECK: load x86_fp80, ptr @{{.+}} // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 %{{.+}} to i32 -// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* getelementptr inbounds (%struct.BitFields2, %struct.BitFields2* @{{.+}}, i32 0, i32 0) monotonic, align 4 +// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, ptr @{{.+}} monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] @@ -340,18 +327,18 @@ int main(void) { // CHECK: [[BF_VALUE:%.+]] = shl i32 [[BF_AND]], 31 // CHECK: [[BF_CLEAR:%.+]] = and i32 %{{.+}}, 2147483647 // CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i32 %{{.+}}, i32* [[LDTEMP:%.+]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[LDTEMP]] -// CHECK: [[RES:%.+]] = cmpxchg i32* getelementptr inbounds (%struct.BitFields2, %struct.BitFields2* @{{.+}}, i32 0, i32 0), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 +// CHECK: store i32 %{{.+}}, ptr [[LDTEMP:%.+]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, ptr [[LDTEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr @{{.+}}, i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic write bfx2.a = ldv; -// CHECK: load x86_fp80, x86_fp80* @{{.+}} +// CHECK: load x86_fp80, ptr @{{.+}} // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 %{{.+}} to i32 -// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr (i8, i8* bitcast (%struct.BitFields2_packed* @{{.+}} to i8*), i64 3) monotonic, align 1 +// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, ptr getelementptr (i8, ptr @{{.+}}, i64 3) monotonic, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] @@ -360,18 +347,18 @@ int main(void) { // CHECK: [[BF_VALUE:%.+]] = shl i8 [[BF_AND]], 7 // CHECK: [[BF_CLEAR:%.+]] = and i8 %{{.+}}, 127 // CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i8 %{{.+}}, i8* [[LDTEMP:%.+]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[LDTEMP]] -// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr (i8, i8* bitcast (%struct.BitFields2_packed* @{{.+}} to i8*), i64 3), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 +// CHECK: store i8 %{{.+}}, ptr [[LDTEMP:%.+]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, ptr [[LDTEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr getelementptr (i8, ptr @{{.+}}, i64 3), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic write bfx2_packed.a = ldv; -// CHECK: load x86_fp80, x86_fp80* @{{.+}} +// CHECK: load x86_fp80, ptr @{{.+}} // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 %{{.+}} to i32 -// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* getelementptr inbounds (%struct.BitFields3, %struct.BitFields3* @{{.+}}, i32 0, i32 0) monotonic, align 4 +// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, ptr @{{.+}} monotonic, align 4 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] @@ -379,40 +366,36 @@ int main(void) { // CHECK: [[BF_VALUE:%.+]] = shl i32 [[BF_AND]], 11 // CHECK: [[BF_CLEAR:%.+]] = and i32 %{{.+}}, -33552385 // CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i32 %{{.+}}, i32* [[LDTEMP:%.+]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[LDTEMP]] -// CHECK: [[RES:%.+]] = cmpxchg i32* getelementptr inbounds (%struct.BitFields3, %struct.BitFields3* @{{.+}}, i32 0, i32 0), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 +// CHECK: store i32 %{{.+}}, ptr [[LDTEMP:%.+]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, ptr [[LDTEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr @{{.+}}, i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic write bfx3.a = ldv; -// CHECK: load x86_fp80, x86_fp80* @{{.+}} +// CHECK: load x86_fp80, ptr @{{.+}} // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 %{{.+}} to i32 -// CHECK: [[LDTEMP:%.+]] = bitcast i32* %{{.+}} to i24* -// CHECK: [[BITCAST:%.+]] = bitcast i24* %{{.+}} to i8* -// CHECK: call void @__atomic_load(i64 noundef 3, i8* noundef getelementptr (i8, i8* bitcast (%struct.BitFields3_packed* @{{.+}} to i8*), i64 1), i8* noundef [[BITCAST]], i32 noundef 0) +// CHECK: call void @__atomic_load(i64 noundef 3, ptr noundef getelementptr (i8, ptr @{{.+}}, i64 1), ptr noundef [[BITCAST:%.+]], i32 noundef 0) // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] -// CHECK: [[OLD_VAL:%.+]] = load i24, i24* %{{.+}}, -// CHECK: store i24 [[OLD_VAL]], i24* [[TEMP:%.+]], +// CHECK: [[OLD_VAL:%.+]] = load i24, ptr %{{.+}}, +// CHECK: store i24 [[OLD_VAL]], ptr [[TEMP:%.+]], // CHECK: [[TRUNC:%.+]] = trunc i32 [[NEW_VAL]] to i24 // CHECK: [[BF_AND:%.+]] = and i24 [[TRUNC]], 16383 // CHECK: [[BF_VALUE:%.+]] = shl i24 [[BF_AND]], 3 // CHECK: [[BF_CLEAR:%.+]] = and i24 %{{.+}}, -131065 // CHECK: or i24 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i24 %{{.+}}, i24* [[TEMP]] -// CHECK: [[BITCAST_TEMP_OLD_BF_ADDR:%.+]] = bitcast i24* [[LDTEMP]] to i8* -// CHECK: [[BITCAST_TEMP_NEW_BF_ADDR:%.+]] = bitcast i24* [[TEMP]] to i8* -// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 3, i8* noundef getelementptr (i8, i8* bitcast (%struct.BitFields3_packed* @{{.+}} to i8*), i64 1), i8* noundef [[BITCAST_TEMP_OLD_BF_ADDR]], i8* noundef [[BITCAST_TEMP_NEW_BF_ADDR]], i32 noundef 0, i32 noundef 0) +// CHECK: store i24 %{{.+}}, ptr [[TEMP]] +// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 3, ptr noundef getelementptr (i8, ptr @{{.+}}, i64 1), ptr noundef [[LDTEMP:%.+]], ptr noundef [[TEMP]], i32 noundef 0, i32 noundef 0) // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic write bfx3_packed.a = ldv; -// CHECK: load x86_fp80, x86_fp80* @{{.+}} +// CHECK: load x86_fp80, ptr @{{.+}} // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 %{{.+}} to i32 -// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, i64* bitcast (%struct.BitFields4* @{{.+}} to i64*) monotonic, align 8 +// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, ptr @{{.+}} monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i64 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] @@ -421,18 +404,18 @@ int main(void) { // CHECK: [[BF_VALUE:%.+]] = shl i64 [[BF_AND]], 16 // CHECK: [[BF_CLEAR:%.+]] = and i64 %{{.+}}, -65537 // CHECK: or i64 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i64 %{{.+}}, i64* [[LDTEMP:%.+]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, i64* [[LDTEMP]] -// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (%struct.BitFields4* @{{.+}} to i64*), i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] monotonic monotonic, align 8 +// CHECK: store i64 %{{.+}}, ptr [[LDTEMP:%.+]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, ptr [[LDTEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr @{{.+}}, i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] monotonic monotonic, align 8 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic write bfx4.a = ldv; -// CHECK: load x86_fp80, x86_fp80* @{{.+}} +// CHECK: load x86_fp80, ptr @{{.+}} // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 %{{.+}} to i32 -// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2) monotonic, align 1 +// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, ptr getelementptr (i8, ptr @{{.+}}, i64 2) monotonic, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] @@ -440,18 +423,18 @@ int main(void) { // CHECK: [[BF_VALUE:%.+]] = and i8 [[TRUNC]], 1 // CHECK: [[BF_CLEAR:%.+]] = and i8 %{{.+}}, -2 // CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i8 %{{.+}}, i8* [[LDTEMP:%.+]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[LDTEMP]] -// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 +// CHECK: store i8 %{{.+}}, ptr [[LDTEMP:%.+]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, ptr [[LDTEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr getelementptr (i8, ptr @{{.+}}, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic write bfx4_packed.a = ldv; -// CHECK: load x86_fp80, x86_fp80* @{{.+}} +// CHECK: load x86_fp80, ptr @{{.+}} // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 %{{.+}} to i64 -// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, i64* bitcast (%struct.BitFields4* @{{.+}} to i64*) monotonic, align 8 +// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, ptr @{{.+}} monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i64 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] @@ -459,18 +442,18 @@ int main(void) { // CHECK: [[BF_VALUE:%.+]] = shl i64 [[BF_AND]], 17 // CHECK: [[BF_CLEAR:%.+]] = and i64 %{{.+}}, -16646145 // CHECK: or i64 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i64 %{{.+}}, i64* [[LDTEMP:%.+]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, i64* [[LDTEMP]] -// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (%struct.BitFields4* @{{.+}} to i64*), i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] monotonic monotonic, align 8 +// CHECK: store i64 %{{.+}}, ptr [[LDTEMP:%.+]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, ptr [[LDTEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr @{{.+}}, i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] monotonic monotonic, align 8 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic write bfx4.b = ldv; -// CHECK: load x86_fp80, x86_fp80* @{{.+}} +// CHECK: load x86_fp80, ptr @{{.+}} // CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 %{{.+}} to i64 -// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2) monotonic, align 1 +// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, ptr getelementptr (i8, ptr @{{.+}}, i64 2) monotonic, align 1 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] @@ -479,28 +462,27 @@ int main(void) { // CHECK: [[BF_VALUE:%.+]] = shl i8 [[BF_AND]], 1 // CHECK: [[BF_CLEAR:%.+]] = and i8 %{{.+}}, 1 // CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]] -// CHECK: store i8 %{{.+}}, i8* [[LDTEMP:%.+]] -// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[LDTEMP]] -// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 +// CHECK: store i8 %{{.+}}, ptr [[LDTEMP:%.+]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, ptr [[LDTEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr getelementptr (i8, ptr @{{.+}}, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 // CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] // CHECK: [[EXIT]] #pragma omp atomic relaxed write bfx4_packed.b = ldv; -// CHECK: load i64, i64* +// CHECK: load i64, ptr // CHECK: [[VEC_ITEM_VAL:%.+]] = uitofp i64 %{{.+}} to float -// CHECK: [[I64VAL:%.+]] = load atomic i64, i64* bitcast (<2 x float>* [[DEST:@.+]] to i64*) monotonic, align 8 +// CHECK: [[I64VAL:%.+]] = load atomic i64, ptr [[DEST:@.+]] monotonic, align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[OLD_I64:%.+]] = phi i64 [ [[I64VAL]], %{{.+}} ], [ [[FAILED_I64_OLD_VAL:%.+]], %[[CONT]] ] -// CHECK: [[BITCAST:%.+]] = bitcast <2 x float>* [[LDTEMP:%.+]] to i64* -// CHECK: store i64 [[OLD_I64]], i64* [[BITCAST]], -// CHECK: [[VEC_VAL:%.+]] = load <2 x float>, <2 x float>* [[LDTEMP]] +// CHECK: store i64 [[OLD_I64]], ptr [[LDTEMP:%.+]], +// CHECK: [[VEC_VAL:%.+]] = load <2 x float>, ptr [[LDTEMP]] // CHECK: [[NEW_VEC_VAL:%.+]] = insertelement <2 x float> [[VEC_VAL]], float [[VEC_ITEM_VAL]], i64 0 -// CHECK: store <2 x float> [[NEW_VEC_VAL]], <2 x float>* [[LDTEMP]] -// CHECK: [[NEW_I64:%.+]] = load i64, i64* [[BITCAST]] -// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (<2 x float>* [[DEST]] to i64*), i64 [[OLD_I64]], i64 [[NEW_I64]] monotonic monotonic, align 8 +// CHECK: store <2 x float> [[NEW_VEC_VAL]], ptr [[LDTEMP]] +// CHECK: [[NEW_I64:%.+]] = load i64, ptr [[LDTEMP]] +// CHECK: [[RES:%.+]] = cmpxchg ptr [[DEST]], i64 [[OLD_I64]], i64 [[NEW_I64]] monotonic monotonic, align 8 // CHECK: [[FAILED_I64_OLD_VAL:%.+]] = extractvalue { i64, i1 } [[RES]], 0 // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1 // CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] @@ -510,7 +492,7 @@ int main(void) { // CHECK: call i32 @llvm.read_register.i32( // CHECK: sitofp i32 %{{.+}} to double // CHECK: bitcast double %{{.+}} to i64 -// CHECK: store atomic i64 %{{.+}}, i64* bitcast (double* @{{.+}} to i64*) seq_cst, align 8 +// CHECK: store atomic i64 %{{.+}}, ptr @{{.+}} seq_cst, align 8 // CHECK: call{{.*}} @__kmpc_flush( #pragma omp atomic write seq_cst dv = rix; diff --git a/clang/test/OpenMP/depobj_codegen.cpp b/clang/test/OpenMP/depobj_codegen.cpp index 18e832f14adb5..be758f68b2756 100644 --- a/clang/test/OpenMP/depobj_codegen.cpp +++ b/clang/test/OpenMP/depobj_codegen.cpp @@ -1,18 +1,18 @@ -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -fopenmp -emit-llvm -o - %s | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -triple x86_64-apple-darwin10 -x c++ -std=c++11 -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -triple x86_64-apple-darwin10 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -fopenmp-simd -emit-llvm -o - %s | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -triple x86_64-apple-darwin10 -x c++ -std=c++11 -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp-simd -emit-llvm -o - %s | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -fopenmp-simd -triple x86_64-apple-darwin10 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s // SIMD-ONLY0-NOT: {{__kmpc|__tgt}} // expected-no-diagnostics #ifndef HEADER #define HEADER -// CHECK-DAG: [[MAIN_A:@.+]] = internal global i8* null, -// CHECK-DAG: [[TMAIN_A:@.+]] = linkonce_odr global i8* null, +// CHECK-DAG: [[MAIN_A:@.+]] = internal global ptr null, +// CHECK-DAG: [[TMAIN_A:@.+]] = linkonce_odr global ptr null, typedef void *omp_depend_t; @@ -40,62 +40,57 @@ int main(int argc, char **argv) { } // CHECK-LABEL: @main -// CHECK: [[B_ADDR:%.+]] = alloca i8*, +// CHECK: [[B_ADDR:%b]] = alloca ptr, // CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num( -// CHECK: [[DEP_ADDR_VOID:%.+]] = call i8* @__kmpc_alloc(i32 [[GTID]], i64 72, i8* null) -// CHECK: [[DEP_ADDR:%.+]] = bitcast i8* [[DEP_ADDR_VOID]] to %struct.kmp_depend_info* -// CHECK: [[SZ_BASE:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[DEP_ADDR]], i{{.+}} 0, i{{.+}} 0 -// CHECK: store i64 2, i64* [[SZ_BASE]], align 8 -// CHECK: [[BASE_ADDR:%.+]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[DEP_ADDR]], i{{.+}} 1 -// CHECK: [[ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 0 -// CHECK: store i64 %{{.+}}, i64* [[ADDR]], align 8 -// CHECK: [[SZ_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 1 -// CHECK: store i64 4, i64* [[SZ_ADDR]], align 8 -// CHECK: [[FLAGS_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 2 -// CHECK: store i8 3, i8* [[FLAGS_ADDR]], align 8 -// CHECK: [[BASE_ADDR:%.+]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[DEP_ADDR]], i{{.+}} 2 -// CHECK: [[ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 0 -// CHECK: store i64 %{{.+}}, i64* [[ADDR]], align 8 -// CHECK: [[SZ_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 1 -// CHECK: store i64 8, i64* [[SZ_ADDR]], align 8 -// CHECK: [[FLAGS_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 2 -// CHECK: store i8 3, i8* [[FLAGS_ADDR]], align 8 -// CHECK: [[BASE_ADDR:%.+]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[DEP_ADDR]], i{{.+}} 1 -// CHECK: [[DEP:%.+]] = bitcast %struct.kmp_depend_info* [[BASE_ADDR]] to i8* -// CHECK: store i8* [[DEP]], i8** [[MAIN_A]], align 8 -// CHECK: [[B:%.+]] = load i8*, i8** [[B_ADDR]], align 8 -// CHECK: [[B_BASE:%.+]] = bitcast i8* [[B]] to %struct.kmp_depend_info* -// CHECK: [[B_REF:%.+]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[B_BASE]], i{{.+}} -1 -// CHECK: [[B:%.+]] = bitcast %struct.kmp_depend_info* [[B_REF]] to i8* -// CHECK: call void @__kmpc_free(i32 [[GTID]], i8* [[B]], i8* null) -// CHECK: [[B_ADDR_CAST:%.+]] = bitcast i8** [[B_ADDR]] to %struct.kmp_depend_info** -// CHECK: [[B_BASE:%.+]] = load %struct.kmp_depend_info*, %struct.kmp_depend_info** [[B_ADDR_CAST]], align 8 -// CHECK: [[NUMDEPS_BASE:%.+]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[B_BASE]], i64 -1 -// CHECK: [[NUMDEPS_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[NUMDEPS_BASE]], i{{.+}} 0, i{{.+}} 0 -// CHECK: [[NUMDEPS:%.+]] = load i64, i64* [[NUMDEPS_ADDR]], align 8 -// CHECK: [[END:%.+]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[B_BASE]], i64 [[NUMDEPS]] +// CHECK: [[DEP_ADDR_VOID:%.+]] = call ptr @__kmpc_alloc(i32 [[GTID]], i64 72, ptr null) +// CHECK: [[SZ_BASE:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[DEP_ADDR_VOID]], i{{.+}} 0, i{{.+}} 0 +// CHECK: store i64 2, ptr [[SZ_BASE]], align 8 +// CHECK: [[BASE_ADDR:%.+]] = getelementptr %struct.kmp_depend_info, ptr [[DEP_ADDR_VOID]], i{{.+}} 1 +// CHECK: [[ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 0 +// CHECK: store i64 %{{.+}}, ptr [[ADDR]], align 8 +// CHECK: [[SZ_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 1 +// CHECK: store i64 4, ptr [[SZ_ADDR]], align 8 +// CHECK: [[FLAGS_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 2 +// CHECK: store i8 3, ptr [[FLAGS_ADDR]], align 8 +// CHECK: [[BASE_ADDR:%.+]] = getelementptr %struct.kmp_depend_info, ptr [[DEP_ADDR_VOID]], i{{.+}} 2 +// CHECK: [[ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 0 +// CHECK: store i64 %{{.+}}, ptr [[ADDR]], align 8 +// CHECK: [[SZ_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 1 +// CHECK: store i64 8, ptr [[SZ_ADDR]], align 8 +// CHECK: [[FLAGS_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 2 +// CHECK: store i8 3, ptr [[FLAGS_ADDR]], align 8 +// CHECK: [[BASE_ADDR:%.+]] = getelementptr %struct.kmp_depend_info, ptr [[DEP_ADDR_VOID]], i{{.+}} 1 +// CHECK: store ptr [[BASE_ADDR]], ptr [[MAIN_A]], align 8 +// CHECK: [[B:%.+]] = load ptr, ptr [[B_ADDR]], align 8 +// CHECK: [[B_REF:%.+]] = getelementptr %struct.kmp_depend_info, ptr [[B]], i{{.+}} -1 +// CHECK: call void @__kmpc_free(i32 [[GTID]], ptr [[B_REF]], ptr null) +// CHECK: [[B_BASE:%.+]] = load ptr, ptr [[B_ADDR]], align 8 +// CHECK: [[NUMDEPS_BASE:%.+]] = getelementptr %struct.kmp_depend_info, ptr [[B_BASE]], i64 -1 +// CHECK: [[NUMDEPS_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[NUMDEPS_BASE]], i{{.+}} 0, i{{.+}} 0 +// CHECK: [[NUMDEPS:%.+]] = load i64, ptr [[NUMDEPS_ADDR]], align 8 +// CHECK: [[END:%.+]] = getelementptr %struct.kmp_depend_info, ptr [[B_BASE]], i64 [[NUMDEPS]] // CHECK: br label %[[BODY:.+]] // CHECK: [[BODY]]: -// CHECK: [[EL:%.+]] = phi %struct.kmp_depend_info* [ [[B_BASE]], %{{.+}} ], [ [[EL_NEXT:%.+]], %[[BODY]] ] -// CHECK: [[FLAG_BASE:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[EL]], i{{.+}} 0, i{{.+}} 2 -// CHECK: store i8 4, i8* [[FLAG_BASE]], align 8 -// CHECK: [[EL_NEXT]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[EL]], i{{.+}} 1 -// CHECK: [[IS_DONE:%.+]] = icmp eq %struct.kmp_depend_info* [[EL_NEXT]], [[END]] +// CHECK: [[EL:%.+]] = phi ptr [ [[B_BASE]], %{{.+}} ], [ [[EL_NEXT:%.+]], %[[BODY]] ] +// CHECK: [[FLAG_BASE:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[EL]], i{{.+}} 0, i{{.+}} 2 +// CHECK: store i8 4, ptr [[FLAG_BASE]], align 8 +// CHECK: [[EL_NEXT]] = getelementptr %struct.kmp_depend_info, ptr [[EL]], i{{.+}} 1 +// CHECK: [[IS_DONE:%.+]] = icmp eq ptr [[EL_NEXT]], [[END]] // CHECK: br i1 [[IS_DONE]], label %[[DONE:.+]], label %[[BODY]] // CHECK: [[DONE]]: // Claculate toal number of elements. // (argv[argc]-argv[0]-(-1)-1) / -(-1); -// CHECK: [[ARGV:%.+]] = load i8**, i8*** [[ARGV_ADDR:%.+]], align 8 -// CHECK: [[ARGC:%.+]] = load i32, i32* [[ARGC_ADDR:%.+]], align 4 +// CHECK: [[ARGV:%.+]] = load ptr, ptr [[ARGV_ADDR:%.+]], align 8 +// CHECK: [[ARGC:%.+]] = load i32, ptr [[ARGC_ADDR:%.+]], align 4 // CHECK: [[IDX:%.+]] = sext i32 [[ARGC]] to i64 -// CHECK: [[BEGIN_ADDR:%.+]] = getelementptr inbounds i8*, i8** [[ARGV]], i64 [[IDX]] -// CHECK: [[BEGIN:%.+]] = load i8*, i8** [[BEGIN_ADDR]], align 8 -// CHECK: [[ARGV:%.+]] = load i8**, i8*** [[ARGV_ADDR]], align 8 -// CHECK: [[END_ADDR:%.+]] = getelementptr inbounds i8*, i8** [[ARGV]], i64 0 -// CHECK: [[END:%.+]] = load i8*, i8** [[END_ADDR]], align 8 -// CHECK: [[BEGIN_INT:%.+]] = ptrtoint i8* [[BEGIN]] to i64 -// CHECK: [[END_INT:%.+]] = ptrtoint i8* [[END]] to i64 +// CHECK: [[BEGIN_ADDR:%.+]] = getelementptr inbounds ptr, ptr [[ARGV]], i64 [[IDX]] +// CHECK: [[BEGIN:%.+]] = load ptr, ptr [[BEGIN_ADDR]], align 8 +// CHECK: [[ARGV:%.+]] = load ptr, ptr [[ARGV_ADDR]], align 8 +// CHECK: [[END_ADDR:%.+]] = getelementptr inbounds ptr, ptr [[ARGV]], i64 0 +// CHECK: [[END:%.+]] = load ptr, ptr [[END_ADDR]], align 8 +// CHECK: [[BEGIN_INT:%.+]] = ptrtoint ptr [[BEGIN]] to i64 +// CHECK: [[END_INT:%.+]] = ptrtoint ptr [[END]] to i64 // CHECK: [[BE_SUB:%.+]] = sub i64 [[BEGIN_INT]], [[END_INT]] // CHECK: [[BE_SUB_ST_SUB:%.+]] = add nsw i64 [[BE_SUB]], 1 // CHECK: [[BE_SUB_ST_SUB_1_SUB:%.+]] = sub nsw i64 [[BE_SUB_ST_SUB]], 1 @@ -109,136 +104,129 @@ int main(int argc, char **argv) { // Allocate memory // kmp_depend_info* dep = (kmp_depend_info*)kmpc_alloc(SIZE); -// CHECK: [[DEP_ADDR_VOID:%.+]] = call i8* @__kmpc_alloc(i32 %{{.+}}, i64 [[SIZE]], i8* null) -// CHECK: [[DEP_ADDR:%.+]] = bitcast i8* [[DEP_ADDR_VOID]] to %struct.kmp_depend_info* +// CHECK: [[DEP_ADDR_VOID:%.+]] = call ptr @__kmpc_alloc(i32 %{{.+}}, i64 [[SIZE]], ptr null) // dep[0].base_addr = NELEMS. -// CHECK: [[BASE_ADDR_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[DEP_ADDR]], i{{.+}} 0, i{{.+}} 0 -// CHECK: store i64 [[NELEMS]], i64* [[BASE_ADDR_ADDR]], align 8 +// CHECK: [[BASE_ADDR_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[DEP_ADDR_VOID]], i{{.+}} 0, i{{.+}} 0 +// CHECK: store i64 [[NELEMS]], ptr [[BASE_ADDR_ADDR]], align 8 // iterator_counter = 1; -// CHECK: store i64 1, i64* [[ITERATOR_COUNTER_ADDR:%.+]], align 8 +// CHECK: store i64 1, ptr [[ITERATOR_COUNTER_ADDR:%.+]], align 8 // NITER = (argv[argc]-argv[0]-(-1)-1) / -(-1); -// CHECK: [[ARGV:%.+]] = load i8**, i8*** [[ARGV_ADDR]], align 8 -// CHECK: [[ARGC:%.+]] = load i32, i32* [[ARGC_ADDR]], align 4 +// CHECK: [[ARGV:%.+]] = load ptr, ptr [[ARGV_ADDR]], align 8 +// CHECK: [[ARGC:%.+]] = load i32, ptr [[ARGC_ADDR]], align 4 // CHECK: [[IDX:%.+]] = sext i32 [[ARGC]] to i64 -// CHECK: [[BEGIN_ADDR:%.+]] = getelementptr inbounds i8*, i8** [[ARGV]], i64 [[IDX]] -// CHECK: [[BEGIN:%.+]] = load i8*, i8** [[BEGIN_ADDR]], align 8 -// CHECK: [[ARGV:%.+]] = load i8**, i8*** [[ARGV_ADDR]], align 8 -// CHECK: [[END_ADDR:%.+]] = getelementptr inbounds i8*, i8** [[ARGV]], i64 0 -// CHECK: [[END:%.+]] = load i8*, i8** [[END_ADDR]], align 8 -// CHECK: [[BEGIN_INT:%.+]] = ptrtoint i8* [[BEGIN]] to i64 -// CHECK: [[END_INT:%.+]] = ptrtoint i8* [[END]] to i64 +// CHECK: [[BEGIN_ADDR:%.+]] = getelementptr inbounds ptr, ptr [[ARGV]], i64 [[IDX]] +// CHECK: [[BEGIN:%.+]] = load ptr, ptr [[BEGIN_ADDR]], align 8 +// CHECK: [[ARGV:%.+]] = load ptr, ptr [[ARGV_ADDR]], align 8 +// CHECK: [[END_ADDR:%.+]] = getelementptr inbounds ptr, ptr [[ARGV]], i64 0 +// CHECK: [[END:%.+]] = load ptr, ptr [[END_ADDR]], align 8 +// CHECK: [[BEGIN_INT:%.+]] = ptrtoint ptr [[BEGIN]] to i64 +// CHECK: [[END_INT:%.+]] = ptrtoint ptr [[END]] to i64 // CHECK: [[BE_SUB:%.+]] = sub i64 [[BEGIN_INT]], [[END_INT]] // CHECK: [[BE_SUB_ST_SUB:%.+]] = add nsw i64 [[BE_SUB]], 1 // CHECK: [[BE_SUB_ST_SUB_1_SUB:%.+]] = sub nsw i64 [[BE_SUB_ST_SUB]], 1 // CHECK: [[NITER:%.+]] = sdiv i64 [[BE_SUB_ST_SUB_1_SUB]], 1 // Loop. -// CHECK: store i64 0, i64* [[COUNTER_ADDR:%.+]], align 8 +// CHECK: store i64 0, ptr [[COUNTER_ADDR:%.+]], align 8 // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]]: -// CHECK: [[COUNTER:%.+]] = load i64, i64* [[COUNTER_ADDR]], align 8 +// CHECK: [[COUNTER:%.+]] = load i64, ptr [[COUNTER_ADDR]], align 8 // CHECK: [[CMP:%.+]] = icmp slt i64 [[COUNTER]], [[NITER]] // CHECK: br i1 [[CMP]], label %[[BODY:.+]], label %[[EXIT:.+]] // CHECK: [[BODY]]: // p = BEGIN + COUNTER * STEP; -// CHECK: [[ARGV:%.+]] = load i8**, i8*** [[ARGV_ADDR]], align 8 -// CHECK: [[ARGC:%.+]] = load i32, i32* [[ARGC_ADDR]], align 4 +// CHECK: [[ARGV:%.+]] = load ptr, ptr [[ARGV_ADDR]], align 8 +// CHECK: [[ARGC:%.+]] = load i32, ptr [[ARGC_ADDR]], align 4 // CHECK: [[IDX:%.+]] = sext i32 [[ARGC]] to i64 -// CHECK: [[BEGIN_ADDR:%.+]] = getelementptr inbounds i8*, i8** [[ARGV]], i64 [[IDX]] -// CHECK: [[BEGIN:%.+]] = load i8*, i8** [[BEGIN_ADDR]], align 8 -// CHECK: [[COUNTER:%.+]] = load i64, i64* [[COUNTER_ADDR]], align 8 +// CHECK: [[BEGIN_ADDR:%.+]] = getelementptr inbounds ptr, ptr [[ARGV]], i64 [[IDX]] +// CHECK: [[BEGIN:%.+]] = load ptr, ptr [[BEGIN_ADDR]], align 8 +// CHECK: [[COUNTER:%.+]] = load i64, ptr [[COUNTER_ADDR]], align 8 // CHECK: [[CS_MUL:%.+]] = mul nsw i64 [[COUNTER]], -1 -// CHECK: [[CS_MUL_BEGIN_ADD:%.+]] = getelementptr inbounds i8, i8* [[BEGIN]], i64 [[CS_MUL]] -// CHECK: store i8* [[CS_MUL_BEGIN_ADD]], i8** [[P_ADDR:%.+]], align 8 +// CHECK: [[CS_MUL_BEGIN_ADD:%.+]] = getelementptr inbounds i8, ptr [[BEGIN]], i64 [[CS_MUL]] +// CHECK: store ptr [[CS_MUL_BEGIN_ADD]], ptr [[P_ADDR:%.+]], align 8 // &p[0] -// CHECK: [[P:%.+]] = load i8*, i8** [[P_ADDR]], align 8 -// CHECK: [[P0:%.+]] = getelementptr inbounds i8, i8* [[P]], i64 0 -// CHECK: [[P0_ADDR:%.+]] = ptrtoint i8* [[P0]] to i64 +// CHECK: [[P:%.+]] = load ptr, ptr [[P_ADDR]], align 8 +// CHECK: [[P0:%.+]] = getelementptr inbounds i8, ptr [[P]], i64 0 +// CHECK: [[P0_ADDR:%.+]] = ptrtoint ptr [[P0]] to i64 // dep[ITERATOR_COUNTER].base_addr = &p[0]; -// CHECK: [[ITERATOR_COUNTER:%.+]] = load i64, i64* [[ITERATOR_COUNTER_ADDR]], align 8 -// CHECK: [[DEP_IC:%.+]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[DEP_ADDR]], i64 [[ITERATOR_COUNTER]] -// CHECK: [[DEP_IC_BASE_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[DEP_IC]], i{{.+}} 0, i{{.+}} 0 -// CHECK: store i64 [[P0_ADDR]], i64* [[DEP_IC_BASE_ADDR]], align 8 +// CHECK: [[ITERATOR_COUNTER:%.+]] = load i64, ptr [[ITERATOR_COUNTER_ADDR]], align 8 +// CHECK: [[DEP_IC:%.+]] = getelementptr %struct.kmp_depend_info, ptr [[DEP_ADDR_VOID]], i64 [[ITERATOR_COUNTER]] +// CHECK: [[DEP_IC_BASE_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[DEP_IC]], i{{.+}} 0, i{{.+}} 0 +// CHECK: store i64 [[P0_ADDR]], ptr [[DEP_IC_BASE_ADDR]], align 8 // dep[ITERATOR_COUNTER].size = sizeof(p[0]); -// CHECK: [[DEP_IC_SIZE:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[DEP_IC]], i{{.+}} 0, i{{.+}} 1 -// CHECK: store i64 1, i64* [[DEP_IC_SIZE]], align 8 +// CHECK: [[DEP_IC_SIZE:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[DEP_IC]], i{{.+}} 0, i{{.+}} 1 +// CHECK: store i64 1, ptr [[DEP_IC_SIZE]], align 8 // dep[ITERATOR_COUNTER].flags = in_out; -// CHECK: [[DEP_IC_FLAGS:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[DEP_IC]], i{{.+}} 0, i{{.+}} 2 -// CHECK: store i8 3, i8* [[DEP_IC_FLAGS]], align 8 +// CHECK: [[DEP_IC_FLAGS:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[DEP_IC]], i{{.+}} 0, i{{.+}} 2 +// CHECK: store i8 3, ptr [[DEP_IC_FLAGS]], align 8 // ITERATOR_COUNTER = ITERATOR_COUNTER + 1; -// CHECK: [[ITERATOR_COUNTER:%.+]] = load i64, i64* [[ITERATOR_COUNTER_ADDR]], align 8 +// CHECK: [[ITERATOR_COUNTER:%.+]] = load i64, ptr [[ITERATOR_COUNTER_ADDR]], align 8 // CHECK: [[INC:%.+]] = add nuw i64 [[ITERATOR_COUNTER]], 1 -// CHECK: store i64 [[INC]], i64* [[ITERATOR_COUNTER_ADDR]], align 8 +// CHECK: store i64 [[INC]], ptr [[ITERATOR_COUNTER_ADDR]], align 8 // COUNTER = COUNTER + 1; -// CHECK: [[COUNTER:%.+]] = load i64, i64* [[COUNTER_ADDR]], align 8 +// CHECK: [[COUNTER:%.+]] = load i64, ptr [[COUNTER_ADDR]], align 8 // CHECK: [[INC:%.+]] = add nsw i64 [[COUNTER]], 1 -// CHECK: store i64 [[INC]], i64* [[COUNTER_ADDR]], align 8 +// CHECK: store i64 [[INC]], ptr [[COUNTER_ADDR]], align 8 // CHECK: br label %[[CONT]] // CHECK: [[EXIT]]: // a = &dep[1]; -// CHECK: [[DEP_BEGIN:%.+]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[DEP_ADDR]], i64 1 -// CHECK: [[DEP:%.+]] = bitcast %struct.kmp_depend_info* [[DEP_BEGIN]] to i8* -// CHECK: store i8* [[DEP]], i8** [[MAIN_A]], align 8 +// CHECK: [[DEP_BEGIN:%.+]] = getelementptr %struct.kmp_depend_info, ptr [[DEP_ADDR_VOID]], i64 1 +// CHECK: store ptr [[DEP_BEGIN]], ptr [[MAIN_A]], align 8 // CHECK-LABEL: tmain -// CHECK: [[ARGC_ADDR:%.+]] = alloca i8*, +// CHECK: [[ARGC_ADDR:%.+]] = alloca ptr, // CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num( -// CHECK: [[DEP_ADDR_VOID:%.+]] = call i8* @__kmpc_alloc(i32 [[GTID]], i64 72, i8* null) -// CHECK: [[DEP_ADDR:%.+]] = bitcast i8* [[DEP_ADDR_VOID]] to %struct.kmp_depend_info* -// CHECK: [[SZ_BASE:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[DEP_ADDR]], i{{.+}} 0, i{{.+}} 0 -// CHECK: store i64 2, i64* [[SZ_BASE]], align 8 -// CHECK: [[BASE_ADDR:%.+]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[DEP_ADDR]], i{{.+}} 1 -// CHECK: [[ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 0 -// CHECK: store i64 %{{.+}}, i64* [[ADDR]], align 8 -// CHECK: [[SZ_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 1 -// CHECK: store i64 8, i64* [[SZ_ADDR]], align 8 -// CHECK: [[FLAGS_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 2 -// CHECK: store i8 1, i8* [[FLAGS_ADDR]], align 8 -// CHECK: [[SHAPE_ADDR:%.+]] = load i32*, i32** [[ARGV_ADDR:%.+]], align 8 +// CHECK: [[DEP_ADDR_VOID:%.+]] = call ptr @__kmpc_alloc(i32 [[GTID]], i64 72, ptr null) +// CHECK: [[SZ_BASE:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[DEP_ADDR_VOID]], i{{.+}} 0, i{{.+}} 0 +// CHECK: store i64 2, ptr [[SZ_BASE]], align 8 +// CHECK: [[BASE_ADDR:%.+]] = getelementptr %struct.kmp_depend_info, ptr [[DEP_ADDR_VOID]], i{{.+}} 1 +// CHECK: [[ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 0 +// CHECK: store i64 %{{.+}}, ptr [[ADDR]], align 8 +// CHECK: [[SZ_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 1 +// CHECK: store i64 8, ptr [[SZ_ADDR]], align 8 +// CHECK: [[FLAGS_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 2 +// CHECK: store i8 1, ptr [[FLAGS_ADDR]], align 8 +// CHECK: [[SHAPE_ADDR:%.+]] = load ptr, ptr [[ARGV_ADDR:%.+]], align 8 // CHECK: [[SZ1:%.+]] = mul nuw i64 12, %{{.+}} // CHECK: [[SZ:%.+]] = mul nuw i64 [[SZ1]], 4 -// CHECK: [[SHAPE:%.+]] = ptrtoint i32* [[SHAPE_ADDR]] to i64 -// CHECK: [[BASE_ADDR:%.+]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[DEP_ADDR]], i{{.+}} 2 -// CHECK: [[ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 0 -// CHECK: store i64 [[SHAPE]], i64* [[ADDR]], align 8 -// CHECK: [[SZ_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 1 -// CHECK: store i64 [[SZ]], i64* [[SZ_ADDR]], align 8 -// CHECK: [[FLAGS_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 2 -// CHECK: store i8 1, i8* [[FLAGS_ADDR]], align 8 -// CHECK: [[BASE_ADDR:%.+]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[DEP_ADDR]], i{{.+}} 1 -// CHECK: [[DEP:%.+]] = bitcast %struct.kmp_depend_info* [[BASE_ADDR]] to i8* -// CHECK: store i8* [[DEP]], i8** [[TMAIN_A]], align 8 -// CHECK: [[ARGC:%.+]] = load i8*, i8** [[ARGC_ADDR]], align 8 -// CHECK: [[ARGC_BASE:%.+]] = bitcast i8* [[ARGC]] to %struct.kmp_depend_info* -// CHECK: [[ARGC_REF:%.+]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[ARGC_BASE]], i{{.+}} -1 -// CHECK: [[ARGC:%.+]] = bitcast %struct.kmp_depend_info* [[ARGC_REF]] to i8* -// CHECK: call void @__kmpc_free(i32 [[GTID]], i8* [[ARGC]], i8* null) -// CHECK: [[ARGC_ADDR_CAST:%.+]] = bitcast i8** [[ARGC_ADDR]] to %struct.kmp_depend_info** -// CHECK: [[ARGC_BASE:%.+]] = load %struct.kmp_depend_info*, %struct.kmp_depend_info** [[ARGC_ADDR_CAST]], align 8 -// CHECK: [[NUMDEPS_BASE:%.+]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[ARGC_BASE]], i64 -1 -// CHECK: [[NUMDEPS_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[NUMDEPS_BASE]], i{{.+}} 0, i{{.+}} 0 -// CHECK: [[NUMDEPS:%.+]] = load i64, i64* [[NUMDEPS_ADDR]], align 8 -// CHECK: [[END:%.+]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[ARGC_BASE]], i64 [[NUMDEPS]] +// CHECK: [[SHAPE:%.+]] = ptrtoint ptr [[SHAPE_ADDR]] to i64 +// CHECK: [[BASE_ADDR:%.+]] = getelementptr %struct.kmp_depend_info, ptr [[DEP_ADDR_VOID]], i{{.+}} 2 +// CHECK: [[ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 0 +// CHECK: store i64 [[SHAPE]], ptr [[ADDR]], align 8 +// CHECK: [[SZ_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 1 +// CHECK: store i64 [[SZ]], ptr [[SZ_ADDR]], align 8 +// CHECK: [[FLAGS_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[BASE_ADDR]], i{{.+}} 0, i{{.+}} 2 +// CHECK: store i8 1, ptr [[FLAGS_ADDR]], align 8 +// CHECK: [[BASE_ADDR:%.+]] = getelementptr %struct.kmp_depend_info, ptr [[DEP_ADDR_VOID]], i{{.+}} 1 +// CHECK: store ptr [[BASE_ADDR]], ptr [[TMAIN_A]], align 8 +// CHECK: [[ARGC:%.+]] = load ptr, ptr [[ARGC_ADDR]], align 8 +// CHECK: [[ARGC_REF:%.+]] = getelementptr %struct.kmp_depend_info, ptr [[ARGC]], i{{.+}} -1 +// CHECK: call void @__kmpc_free(i32 [[GTID]], ptr [[ARGC_REF]], ptr null) +// CHECK: [[ARGC_BASE:%.+]] = load ptr, ptr [[ARGC_ADDR]], align 8 +// CHECK: [[NUMDEPS_BASE:%.+]] = getelementptr %struct.kmp_depend_info, ptr [[ARGC_BASE]], i64 -1 +// CHECK: [[NUMDEPS_ADDR:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[NUMDEPS_BASE]], i{{.+}} 0, i{{.+}} 0 +// CHECK: [[NUMDEPS:%.+]] = load i64, ptr [[NUMDEPS_ADDR]], align 8 +// CHECK: [[END:%.+]] = getelementptr %struct.kmp_depend_info, ptr [[ARGC_BASE]], i64 [[NUMDEPS]] // CHECK: br label %[[BODY:.+]] // CHECK: [[BODY]]: -// CHECK: [[EL:%.+]] = phi %struct.kmp_depend_info* [ [[ARGC_BASE]], %{{.+}} ], [ [[EL_NEXT:%.+]], %[[BODY]] ] -// CHECK: [[FLAG_BASE:%.+]] = getelementptr inbounds %struct.kmp_depend_info, %struct.kmp_depend_info* [[EL]], i{{.+}} 0, i{{.+}} 2 -// CHECK: store i8 3, i8* [[FLAG_BASE]], align 8 -// CHECK: [[EL_NEXT]] = getelementptr %struct.kmp_depend_info, %struct.kmp_depend_info* [[EL]], i{{.+}} 1 -// CHECK: [[IS_DONE:%.+]] = icmp eq %struct.kmp_depend_info* [[EL_NEXT]], [[END]] +// CHECK: [[EL:%.+]] = phi ptr [ [[ARGC_BASE]], %{{.+}} ], [ [[EL_NEXT:%.+]], %[[BODY]] ] +// CHECK: [[FLAG_BASE:%.+]] = getelementptr inbounds %struct.kmp_depend_info, ptr [[EL]], i{{.+}} 0, i{{.+}} 2 +// CHECK: store i8 3, ptr [[FLAG_BASE]], align 8 +// CHECK: [[EL_NEXT]] = getelementptr %struct.kmp_depend_info, ptr [[EL]], i{{.+}} 1 +// CHECK: [[IS_DONE:%.+]] = icmp eq ptr [[EL_NEXT]], [[END]] // CHECK: br i1 [[IS_DONE]], label %[[DONE:.+]], label %[[BODY]] // CHECK: [[DONE]]: diff --git a/clang/test/OpenMP/distribute_parallel_for_reduction_codegen.cpp b/clang/test/OpenMP/distribute_parallel_for_reduction_codegen.cpp index 15aff901fcfa5..55d9e6550c400 100644 --- a/clang/test/OpenMP/distribute_parallel_for_reduction_codegen.cpp +++ b/clang/test/OpenMP/distribute_parallel_for_reduction_codegen.cpp @@ -1,35 +1,35 @@ // Test host code gen -// RUN: %clang_cc1 -no-opaque-pointers -verify -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64 -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64 -// RUN: %clang_cc1 -no-opaque-pointers -verify -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32 -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32 - -// RUN: %clang_cc1 -no-opaque-pointers -verify -fopenmp-simd -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY1 %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY1 %s -// RUN: %clang_cc1 -no-opaque-pointers -verify -fopenmp-simd -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY1 %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY1 %s +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64 +// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64 +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32 +// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32 + +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY1 %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY1 %s +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY1 %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY1 %s // SIMD-ONLY1-NOT: {{__kmpc|__tgt}} // Test host code gen -// RUN: %clang_cc1 -no-opaque-pointers -verify -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64 -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64 -// RUN: %clang_cc1 -no-opaque-pointers -verify -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32 -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32 - -// RUN: %clang_cc1 -no-opaque-pointers -verify -fopenmp-simd -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY1 %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY1 %s -// RUN: %clang_cc1 -no-opaque-pointers -verify -fopenmp-simd -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY1 %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY1 %s +// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64 +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64 +// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32 +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32 + +// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY1 %s +// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY1 %s +// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY1 %s +// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY1 %s // SIMD-ONLY1-NOT: {{__kmpc|__tgt}} // expected-no-diagnostics @@ -63,17 +63,17 @@ int main() { } // CHECK-LABEL: main -// CHECK: call{{.+}} @__tgt_target_kernel(%struct.ident_t* @{{.+}}, +// CHECK: call{{.+}} @__tgt_target_kernel(ptr @{{.+}}, // CHECK: call void [[OFFL:@.+]]( -// CHECK: call{{.+}} [[TMAIN:@.+]](i{{32|64}} +// CHECK: call{{.+}} [[TMAIN:@.+]](ptr // CHECK: ret // CHECK: define{{.+}} [[OFFL]]( -// CHECK: call{{.+}} @__kmpc_fork_teams({{.+}}, {{.+}}, {{.+}} [[TEOUTL:@.+]] to{{.+}} +// CHECK: call{{.+}} @__kmpc_fork_teams({{.+}}, {{.+}}, {{.+}} [[TEOUTL:@[^,]+]] // CHECK: ret void // CHECK: define{{.+}} [[TEOUTL]]( -// CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}} [[PAROUTL:@.+]] to{{.+}} +// CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}} [[PAROUTL:@[^,]+]] // CHECK: ret void // CHECK: define{{.+}} [[PAROUTL]]( @@ -81,17 +81,17 @@ int main() { // CHECK: call{{.+}} @__kmpc_end_reduce_nowait( // CHECK: ret void -// CHECK: define{{.+}} [[TMAIN]](i{{32|64}} -// CHECK: call{{.+}} @__tgt_target_kernel(%struct.ident_t* @{{.+}}, +// CHECK: define{{.+}} [[TMAIN]](ptr +// CHECK: call{{.+}} @__tgt_target_kernel(ptr @{{.+}}, // CHECK: call void [[TOFFL:@.+]]( // CHECK: ret // CHECK: define{{.+}} [[TOFFL]]( -// CHECK: call{{.+}} @__kmpc_fork_teams({{.+}}, {{.+}}, {{.+}} [[TEMPLTEOUTL:@.+]] to{{.+}} +// CHECK: call{{.+}} @__kmpc_fork_teams({{.+}}, {{.+}}, {{.+}} [[TEMPLTEOUTL:@[^,]+]] // CHECK: ret void // CHECK: define{{.+}} [[TEMPLTEOUTL]]( -// CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}} [[TPAROUTL:@.+]] to{{.+}} +// CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}} [[TPAROUTL:@[^,]+]] // CHECK: ret void // CHECK: define{{.+}} [[TPAROUTL]]( diff --git a/clang/test/OpenMP/distribute_parallel_for_reduction_task_codegen.cpp b/clang/test/OpenMP/distribute_parallel_for_reduction_task_codegen.cpp index de9b18bbb5fba..ce7171c35020e 100644 --- a/clang/test/OpenMP/distribute_parallel_for_reduction_task_codegen.cpp +++ b/clang/test/OpenMP/distribute_parallel_for_reduction_task_codegen.cpp @@ -448,7 +448,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP3:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP2]], i64 [[TMP4]] // CHECK1-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP5]] @@ -470,7 +470,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: [[TMP2:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP2:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 8 // CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 diff --git a/clang/test/OpenMP/for_reduction_task_codegen.cpp b/clang/test/OpenMP/for_reduction_task_codegen.cpp index 48587ce9a34b6..6a024fb7d3785 100644 --- a/clang/test/OpenMP/for_reduction_task_codegen.cpp +++ b/clang/test/OpenMP/for_reduction_task_codegen.cpp @@ -19,22 +19,6 @@ int main(int argc, char **argv) { } } - - -// Init firstprivate copy of argc - -// Init firstprivate copy of argv[0:10][0:argc] - -// Register task reduction. - - - - - - - - - #endif // CHECK1-LABEL: define {{[^@]+}}@main // CHECK1-SAME: (i32 noundef [[ARGC:%.*]], ptr noundef [[ARGV:%.*]]) #[[ATTR0:[0-9]+]] { @@ -361,7 +345,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP3:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP2]], i64 [[TMP4]] // CHECK1-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP5]] @@ -383,7 +367,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: [[TMP2:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP2:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 8 // CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 diff --git a/clang/test/OpenMP/for_simd_codegen.cpp b/clang/test/OpenMP/for_simd_codegen.cpp index c3ca5258542ae..1ac95e8943640 100644 --- a/clang/test/OpenMP/for_simd_codegen.cpp +++ b/clang/test/OpenMP/for_simd_codegen.cpp @@ -1,20 +1,20 @@ -// RUN: %clang_cc1 -no-opaque-pointers -verify -fopenmp -fopenmp-version=45 -x c++ -triple x86_64-unknown-unknown -emit-llvm -fexceptions -fcxx-exceptions -o - < %s | FileCheck %s --check-prefix=CHECK --check-prefix=OMP45 -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t < %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -fopenmp-version=45 -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify -emit-llvm -o - < %s | FileCheck %s --check-prefix=CHECK --check-prefix=OMP45 -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -fopenmp -fopenmp-version=45 -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm -o - < %s | FileCheck %s --check-prefix=TERM_DEBUG -// RUN: %clang_cc1 -no-opaque-pointers -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm -fexceptions -fcxx-exceptions -o - < %s -DOMP5 | FileCheck %s --check-prefix=CHECK --check-prefix=OMP50 -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t < %s -DOMP5 -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify -emit-llvm -o - -DOMP5 < %s | FileCheck %s --check-prefix=CHECK --check-prefix=OMP50 -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm -o - < %s -DOMP5 | FileCheck %s --check-prefix=TERM_DEBUG - -// RUN: %clang_cc1 -no-opaque-pointers -verify -fopenmp-simd -fopenmp-version=45 -x c++ -triple x86_64-unknown-unknown -emit-llvm -fexceptions -fcxx-exceptions -o - < %s | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -fopenmp-version=45 -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t < %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -fopenmp-version=45 -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify -emit-llvm -o - < %s | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -fopenmp-simd -fopenmp-version=45 -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm -o - < %s | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -no-opaque-pointers -verify -fopenmp-simd -x c++ -triple x86_64-unknown-unknown -emit-llvm -fexceptions -fcxx-exceptions -o - < %s -DOMP5 | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t < %s -DOMP5 -// RUN: %clang_cc1 -no-opaque-pointers -fopenmp-simd -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify -DOMP5 -emit-llvm -o - < %s | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-apple-darwin10 -fopenmp-simd -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm -o - < %s -DOMP5 | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple x86_64-unknown-unknown -emit-llvm -fexceptions -fcxx-exceptions -o - < %s | FileCheck %s --check-prefix=CHECK --check-prefix=OMP45 +// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t < %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify -emit-llvm -o - < %s | FileCheck %s --check-prefix=CHECK --check-prefix=OMP45 +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fopenmp-version=45 -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm -o - < %s | FileCheck %s --check-prefix=TERM_DEBUG +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm -fexceptions -fcxx-exceptions -o - < %s -DOMP5 | FileCheck %s --check-prefix=CHECK --check-prefix=OMP50 +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t < %s -DOMP5 +// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify -emit-llvm -o - -DOMP5 < %s | FileCheck %s --check-prefix=CHECK --check-prefix=OMP50 +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm -o - < %s -DOMP5 | FileCheck %s --check-prefix=TERM_DEBUG + +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=45 -x c++ -triple x86_64-unknown-unknown -emit-llvm -fexceptions -fcxx-exceptions -o - < %s | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=45 -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t < %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=45 -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify -emit-llvm -o - < %s | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp-simd -fopenmp-version=45 -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm -o - < %s | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple x86_64-unknown-unknown -emit-llvm -fexceptions -fcxx-exceptions -o - < %s -DOMP5 | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t < %s -DOMP5 +// RUN: %clang_cc1 -fopenmp-simd -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify -DOMP5 -emit-llvm -o - < %s | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp-simd -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm -o - < %s -DOMP5 | FileCheck --check-prefix SIMD-ONLY0 %s // SIMD-ONLY0-NOT: {{__kmpc|__tgt}} // expected-no-diagnostics #ifndef HEADER @@ -23,246 +23,246 @@ long long get_val() { extern void mayThrow(); mayThrow(); return 0; } double *g_ptr; -// CHECK-LABEL: define {{.*void}} @{{.*}}simple{{.*}}(float* noundef {{.+}}, float* noundef {{.+}}, float* noundef {{.+}}, float* noundef {{.+}}) +// CHECK-LABEL: define {{.*void}} @{{.*}}simple{{.*}}(ptr noundef {{.+}}, ptr noundef {{.+}}, ptr noundef {{.+}}, ptr noundef {{.+}}) void simple(float *a, float *b, float *c, float *d) { #ifdef OMP5 #pragma omp for simd if (true) #else #pragma omp for simd #endif -// CHECK: call void @__kmpc_for_static_init_4(%struct.ident_t* {{[^,]+}}, i32 %{{[^,]+}}, i32 34, i32* %{{[^,]+}}, i32* [[LB:%[^,]+]], i32* [[UB:%[^,]+]], i32* [[STRIDE:%[^,]+]], i32 1, i32 1) -// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]], +// CHECK: call void @__kmpc_for_static_init_4(ptr {{[^,]+}}, i32 %{{[^,]+}}, i32 34, ptr %{{[^,]+}}, ptr [[LB:%[^,]+]], ptr [[UB:%[^,]+]], ptr [[STRIDE:%[^,]+]], i32 1, i32 1) +// CHECK: [[UB_VAL:%.+]] = load i32, ptr [[UB]], // CHECK: [[CMP:%.+]] = icmp sgt i32 [[UB_VAL]], 5 // CHECK: br i1 [[CMP]], label %[[TRUE:.+]], label %[[FALSE:[^,]+]] // CHECK: [[TRUE]]: // CHECK: br label %[[SWITCH:[^,]+]] // CHECK: [[FALSE]]: -// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]], +// CHECK: [[UB_VAL:%.+]] = load i32, ptr [[UB]], // CHECK: br label %[[SWITCH]] // CHECK: [[SWITCH]]: // CHECK: [[UP:%.+]] = phi i32 [ 5, %[[TRUE]] ], [ [[UB_VAL]], %[[FALSE]] ] -// CHECK: store i32 [[UP]], i32* [[UB]], -// CHECK: [[LB_VAL:%.+]] = load i32, i32* [[LB]], -// CHECK: store i32 [[LB_VAL]], i32* [[OMP_IV:%[^,]+]], +// CHECK: store i32 [[UP]], ptr [[UB]], +// CHECK: [[LB_VAL:%.+]] = load i32, ptr [[LB]], +// CHECK: store i32 [[LB_VAL]], ptr [[OMP_IV:%[^,]+]], -// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]] -// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]] +// CHECK: [[IV:%.+]] = load i32, ptr [[OMP_IV]] +// CHECK: [[UB_VAL:%.+]] = load i32, ptr [[UB]] // CHECK-NEXT: [[CMP:%.+]] = icmp sle i32 [[IV]], [[UB_VAL]] // CHECK-NEXT: br i1 [[CMP]], label %[[SIMPLE_LOOP1_BODY:.+]], label %[[SIMPLE_LOOP1_END:[^,]+]] for (int i = 3; i < 32; i += 5) { // CHECK: [[SIMPLE_LOOP1_BODY]]: // Start of body: calculate i from IV: -// CHECK: [[IV1_1:%.+]] = load i32, i32* [[OMP_IV]]{{.*}} +// CHECK: [[IV1_1:%.+]] = load i32, ptr [[OMP_IV]]{{.*}} // CHECK: [[CALC_I_1:%.+]] = mul nsw i32 [[IV1_1]], 5 // CHECK-NEXT: [[CALC_I_2:%.+]] = add nsw i32 3, [[CALC_I_1]] -// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]] +// CHECK-NEXT: store i32 [[CALC_I_2]], ptr [[LC_I:.+]] // ... loop body ... // End of body: store into a[i]: -// CHECK: store float [[RESULT:%.+]], float* +// CHECK: store float [[RESULT:%.+]], ptr a[i] = b[i] * c[i] * d[i]; -// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]] +// CHECK: [[IV1_2:%.+]] = load i32, ptr [[OMP_IV]] // CHECK-NEXT: [[ADD1_2:%.+]] = add nsw i32 [[IV1_2]], 1 -// CHECK-NEXT: store i32 [[ADD1_2]], i32* [[OMP_IV]] +// CHECK-NEXT: store i32 [[ADD1_2]], ptr [[OMP_IV]] // br label %{{.+}}, !llvm.loop !{{.+}} } // CHECK: [[SIMPLE_LOOP1_END]]: -// CHECK: call void @__kmpc_for_static_fini(%struct.ident_t* {{.+}}, i32 %{{.+}}) -// CHECK: call void @__kmpc_barrier(%struct.ident_t* {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_for_static_fini(ptr {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_barrier(ptr {{.+}}, i32 %{{.+}}) long long k = get_val(); #pragma omp for simd linear(k : 3) schedule(simd, nonmonotonic: dynamic) // CHECK: [[K0:%.+]] = call {{.*}}i64 @{{.*}}get_val -// CHECK-NEXT: store i64 [[K0]], i64* [[K_VAR:%[^,]+]] -// CHECK: [[K0LOAD:%.+]] = load i64, i64* [[K_VAR]] -// CHECK-NEXT: store i64 [[K0LOAD]], i64* [[LIN0:%[^,]+]] +// CHECK-NEXT: store i64 [[K0]], ptr [[K_VAR:%[^,]+]] +// CHECK: [[K0LOAD:%.+]] = load i64, ptr [[K_VAR]] +// CHECK-NEXT: store i64 [[K0LOAD]], ptr [[LIN0:%[^,]+]] -// CHECK: call void @__kmpc_dispatch_init_4(%struct.ident_t* {{.+}}, i32 %{{.+}}, i32 1073741859, i32 0, i32 8, i32 1, i32 1) -// CHECK: [[NEXT:%.+]] = call i32 @__kmpc_dispatch_next_4(%struct.ident_t* {{.+}}, i32 %{{.+}}, i32* %{{.+}}, i32* [[LB:%.+]], i32* [[UB:%.+]], i32* %{{.+}}) +// CHECK: call void @__kmpc_dispatch_init_4(ptr {{.+}}, i32 %{{.+}}, i32 1073741859, i32 0, i32 8, i32 1, i32 1) +// CHECK: [[NEXT:%.+]] = call i32 @__kmpc_dispatch_next_4(ptr {{.+}}, i32 %{{.+}}, ptr %{{.+}}, ptr [[LB:%.+]], ptr [[UB:%.+]], ptr %{{.+}}) // CHECK: [[COND:%.+]] = icmp ne i32 [[NEXT]], 0 // CHECK: br i1 [[COND]], label %[[CONT:.+]], label %[[END:.+]] // CHECK: [[CONT]]: -// CHECK: [[LB_VAL:%.+]] = load i32, i32* [[LB]], -// CHECK: store i32 [[LB_VAL]], i32* [[OMP_IV2:%[^,]+]], +// CHECK: [[LB_VAL:%.+]] = load i32, ptr [[LB]], +// CHECK: store i32 [[LB_VAL]], ptr [[OMP_IV2:%[^,]+]], -// CHECK: [[IV2:%.+]] = load i32, i32* [[OMP_IV2]]{{.*}}!llvm.access.group -// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]{{.*}}!llvm.access.group +// CHECK: [[IV2:%.+]] = load i32, ptr [[OMP_IV2]]{{.*}}!llvm.access.group +// CHECK: [[UB_VAL:%.+]] = load i32, ptr [[UB]]{{.*}}!llvm.access.group // CHECK-NEXT: [[CMP2:%.+]] = icmp sle i32 [[IV2]], [[UB_VAL]] // CHECK-NEXT: br i1 [[CMP2]], label %[[SIMPLE_LOOP2_BODY:.+]], label %[[SIMPLE_LOOP2_END:[^,]+]] for (int i = 10; i > 1; i--) { // CHECK: [[SIMPLE_LOOP2_BODY]]: // Start of body: calculate i from IV: -// CHECK: [[IV2_0:%.+]] = load i32, i32* [[OMP_IV2]]{{.*}}!llvm.access.group +// CHECK: [[IV2_0:%.+]] = load i32, ptr [[OMP_IV2]]{{.*}}!llvm.access.group // FIXME: It is interesting, why the following "mul 1" was not constant folded? // CHECK-NEXT: [[IV2_1:%.+]] = mul nsw i32 [[IV2_0]], 1 // CHECK-NEXT: [[LC_I_1:%.+]] = sub nsw i32 10, [[IV2_1]] -// CHECK-NEXT: store i32 [[LC_I_1]], i32* {{.+}}, !llvm.access.group +// CHECK-NEXT: store i32 [[LC_I_1]], ptr {{.+}}, !llvm.access.group // -// CHECK-NEXT: [[LIN0_1:%.+]] = load i64, i64* [[LIN0]]{{.*}}!llvm.access.group -// CHECK-NEXT: [[IV2_2:%.+]] = load i32, i32* [[OMP_IV2]]{{.*}}!llvm.access.group +// CHECK-NEXT: [[LIN0_1:%.+]] = load i64, ptr [[LIN0]]{{.*}}!llvm.access.group +// CHECK-NEXT: [[IV2_2:%.+]] = load i32, ptr [[OMP_IV2]]{{.*}}!llvm.access.group // CHECK-NEXT: [[LIN_MUL1:%.+]] = mul nsw i32 [[IV2_2]], 3 // CHECK-NEXT: [[LIN_EXT1:%.+]] = sext i32 [[LIN_MUL1]] to i64 // CHECK-NEXT: [[LIN_ADD1:%.+]] = add nsw i64 [[LIN0_1]], [[LIN_EXT1]] // Update of the privatized version of linear variable! -// CHECK-NEXT: store i64 [[LIN_ADD1]], i64* [[K_PRIVATIZED:%[^,]+]] +// CHECK-NEXT: store i64 [[LIN_ADD1]], ptr [[K_PRIVATIZED:%[^,]+]] a[k]++; k = k + 3; -// CHECK: [[IV2_2:%.+]] = load i32, i32* [[OMP_IV2]]{{.*}}!llvm.access.group +// CHECK: [[IV2_2:%.+]] = load i32, ptr [[OMP_IV2]]{{.*}}!llvm.access.group // CHECK-NEXT: [[ADD2_2:%.+]] = add nsw i32 [[IV2_2]], 1 -// CHECK-NEXT: store i32 [[ADD2_2]], i32* [[OMP_IV2]]{{.*}}!llvm.access.group +// CHECK-NEXT: store i32 [[ADD2_2]], ptr [[OMP_IV2]]{{.*}}!llvm.access.group // br label {{.+}}, !llvm.loop ![[SIMPLE_LOOP2_ID]] } // CHECK: [[SIMPLE_LOOP2_END]]: // // Update linear vars after loop, as the loop was operating on a private version. -// CHECK: [[LIN0_2:%.+]] = load i64, i64* [[K_PRIVATIZED]] -// CHECK-NEXT: store i64 [[LIN0_2]], i64* [[K_VAR]] -// CHECK: call void @__kmpc_barrier(%struct.ident_t* {{.+}}, i32 %{{.+}}) +// CHECK: [[LIN0_2:%.+]] = load i64, ptr [[K_PRIVATIZED]] +// CHECK-NEXT: store i64 [[LIN0_2]], ptr [[K_VAR]] +// CHECK: call void @__kmpc_barrier(ptr {{.+}}, i32 %{{.+}}) int lin = 12; #pragma omp for simd linear(lin : get_val()), linear(g_ptr) // Init linear private var. -// CHECK: store i32 12, i32* [[LIN_VAR:%[^,]+]] -// CHECK: [[LIN_LOAD:%.+]] = load i32, i32* [[LIN_VAR]] -// CHECK-NEXT: store i32 [[LIN_LOAD]], i32* [[LIN_START:%[^,]+]] +// CHECK: store i32 12, ptr [[LIN_VAR:%[^,]+]] +// CHECK: [[LIN_LOAD:%.+]] = load i32, ptr [[LIN_VAR]] +// CHECK-NEXT: store i32 [[LIN_LOAD]], ptr [[LIN_START:%[^,]+]] // Remember linear step. // CHECK: [[CALL_VAL:%.+]] = invoke -// CHECK: store i64 [[CALL_VAL]], i64* [[LIN_STEP:%[^,]+]] +// CHECK: store i64 [[CALL_VAL]], ptr [[LIN_STEP:%[^,]+]] -// CHECK: [[GLIN_LOAD:%.+]] = load double*, double** [[GLIN_VAR:@[^,]+]] -// CHECK-NEXT: store double* [[GLIN_LOAD]], double** [[GLIN_START:%[^,]+]] +// CHECK: [[GLIN_LOAD:%.+]] = load ptr, ptr [[GLIN_VAR:@[^,]+]] +// CHECK-NEXT: store ptr [[GLIN_LOAD]], ptr [[GLIN_START:%[^,]+]] -// CHECK: call void @__kmpc_for_static_init_8u(%struct.ident_t* {{[^,]+}}, i32 %{{[^,]+}}, i32 34, i32* %{{[^,]+}}, i64* [[LB:%[^,]+]], i64* [[UB:%[^,]+]], i64* [[STRIDE:%[^,]+]], i64 1, i64 1) -// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]], +// CHECK: call void @__kmpc_for_static_init_8u(ptr {{[^,]+}}, i32 %{{[^,]+}}, i32 34, ptr %{{[^,]+}}, ptr [[LB:%[^,]+]], ptr [[UB:%[^,]+]], ptr [[STRIDE:%[^,]+]], i64 1, i64 1) +// CHECK: [[UB_VAL:%.+]] = load i64, ptr [[UB]], // CHECK: [[CMP:%.+]] = icmp ugt i64 [[UB_VAL]], 3 // CHECK: br i1 [[CMP]], label %[[TRUE:.+]], label %[[FALSE:[^,]+]] // CHECK: [[TRUE]]: // CHECK: br label %[[SWITCH:[^,]+]] // CHECK: [[FALSE]]: -// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]], +// CHECK: [[UB_VAL:%.+]] = load i64, ptr [[UB]], // CHECK: br label %[[SWITCH]] // CHECK: [[SWITCH]]: // CHECK: [[UP:%.+]] = phi i64 [ 3, %[[TRUE]] ], [ [[UB_VAL]], %[[FALSE]] ] -// CHECK: store i64 [[UP]], i64* [[UB]], -// CHECK: [[LB_VAL:%.+]] = load i64, i64* [[LB]], -// CHECK: store i64 [[LB_VAL]], i64* [[OMP_IV3:%[^,]+]], +// CHECK: store i64 [[UP]], ptr [[UB]], +// CHECK: [[LB_VAL:%.+]] = load i64, ptr [[LB]], +// CHECK: store i64 [[LB_VAL]], ptr [[OMP_IV3:%[^,]+]], -// CHECK: [[IV3:%.+]] = load i64, i64* [[OMP_IV3]] -// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]] +// CHECK: [[IV3:%.+]] = load i64, ptr [[OMP_IV3]] +// CHECK: [[UB_VAL:%.+]] = load i64, ptr [[UB]] // CHECK-NEXT: [[CMP3:%.+]] = icmp ule i64 [[IV3]], [[UB_VAL]] // CHECK-NEXT: br i1 [[CMP3]], label %[[SIMPLE_LOOP3_BODY:.+]], label %[[SIMPLE_LOOP3_END:[^,]+]] for (unsigned long long it = 2000; it >= 600; it-=400) { // CHECK: [[SIMPLE_LOOP3_BODY]]: // Start of body: calculate it from IV: -// CHECK: [[IV3_0:%.+]] = load i64, i64* [[OMP_IV3]] +// CHECK: [[IV3_0:%.+]] = load i64, ptr [[OMP_IV3]] // CHECK-NEXT: [[LC_IT_1:%.+]] = mul i64 [[IV3_0]], 400 // CHECK-NEXT: [[LC_IT_2:%.+]] = sub i64 2000, [[LC_IT_1]] -// CHECK-NEXT: store i64 [[LC_IT_2]], i64* +// CHECK-NEXT: store i64 [[LC_IT_2]], ptr // // Linear start and step are used to calculate current value of the linear variable. -// CHECK: [[LINSTART:.+]] = load i32, i32* [[LIN_START]] -// CHECK: [[LINSTEP:.+]] = load i64, i64* [[LIN_STEP]] -// CHECK-NOT: store i32 {{.+}}, i32* [[LIN_VAR]], -// CHECK: store i32 {{.+}}, i32* [[LIN_PRIV:%[^,]+]], -// CHECK: [[GLINSTART:.+]] = load double*, double** [[GLIN_START]] -// CHECK-NEXT: [[IV3_1:%.+]] = load i64, i64* [[OMP_IV3]] +// CHECK: [[LINSTART:.+]] = load i32, ptr [[LIN_START]] +// CHECK: [[LINSTEP:.+]] = load i64, ptr [[LIN_STEP]] +// CHECK-NOT: store i32 {{.+}}, ptr [[LIN_VAR]], +// CHECK: store i32 {{.+}}, ptr [[LIN_PRIV:%[^,]+]], +// CHECK: [[GLINSTART:.+]] = load ptr, ptr [[GLIN_START]] +// CHECK-NEXT: [[IV3_1:%.+]] = load i64, ptr [[OMP_IV3]] // CHECK-NEXT: [[MUL:%.+]] = mul i64 [[IV3_1]], 1 // CHECK: [[GEP:%.+]] = getelementptr{{.*}}[[GLINSTART]] -// CHECK-NEXT: store double* [[GEP]], double** [[G_PTR_CUR:%[^,]+]] +// CHECK-NEXT: store ptr [[GEP]], ptr [[G_PTR_CUR:%[^,]+]] *g_ptr++ = 0.0; -// CHECK: [[GEP_VAL:%.+]] = load double{{.*}}[[G_PTR_CUR]] +// CHECK: [[GEP_VAL:%.+]] = load ptr{{.*}}[[G_PTR_CUR]] // CHECK: store double{{.*}}[[GEP_VAL]] a[it + lin]++; // CHECK: [[FLT_INC:%.+]] = fadd float // CHECK-NEXT: store float [[FLT_INC]], -// CHECK: [[IV3_2:%.+]] = load i64, i64* [[OMP_IV3]] +// CHECK: [[IV3_2:%.+]] = load i64, ptr [[OMP_IV3]] // CHECK-NEXT: [[ADD3_2:%.+]] = add i64 [[IV3_2]], 1 -// CHECK-NEXT: store i64 [[ADD3_2]], i64* [[OMP_IV3]] +// CHECK-NEXT: store i64 [[ADD3_2]], ptr [[OMP_IV3]] } // CHECK: [[SIMPLE_LOOP3_END]]: -// CHECK: call void @__kmpc_for_static_fini(%struct.ident_t* {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_for_static_fini(ptr {{.+}}, i32 %{{.+}}) // // Linear start and step are used to calculate final value of the linear variables. -// CHECK: [[LIN:%.+]] = load i32, i32* [[LIN_PRIV]], -// CHECK-NEXT: store i32 [[LIN]], i32* [[LIN_VAR]], -// CHECK: [[GLIN:%.+]] = load double*, double** [[G_PTR_CUR]], -// CHECK-NEXT: store double* [[GLIN]], double** [[GLIN_VAR]], -// CHECK: call void @__kmpc_barrier(%struct.ident_t* {{.+}}, i32 %{{.+}}) +// CHECK: [[LIN:%.+]] = load i32, ptr [[LIN_PRIV]], +// CHECK-NEXT: store i32 [[LIN]], ptr [[LIN_VAR]], +// CHECK: [[GLIN:%.+]] = load ptr, ptr [[G_PTR_CUR]], +// CHECK-NEXT: store ptr [[GLIN]], ptr [[GLIN_VAR]], +// CHECK: call void @__kmpc_barrier(ptr {{.+}}, i32 %{{.+}}) #pragma omp for simd -// CHECK: call void @__kmpc_for_static_init_4(%struct.ident_t* {{[^,]+}}, i32 %{{[^,]+}}, i32 34, i32* %{{[^,]+}}, i32* [[LB:%[^,]+]], i32* [[UB:%[^,]+]], i32* [[STRIDE:%[^,]+]], i32 1, i32 1) -// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]], +// CHECK: call void @__kmpc_for_static_init_4(ptr {{[^,]+}}, i32 %{{[^,]+}}, i32 34, ptr %{{[^,]+}}, ptr [[LB:%[^,]+]], ptr [[UB:%[^,]+]], ptr [[STRIDE:%[^,]+]], i32 1, i32 1) +// CHECK: [[UB_VAL:%.+]] = load i32, ptr [[UB]], // CHECK: [[CMP:%.+]] = icmp sgt i32 [[UB_VAL]], 3 // CHECK: br i1 [[CMP]], label %[[TRUE:.+]], label %[[FALSE:[^,]+]] // CHECK: [[TRUE]]: // CHECK: br label %[[SWITCH:[^,]+]] // CHECK: [[FALSE]]: -// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]], +// CHECK: [[UB_VAL:%.+]] = load i32, ptr [[UB]], // CHECK: br label %[[SWITCH]] // CHECK: [[SWITCH]]: // CHECK: [[UP:%.+]] = phi i32 [ 3, %[[TRUE]] ], [ [[UB_VAL]], %[[FALSE]] ] -// CHECK: store i32 [[UP]], i32* [[UB]], -// CHECK: [[LB_VAL:%.+]] = load i32, i32* [[LB]], -// CHECK: store i32 [[LB_VAL]], i32* [[OMP_IV4:%[^,]+]], +// CHECK: store i32 [[UP]], ptr [[UB]], +// CHECK: [[LB_VAL:%.+]] = load i32, ptr [[LB]], +// CHECK: store i32 [[LB_VAL]], ptr [[OMP_IV4:%[^,]+]], -// CHECK: [[IV4:%.+]] = load i32, i32* [[OMP_IV4]] -// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]] +// CHECK: [[IV4:%.+]] = load i32, ptr [[OMP_IV4]] +// CHECK: [[UB_VAL:%.+]] = load i32, ptr [[UB]] // CHECK-NEXT: [[CMP4:%.+]] = icmp sle i32 [[IV4]], [[UB_VAL]] // CHECK-NEXT: br i1 [[CMP4]], label %[[SIMPLE_LOOP4_BODY:.+]], label %[[SIMPLE_LOOP4_END:[^,]+]] for (short it = 6; it <= 20; it-=-4) { // CHECK: [[SIMPLE_LOOP4_BODY]]: // Start of body: calculate it from IV: -// CHECK: [[IV4_0:%.+]] = load i32, i32* [[OMP_IV4]] +// CHECK: [[IV4_0:%.+]] = load i32, ptr [[OMP_IV4]] // CHECK-NEXT: [[LC_IT_1:%.+]] = mul nsw i32 [[IV4_0]], 4 // CHECK-NEXT: [[LC_IT_2:%.+]] = add nsw i32 6, [[LC_IT_1]] // CHECK-NEXT: [[LC_IT_3:%.+]] = trunc i32 [[LC_IT_2]] to i16 -// CHECK-NEXT: store i16 [[LC_IT_3]], i16* +// CHECK-NEXT: store i16 [[LC_IT_3]], ptr -// CHECK: [[IV4_2:%.+]] = load i32, i32* [[OMP_IV4]] +// CHECK: [[IV4_2:%.+]] = load i32, ptr [[OMP_IV4]] // CHECK-NEXT: [[ADD4_2:%.+]] = add nsw i32 [[IV4_2]], 1 -// CHECK-NEXT: store i32 [[ADD4_2]], i32* [[OMP_IV4]] +// CHECK-NEXT: store i32 [[ADD4_2]], ptr [[OMP_IV4]] } // CHECK: [[SIMPLE_LOOP4_END]]: -// CHECK: call void @__kmpc_for_static_fini(%struct.ident_t* {{.+}}, i32 %{{.+}}) -// CHECK: call void @__kmpc_barrier(%struct.ident_t* {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_for_static_fini(ptr {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_barrier(ptr {{.+}}, i32 %{{.+}}) #pragma omp for simd -// CHECK: call void @__kmpc_for_static_init_4(%struct.ident_t* {{[^,]+}}, i32 %{{[^,]+}}, i32 34, i32* %{{[^,]+}}, i32* [[LB:%[^,]+]], i32* [[UB:%[^,]+]], i32* [[STRIDE:%[^,]+]], i32 1, i32 1) -// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]], +// CHECK: call void @__kmpc_for_static_init_4(ptr {{[^,]+}}, i32 %{{[^,]+}}, i32 34, ptr %{{[^,]+}}, ptr [[LB:%[^,]+]], ptr [[UB:%[^,]+]], ptr [[STRIDE:%[^,]+]], i32 1, i32 1) +// CHECK: [[UB_VAL:%.+]] = load i32, ptr [[UB]], // CHECK: [[CMP:%.+]] = icmp sgt i32 [[UB_VAL]], 25 // CHECK: br i1 [[CMP]], label %[[TRUE:.+]], label %[[FALSE:[^,]+]] // CHECK: [[TRUE]]: // CHECK: br label %[[SWITCH:[^,]+]] // CHECK: [[FALSE]]: -// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]], +// CHECK: [[UB_VAL:%.+]] = load i32, ptr [[UB]], // CHECK: br label %[[SWITCH]] // CHECK: [[SWITCH]]: // CHECK: [[UP:%.+]] = phi i32 [ 25, %[[TRUE]] ], [ [[UB_VAL]], %[[FALSE]] ] -// CHECK: store i32 [[UP]], i32* [[UB]], -// CHECK: [[LB_VAL:%.+]] = load i32, i32* [[LB]], -// CHECK: store i32 [[LB_VAL]], i32* [[OMP_IV5:%[^,]+]], +// CHECK: store i32 [[UP]], ptr [[UB]], +// CHECK: [[LB_VAL:%.+]] = load i32, ptr [[LB]], +// CHECK: store i32 [[LB_VAL]], ptr [[OMP_IV5:%[^,]+]], -// CHECK: [[IV5:%.+]] = load i32, i32* [[OMP_IV5]] -// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]] +// CHECK: [[IV5:%.+]] = load i32, ptr [[OMP_IV5]] +// CHECK: [[UB_VAL:%.+]] = load i32, ptr [[UB]] // CHECK-NEXT: [[CMP5:%.+]] = icmp sle i32 [[IV5]], [[UB_VAL]] // CHECK-NEXT: br i1 [[CMP5]], label %[[SIMPLE_LOOP5_BODY:.+]], label %[[SIMPLE_LOOP5_END:[^,]+]] for (unsigned char it = 'z'; it >= 'a'; it+=-1) { // CHECK: [[SIMPLE_LOOP5_BODY]]: // Start of body: calculate it from IV: -// CHECK: [[IV5_0:%.+]] = load i32, i32* [[OMP_IV5]] +// CHECK: [[IV5_0:%.+]] = load i32, ptr [[OMP_IV5]] // CHECK-NEXT: [[IV5_1:%.+]] = mul nsw i32 [[IV5_0]], 1 // CHECK-NEXT: [[LC_IT_1:%.+]] = sub nsw i32 122, [[IV5_1]] // CHECK-NEXT: [[LC_IT_2:%.+]] = trunc i32 [[LC_IT_1]] to i8 -// CHECK-NEXT: store i8 [[LC_IT_2]], i8* +// CHECK-NEXT: store i8 [[LC_IT_2]], ptr -// CHECK: [[IV5_2:%.+]] = load i32, i32* [[OMP_IV5]] +// CHECK: [[IV5_2:%.+]] = load i32, ptr [[OMP_IV5]] // CHECK-NEXT: [[ADD5_2:%.+]] = add nsw i32 [[IV5_2]], 1 -// CHECK-NEXT: store i32 [[ADD5_2]], i32* [[OMP_IV5]] +// CHECK-NEXT: store i32 [[ADD5_2]], ptr [[OMP_IV5]] } // CHECK: [[SIMPLE_LOOP5_END]]: -// CHECK: call void @__kmpc_for_static_fini(%struct.ident_t* {{.+}}, i32 %{{.+}}) -// CHECK: call void @__kmpc_barrier(%struct.ident_t* {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_for_static_fini(ptr {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_barrier(ptr {{.+}}, i32 %{{.+}}) // CHECK-NOT: mul i32 %{{.+}}, 10 #pragma omp for simd @@ -272,62 +272,62 @@ void simple(float *a, float *b, float *c, float *d) { int A; #pragma omp parallel { - // CHECK: store i32 -1, i32* [[A:%.+]], + // CHECK: store i32 -1, ptr [[A:%.+]], A = -1; #pragma omp for simd lastprivate(A) -// CHECK: call void @__kmpc_for_static_init_8(%struct.ident_t* {{[^,]+}}, i32 %{{[^,]+}}, i32 34, i32* %{{[^,]+}}, i64* [[LB:%[^,]+]], i64* [[UB:%[^,]+]], i64* [[STRIDE:%[^,]+]], i64 1, i64 1) -// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]], +// CHECK: call void @__kmpc_for_static_init_8(ptr {{[^,]+}}, i32 %{{[^,]+}}, i32 34, ptr %{{[^,]+}}, ptr [[LB:%[^,]+]], ptr [[UB:%[^,]+]], ptr [[STRIDE:%[^,]+]], i64 1, i64 1) +// CHECK: [[UB_VAL:%.+]] = load i64, ptr [[UB]], // CHECK: [[CMP:%.+]] = icmp sgt i64 [[UB_VAL]], 6 // CHECK: br i1 [[CMP]], label %[[TRUE:.+]], label %[[FALSE:[^,]+]] // CHECK: [[TRUE]]: // CHECK: br label %[[SWITCH:[^,]+]] // CHECK: [[FALSE]]: -// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]], +// CHECK: [[UB_VAL:%.+]] = load i64, ptr [[UB]], // CHECK: br label %[[SWITCH]] // CHECK: [[SWITCH]]: // CHECK: [[UP:%.+]] = phi i64 [ 6, %[[TRUE]] ], [ [[UB_VAL]], %[[FALSE]] ] -// CHECK: store i64 [[UP]], i64* [[UB]], -// CHECK: [[LB_VAL:%.+]] = load i64, i64* [[LB]], -// CHECK: store i64 [[LB_VAL]], i64* [[OMP_IV7:%[^,]+]], +// CHECK: store i64 [[UP]], ptr [[UB]], +// CHECK: [[LB_VAL:%.+]] = load i64, ptr [[LB]], +// CHECK: store i64 [[LB_VAL]], ptr [[OMP_IV7:%[^,]+]], // CHECK: br label %[[SIMD_LOOP7_COND:[^,]+]] // CHECK: [[SIMD_LOOP7_COND]]: -// CHECK-NEXT: [[IV7:%.+]] = load i64, i64* [[OMP_IV7]] -// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]] +// CHECK-NEXT: [[IV7:%.+]] = load i64, ptr [[OMP_IV7]] +// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, ptr [[UB]] // CHECK-NEXT: [[CMP7:%.+]] = icmp sle i64 [[IV7]], [[UB_VAL]] // CHECK-NEXT: br i1 [[CMP7]], label %[[SIMPLE_LOOP7_BODY:.+]], label %[[SIMPLE_LOOP7_END:[^,]+]] for (long long i = -10; i < 10; i += 3) { // CHECK: [[SIMPLE_LOOP7_BODY]]: // Start of body: calculate i from IV: -// CHECK: [[IV7_0:%.+]] = load i64, i64* [[OMP_IV7]] +// CHECK: [[IV7_0:%.+]] = load i64, ptr [[OMP_IV7]] // CHECK-NEXT: [[LC_IT_1:%.+]] = mul nsw i64 [[IV7_0]], 3 // CHECK-NEXT: [[LC_IT_2:%.+]] = add nsw i64 -10, [[LC_IT_1]] -// CHECK-NEXT: store i64 [[LC_IT_2]], i64* [[LC:%[^,]+]], -// CHECK-NEXT: [[LC_VAL:%.+]] = load i64, i64* [[LC]] +// CHECK-NEXT: store i64 [[LC_IT_2]], ptr [[LC:%[^,]+]], +// CHECK-NEXT: [[LC_VAL:%.+]] = load i64, ptr [[LC]] // CHECK-NEXT: [[CONV:%.+]] = trunc i64 [[LC_VAL]] to i32 -// CHECK-NEXT: store i32 [[CONV]], i32* [[A_PRIV:%[^,]+]], +// CHECK-NEXT: store i32 [[CONV]], ptr [[A_PRIV:%[^,]+]], A = i; -// CHECK: [[IV7_2:%.+]] = load i64, i64* [[OMP_IV7]] +// CHECK: [[IV7_2:%.+]] = load i64, ptr [[OMP_IV7]] // CHECK-NEXT: [[ADD7_2:%.+]] = add nsw i64 [[IV7_2]], 1 -// CHECK-NEXT: store i64 [[ADD7_2]], i64* [[OMP_IV7]] +// CHECK-NEXT: store i64 [[ADD7_2]], ptr [[OMP_IV7]] } // CHECK: [[SIMPLE_LOOP7_END]]: -// CHECK: call void @__kmpc_for_static_fini(%struct.ident_t* {{.+}}, i32 %{{.+}}) -// CHECK: load i32, i32* +// CHECK: call void @__kmpc_for_static_fini(ptr {{.+}}, i32 %{{.+}}) +// CHECK: load i32, ptr // CHECK: icmp ne i32 %{{.+}}, 0 // CHECK: br i1 %{{.+}}, label -// CHECK: [[A_PRIV_VAL:%.+]] = load i32, i32* [[A_PRIV]], -// CHECK-NEXT: store i32 [[A_PRIV_VAL]], i32* %{{.+}}, +// CHECK: [[A_PRIV_VAL:%.+]] = load i32, ptr [[A_PRIV]], +// CHECK-NEXT: store i32 [[A_PRIV_VAL]], ptr %{{.+}}, // CHECK-NEXT: br label -// CHECK: call void @__kmpc_barrier(%struct.ident_t* {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_barrier(ptr {{.+}}, i32 %{{.+}}) } int R; #pragma omp parallel { - // CHECK: store i32 -1, i32* [[R:%[^,]+]], + // CHECK: store i32 -1, ptr [[R:%[^,]+]], R = -1; -// CHECK: store i32 1, i32* [[R_PRIV:%[^,]+]], -// OMP50: [[A_VAL:%.+]] = load i32, i32* % +// CHECK: store i32 1, ptr [[R_PRIV:%[^,]+]], +// OMP50: [[A_VAL:%.+]] = load i32, ptr % // OMP50: [[COND:%.+]] = icmp ne i32 [[A_VAL]], 0 // OMP50: br i1 [[COND]], label {{%?}}[[THEN:[^,]+]], label {{%?}}[[ELSE:[^,]+]] // OMP50: [[THEN]]: @@ -336,90 +336,90 @@ void simple(float *a, float *b, float *c, float *d) { #else #pragma omp for simd reduction(*:R) #endif -// CHECK: call void @__kmpc_for_static_init_8(%struct.ident_t* {{[^,]+}}, i32 %{{[^,]+}}, i32 34, i32* %{{[^,]+}}, i64* [[LB:%[^,]+]], i64* [[UB:%[^,]+]], i64* [[STRIDE:%[^,]+]], i64 1, i64 1) -// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]], +// CHECK: call void @__kmpc_for_static_init_8(ptr {{[^,]+}}, i32 %{{[^,]+}}, i32 34, ptr %{{[^,]+}}, ptr [[LB:%[^,]+]], ptr [[UB:%[^,]+]], ptr [[STRIDE:%[^,]+]], i64 1, i64 1) +// CHECK: [[UB_VAL:%.+]] = load i64, ptr [[UB]], // CHECK: [[CMP:%.+]] = icmp sgt i64 [[UB_VAL]], 6 // CHECK: br i1 [[CMP]], label %[[TRUE:.+]], label %[[FALSE:[^,]+]] // CHECK: [[TRUE]]: // CHECK: br label %[[SWITCH:[^,]+]] // CHECK: [[FALSE]]: -// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]], +// CHECK: [[UB_VAL:%.+]] = load i64, ptr [[UB]], // CHECK: br label %[[SWITCH]] // CHECK: [[SWITCH]]: // CHECK: [[UP:%.+]] = phi i64 [ 6, %[[TRUE]] ], [ [[UB_VAL]], %[[FALSE]] ] -// CHECK: store i64 [[UP]], i64* [[UB]], -// CHECK: [[LB_VAL:%.+]] = load i64, i64* [[LB]], -// CHECK: store i64 [[LB_VAL]], i64* [[OMP_IV8:%[^,]+]], +// CHECK: store i64 [[UP]], ptr [[UB]], +// CHECK: [[LB_VAL:%.+]] = load i64, ptr [[LB]], +// CHECK: store i64 [[LB_VAL]], ptr [[OMP_IV8:%[^,]+]], // CHECK: br label %[[SIMD_LOOP8_COND:[^,]+]] // CHECK: [[SIMD_LOOP8_COND]]: -// CHECK-NEXT: [[IV8:%.+]] = load i64, i64* [[OMP_IV8]] -// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]] +// CHECK-NEXT: [[IV8:%.+]] = load i64, ptr [[OMP_IV8]] +// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, ptr [[UB]] // CHECK-NEXT: [[CMP8:%.+]] = icmp sle i64 [[IV8]], [[UB_VAL]] // CHECK-NEXT: br i1 [[CMP8]], label %[[SIMPLE_LOOP8_BODY:.+]], label %[[SIMPLE_LOOP8_END:[^,]+]] for (long long i = -10; i < 10; i += 3) { // CHECK: [[SIMPLE_LOOP8_BODY]]: // Start of body: calculate i from IV: -// CHECK: [[IV8_0:%.+]] = load i64, i64* [[OMP_IV8]] +// CHECK: [[IV8_0:%.+]] = load i64, ptr [[OMP_IV8]] // CHECK-NEXT: [[LC_IT_1:%.+]] = mul nsw i64 [[IV8_0]], 3 // CHECK-NEXT: [[LC_IT_2:%.+]] = add nsw i64 -10, [[LC_IT_1]] -// CHECK-NEXT: store i64 [[LC_IT_2]], i64* [[LC:%[^,]+]], -// CHECK-NEXT: [[LC_VAL:%.+]] = load i64, i64* [[LC]] -// OMP45: store i32 %{{.+}}, i32* [[R_PRIV]], -// OMP50: store i32 %{{.+}}, i32* [[R_PRIV]],{{.*}}!nontemporal +// CHECK-NEXT: store i64 [[LC_IT_2]], ptr [[LC:%[^,]+]], +// CHECK-NEXT: [[LC_VAL:%.+]] = load i64, ptr [[LC]] +// OMP45: store i32 %{{.+}}, ptr [[R_PRIV]], +// OMP50: store i32 %{{.+}}, ptr [[R_PRIV]],{{.*}}!nontemporal R *= i; -// CHECK: [[IV8_2:%.+]] = load i64, i64* [[OMP_IV8]] +// CHECK: [[IV8_2:%.+]] = load i64, ptr [[OMP_IV8]] // CHECK-NEXT: [[ADD8_2:%.+]] = add nsw i64 [[IV8_2]], 1 -// CHECK-NEXT: store i64 [[ADD8_2]], i64* [[OMP_IV8]] +// CHECK-NEXT: store i64 [[ADD8_2]], ptr [[OMP_IV8]] // CHECK-NEXT: br label {{%?}}[[SIMD_LOOP8_COND]], {{.*}}!llvm.loop ![[SIMD_LOOP:.+]] } // CHECK: [[SIMPLE_LOOP8_END]]: // OMP50: br label {{%?}}[[IF_EXIT:[^,]+]] // OMP50: [[ELSE]]: -// OMP50: call void @__kmpc_for_static_init_8(%struct.ident_t* {{[^,]+}}, i32 %{{[^,]+}}, i32 34, i32* %{{[^,]+}}, i64* [[LB:%[^,]+]], i64* [[UB:%[^,]+]], i64* [[STRIDE:%[^,]+]], i64 1, i64 1) -// OMP50: [[UB_VAL:%.+]] = load i64, i64* [[UB]], +// OMP50: call void @__kmpc_for_static_init_8(ptr {{[^,]+}}, i32 %{{[^,]+}}, i32 34, ptr %{{[^,]+}}, ptr [[LB:%[^,]+]], ptr [[UB:%[^,]+]], ptr [[STRIDE:%[^,]+]], i64 1, i64 1) +// OMP50: [[UB_VAL:%.+]] = load i64, ptr [[UB]], // OMP50: [[CMP:%.+]] = icmp sgt i64 [[UB_VAL]], 6 // OMP50: br i1 [[CMP]], label %[[TRUE:.+]], label %[[FALSE:[^,]+]] // OMP50: [[TRUE]]: // OMP50: br label %[[SWITCH:[^,]+]] // OMP50: [[FALSE]]: -// OMP50: [[UB_VAL:%.+]] = load i64, i64* [[UB]], +// OMP50: [[UB_VAL:%.+]] = load i64, ptr [[UB]], // OMP50: br label %[[SWITCH]] // OMP50: [[SWITCH]]: // OMP50: [[UP:%.+]] = phi i64 [ 6, %[[TRUE]] ], [ [[UB_VAL]], %[[FALSE]] ] -// OMP50: store i64 [[UP]], i64* [[UB]], -// OMP50: [[LB_VAL:%.+]] = load i64, i64* [[LB]], -// OMP50: store i64 [[LB_VAL]], i64* [[OMP_IV8:%[^,]+]], +// OMP50: store i64 [[UP]], ptr [[UB]], +// OMP50: [[LB_VAL:%.+]] = load i64, ptr [[LB]], +// OMP50: store i64 [[LB_VAL]], ptr [[OMP_IV8:%[^,]+]], // OMP50: br label %[[SIMD_LOOP8_COND:[^,]+]] // OMP50: [[SIMD_LOOP8_COND]]: -// OMP50-NEXT: [[IV8:%.+]] = load i64, i64* [[OMP_IV8]] -// OMP50-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]] +// OMP50-NEXT: [[IV8:%.+]] = load i64, ptr [[OMP_IV8]] +// OMP50-NEXT: [[UB_VAL:%.+]] = load i64, ptr [[UB]] // OMP50-NEXT: [[CMP8:%.+]] = icmp sle i64 [[IV8]], [[UB_VAL]] // OMP50-NEXT: br i1 [[CMP8]], label %[[SIMPLE_LOOP8_BODY:.+]], label %[[SIMPLE_LOOP8_END:[^,]+]] // OMP50: [[SIMPLE_LOOP8_BODY]]: // Start of body: calculate i from IV: -// OMP50: [[IV8_0:%.+]] = load i64, i64* [[OMP_IV8]] +// OMP50: [[IV8_0:%.+]] = load i64, ptr [[OMP_IV8]] // OMP50-NEXT: [[LC_IT_1:%.+]] = mul nsw i64 [[IV8_0]], 3 // OMP50-NEXT: [[LC_IT_2:%.+]] = add nsw i64 -10, [[LC_IT_1]] -// OMP50-NEXT: store i64 [[LC_IT_2]], i64* [[LC:%[^,]+]], -// OMP50-NEXT: [[LC_VAL:%.+]] = load i64, i64* [[LC]] -// OMP50: store i32 %{{.+}}, i32* [[R_PRIV]], -// OMP50: [[IV8_2:%.+]] = load i64, i64* [[OMP_IV8]] +// OMP50-NEXT: store i64 [[LC_IT_2]], ptr [[LC:%[^,]+]], +// OMP50-NEXT: [[LC_VAL:%.+]] = load i64, ptr [[LC]] +// OMP50: store i32 %{{.+}}, ptr [[R_PRIV]], +// OMP50: [[IV8_2:%.+]] = load i64, ptr [[OMP_IV8]] // OMP50-NEXT: [[ADD8_2:%.+]] = add nsw i64 [[IV8_2]], 1 -// OMP50-NEXT: store i64 [[ADD8_2]], i64* [[OMP_IV8]] +// OMP50-NEXT: store i64 [[ADD8_2]], ptr [[OMP_IV8]] // OMP50-NEXT: br label {{%?}}[[SIMD_LOOP8_COND]], {{.*}}!llvm.loop ![[NOSIMD_LOOP:.+]] // OMP50: [[SIMPLE_LOOP8_END]]: // OMP50: br label {{%?}}[[IF_EXIT]] // OMP50: [[IF_EXIT]]: -// CHECK: call void @__kmpc_for_static_fini(%struct.ident_t* {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_for_static_fini(ptr {{.+}}, i32 %{{.+}}) // CHECK: call i32 @__kmpc_reduce( -// CHECK: [[R_PRIV_VAL:%.+]] = load i32, i32* [[R_PRIV]], +// CHECK: [[R_PRIV_VAL:%.+]] = load i32, ptr [[R_PRIV]], // CHECK: [[RED:%.+]] = mul nsw i32 %{{.+}}, [[R_PRIV_VAL]] -// CHECK-NEXT: store i32 [[RED]], i32* %{{.+}}, +// CHECK-NEXT: store i32 [[RED]], ptr %{{.+}}, // CHECK-NEXT: call void @__kmpc_end_reduce( -// CHECK: call void @__kmpc_barrier(%struct.ident_t* {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_barrier(ptr {{.+}}, i32 %{{.+}}) } } @@ -437,52 +437,52 @@ int templ1(T a, T *z) { } // Instatiation templ1 -// CHECK-LABEL: define {{.*i32}} @{{.*}}templ1{{.*}}(float noundef {{.+}}, float* noundef {{.+}}) -// CHECK: call void @__kmpc_for_static_init_8(%struct.ident_t* {{[^,]+}}, i32 %{{[^,]+}}, i32 45, i32* %{{[^,]+}}, i64* [[LB:%[^,]+]], i64* [[UB:%[^,]+]], i64* [[STRIDE:%[^,]+]], i64 1, i64 2) -// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]], +// CHECK-LABEL: define {{.*i32}} @{{.*}}templ1{{.*}}(float noundef {{.+}}, ptr noundef {{.+}}) +// CHECK: call void @__kmpc_for_static_init_8(ptr {{[^,]+}}, i32 %{{[^,]+}}, i32 45, ptr %{{[^,]+}}, ptr [[LB:%[^,]+]], ptr [[UB:%[^,]+]], ptr [[STRIDE:%[^,]+]], i64 1, i64 2) +// CHECK: [[UB_VAL:%.+]] = load i64, ptr [[UB]], // CHECK: [[CMP:%.+]] = icmp sgt i64 [[UB_VAL]], 15 // CHECK: br i1 [[CMP]], label %[[TRUE:.+]], label %[[FALSE:[^,]+]] // CHECK: [[TRUE]]: // CHECK: br label %[[SWITCH:[^,]+]] // CHECK: [[FALSE]]: -// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]], +// CHECK: [[UB_VAL:%.+]] = load i64, ptr [[UB]], // CHECK: br label %[[SWITCH]] // CHECK: [[SWITCH]]: // CHECK: [[UP:%.+]] = phi i64 [ 15, %[[TRUE]] ], [ [[UB_VAL]], %[[FALSE]] ] -// CHECK: store i64 [[UP]], i64* [[UB]], -// CHECK: [[LB_VAL:%.+]] = load i64, i64* [[LB]], -// CHECK: store i64 [[LB_VAL]], i64* [[T1_OMP_IV:%[^,]+]], +// CHECK: store i64 [[UP]], ptr [[UB]], +// CHECK: [[LB_VAL:%.+]] = load i64, ptr [[LB]], +// CHECK: store i64 [[LB_VAL]], ptr [[T1_OMP_IV:%[^,]+]], // ... // CHECK: icmp sle i64 -// CHECK: [[IV:%.+]] = load i64, i64* [[T1_OMP_IV]] -// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]] +// CHECK: [[IV:%.+]] = load i64, ptr [[T1_OMP_IV]] +// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, ptr [[UB]] // CHECK-NEXT: [[CMP1:%.+]] = icmp sle i64 [[IV]], [[UB_VAL]] // CHECK-NEXT: br i1 [[CMP1]], label %[[T1_BODY:.+]], label %[[T1_END:[^,]+]] // CHECK: [[T1_BODY]]: // Loop counters i and j updates: -// CHECK: [[IV1:%.+]] = load i64, i64* [[T1_OMP_IV]] +// CHECK: [[IV1:%.+]] = load i64, ptr [[T1_OMP_IV]] // CHECK-NEXT: [[I_1:%.+]] = sdiv i64 [[IV1]], 4 // CHECK-NEXT: [[I_1_MUL1:%.+]] = mul nsw i64 [[I_1]], 1 // CHECK-NEXT: [[I_1_ADD0:%.+]] = add nsw i64 0, [[I_1_MUL1]] // CHECK-NEXT: [[I_2:%.+]] = trunc i64 [[I_1_ADD0]] to i32 -// CHECK-NEXT: store i32 [[I_2]], i32* -// CHECK: [[IV2:%.+]] = load i64, i64* [[T1_OMP_IV]] -// CHECK-NEXT: [[IV2_1:%.+]] = load i64, i64* [[T1_OMP_IV]] +// CHECK-NEXT: store i32 [[I_2]], ptr +// CHECK: [[IV2:%.+]] = load i64, ptr [[T1_OMP_IV]] +// CHECK-NEXT: [[IV2_1:%.+]] = load i64, ptr [[T1_OMP_IV]] // CHECK-NEXT: [[DIV_2:%.+]] = sdiv i64 [[IV2_1]], 4 // CHECK-NEXT: [[MUL_2:%.+]] = mul nsw i64 [[DIV_2]], 4 // CHECK-NEXT: [[J_1:%.+]] = sub nsw i64 [[IV2]], [[MUL_2]] // CHECK-NEXT: [[J_2:%.+]] = mul nsw i64 [[J_1]], 2 // CHECK-NEXT: [[J_2_ADD0:%.+]] = add nsw i64 0, [[J_2]] -// CHECK-NEXT: store i64 [[J_2_ADD0]], i64* +// CHECK-NEXT: store i64 [[J_2_ADD0]], ptr // simd.for.inc: -// CHECK: [[IV3:%.+]] = load i64, i64* [[T1_OMP_IV]] +// CHECK: [[IV3:%.+]] = load i64, ptr [[T1_OMP_IV]] // CHECK-NEXT: [[INC:%.+]] = add nsw i64 [[IV3]], 1 -// CHECK-NEXT: store i64 [[INC]], i64* [[T1_OMP_IV]] +// CHECK-NEXT: store i64 [[INC]], ptr [[T1_OMP_IV]] // CHECK-NEXT: br label {{%.+}} // CHECK: [[T1_END]]: -// CHECK: call void @__kmpc_for_static_fini(%struct.ident_t* {{.+}}, i32 %{{.+}}) -// CHECK: call void @__kmpc_barrier(%struct.ident_t* {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_for_static_fini(ptr {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_barrier(ptr {{.+}}, i32 %{{.+}}) // CHECK: ret i32 0 // void inst_templ1() { @@ -529,34 +529,34 @@ void iter_simple(IterDouble ia, IterDouble ib, IterDouble ic) { // CHECK-NEXT: [[DIFF3:%.+]] = add nsw i32 [[DIFF2]], 1 // CHECK-NEXT: [[DIFF4:%.+]] = sdiv i32 [[DIFF3]], 1 // CHECK-NEXT: [[DIFF5:%.+]] = sub nsw i32 [[DIFF4]], 1 -// CHECK-NEXT: store i32 [[DIFF5]], i32* [[OMP_LAST_IT:%[^,]+]]{{.+}} +// CHECK-NEXT: store i32 [[DIFF5]], ptr [[OMP_LAST_IT:%[^,]+]]{{.+}} #pragma omp for simd -// CHECK: call void @__kmpc_for_static_init_4(%struct.ident_t* {{[^,]+}}, i32 %{{[^,]+}}, i32 34, i32* %{{[^,]+}}, i32* [[LB:%[^,]+]], i32* [[UB:%[^,]+]], i32* [[STRIDE:%[^,]+]], i32 1, i32 1) -// CHECK-DAG: [[UB_VAL:%.+]] = load i32, i32* [[UB]], -// CHECK-DAG: [[OMP_LAST_IT_VAL:%.+]] = load i32, i32* [[OMP_LAST_IT]], +// CHECK: call void @__kmpc_for_static_init_4(ptr {{[^,]+}}, i32 %{{[^,]+}}, i32 34, ptr %{{[^,]+}}, ptr [[LB:%[^,]+]], ptr [[UB:%[^,]+]], ptr [[STRIDE:%[^,]+]], i32 1, i32 1) +// CHECK-DAG: [[UB_VAL:%.+]] = load i32, ptr [[UB]], +// CHECK-DAG: [[OMP_LAST_IT_VAL:%.+]] = load i32, ptr [[OMP_LAST_IT]], // CHECK: [[CMP:%.+]] = icmp sgt i32 [[UB_VAL]], [[OMP_LAST_IT_VAL]] // CHECK: br i1 [[CMP]], label %[[TRUE:.+]], label %[[FALSE:[^,]+]] // CHECK: [[TRUE]]: -// CHECK: [[OMP_LAST_IT_VAL:%.+]] = load i32, i32* [[OMP_LAST_IT]], +// CHECK: [[OMP_LAST_IT_VAL:%.+]] = load i32, ptr [[OMP_LAST_IT]], // CHECK: br label %[[SWITCH:[^,]+]] // CHECK: [[FALSE]]: -// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]], +// CHECK: [[UB_VAL:%.+]] = load i32, ptr [[UB]], // CHECK: br label %[[SWITCH]] // CHECK: [[SWITCH]]: // CHECK: [[UP:%.+]] = phi i32 [ [[OMP_LAST_IT_VAL]], %[[TRUE]] ], [ [[UB_VAL]], %[[FALSE]] ] -// CHECK: store i32 [[UP]], i32* [[UB]], -// CHECK: [[LB_VAL:%.+]] = load i32, i32* [[LB]], -// CHECK: store i32 [[LB_VAL]], i32* [[IT_OMP_IV:%[^,]+]], +// CHECK: store i32 [[UP]], ptr [[UB]], +// CHECK: [[LB_VAL:%.+]] = load i32, ptr [[LB]], +// CHECK: store i32 [[LB_VAL]], ptr [[IT_OMP_IV:%[^,]+]], -// CHECK: [[IV:%.+]] = load i32, i32* [[IT_OMP_IV]] -// CHECK-NEXT: [[UB_VAL:%.+]] = load i32, i32* [[UB]] +// CHECK: [[IV:%.+]] = load i32, ptr [[IT_OMP_IV]] +// CHECK-NEXT: [[UB_VAL:%.+]] = load i32, ptr [[UB]] // CHECK-NEXT: [[CMP:%.+]] = icmp sle i32 [[IV]], [[UB_VAL]] // CHECK-NEXT: br i1 [[CMP]], label %[[IT_BODY:[^,]+]], label %[[IT_END:[^,]+]] for (IterDouble i = ia; i < ib; ++i) { // CHECK: [[IT_BODY]]: // Start of body: calculate i from index: -// CHECK: [[IV1:%.+]] = load i32, i32* [[IT_OMP_IV]] +// CHECK: [[IV1:%.+]] = load i32, ptr [[IT_OMP_IV]] // Call of operator+ (i, IV). // CHECK: {{%.+}} = invoke {{.+}} @{{.*}}IterDouble{{.*}} // ... loop body ... @@ -564,17 +564,17 @@ void iter_simple(IterDouble ia, IterDouble ib, IterDouble ic) { // Float multiply and save result. // CHECK: [[MULR:%.+]] = fmul double {{%.+}}, 5.000000e-01 // CHECK-NEXT: invoke {{.+}} @{{.*}}IterDouble{{.*}} -// CHECK: store double [[MULR:%.+]], double* [[RESULT_ADDR:%.+]] +// CHECK: store double [[MULR:%.+]], ptr [[RESULT_ADDR:%.+]] ++ic; // -// CHECK: [[IV2:%.+]] = load i32, i32* [[IT_OMP_IV]] +// CHECK: [[IV2:%.+]] = load i32, ptr [[IT_OMP_IV]] // CHECK-NEXT: [[ADD2:%.+]] = add nsw i32 [[IV2]], 1 -// CHECK-NEXT: store i32 [[ADD2]], i32* [[IT_OMP_IV]] +// CHECK-NEXT: store i32 [[ADD2]], ptr [[IT_OMP_IV]] // br label %{{.*}}, !llvm.loop ![[ITER_LOOP_ID]] } // CHECK: [[IT_END]]: -// CHECK: call void @__kmpc_for_static_fini(%struct.ident_t* {{.+}}, i32 %{{.+}}) -// CHECK: call void @__kmpc_barrier(%struct.ident_t* {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_for_static_fini(ptr {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_barrier(ptr {{.+}}, i32 %{{.+}}) // CHECK: ret void } @@ -585,25 +585,25 @@ void collapsed(float *a, float *b, float *c, float *d) { unsigned j; // middle loop couter, leads to unsigned icmp in loop header. // k declared in the loop init below short l; // inner loop counter -// CHECK: call void @__kmpc_for_static_init_4u(%struct.ident_t* {{[^,]+}}, i32 %{{[^,]+}}, i32 34, i32* %{{[^,]+}}, i32* [[LB:%[^,]+]], i32* [[UB:%[^,]+]], i32* [[STRIDE:%[^,]+]], i32 1, i32 1) -// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]], +// CHECK: call void @__kmpc_for_static_init_4u(ptr {{[^,]+}}, i32 %{{[^,]+}}, i32 34, ptr %{{[^,]+}}, ptr [[LB:%[^,]+]], ptr [[UB:%[^,]+]], ptr [[STRIDE:%[^,]+]], i32 1, i32 1) +// CHECK: [[UB_VAL:%.+]] = load i32, ptr [[UB]], // CHECK: [[CMP:%.+]] = icmp ugt i32 [[UB_VAL]], 119 // CHECK: br i1 [[CMP]], label %[[TRUE:.+]], label %[[FALSE:[^,]+]] // CHECK: [[TRUE]]: // CHECK: br label %[[SWITCH:[^,]+]] // CHECK: [[FALSE]]: -// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]], +// CHECK: [[UB_VAL:%.+]] = load i32, ptr [[UB]], // CHECK: br label %[[SWITCH]] // CHECK: [[SWITCH]]: // CHECK: [[UP:%.+]] = phi i32 [ 119, %[[TRUE]] ], [ [[UB_VAL]], %[[FALSE]] ] -// CHECK: store i32 [[UP]], i32* [[UB]], -// CHECK: [[LB_VAL:%.+]] = load i32, i32* [[LB]], -// CHECK: store i32 [[LB_VAL]], i32* [[OMP_IV:%[^,]+]], +// CHECK: store i32 [[UP]], ptr [[UB]], +// CHECK: [[LB_VAL:%.+]] = load i32, ptr [[LB]], +// CHECK: store i32 [[LB_VAL]], ptr [[OMP_IV:%[^,]+]], // #pragma omp for simd collapse(4) -// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]] -// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]] +// CHECK: [[IV:%.+]] = load i32, ptr [[OMP_IV]] +// CHECK: [[UB_VAL:%.+]] = load i32, ptr [[UB]] // CHECK-NEXT: [[CMP:%.+]] = icmp ule i32 [[IV]], [[UB_VAL]] // CHECK-NEXT: br i1 [[CMP]], label %[[COLL1_BODY:[^,]+]], label %[[COLL1_END:[^,]+]] for (i = 1; i < 3; i++) // 2 iterations @@ -613,31 +613,31 @@ void collapsed(float *a, float *b, float *c, float *d) { { // CHECK: [[COLL1_BODY]]: // Start of body: calculate i from index: -// CHECK: [[IV1:%.+]] = load i32, i32* [[OMP_IV]] +// CHECK: [[IV1:%.+]] = load i32, ptr [[OMP_IV]] // Calculation of the loop counters values. // CHECK: [[CALC_I_1:%.+]] = udiv i32 [[IV1]], 60 // CHECK-NEXT: [[CALC_I_1_MUL1:%.+]] = mul i32 [[CALC_I_1]], 1 // CHECK-NEXT: [[CALC_I_2:%.+]] = add i32 1, [[CALC_I_1_MUL1]] -// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]] +// CHECK-NEXT: store i32 [[CALC_I_2]], ptr [[LC_I:.+]] -// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]] -// CHECK: [[IV1_2_1:%.+]] = load i32, i32* [[OMP_IV]] +// CHECK: [[IV1_2:%.+]] = load i32, ptr [[OMP_IV]] +// CHECK: [[IV1_2_1:%.+]] = load i32, ptr [[OMP_IV]] // CHECK-NEXT: [[CALC_J_1:%.+]] = udiv i32 [[IV1_2_1]], 60 // CHECK-NEXT: [[MUL_1:%.+]] = mul i32 [[CALC_J_1]], 60 // CHECK-NEXT: [[SUB_3:%.+]] = sub i32 [[IV1_2]], [[MUL_1]] // CHECK-NEXT: [[CALC_J_2:%.+]] = udiv i32 [[SUB_3]], 20 // CHECK-NEXT: [[CALC_J_2_MUL1:%.+]] = mul i32 [[CALC_J_2]], 1 // CHECK-NEXT: [[CALC_J_3:%.+]] = add i32 2, [[CALC_J_2_MUL1]] -// CHECK-NEXT: store i32 [[CALC_J_3]], i32* [[LC_J:.+]] +// CHECK-NEXT: store i32 [[CALC_J_3]], ptr [[LC_J:.+]] -// CHECK: [[IV1_3:%.+]] = load i32, i32* [[OMP_IV]] -// CHECK: [[IV1_3_1:%.+]] = load i32, i32* [[OMP_IV]] +// CHECK: [[IV1_3:%.+]] = load i32, ptr [[OMP_IV]] +// CHECK: [[IV1_3_1:%.+]] = load i32, ptr [[OMP_IV]] // CHECK-NEXT: [[DIV_1:%.+]] = udiv i32 [[IV1_3_1]], 60 // CHECK-NEXT: [[MUL_2:%.+]] = mul i32 [[DIV_1]], 60 // CHECK-NEXT: [[ADD_3:%.+]] = sub i32 [[IV1_3]], [[MUL_2]] -// CHECK: [[IV1_4:%.+]] = load i32, i32* [[OMP_IV]] -// CHECK: [[IV1_4_1:%.+]] = load i32, i32* [[OMP_IV]] +// CHECK: [[IV1_4:%.+]] = load i32, ptr [[OMP_IV]] +// CHECK: [[IV1_4_1:%.+]] = load i32, ptr [[OMP_IV]] // CHECK-NEXT: [[DIV_2:%.+]] = udiv i32 [[IV1_4_1]], 60 // CHECK-NEXT: [[MUL_3:%.+]] = mul i32 [[DIV_2]], 60 // CHECK-NEXT: [[SUB_6:%.+]] = sub i32 [[IV1_4]], [[MUL_3]] @@ -647,16 +647,16 @@ void collapsed(float *a, float *b, float *c, float *d) { // CHECK-NEXT: [[DIV_4:%.+]] = udiv i32 [[SUB_7]], 5 // CHECK-NEXT: [[MUL_5:%.+]] = mul i32 [[DIV_4]], 1 // CHECK-NEXT: [[ADD_6:%.+]] = add i32 3, [[MUL_5]] -// CHECK-NEXT: store i32 [[ADD_6]], i32* [[LC_K:.+]] +// CHECK-NEXT: store i32 [[ADD_6]], ptr [[LC_K:.+]] -// CHECK: [[IV1_5:%.+]] = load i32, i32* [[OMP_IV]] -// CHECK: [[IV1_5_1:%.+]] = load i32, i32* [[OMP_IV]] +// CHECK: [[IV1_5:%.+]] = load i32, ptr [[OMP_IV]] +// CHECK: [[IV1_5_1:%.+]] = load i32, ptr [[OMP_IV]] // CHECK-NEXT: [[DIV_5:%.+]] = udiv i32 [[IV1_5_1]], 60 // CHECK-NEXT: [[MUL_6:%.+]] = mul i32 [[DIV_5]], 60 // CHECK-NEXT: [[ADD_7:%.+]] = sub i32 [[IV1_5]], [[MUL_6]] -// CHECK: [[IV1_6:%.+]] = load i32, i32* [[OMP_IV]] -// CHECK: [[IV1_6_1:%.+]] = load i32, i32* [[OMP_IV]] +// CHECK: [[IV1_6:%.+]] = load i32, ptr [[OMP_IV]] +// CHECK: [[IV1_6_1:%.+]] = load i32, ptr [[OMP_IV]] // CHECK-NEXT: [[DIV_6:%.+]] = udiv i32 [[IV1_6_1]], 60 // CHECK-NEXT: [[MUL_7:%.+]] = mul i32 [[DIV_6]], 60 // CHECK-NEXT: [[SUB_10:%.+]] = sub i32 [[IV1_6]], [[MUL_7]] @@ -664,14 +664,14 @@ void collapsed(float *a, float *b, float *c, float *d) { // CHECK-NEXT: [[MUL_8:%.+]] = mul i32 [[DIV_7]], 20 // CHECK-NEXT: [[ADD_9:%.+]] = sub i32 [[ADD_7]], [[MUL_8]] -// CHECK: [[IV1_7:%.+]] = load i32, i32* [[OMP_IV]] -// CHECK: [[IV1_7_1:%.+]] = load i32, i32* [[OMP_IV]] +// CHECK: [[IV1_7:%.+]] = load i32, ptr [[OMP_IV]] +// CHECK: [[IV1_7_1:%.+]] = load i32, ptr [[OMP_IV]] // CHECK-NEXT: [[DIV_8:%.+]] = udiv i32 [[IV1_7_1]], 60 // CHECK-NEXT: [[MUL_9:%.+]] = mul i32 [[DIV_8]], 60 // CHECK-NEXT: [[ADD_10:%.+]] = sub i32 [[IV1_7]], [[MUL_9]] -// CHECK: [[IV1_8:%.+]] = load i32, i32* [[OMP_IV]] -// CHECK: [[IV1_8_1:%.+]] = load i32, i32* [[OMP_IV]] +// CHECK: [[IV1_8:%.+]] = load i32, ptr [[OMP_IV]] +// CHECK: [[IV1_8_1:%.+]] = load i32, ptr [[OMP_IV]] // CHECK-NEXT: [[DIV_3:%.+]] = udiv i32 [[IV1_8_1]], 60 // CHECK-NEXT: [[MUL_4:%.+]] = mul i32 [[DIV_3]], 60 // CHECK-NEXT: [[SUB_7:%.+]] = sub i32 [[IV1_8]], [[MUL_4]] @@ -684,26 +684,26 @@ void collapsed(float *a, float *b, float *c, float *d) { // CHECK-NEXT: [[MUL_6:%.+]] = mul i32 [[SUB_9]], 1 // CHECK-NEXT: [[CALC_L_2:%.+]] = add i32 4, [[MUL_6]] // CHECK-NEXT: [[CALC_L_3:%.+]] = trunc i32 [[CALC_L_2]] to i16 -// CHECK-NEXT: store i16 [[CALC_L_3]], i16* [[LC_L:.+]] +// CHECK-NEXT: store i16 [[CALC_L_3]], ptr [[LC_L:.+]] // ... loop body ... // End of body: store into a[i]: -// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]] +// CHECK: store float [[RESULT:%.+]], ptr [[RESULT_ADDR:%.+]] float res = b[j] * c[k]; a[i] = res * d[l]; -// CHECK: [[IV2:%.+]] = load i32, i32* [[OMP_IV]] +// CHECK: [[IV2:%.+]] = load i32, ptr [[OMP_IV]] // CHECK-NEXT: [[ADD2:%.+]] = add i32 [[IV2]], 1 -// CHECK-NEXT: store i32 [[ADD2]], i32* [[OMP_IV]] +// CHECK-NEXT: store i32 [[ADD2]], ptr [[OMP_IV]] // br label %{{[^,]+}}, !llvm.loop ![[COLL1_LOOP_ID]] // CHECK: [[COLL1_END]]: } // i,j,l are updated; k is not updated. -// CHECK: call void @__kmpc_for_static_fini(%struct.ident_t* {{.+}}, i32 %{{.+}}) +// CHECK: call void @__kmpc_for_static_fini(ptr {{.+}}, i32 %{{.+}}) // CHECK: br i1 -// CHECK: store i32 3, i32* +// CHECK: store i32 3, ptr // CHECK-NEXT: store i32 5, // CHECK-NEXT: store i32 7, -// CHECK-NEXT: store i16 9, i16* -// CHECK: call void @__kmpc_barrier(%struct.ident_t* {{.+}}, i32 %{{.+}}) +// CHECK-NEXT: store i16 9, ptr +// CHECK: call void @__kmpc_barrier(ptr {{.+}}, i32 %{{.+}}) // CHECK: ret void } @@ -716,32 +716,32 @@ void widened(float *a, float *b, float *c, float *d) { short j; // inner loop counter globalfloat = 1.0; int localint = 1; -// CHECK: store double {{.+}}, double* [[GLOBALFLOAT:@.+]] +// CHECK: store double {{.+}}, ptr [[GLOBALFLOAT:@.+]] // Counter is widened to 64 bits. // CHECK: [[MUL:%.+]] = mul nsw i64 2, %{{.+}} // CHECK-NEXT: [[SUB:%.+]] = sub nsw i64 [[MUL]], 1 -// CHECK-NEXT: store i64 [[SUB]], i64* [[OMP_LAST_IT:%[^,]+]], -// CHECK: call void @__kmpc_for_static_init_8(%struct.ident_t* {{[^,]+}}, i32 %{{[^,]+}}, i32 34, i32* %{{[^,]+}}, i64* [[LB:%[^,]+]], i64* [[UB:%[^,]+]], i64* [[STRIDE:%[^,]+]], i64 1, i64 1) -// CHECK-DAG: [[UB_VAL:%.+]] = load i64, i64* [[UB]], -// CHECK-DAG: [[OMP_LAST_IT_VAL:%.+]] = load i64, i64* [[OMP_LAST_IT]], +// CHECK-NEXT: store i64 [[SUB]], ptr [[OMP_LAST_IT:%[^,]+]], +// CHECK: call void @__kmpc_for_static_init_8(ptr {{[^,]+}}, i32 %{{[^,]+}}, i32 34, ptr %{{[^,]+}}, ptr [[LB:%[^,]+]], ptr [[UB:%[^,]+]], ptr [[STRIDE:%[^,]+]], i64 1, i64 1) +// CHECK-DAG: [[UB_VAL:%.+]] = load i64, ptr [[UB]], +// CHECK-DAG: [[OMP_LAST_IT_VAL:%.+]] = load i64, ptr [[OMP_LAST_IT]], // CHECK: [[CMP:%.+]] = icmp sgt i64 [[UB_VAL]], [[OMP_LAST_IT_VAL]] // CHECK: br i1 [[CMP]], label %[[TRUE:.+]], label %[[FALSE:[^,]+]] // CHECK: [[TRUE]]: -// CHECK: [[OMP_LAST_IT_VAL:%.+]] = load i64, i64* [[OMP_LAST_IT]], +// CHECK: [[OMP_LAST_IT_VAL:%.+]] = load i64, ptr [[OMP_LAST_IT]], // CHECK: br label %[[SWITCH:[^,]+]] // CHECK: [[FALSE]]: -// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]], +// CHECK: [[UB_VAL:%.+]] = load i64, ptr [[UB]], // CHECK: br label %[[SWITCH]] // CHECK: [[SWITCH]]: // CHECK: [[UP:%.+]] = phi i64 [ [[OMP_LAST_IT_VAL]], %[[TRUE]] ], [ [[UB_VAL]], %[[FALSE]] ] -// CHECK: store i64 [[UP]], i64* [[UB]], -// CHECK: [[LB_VAL:%.+]] = load i64, i64* [[LB]], -// CHECK: store i64 [[LB_VAL]], i64* [[OMP_IV:%[^,]+]], +// CHECK: store i64 [[UP]], ptr [[UB]], +// CHECK: [[LB_VAL:%.+]] = load i64, ptr [[LB]], +// CHECK: store i64 [[LB_VAL]], ptr [[OMP_IV:%[^,]+]], // #pragma omp for simd collapse(2) private(globalfloat, localint) -// CHECK: [[IV:%.+]] = load i64, i64* [[OMP_IV]] -// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]] +// CHECK: [[IV:%.+]] = load i64, ptr [[OMP_IV]] +// CHECK: [[UB_VAL:%.+]] = load i64, ptr [[UB]] // CHECK-NEXT: [[CMP:%.+]] = icmp sle i64 [[IV]], [[UB_VAL]] // CHECK-NEXT: br i1 [[CMP]], label %[[WIDE1_BODY:[^,]+]], label %[[WIDE1_END:[^,]+]] for (i = 1; i < 3; i++) // 2 iterations @@ -749,36 +749,36 @@ void widened(float *a, float *b, float *c, float *d) { { // CHECK: [[WIDE1_BODY]]: // Start of body: calculate i from index: -// CHECK: [[IV1:%.+]] = load i64, i64* [[OMP_IV]] +// CHECK: [[IV1:%.+]] = load i64, ptr [[OMP_IV]] // Calculation of the loop counters values... -// CHECK: store i32 {{[^,]+}}, i32* [[LC_I:.+]] -// CHECK: [[IV1_2:%.+]] = load i64, i64* [[OMP_IV]] -// CHECK: store i16 {{[^,]+}}, i16* [[LC_J:.+]] +// CHECK: store i32 {{[^,]+}}, ptr [[LC_I:.+]] +// CHECK: [[IV1_2:%.+]] = load i64, ptr [[OMP_IV]] +// CHECK: store i16 {{[^,]+}}, ptr [[LC_J:.+]] // ... loop body ... // // Here we expect store into private double var, not global -// CHECK-NOT: store double {{.+}}, double* [[GLOBALFLOAT]] +// CHECK-NOT: store double {{.+}}, ptr [[GLOBALFLOAT]] globalfloat = (float)j/i; float res = b[j] * c[j]; // Store into a[i]: -// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]] +// CHECK: store float [[RESULT:%.+]], ptr [[RESULT_ADDR:%.+]] a[i] = res * d[i]; // Then there's a store into private var localint: -// CHECK: store i32 {{.+}}, i32* [[LOCALINT:%[^,]+]] +// CHECK: store i32 {{.+}}, ptr [[LOCALINT:%[^,]+]] localint = (int)j; -// CHECK: [[IV2:%.+]] = load i64, i64* [[OMP_IV]] +// CHECK: [[IV2:%.+]] = load i64, ptr [[OMP_IV]] // CHECK-NEXT: [[ADD2:%.+]] = add nsw i64 [[IV2]], 1 -// CHECK-NEXT: store i64 [[ADD2]], i64* [[OMP_IV]] +// CHECK-NEXT: store i64 [[ADD2]], ptr [[OMP_IV]] // // br label %{{[^,]+}}, !llvm.loop ![[WIDE1_LOOP_ID]] // CHECK: [[WIDE1_END]]: } // i,j are updated. -// CHECK: store i32 3, i32* [[I:%[^,]+]] +// CHECK: store i32 3, ptr [[I:%[^,]+]] // CHECK: store i16 // // Here we expect store into original localint, not its privatized version. -// CHECK-NOT: store i32 {{.+}}, i32* [[LOCALINT]] +// CHECK-NOT: store i32 {{.+}}, ptr [[LOCALINT]] localint = (int)j; // CHECK: ret void } diff --git a/clang/test/OpenMP/interop_irbuilder.cpp b/clang/test/OpenMP/interop_irbuilder.cpp index 337af16c5c90a..a0e666955ab11 100644 --- a/clang/test/OpenMP/interop_irbuilder.cpp +++ b/clang/test/OpenMP/interop_irbuilder.cpp @@ -10,23 +10,17 @@ void test1() { int D0, D1; omp_interop_t interop; -#pragma omp interop init(target \ - : interop) +#pragma omp interop init(target : interop) -#pragma omp interop init(targetsync \ - : interop) +#pragma omp interop init(targetsync : interop) -#pragma omp interop init(target \ - : interop) device(device_id) +#pragma omp interop init(target : interop) device(device_id) -#pragma omp interop init(targetsync \ - : interop) device(device_id) +#pragma omp interop init(targetsync : interop) device(device_id) -#pragma omp interop use(interop) depend(in \ - : D0, D1) nowait +#pragma omp interop use(interop) depend(in : D0, D1) nowait -#pragma omp interop destroy(interop) depend(in \ - : D0, D1) +#pragma omp interop destroy(interop) depend(in : D0, D1) } struct S { @@ -39,23 +33,17 @@ void S::member_test() { int device_id = 4; int D0, D1; -#pragma omp interop init(target \ - : interop) +#pragma omp interop init(target : interop) -#pragma omp interop init(targetsync \ - : interop) +#pragma omp interop init(targetsync : interop) -#pragma omp interop init(target \ - : interop) device(device_id) +#pragma omp interop init(target : interop) device(device_id) -#pragma omp interop init(targetsync \ - : interop) device(device_id) +#pragma omp interop init(targetsync : interop) device(device_id) -#pragma omp interop use(interop) depend(in \ - : D0, D1) nowait +#pragma omp interop use(interop) depend(in : D0, D1) nowait -#pragma omp interop destroy(interop) depend(in \ - : D0, D1) +#pragma omp interop destroy(interop) depend(in : D0, D1) } // CHECK-LABEL: @_Z5test1v( // CHECK-NEXT: entry: @@ -69,15 +57,15 @@ void S::member_test() { // CHECK-NEXT: [[DEP_COUNTER_ADDR6:%.*]] = alloca i64, align 8 // CHECK-NEXT: store i32 4, ptr [[DEVICE_ID]], align 4 // CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1:[0-9]+]]) -// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]], ptr [[INTEROP]], i32 1, i32 -1, i64 0, ptr null, i32 0) +// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]], ptr [[INTEROP]], i32 1, i32 -1, i32 0, ptr null, i32 0) // CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM1:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) -// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM1]], ptr [[INTEROP]], i32 2, i32 -1, i64 0, ptr null, i32 0) +// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM1]], ptr [[INTEROP]], i32 2, i32 -1, i32 0, ptr null, i32 0) // CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[DEVICE_ID]], align 4 // CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) -// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM2]], ptr [[INTEROP]], i32 1, i32 [[TMP0]], i64 0, ptr null, i32 0) +// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM2]], ptr [[INTEROP]], i32 1, i32 [[TMP0]], i32 0, ptr null, i32 0) // CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DEVICE_ID]], align 4 // CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM3:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) -// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM3]], ptr [[INTEROP]], i32 2, i32 [[TMP1]], i64 0, ptr null, i32 0) +// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM3]], ptr [[INTEROP]], i32 2, i32 [[TMP1]], i32 0, ptr null, i32 0) // CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds [2 x %struct.kmp_depend_info], ptr [[DOTDEP_ARR_ADDR]], i64 0, i64 0 // CHECK-NEXT: [[TMP3:%.*]] = ptrtoint ptr [[D0]] to i64 // CHECK-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO:%.*]], ptr [[TMP2]], i64 0 @@ -136,18 +124,18 @@ void S::member_test() { // CHECK-NEXT: store i32 4, ptr [[DEVICE_ID]], align 4 // CHECK-NEXT: [[INTEROP:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], ptr [[THIS1]], i32 0, i32 0 // CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) -// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]], ptr [[INTEROP]], i32 1, i32 -1, i64 0, ptr null, i32 0) +// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]], ptr [[INTEROP]], i32 1, i32 -1, i32 0, ptr null, i32 0) // CHECK-NEXT: [[INTEROP2:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[THIS1]], i32 0, i32 0 // CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM3:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) -// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM3]], ptr [[INTEROP2]], i32 2, i32 -1, i64 0, ptr null, i32 0) +// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM3]], ptr [[INTEROP2]], i32 2, i32 -1, i32 0, ptr null, i32 0) // CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[DEVICE_ID]], align 4 // CHECK-NEXT: [[INTEROP4:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[THIS1]], i32 0, i32 0 // CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM5:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) -// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM5]], ptr [[INTEROP4]], i32 1, i32 [[TMP0]], i64 0, ptr null, i32 0) +// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM5]], ptr [[INTEROP4]], i32 1, i32 [[TMP0]], i32 0, ptr null, i32 0) // CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DEVICE_ID]], align 4 // CHECK-NEXT: [[INTEROP6:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[THIS1]], i32 0, i32 0 // CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM7:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) -// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM7]], ptr [[INTEROP6]], i32 2, i32 [[TMP1]], i64 0, ptr null, i32 0) +// CHECK-NEXT: call void @__tgt_interop_init(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM7]], ptr [[INTEROP6]], i32 2, i32 [[TMP1]], i32 0, ptr null, i32 0) // CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds [2 x %struct.kmp_depend_info], ptr [[DOTDEP_ARR_ADDR]], i64 0, i64 0 // CHECK-NEXT: [[TMP3:%.*]] = ptrtoint ptr [[D0]] to i64 // CHECK-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO:%.*]], ptr [[TMP2]], i64 0 diff --git a/clang/test/OpenMP/parallel_for_reduction_task_codegen.cpp b/clang/test/OpenMP/parallel_for_reduction_task_codegen.cpp index 2770409411af2..4a5bad8a9b807 100644 --- a/clang/test/OpenMP/parallel_for_reduction_task_codegen.cpp +++ b/clang/test/OpenMP/parallel_for_reduction_task_codegen.cpp @@ -356,7 +356,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP3:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP2]], i64 [[TMP4]] // CHECK1-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP5]] @@ -378,7 +378,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: [[TMP2:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP2:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 8 // CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 diff --git a/clang/test/OpenMP/parallel_master_reduction_task_codegen.cpp b/clang/test/OpenMP/parallel_master_reduction_task_codegen.cpp index b48892e7eafca..eec89bf274603 100644 --- a/clang/test/OpenMP/parallel_master_reduction_task_codegen.cpp +++ b/clang/test/OpenMP/parallel_master_reduction_task_codegen.cpp @@ -311,7 +311,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP3:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP2]], i64 [[TMP4]] // CHECK1-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP5]] @@ -333,7 +333,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: [[TMP2:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP2:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 8 // CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 diff --git a/clang/test/OpenMP/parallel_reduction_task_codegen.cpp b/clang/test/OpenMP/parallel_reduction_task_codegen.cpp index 0a4f21fc9bf0b..eec48124a4526 100644 --- a/clang/test/OpenMP/parallel_reduction_task_codegen.cpp +++ b/clang/test/OpenMP/parallel_reduction_task_codegen.cpp @@ -302,7 +302,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP3:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP2]], i64 [[TMP4]] // CHECK1-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP5]] @@ -324,7 +324,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: [[TMP2:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP2:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 8 // CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 diff --git a/clang/test/OpenMP/parallel_sections_reduction_task_codegen.cpp b/clang/test/OpenMP/parallel_sections_reduction_task_codegen.cpp index bc48f493eeeee..3d5e5464bb6d9 100644 --- a/clang/test/OpenMP/parallel_sections_reduction_task_codegen.cpp +++ b/clang/test/OpenMP/parallel_sections_reduction_task_codegen.cpp @@ -344,7 +344,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP3:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP2]], i64 [[TMP4]] // CHECK1-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP5]] @@ -366,7 +366,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: [[TMP2:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP2:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 8 // CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 diff --git a/clang/test/OpenMP/reduction_implicit_map.cpp b/clang/test/OpenMP/reduction_implicit_map.cpp index 0fbb708f1bd42..29055bf1706a5 100644 --- a/clang/test/OpenMP/reduction_implicit_map.cpp +++ b/clang/test/OpenMP/reduction_implicit_map.cpp @@ -704,7 +704,7 @@ int main() // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP3:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr double, ptr [[TMP2]], i64 [[TMP4]] // CHECK1-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP5]] @@ -726,7 +726,7 @@ int main() // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: [[TMP2:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP2:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 8 // CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 diff --git a/clang/test/OpenMP/sections_reduction_task_codegen.cpp b/clang/test/OpenMP/sections_reduction_task_codegen.cpp index 2af379d7c0068..fdface64a3ee4 100644 --- a/clang/test/OpenMP/sections_reduction_task_codegen.cpp +++ b/clang/test/OpenMP/sections_reduction_task_codegen.cpp @@ -349,7 +349,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP3:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP2]], i64 [[TMP4]] // CHECK1-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP5]] @@ -371,7 +371,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: [[TMP2:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP2:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 8 // CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 diff --git a/clang/test/OpenMP/target_parallel_for_reduction_task_codegen.cpp b/clang/test/OpenMP/target_parallel_for_reduction_task_codegen.cpp index f6b9bfa0d026f..8c815e96151fe 100644 --- a/clang/test/OpenMP/target_parallel_for_reduction_task_codegen.cpp +++ b/clang/test/OpenMP/target_parallel_for_reduction_task_codegen.cpp @@ -369,7 +369,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP3:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP2]], i64 [[TMP4]] // CHECK1-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP5]] @@ -391,7 +391,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: [[TMP2:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP2:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 8 // CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 diff --git a/clang/test/OpenMP/target_parallel_reduction_task_codegen.cpp b/clang/test/OpenMP/target_parallel_reduction_task_codegen.cpp index f1f257c5dac94..0ad703cfe2591 100644 --- a/clang/test/OpenMP/target_parallel_reduction_task_codegen.cpp +++ b/clang/test/OpenMP/target_parallel_reduction_task_codegen.cpp @@ -315,7 +315,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP3:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP2]], i64 [[TMP4]] // CHECK1-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP5]] @@ -337,7 +337,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: [[TMP2:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP2:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 8 // CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 diff --git a/clang/test/OpenMP/target_teams_distribute_parallel_for_reduction_task_codegen.cpp b/clang/test/OpenMP/target_teams_distribute_parallel_for_reduction_task_codegen.cpp index df9cd7731f856..f0e84b691a577 100644 --- a/clang/test/OpenMP/target_teams_distribute_parallel_for_reduction_task_codegen.cpp +++ b/clang/test/OpenMP/target_teams_distribute_parallel_for_reduction_task_codegen.cpp @@ -344,7 +344,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP3:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP2]], i64 [[TMP4]] // CHECK1-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP5]] @@ -366,7 +366,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: [[TMP2:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP2:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 8 // CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 @@ -708,7 +708,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP3:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP2]], i64 [[TMP4]] // CHECK1-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP5]] @@ -730,7 +730,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: [[TMP2:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP2:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 8 // CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 diff --git a/clang/test/OpenMP/taskloop_reduction_codegen.cpp b/clang/test/OpenMP/taskloop_reduction_codegen.cpp index 23489126b7e8d..ee2dde82e24f0 100644 --- a/clang/test/OpenMP/taskloop_reduction_codegen.cpp +++ b/clang/test/OpenMP/taskloop_reduction_codegen.cpp @@ -175,13 +175,13 @@ sum = 0.0; // CHECK: call void @llvm.memcpy.p0.p0.i64( // CHECK: define internal void @[[RED_FINI2]](ptr noundef %0) -// CHECK: [[RED_SIZE1_ADDR:%.+]] = call ptr @llvm.threadlocal.address.p0(ptr [[RED_SIZE1]] +// CHECK: [[RED_SIZE1_ADDR:%.+]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 [[RED_SIZE1]] // CHECK: load i64, ptr [[RED_SIZE1_ADDR]] // CHECK: call void @ // CHECK: ret void // CHECK: define internal void @[[RED_COMB2]](ptr noundef %0, ptr noundef %1) -// CHECK: [[RED_SIZE1_ADDR2:%.+]] = call ptr @llvm.threadlocal.address.p0(ptr [[RED_SIZE1]] +// CHECK: [[RED_SIZE1_ADDR2:%.+]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 [[RED_SIZE1]] // CHECK: load i64, ptr [[RED_SIZE1_ADDR2]] // CHECK: call void [[OMP_COMB1]]( // CHECK: ret void @@ -196,13 +196,13 @@ sum = 0.0; // CHECK: ret void // CHECK: define internal void @[[RED_INIT4]](ptr noalias noundef %{{.+}}, ptr noalias noundef %{{.+}}) -// CHECK: [[RED_SIZE2_ADDR:%.+]] = call ptr @llvm.threadlocal.address.p0(ptr [[RED_SIZE2]] +// CHECK: [[RED_SIZE2_ADDR:%.+]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 [[RED_SIZE2]] // CHECK: load i64, ptr [[RED_SIZE2_ADDR]] // CHECK: store float 0.000000e+00, ptr % // CHECK: ret void // CHECK: define internal void @[[RED_COMB4]](ptr noundef %0, ptr noundef %1) -// CHECK: [[RED_SIZE2_ADDR2:%.+]] = call ptr @llvm.threadlocal.address.p0(ptr [[RED_SIZE2]] +// CHECK: [[RED_SIZE2_ADDR2:%.+]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 [[RED_SIZE2]] // CHECK: load i64, ptr [[RED_SIZE2_ADDR2]] // CHECK: fadd float % // CHECK: store float %{{.+}}, ptr % diff --git a/clang/test/OpenMP/teams_distribute_parallel_for_reduction_task_codegen.cpp b/clang/test/OpenMP/teams_distribute_parallel_for_reduction_task_codegen.cpp index 846aa737453b9..e4810956330bc 100644 --- a/clang/test/OpenMP/teams_distribute_parallel_for_reduction_task_codegen.cpp +++ b/clang/test/OpenMP/teams_distribute_parallel_for_reduction_task_codegen.cpp @@ -348,7 +348,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP3:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP2]], i64 [[TMP4]] // CHECK1-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP5]] @@ -370,7 +370,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: [[TMP2:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP2:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 8 // CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 @@ -712,7 +712,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP3:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP2]], i64 [[TMP4]] // CHECK1-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP5]] @@ -734,7 +734,7 @@ int main(int argc, char **argv) { // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: [[TMP2:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @{{reduction_size[.].+[.]}}) +// CHECK1-NEXT: [[TMP2:%.*]] = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @{{reduction_size[.].+[.]}}) // CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 8 // CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 diff --git a/clang/test/PCH/arc-blocks.mm b/clang/test/PCH/arc-blocks.mm index fc7a8c445ade7..736a9144675f6 100644 --- a/clang/test/PCH/arc-blocks.mm +++ b/clang/test/PCH/arc-blocks.mm @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-apple-darwin10 -fobjc-arc -fblocks -std=c++1y -emit-pch %s -o %t -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-apple-darwin10 -fobjc-arc -fblocks -std=c++1y -include-pch %t -fobjc-avoid-heapify-local-blocks -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -fblocks -std=c++1y -emit-pch %s -o %t +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -fblocks -std=c++1y -include-pch %t -fobjc-avoid-heapify-local-blocks -emit-llvm -o - %s | FileCheck %s #ifndef HEADER_INCLUDED #define HEADER_INCLUDED @@ -25,8 +25,6 @@ inline void assignmentConditional(id a, bool c) { #else -// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 } - namespace test_block_retain { // CHECK-LABEL: define linkonce_odr void @_ZN17test_block_retain14initializationEP11objc_object( // CHECK-NOT: call i8* @llvm.objc.retainBlock( @@ -36,10 +34,8 @@ void test_initialization(id a) { } // CHECK-LABEL: define{{.*}} void @_ZN17test_block_retain26test_assignmentConditionalEP11objc_objectb( -// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8 -// CHECK: %[[V4:.*]] = bitcast <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]] to void ()* -// CHECK: %[[V5:.*]] = bitcast void ()* %[[V4]] to i8* -// CHECK: call i8* @llvm.objc.retainBlock(i8* %[[V5]]) +// CHECK: %[[BLOCK:.*]] = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8 +// CHECK: call ptr @llvm.objc.retainBlock(ptr %[[BLOCK]]) void test_assignmentConditional(id a, bool c) { assignmentConditional(a, c); diff --git a/clang/test/PCH/cxx1y-init-captures.cpp b/clang/test/PCH/cxx1y-init-captures.cpp index 7f8a9fa4b3c1d..c19dd90ac90be 100644 --- a/clang/test/PCH/cxx1y-init-captures.cpp +++ b/clang/test/PCH/cxx1y-init-captures.cpp @@ -25,6 +25,7 @@ int y = counter(); void g() { f(0); // ok // expected-error@18 {{lvalue of type 'const char *const'}} + // expected-note@18 {{substituting into a lambda}} f("foo"); // expected-note {{here}} } diff --git a/clang/test/Parser/cxx-namespace-after-missing-semicolon.cpp b/clang/test/Parser/cxx-namespace-after-missing-semicolon.cpp new file mode 100644 index 0000000000000..6d2dc606ef642 --- /dev/null +++ b/clang/test/Parser/cxx-namespace-after-missing-semicolon.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +UNKNOWN_MACRO_1("z", 1) // expected-error {{a type specifier is required for all declarations}} +// expected-error@-1 {{expected ';' after top level declarator}} + +namespace foo { + class bar {}; +} + +int variable = 0; // ok +foo::bar something; // ok + +UNKNOWN_MACRO_2(void) // expected-error {{a type specifier is required for all declarations}} +// expected-error@-1 {{expected ';' after top level declarator}} + +namespace baz { + using Bool = bool; +} + +int variable2 = 2; // ok +const baz::Bool flag = false; // ok diff --git a/clang/test/Parser/cxx-template-recovery.cpp b/clang/test/Parser/cxx-template-recovery.cpp new file mode 100644 index 0000000000000..e22f6c55e3f0c --- /dev/null +++ b/clang/test/Parser/cxx-template-recovery.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template +void Foo::Bar(void* aRawPtr) { // expected-error {{no template named 'Foo'}} + (void)(aRawPtr); +} + +namespace baz { + class klass {}; +} + +int *variable = 0; // ok +const baz::klass object; // ok diff --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c index f4d4a5793b080..146e4c2237f0e 100644 --- a/clang/test/Preprocessor/init.c +++ b/clang/test/Preprocessor/init.c @@ -8,14 +8,24 @@ // BLOCKS:#define __BLOCKS__ 1 // BLOCKS:#define __block __attribute__((__blocks__(byref))) // +// RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=c++26 -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix CXX26 %s +// RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=c++2c -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix CXX26 %s +// +// CXX26:#define __GNUG__ 4 +// CXX26:#define __GXX_EXPERIMENTAL_CXX0X__ 1 +// CXX26:#define __GXX_RTTI 1 +// CXX26:#define __GXX_WEAK__ 1 +// CXX26:#define __cplusplus 202400L +// CXX26:#define __private_extern__ extern // // RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=c++23 -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix CXX2B %s +// RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=c++2b -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix CXX2B %s // // CXX2B:#define __GNUG__ 4 // CXX2B:#define __GXX_EXPERIMENTAL_CXX0X__ 1 // CXX2B:#define __GXX_RTTI 1 // CXX2B:#define __GXX_WEAK__ 1 -// CXX2B:#define __cplusplus 202101L +// CXX2B:#define __cplusplus 202302L // CXX2B:#define __private_extern__ extern // // RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=c++20 -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix CXX2A %s @@ -133,11 +143,20 @@ // RUN: %clang_cc1 -ffreestanding -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix FREESTANDING %s // FREESTANDING:#define __STDC_HOSTED__ 0 // +// RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=gnu++26 -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GXX26 %s +// RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=gnu++2c -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GXX26 %s +// +// GXX26:#define __GNUG__ 4 +// GXX26:#define __GXX_WEAK__ 1 +// GXX26:#define __cplusplus 202400L +// GXX26:#define __private_extern__ extern +// // RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=gnu++23 -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GXX2B %s +// RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=gnu++2b -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GXX2B %s // // GXX2B:#define __GNUG__ 4 // GXX2B:#define __GXX_WEAK__ 1 -// GXX2B:#define __cplusplus 202101L +// GXX2B:#define __cplusplus 202302L // GXX2B:#define __private_extern__ extern // // RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=gnu++20 -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GXX2A %s diff --git a/clang/test/Profile/objc-general.m b/clang/test/Profile/objc-general.m index 1177d14eef17e..a3dcb1b2128c6 100644 --- a/clang/test/Profile/objc-general.m +++ b/clang/test/Profile/objc-general.m @@ -1,9 +1,9 @@ // Test instrumentation of general constructs in objective C. -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instrument=clang | FileCheck -check-prefix=PGOGEN %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instrument=clang | FileCheck -check-prefix=PGOGEN %s // RUN: llvm-profdata merge %S/Inputs/objc-general.proftext -o %t.profdata -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck -check-prefix=PGOUSE %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck -check-prefix=PGOUSE %s // PGOUSE-NOT: warning: profile data may be out of date @@ -44,7 +44,7 @@ + (void)foreach: (NSArray *)array; @implementation A // PGOGEN: define {{.*}}+[A foreach:] // PGOUSE: define {{.*}}+[A foreach:] -// PGOGEN: store {{.*}} @[[FRC]], i32 0, i32 0 +// PGOGEN: store {{.*}} @[[FRC]] + (void)foreach: (NSArray *)array { __block id result; @@ -54,7 +54,7 @@ + (void)foreach: (NSArray *)array for (id x in array) { // PGOGEN: define {{.*}}_block_invoke // PGOUSE: define {{.*}}_block_invoke - // PGOGEN: store {{.*}} @[[BLC]], i32 0, i32 0 + // PGOGEN: store {{.*}} @[[BLC]] ^{ static int init = 0; // PGOGEN: store {{.*}} @[[BLC]], i32 0, i32 1 diff --git a/clang/test/Rewriter/rewrite-super-message.mm b/clang/test/Rewriter/rewrite-super-message.mm index 3a702525f97cc..def62de1136e8 100644 --- a/clang/test/Rewriter/rewrite-super-message.mm +++ b/clang/test/Rewriter/rewrite-super-message.mm @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -no-opaque-pointers -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-runtime=macosx-fragile-10.5 %s -o %t-rw.cpp -// RUN: %clang_cc1 -no-opaque-pointers -fsyntax-only -Wno-address-of-temporary -DKEEP_ATTRIBUTES -D"id=struct objc_object *" -D"Class=struct objc_class *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o - %t-rw.cpp | FileCheck %t-rw.cpp +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-runtime=macosx-fragile-10.5 %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -DKEEP_ATTRIBUTES -D"id=struct objc_object *" -D"Class=struct objc_class *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o - %t-rw.cpp | FileCheck %t-rw.cpp // radar 7738453 void *sel_registerName(const char *); @@ -17,7 +17,7 @@ - (const char *)UTF8String { } @end -// CHECK: call %struct.objc_class* @class_getSuperclass +// CHECK: call ptr @class_getSuperclass @class NSZone; diff --git a/clang/test/Sema/ms_predefined_expr.cpp b/clang/test/Sema/ms_predefined_expr.cpp new file mode 100644 index 0000000000000..be56c59e5a126 --- /dev/null +++ b/clang/test/Sema/ms_predefined_expr.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 %s -fsyntax-only -Wmicrosoft -verify -fms-extensions + +void f() { + const char a[] = __FUNCTION__; // expected-warning{{initializing an array from a '__FUNCTION__' predefined identifier is a Microsoft extension}} + const char b[] = __FUNCDNAME__; // expected-warning{{initializing an array from a '__FUNCDNAME__' predefined identifier is a Microsoft extension}} + const char c[] = __FUNCSIG__; // expected-warning{{initializing an array from a '__FUNCSIG__' predefined identifier is a Microsoft extension}} + const char d[] = __func__; // expected-warning{{initializing an array from a '__func__' predefined identifier is a Microsoft extension}} + const char e[] = __PRETTY_FUNCTION__; // expected-warning{{initializing an array from a '__PRETTY_FUNCTION__' predefined identifier is a Microsoft extension}} +} diff --git a/clang/test/Sema/ppc-mma-builtins.c b/clang/test/Sema/ppc-mma-builtins.c deleted file mode 100644 index 20d779557d28a..0000000000000 --- a/clang/test/Sema/ppc-mma-builtins.c +++ /dev/null @@ -1,33 +0,0 @@ -// REQUIRES: powerpc-registered-target -// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -target-cpu pwr10 \ -// RUN: -target-feature -mma -fsyntax-only %s -verify - -void test1(unsigned char *vqp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { - __vector_pair res; - __builtin_vsx_assemble_pair(&res, vc, vc); -} - -void test2(unsigned char *vqp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { - __builtin_vsx_disassemble_pair(resp, (__vector_pair*)vpp); -} - -void test3(const __vector_pair *vpp, signed long offset, __vector_pair *vp2) { - __vector_pair vp = __builtin_vsx_lxvp(offset, vpp); - __builtin_vsx_stxvp(vp, offset, vp2); -} - -void test4(unsigned char *vqp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { - __vector_quad vq = *((__vector_quad *)vqp); - __vector_pair vp = *((__vector_pair *)vpp); - __builtin_mma_xxmtacc(&vq); // expected-error {{this builtin is only valid on POWER10 or later CPUs}} - *((__vector_quad *)resp) = vq; -} - -void test5(unsigned char *vqp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { - __vector_quad vq = *((__vector_quad *)vqp); - __vector_pair vp = *((__vector_pair *)vpp); - __builtin_mma_pmxvf64ger(&vq, vp, vc, 0, 0); // expected-error {{this builtin is only valid on POWER10 or later CPUs}} - *((__vector_quad *)resp) = vq; -} - - diff --git a/clang/test/Sema/ppc-paired-vector-builtins.c b/clang/test/Sema/ppc-paired-vector-builtins.c deleted file mode 100644 index 67010909256fa..0000000000000 --- a/clang/test/Sema/ppc-paired-vector-builtins.c +++ /dev/null @@ -1,28 +0,0 @@ -// REQUIRES: powerpc-registered-target -// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -target-cpu pwr10 \ -// RUN: -target-feature -paired-vector-memops -fsyntax-only %s -verify -// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -target-cpu pwr9 \ -// RUN: -fsyntax-only %s -verify - -void test1(unsigned char *vqp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { - __vector_pair res; - __builtin_vsx_assemble_pair(&res, vc, vc); // expected-error {{this builtin is only valid on POWER10 or later CPUs}} -} - -void test2(unsigned char *vqp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { - __builtin_vsx_disassemble_pair(resp, (__vector_pair*)vpp); // expected-error {{this builtin is only valid on POWER10 or later CPUs}} -} - -void test3(const __vector_pair *vpp, signed long long offset, const __vector_pair *vp2) { - __vector_pair vp = __builtin_vsx_lxvp(offset, vpp); // expected-error {{this builtin is only valid on POWER10 or later CPUs}} - __builtin_vsx_stxvp(vp, offset, vp2); // expected-error {{this builtin is only valid on POWER10 or later CPUs}} -} - -void test4(unsigned char *vqp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { - __vector_quad vq = *((__vector_quad *)vqp); - __vector_pair vp = *((__vector_pair *)vpp); - __builtin_mma_xxmtacc(&vq); // expected-error {{this builtin is only valid on POWER10 or later CPUs}} - *((__vector_quad *)resp) = vq; -} - - diff --git a/clang/test/SemaCXX/GH62596.cpp b/clang/test/SemaCXX/GH62596.cpp new file mode 100644 index 0000000000000..c3fefe693db98 --- /dev/null +++ b/clang/test/SemaCXX/GH62596.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s + +struct foo { + static constexpr bool bar() { + return true; + } + + template + static constexpr bool baz() { + return B; + } +}; +static_assert(foo::baz(), ""); + +// expected-no-diagnostics diff --git a/clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp b/clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp index e9e2ecab8e028..dcc964cd60b34 100644 --- a/clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp +++ b/clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp @@ -563,8 +563,8 @@ struct X { int g() { auto L = [=](auto a) { - return [](int i) { // expected-note {{explicitly capture 'this'}} - return [=](auto b) { + return [](int i) { // expected-note {{explicitly capture 'this'}} expected-note {{while substituting into a lambda}} + return [=](auto b) { // expected-note {{while substituting into a lambda}} f(decltype(a){}); //expected-error{{this}} int x = i; }; @@ -587,8 +587,8 @@ struct X { int g() { auto L = [=](auto a) { - return [](auto b) { // expected-note {{explicitly capture 'this'}} - return [=](int i) { + return [](auto b) { // expected-note {{explicitly capture 'this'}} expected-note {{while substituting into a lambda}} + return [=](int i) { // expected-note {{while substituting into a lambda}} f(b); f(decltype(a){}); //expected-error{{this}} }; @@ -612,7 +612,7 @@ struct X { int g() { auto L = [=](auto a) { return [](auto b) { // expected-note {{explicitly capture 'this'}} - return [=](int i) { + return [=](int i) { // expected-note {{while substituting into a lambda}} f(b); //expected-error{{this}} f(decltype(a){}); }; diff --git a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp index 61dfd654f6d65..3c2d460ab9b4a 100644 --- a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp +++ b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp @@ -259,7 +259,7 @@ int test() { { int i = 10; //expected-note 3{{declared here}} auto L = [](auto a) { - return [](auto b) { //expected-note 3{{begins here}} expected-note 6 {{capture 'i' by}} expected-note 6 {{default capture by}} + return [](auto b) { //expected-note 3{{begins here}} expected-note 6 {{capture 'i' by}} expected-note 6 {{default capture by}} expected-note {{while substituting into a lambda}} i = b; //expected-error 3{{cannot be implicitly captured}} return b; }; diff --git a/clang/test/SemaCXX/cxx1y-init-captures.cpp b/clang/test/SemaCXX/cxx1y-init-captures.cpp index 1c1c93c757a0d..4cb53cc8bfc1c 100644 --- a/clang/test/SemaCXX/cxx1y-init-captures.cpp +++ b/clang/test/SemaCXX/cxx1y-init-captures.cpp @@ -21,17 +21,17 @@ namespace variadic_expansion { return a; }() ...); }; - auto N2 = [x = y, //expected-note3{{begins here}} expected-note 6 {{default capture by}} + auto N2 = [x = y, //expected-note3{{begins here}} expected-note 6 {{default capture by}} expected-note 2 {{substituting into a lambda}} &z = y, n = f(t...), o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...)](T& ... s) { // expected-note 6 {{capture 't' by}} - fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}} + fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}} expected-note 2{{substituting into a lambda}} return a; }() ...); }; } - void h(int i, char c) { g(i, c); } //expected-note{{in instantiation}} + void h(int i, char c) { g(i, c); } //expected-note 2{{in instantiation}} } namespace odr_use_within_init_capture { @@ -117,7 +117,7 @@ int test(T t = T{}) { } { // will need to capture x in outer lambda const T x = 10; //expected-note {{declared}} - auto L = [z = x](char a) { //expected-note {{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}} + auto L = [z = x](char a) { //expected-note {{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}} expected-note {{substituting into a lambda}} auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}} return y; }; @@ -145,7 +145,7 @@ int test(T t = T{}) { } { // will need to capture x in outer lambda const int x = 10; //expected-note {{declared}} - auto L = [z = x](char a) { //expected-note {{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}} + auto L = [z = x](char a) { //expected-note {{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}} expected-note {{substituting into a lambda}} auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}} return y; }; @@ -164,7 +164,7 @@ int test(T t = T{}) { return 0; } -int run = test(); //expected-note {{instantiation}} +int run = test(); //expected-note 2 {{instantiation}} } diff --git a/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp b/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp index 95bc32b603ddf..0cee41ff5ed38 100644 --- a/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp +++ b/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp @@ -46,7 +46,7 @@ class B { template void foo() { (void)[this] { return x; }; - (void)[*this] { return x; }; //expected-error2{{call to deleted}} + (void)[*this] { return x; }; //expected-error2{{call to deleted}} expected-note {{while substituting into a lambda}} } B() = default; @@ -63,7 +63,7 @@ class B { public: template auto foo() { - const auto &L = [*this](auto a) mutable { //expected-error{{call to deleted}} + const auto &L = [*this](auto a) mutable { //expected-error{{call to deleted}} expected-note {{while substituting into a lambda}} d += a; return [this](auto b) { return d += b; }; }; diff --git a/clang/test/SemaCXX/cxx20-decomposition.cpp b/clang/test/SemaCXX/cxx20-decomposition.cpp index 34f46f866c7df..430a158ff458e 100644 --- a/clang/test/SemaCXX/cxx20-decomposition.cpp +++ b/clang/test/SemaCXX/cxx20-decomposition.cpp @@ -177,7 +177,8 @@ namespace ODRUseTests { (void)[&b](auto c) { return b + [](auto) { // expected-note 3{{lambda expression begins here}} \ // expected-note 6{{capture 'a'}} \ // expected-note 6{{default capture}} \ - // expected-note {{in instantiation}} + // expected-note {{in instantiation}} \ + // expected-note {{while substituting into a lambda}} return a; // expected-error 3{{variable 'a' cannot be implicitly captured}} }(0); }(0); // expected-note 2{{in instantiation}} } diff --git a/clang/test/SemaCXX/cxx2a-consteval-default-params.cpp b/clang/test/SemaCXX/cxx2a-consteval-default-params.cpp index 8bce70608be58..dfc32c983e14c 100644 --- a/clang/test/SemaCXX/cxx2a-consteval-default-params.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval-default-params.cpp @@ -79,3 +79,16 @@ namespace ShouldNotCrash { }; void f(A a = A()) { } } + +namespace GH62224 { + consteval int fwd(); + template + struct C { + consteval C(int = fwd()) { } + consteval int get() { return i; } + }; + + consteval int fwd() { return 42; } + C<> Val; // No error since fwd is defined already. + static_assert(Val.get() == 42); +} diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp index aeecf2109beff..b186583a7d82b 100644 --- a/clang/test/SemaCXX/lambda-expressions.cpp +++ b/clang/test/SemaCXX/lambda-expressions.cpp @@ -260,10 +260,11 @@ namespace VariadicPackExpansion { f([&ts] { return (int)f(ts...); } ()...); // \ // expected-error 2{{'ts' cannot be implicitly captured}} \ // expected-note 2{{lambda expression begins here}} \ - // expected-note 4 {{capture 'ts' by}} + // expected-note 4 {{capture 'ts' by}} \ + // expected-note 2 {{while substituting into a lambda}} } template void nested2(int); // ok - template void nested2(int, int); // expected-note {{in instantiation of}} + template void nested2(int, int); // expected-note 2 {{in instantiation of}} } namespace PR13860 { @@ -383,7 +384,7 @@ namespace PR18128 { namespace PR18473 { template void f() { T t(0); - (void) [=]{ int n = t; }; // expected-error {{deleted}} + (void) [=]{ int n = t; }; // expected-error {{deleted}} expected-note {{while substituting into a lambda}} } template void f(); @@ -466,7 +467,7 @@ namespace error_in_transform_prototype { void f(T t) { // expected-error@+2 {{type 'int' cannot be used prior to '::' because it has no members}} // expected-error@+1 {{no member named 'ns' in 'error_in_transform_prototype::S'}} - auto x = [](typename T::ns::type &k) {}; + auto x = [](typename T::ns::type &k) {}; // expected-note 2 {{while substituting into a lambda}} } class S {}; void foo() { diff --git a/clang/test/SemaCXX/lambda-pack-expansion.cpp b/clang/test/SemaCXX/lambda-pack-expansion.cpp index e3e968e2704ed..936e7c6b0e5c5 100644 --- a/clang/test/SemaCXX/lambda-pack-expansion.cpp +++ b/clang/test/SemaCXX/lambda-pack-expansion.cpp @@ -8,6 +8,7 @@ struct X { void take_by_copy(auto &...args) { [...args = args] {}(); // expected-error {{call to deleted constructor}} + // expected-note@-1 {{substituting into a lambda}} } void take_by_ref(auto &...args) { diff --git a/clang/test/SemaCXX/lambda-unevaluated.cpp b/clang/test/SemaCXX/lambda-unevaluated.cpp index 135c6f6bfc05e..179c7327ebdff 100644 --- a/clang/test/SemaCXX/lambda-unevaluated.cpp +++ b/clang/test/SemaCXX/lambda-unevaluated.cpp @@ -28,8 +28,11 @@ static_assert(&unique_test1<[](){}> != &unique_test1<[](){}>); template auto g(T) -> decltype([]() { T::invalid; } ()); -auto e = g(0); // expected-error{{no matching function for call}} -// expected-note@-2 {{substitution failure}} +auto e = g(0); // expected-error@-1{{type 'int' cannot be used prior to '::'}} + // expected-note@-1{{while substituting deduced template}} + // expected-note@-3{{while substituting into a lambda}} + // expected-error@-3 {{no matching function for call to 'g'}} + // expected-note@-5 {{substitution failure}} template auto foo(decltype([] { @@ -146,3 +149,36 @@ using d = decltype(sizeof([] static { return 0; })); namespace lambda_in_trailing_decltype { auto x = ([](auto) -> decltype([] {}()) {}(0), 2); } + +namespace lambda_in_constraints { +struct WithFoo { static void foo(); }; + +template +concept lambda_works = requires { + []() { T::foo(); }; +}; + +static_assert(!lambda_works); +static_assert(lambda_works); + +template +int* func(T) requires requires { []() { T::foo(); }; }; +double* func(...); + +static_assert(__is_same(decltype(func(0)), double*)); +static_assert(__is_same(decltype(func(WithFoo())), int*)); + +template +auto direct_lambda(T) -> decltype([] { T::foo(); }) {} +void direct_lambda(...) {} + +void recursive() { + direct_lambda(0); // expected-error@-4 {{type 'int' cannot be used prior to '::'}} + // expected-note@-1 {{while substituting deduced template arguments}} + // expected-note@-6 {{while substituting into a lambda}} + bool x = requires { direct_lambda(0); }; // expected-error@-7 {{type 'int' cannot be used prior to '::'}} + // expected-note@-1 {{while substituting deduced template arguments}} + // expected-note@-9 {{while substituting into a lambda}} + +} +} diff --git a/clang/test/SemaCXX/pr62174.cpp b/clang/test/SemaCXX/pr62174.cpp new file mode 100644 index 0000000000000..a5283706ec4f6 --- /dev/null +++ b/clang/test/SemaCXX/pr62174.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -std=c++20 %s -fsyntax-only -verify +// expected-no-diagnostics +namespace lib { + namespace impl { + template + inline constexpr bool test = false; + } + using impl::test; +} + +struct foo {}; + +template <> +inline constexpr bool lib::test = true; + +static_assert(lib::test); diff --git a/clang/test/SemaCXX/predefined-expr-msvc.cpp b/clang/test/SemaCXX/predefined-expr-msvc.cpp new file mode 100644 index 0000000000000..a2560f2d2d015 --- /dev/null +++ b/clang/test/SemaCXX/predefined-expr-msvc.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify +// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify -fms-extensions + +// expected-no-diagnostics + +struct StringRef { + StringRef(const char *); +}; +template +StringRef getTypeName() { + StringRef s = __func__; +} + diff --git a/clang/test/SemaCXX/vartemplate-lambda.cpp b/clang/test/SemaCXX/vartemplate-lambda.cpp index 8b232abe976b6..d2b53b53dcd49 100644 --- a/clang/test/SemaCXX/vartemplate-lambda.cpp +++ b/clang/test/SemaCXX/vartemplate-lambda.cpp @@ -8,6 +8,7 @@ template auto v1 = [](int a = T()) { return a; }(); // expected-error@-1{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}} // expected-note@-2{{in instantiation of default function argument expression for 'operator()' required here}} // expected-note@-3{{passing argument to parameter 'a' here}} +// expected-note@-4{{substituting into a lambda}} struct S { template diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp index 62aeb1c24b547..0581ece928a82 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp @@ -220,11 +220,11 @@ void testPointerArithmetic(int * p, const int **q, T * x) { void testTemplate(int * p) { int *a[10]; foo(f(p, &p, a, a)[1]); // expected-warning{{unsafe buffer access}} - // expected-note@-1{{in instantiation of function template specialization 'f' requested here}} + // FIXME: expected note@-1{{in instantiation of function template specialization 'f' requested here}} const int **q = const_cast(&p); - testPointerArithmetic(p, q, p); //expected-note{{in instantiation of}} + testPointerArithmetic(p, q, p); //FIXME: expected note{{in instantiation of}} } void testPointerToMember() { @@ -315,7 +315,7 @@ template void fArr(T t[]) { foo(ar[5]); // expected-note{{used in buffer access here}} } -template void fArr(int t[]); // expected-note {{in instantiation of}} +template void fArr(int t[]); // FIXME: expected note {{in instantiation of}} int testReturn(int t[]) { // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}} diff --git a/clang/test/SemaCXX/warn-unused-lambda-capture.cpp b/clang/test/SemaCXX/warn-unused-lambda-capture.cpp index 52ec390b0bba6..67b8fc3b661c8 100644 --- a/clang/test/SemaCXX/warn-unused-lambda-capture.cpp +++ b/clang/test/SemaCXX/warn-unused-lambda-capture.cpp @@ -145,38 +145,38 @@ void test_templated() { auto explicit_by_value_used_generic = [i](auto c) { return i + 1; }; auto explicit_by_value_used_void = [i] { (void)i; }; - auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}} - auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}} - auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}} - auto explicit_by_value_unused_const = [k] { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}} - auto explicit_by_value_unused_const_generic = [k](auto c) { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}} + auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}} + auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}} expected-note {{substituting into a lambda}} + auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}} + auto explicit_by_value_unused_const = [k] { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}} expected-note {{substituting into a lambda}} + auto explicit_by_value_unused_const_generic = [k](auto c) { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}} expected-note {{substituting into a lambda}} auto explicit_by_reference_used = [&i] { i++; }; - auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}} + auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}} auto explicit_initialized_reference_used = [&j = i] { return j + 1; }; - auto explicit_initialized_reference_unused = [&j = i]{}; // expected-warning{{lambda capture 'j' is not used}} + auto explicit_initialized_reference_unused = [&j = i]{}; // expected-warning{{lambda capture 'j' is not used}} expected-note {{substituting into a lambda}} auto explicit_initialized_value_used = [j = 1] { return j + 1; }; - auto explicit_initialized_value_unused = [j = 1] {}; // expected-warning{{lambda capture 'j' is not used}} + auto explicit_initialized_value_unused = [j = 1] {}; // expected-warning{{lambda capture 'j' is not used}} expected-note {{substituting into a lambda}} auto explicit_initialized_value_non_trivial_constructor = [j = NonTrivialConstructor()]{}; auto explicit_initialized_value_non_trivial_destructor = [j = NonTrivialDestructor()]{}; - auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}} + auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}} expected-note {{substituting into a lambda}} auto explicit_initialized_value_non_trivial_init = [j = Trivial(42)]{}; auto explicit_initialized_value_with_side_effect = [j = side_effect()]{}; auto explicit_initialized_value_generic_used = [i = 1](auto c) mutable { i++; }; - auto explicit_initialized_value_generic_unused = [i = 1](auto c) mutable {}; // expected-warning{{lambda capture 'i' is not used}} + auto explicit_initialized_value_generic_unused = [i = 1](auto c) mutable {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}} - auto nested = [&i] { + auto nested = [&i] { // expected-note {{substituting into a lambda}} auto explicit_by_value_used = [i] { return i + 1; }; - auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}} + auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}} }; Trivial trivial; - auto explicit_by_value_trivial = [trivial] {}; // expected-warning{{lambda capture 'trivial' is not used}} + auto explicit_by_value_trivial = [trivial] {}; // expected-warning{{lambda capture 'trivial' is not used}} expected-note {{substituting into a lambda}} NonTrivialConstructor cons; - auto explicit_by_value_non_trivial_constructor = [cons] {}; // expected-warning{{lambda capture 'cons' is not used}} + auto explicit_by_value_non_trivial_constructor = [cons] {}; // expected-warning{{lambda capture 'cons' is not used}} expected-note {{substituting into a lambda}} NonTrivialCopyConstructor copy_cons; auto explicit_by_value_non_trivial_copy_constructor = [copy_cons] {}; @@ -189,7 +189,7 @@ void test_templated() { } void test_use_template() { - test_templated(); // expected-note{{in instantiation of function template specialization 'test_templated' requested here}} + test_templated(); // expected-note 13{{in instantiation of function template specialization 'test_templated' requested here}} } namespace pr35555 { diff --git a/clang/test/SemaObjC/arc-objc-lifetime-conflict.m b/clang/test/SemaObjC/arc-objc-lifetime-conflict.m index ed7ad2a9c206c..4204ff51d3419 100644 --- a/clang/test/SemaObjC/arc-objc-lifetime-conflict.m +++ b/clang/test/SemaObjC/arc-objc-lifetime-conflict.m @@ -1,19 +1,12 @@ -// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-apple-darwin11 -fobjc-arc -fobjc-runtime-has-weak %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-arc -fobjc-runtime-has-weak %s -emit-llvm -o - | FileCheck %s -// CHECK: bitcast {{.*}} %self_weak_s_w_s -// CHECK-NEXT: llvm.objc.destroyWeak -// CHECK-NEXT: bitcast {{.*}} %self_strong_w_s -// CHECK-NEXT: llvm.objc.storeStrong -// CHECK-NEXT: bitcast {{.*}} %self_weak_s -// CHECK-NEXT: llvm.objc.destroyWeak -// CHECK-NEXT: bitcast {{.*}} %self_weak_s3 -// CHECK-NEXT: llvm.objc.destroyWeak -// CHECK-NEXT: bitcast {{.*}} %self_strong3 -// CHECK-NEXT: llvm.objc.storeStrong -// CHECK-NEXT: bitcast {{.*}} %self_strong2 -// CHECK-NEXT: llvm.objc.storeStrong -// CHECK-NEXT: bitcast {{.*}} %self_strong -// CHECK-NEXT: llvm.objc.storeStrong +// CHECK-DAG: llvm.objc.destroyWeak(ptr %self_weak_s_w_s) +// CHECK-DAG: llvm.objc.storeStrong(ptr %self_strong_w_s, ptr null) +// CHECK-DAG: llvm.objc.destroyWeak(ptr %self_weak_s) +// CHECK-DAG: llvm.objc.destroyWeak(ptr %self_weak_s3) +// CHECK-DAG: llvm.objc.storeStrong(ptr %self_strong3, ptr null) +// CHECK-DAG: llvm.objc.storeStrong(ptr %self_strong2, ptr null) +// CHECK-DAG: llvm.objc.storeStrong(ptr %self_strong, ptr null) @interface NSObject @end @interface A : NSObject diff --git a/clang/test/SemaSYCL/intel-fpga-loops.cpp b/clang/test/SemaSYCL/intel-fpga-loops.cpp index 38dedaa6a4a30..bd82641207594 100644 --- a/clang/test/SemaSYCL/intel-fpga-loops.cpp +++ b/clang/test/SemaSYCL/intel-fpga-loops.cpp @@ -443,7 +443,8 @@ void ivdep_dependent() { a[i] = 0; (void)[]() { - // expected-warning@+3 2{{ignoring redundant Intel FPGA loop attribute 'ivdep': safelen INF >= safelen INF}} + // expected-warning@+4 2{{ignoring redundant Intel FPGA loop attribute 'ivdep': safelen INF >= safelen INF}} + // expected-note@-2 2{{while substituting into a lambda expression here}} // expected-note@+1 2{{previous attribute is here}} [[intel::ivdep]] [[intel::ivdep]] while (true); diff --git a/clang/test/SemaTemplate/concepts-friends.cpp b/clang/test/SemaTemplate/concepts-friends.cpp index 3a9b308a65c5d..5c4609520a3c7 100644 --- a/clang/test/SemaTemplate/concepts-friends.cpp +++ b/clang/test/SemaTemplate/concepts-friends.cpp @@ -441,3 +441,27 @@ namespace NTTP { templ_func<1>(u2); } } + + +namespace FriendOfFriend { + +template +concept Concept = true; + +template class FriendOfBar; + +template class Bar { + template friend class FriendOfBar; +}; + +Bar BarInstance; + +namespace internal { +void FriendOfFoo(FriendOfBar); +} + +template class Foo { + friend void internal::FriendOfFoo(FriendOfBar); +}; + +} // namespace FriendOfFriend diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp index 222b78e0d22f7..b7c91712f8713 100644 --- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp +++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp @@ -127,3 +127,275 @@ static_assert(S::specialization("str") == SPECIALIZATION_CONCEPT); static_assert(S::specialization("str") == SPECIALIZATION_REQUIRES); } // namespace multiple_template_parameter_lists + +static constexpr int CONSTRAINED_METHOD_1 = 1; +static constexpr int CONSTRAINED_METHOD_2 = 2; + +namespace constrained_members { + +template +struct S { + template + static constexpr int constrained_method(); +}; + +template <> +template +constexpr int S<1>::constrained_method() { return CONSTRAINED_METHOD_1; } + +template <> +template +constexpr int S<2>::constrained_method() { return CONSTRAINED_METHOD_2; } + +static_assert(S<1>::constrained_method() == CONSTRAINED_METHOD_1); +static_assert(S<2>::constrained_method() == CONSTRAINED_METHOD_2); + + +template +concept ConceptT1T2 = true; + +template +struct S12 { + template T4> + static constexpr int constrained_method(); +}; + +template<> +template T5> +constexpr int S12::constrained_method() { return CONSTRAINED_METHOD_1; } + +template<> +template T5> +constexpr int S12::constrained_method() { return CONSTRAINED_METHOD_2; } + +static_assert(S12::constrained_method() == CONSTRAINED_METHOD_1); +static_assert(S12::constrained_method() == CONSTRAINED_METHOD_2); + +} // namespace constrained members + +namespace constrained_members_of_nested_types { + +template +struct S { + struct Inner0 { + struct Inner1 { + template + static constexpr int constrained_method(); + }; + }; +}; + +template <> +template +constexpr int S<1>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_1; } + +template <> +template +constexpr int S<2>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_2; } + +static_assert(S<1>::Inner0::Inner1::constrained_method() == CONSTRAINED_METHOD_1); +static_assert(S<2>::Inner0::Inner1::constrained_method() == CONSTRAINED_METHOD_2); + + +template +concept ConceptT1T2 = true; + +template +struct S12 { + struct Inner0 { + struct Inner1 { + template T4> + static constexpr int constrained_method(); + }; + }; +}; + +template<> +template T5> +constexpr int S12::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_1; } + +template<> +template T5> +constexpr int S12::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_2; } + +static_assert(S12::Inner0::Inner1::constrained_method() == CONSTRAINED_METHOD_1); +static_assert(S12::Inner0::Inner1::constrained_method() == CONSTRAINED_METHOD_2); + +} // namespace constrained_members_of_nested_types + +namespace constrained_member_sfinae { + +template struct S { + template + static constexpr int constrained_method() requires (sizeof(int[N * 1073741824 + 4]) == 16) { + return CONSTRAINED_METHOD_1; + } + + template + static constexpr int constrained_method() requires (sizeof(int[N]) == 16); +}; + +template<> +template +constexpr int S<4>::constrained_method() requires (sizeof(int[4]) == 16) { + return CONSTRAINED_METHOD_2; +} + +// Verify that there is no amiguity in this case. +static_assert(S<4>::constrained_method() == CONSTRAINED_METHOD_2); + +} // namespace constrained_member_sfinae + +namespace requires_expression_references_members { + +void accept1(int x); +void accept2(XY xy); + +template struct S { + T Field = T(); + + constexpr int constrained_method() + requires requires { accept1(Field); }; + + constexpr int constrained_method() + requires requires { accept2(Field); }; +}; + +template +constexpr int S::constrained_method() + requires requires { accept1(Field); } { + return CONSTRAINED_METHOD_1; +} + +template +constexpr int S::constrained_method() + requires requires { accept2(Field); } { + return CONSTRAINED_METHOD_2; +} + +static_assert(S().constrained_method() == CONSTRAINED_METHOD_1); +static_assert(S().constrained_method() == CONSTRAINED_METHOD_2); + +} // namespace requires_expression_references_members + +namespace GH60231 { + +template concept C = true; + +template +struct S { + template requires C> + void foo1(F1 f); + + template + void foo2(F2 f) requires C>; + + template requires C + void foo3(F3 f); +}; + +template +template requires C> +void S::foo1(F4 f) {} + +template +template +void S::foo2(F5 f) requires C> {} + +template +template requires C +void S::foo3(F6 f) {} + +} // namespace GH60231 + +namespace GH62003 { + +template concept Concept = true; + +template +struct S1 { + template + static constexpr int foo(); +}; +template +template +constexpr int S1::foo() { return 1; } + +template +struct S2 { + template + static constexpr int foo(); +}; +template +template +constexpr int S2::foo() { return 2; } + +template +struct S3 { + template + static constexpr int foo(); +}; +template +template +constexpr int S3::foo() { return 3; } + +static_assert(S1::foo() == 1); +static_assert(S2::foo() == 2); +static_assert(S3::foo() == 3); + +} // namespace GH62003 + +namespace MultilevelTemplateWithPartialSpecialization { +template +concept Concept = true; + +namespace two_level { +template +struct W0 { + template + requires (Concept) + void f(const T2 &); +}; + +template +struct W0 { + template + requires (Concept) + void f(const T4 &); +}; + +template +template +requires (Concept) +inline void W0::f(const T4 &) {} +} // namespace two_level + +namespace three_level { +template +struct W0 { + template + struct W1 { + template + requires (Concept) + void f(const T3 &); + }; +}; + +template +struct W0 { + template + struct W1 { + template + requires (Concept) + void f(const T6 &); + }; +}; + +template +template +template +requires (Concept) +inline void W0::W1::f(const T9 &) {} +} // namespace three_level + +} // namespace MultilevelTemplateWithPartialSpecialization diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index d28c2b22bd045..c6fb5c441abd6 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -119,7 +119,7 @@ namespace PackInTypeConstraint { []() -> C auto{ return T(); }(); // expected-error {{expression contains unexpanded parameter pack 'T'}} } template void g5() { - ([]() -> C auto{ // expected-error-re {{deduced type {{.*}} does not satisfy}} + ([]() -> C auto{ // expected-error-re {{deduced type {{.*}} does not satisfy}} expected-note {{while substituting into a lambda}} return T(); }(), ...); } @@ -816,3 +816,101 @@ static_assert(Parent::TakesBinary::i == 0); static_assert(Parent::TakesBinary::i == 0); } +namespace TemplateInsideNonTemplateClass { +template concept C = true; + +template auto L = [] U>() {}; + +struct Q { + template U> friend constexpr auto decltype(L)::operator()() const; +}; + +template +concept C1 = false; + +struct Foo { + template + struct Bar {}; + + template + requires(C1) + struct Bar; +}; + +Foo::Bar BarInstance; +} // namespace TemplateInsideNonTemplateClass + +namespace GH61959 { +template +concept C = (sizeof(T0) >= 4); + +template +struct Orig { }; + +template +struct Orig { + template requires C + void f() { } + + template requires true + void f() { } +}; + +template struct Mod {}; + +template +struct Mod { + template requires C + constexpr static int f() { return 1; } + + template requires C + constexpr static int f() { return 2; } +}; + +static_assert(Mod::f() == 1); +static_assert(Mod::f() == 2); + +template +struct Outer { + template + struct Inner {}; + + template + struct Inner { + template + void foo() requires C && C && C{} + template + void foo() requires true{} + }; +}; + +void bar() { + Outer::Inner I; + I.foo(); +} +} // namespace GH61959 + + +namespace TemplateInsideTemplateInsideTemplate { +template +concept C1 = false; + +template +struct W0 { + template + struct W1 { + template + struct F { + enum { value = 1 }; + }; + + template + requires C1 + struct F { + enum { value = 2 }; + }; + }; +}; + +static_assert(W0<0>::W1<1>::F::value == 1); +} // TemplateInsideTemplateInsideTemplate diff --git a/clang/test/SemaTemplate/cxx1z-using-declaration.cpp b/clang/test/SemaTemplate/cxx1z-using-declaration.cpp index 84e3bff159822..a1f1988efd608 100644 --- a/clang/test/SemaTemplate/cxx1z-using-declaration.cpp +++ b/clang/test/SemaTemplate/cxx1z-using-declaration.cpp @@ -157,7 +157,7 @@ template void fn2() { // Test partial substitution into class-scope pack. template auto lambda1() { - return [](auto x) { + return [](auto x) { // expected-note 1+{{substituting into a lambda}} struct A : T::template X... { // expected-note 1+{{instantiation of}} using T::template X::f ...; using typename T::template X::type ...; diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp index 3beccd3566678..9de2975656ee2 100644 --- a/clang/test/SemaTemplate/deduction-guide.cpp +++ b/clang/test/SemaTemplate/deduction-guide.cpp @@ -224,9 +224,7 @@ F s(0); // CHECK: |-NonTypeTemplateParmDecl {{.*}} 'char' depth 0 index 0 // CHECK: `-TemplateArgument expr // CHECK: | |-inherited from NonTypeTemplateParm {{.*}} '' 'char' -// CHECK: | `-ConstantExpr {{.*}} 'char' -// CHECK: | |-value: Int 120 -// CHECK: | `-CharacterLiteral {{.*}} 'char' 120 +// CHECK: | `-CharacterLiteral {{.*}} 'char' 120 // CHECK: |-TemplateTypeParmDecl {{.*}} typename depth 0 index 1 U // CHECK: |-ParenExpr {{.*}} 'bool' // CHECK: | `-CXXBoolLiteralExpr {{.*}} 'bool' false diff --git a/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp b/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp index c5290efafc1ab..d66e68dc9e9c8 100644 --- a/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp +++ b/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp @@ -160,7 +160,7 @@ namespace Variadic { consume([]() noexcept(sizeof(T) == 4) {} ...); } template void j() { - consume([](void (*p)() noexcept(B)) { + consume([](void (*p)() noexcept(B)) { // expected-note {{substituting into a lambda}} void (*q)() noexcept = p; // expected-error {{not superset of source}} } ...); } diff --git a/clang/test/SemaTemplate/instantiate-local-class.cpp b/clang/test/SemaTemplate/instantiate-local-class.cpp index f0f3d2b146b67..430516aaac5b5 100644 --- a/clang/test/SemaTemplate/instantiate-local-class.cpp +++ b/clang/test/SemaTemplate/instantiate-local-class.cpp @@ -473,7 +473,8 @@ namespace rdar23721638 { template void bar() { auto lambda = [](T a = "") {}; // expected-error {{conversion function from 'const char[1]' to 'rdar23721638::A' invokes a deleted function}} \ // expected-note {{in instantiation of default function argument expression for 'operator()' required here}} \ - // expected-note {{passing argument to parameter 'a' here}} + // expected-note {{passing argument to parameter 'a' here}} \ + // expected-note {{while substituting into a lambda}} lambda(); } template void bar(); // expected-note {{in instantiation}} @@ -496,6 +497,7 @@ namespace PR45000 { // expected-error@-1 {{cannot initialize a parameter of type 'int' with an rvalue of type 'std::nullptr_t'}} // expected-note@-2 {{in instantiation of default function argument expression for 'operator()' required here}} // expected-note@-3 {{passing argument to parameter 'x' here}} + // expected-note@-4 {{while substituting into a lambda}} void g() { f(); } // expected-note@-1 {{in instantiation of default function argument expression for 'f' required here}} diff --git a/clang/test/SemaTemplate/partial-spec-instantiate.cpp b/clang/test/SemaTemplate/partial-spec-instantiate.cpp index 369ff69aa3756..c457c03baba0f 100644 --- a/clang/test/SemaTemplate/partial-spec-instantiate.cpp +++ b/clang/test/SemaTemplate/partial-spec-instantiate.cpp @@ -134,3 +134,23 @@ namespace IgnorePartialSubstitution { _Static_assert(S::value, ""); } + +namespace GH60778 { + template class ClassTemplate { + public: + template class Nested {}; + }; + + template class Base {}; + + template <> + template + class ClassTemplate<>::Nested : public Base::Nested > {}; + + void use() { + // This should instantiate the body of Nested with the template arguments + // from the Partial Specialization. This would previously get confused and + // get the template arguments from the primary template instead. + ClassTemplate<>::Nested instantiation; + } +} diff --git a/clang/test/SemaTemplate/temp_arg_nontype.cpp b/clang/test/SemaTemplate/temp_arg_nontype.cpp index 9ee92891b78dd..55bc57430937f 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype.cpp @@ -204,8 +204,8 @@ namespace EntityReferenced { } namespace PR6964 { - template // expected-warning 2{{non-type template argument value '9223372036854775807' truncated to '-1' for template parameter of type 'int'}} \ - // expected-note 2{{template parameter is declared here}} + template // expected-warning {{non-type template argument value '9223372036854775807' truncated to '-1' for template parameter of type 'int'}} \ + // expected-note {{template parameter is declared here}} struct as_nview { }; template diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index cb33692cd2623..9e7f8679b4cbd 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -213,9 +213,7 @@ int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { bool Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(), Argv, Diags, Argv0); - if (Clang->getFrontendOpts().TimeTrace || - !Clang->getFrontendOpts().TimeTracePath.empty()) { - Clang->getFrontendOpts().TimeTrace = 1; + if (!Clang->getFrontendOpts().TimeTracePath.empty()) { llvm::timeTraceProfilerInitialize( Clang->getFrontendOpts().TimeTraceGranularity, Argv0); } @@ -257,16 +255,6 @@ int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { llvm::TimerGroup::clearAll(); if (llvm::timeTraceProfilerEnabled()) { - SmallString<128> Path(Clang->getFrontendOpts().OutputFile); - llvm::sys::path::replace_extension(Path, "json"); - if (!Clang->getFrontendOpts().TimeTracePath.empty()) { - // replace the suffix to '.json' directly - SmallString<128> TracePath(Clang->getFrontendOpts().TimeTracePath); - if (llvm::sys::fs::is_directory(TracePath)) - llvm::sys::path::append(TracePath, llvm::sys::path::filename(Path)); - Path.assign(TracePath); - } - // It is possible that the compiler instance doesn't own a file manager here // if we're compiling a module unit. Since the file manager are owned by AST // when we're compiling a module unit. So the file manager may be invalid @@ -280,7 +268,8 @@ int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { Clang->getInvocation(), Clang->getDiagnostics())); if (auto profilerOutput = Clang->createOutputFile( - Path.str(), /*Binary=*/false, /*RemoveFileOnSignal=*/false, + Clang->getFrontendOpts().TimeTracePath, /*Binary=*/false, + /*RemoveFileOnSignal=*/false, /*useTemporary=*/false)) { llvm::timeTraceProfilerWrite(*profilerOutput); profilerOutput.reset(); diff --git a/clang/tools/scan-build-py/tests/functional/exec/CMakeLists.txt b/clang/tools/scan-build-py/tests/functional/exec/CMakeLists.txt index 007ad4530d6dc..95c6fdb610e0f 100644 --- a/clang/tools/scan-build-py/tests/functional/exec/CMakeLists.txt +++ b/clang/tools/scan-build-py/tests/functional/exec/CMakeLists.txt @@ -1,6 +1,6 @@ project(exec C) -cmake_minimum_required(VERSION 3.13.4) +cmake_minimum_required(VERSION 3.20.0) include(CheckCCompilerFlag) check_c_compiler_flag("-std=c99" C99_SUPPORTED) diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 532fef6df5e3f..8d8a8f58161bc 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -1156,8 +1156,6 @@ TEST_P(ASTImporterOptionSpecificTestBase, NonTypeTemplateParmDeclDefaultArg) { NonTypeTemplateParmDecl *To = Import(From, Lang_CXX03); ASSERT_TRUE(To->hasDefaultArgument()); Stmt *ToArg = To->getDefaultArgument(); - ASSERT_TRUE(isa(ToArg)); - ToArg = *ToArg->child_begin(); ASSERT_TRUE(isa(ToArg)); ASSERT_EQ(cast(ToArg)->getValue().getLimitedValue(), 1U); } diff --git a/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp index 86feca486ec7c..f88a179f93a45 100644 --- a/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp @@ -158,7 +158,7 @@ TEST(ChromiumCheckModelTest, CheckSuccessImpliesConditionHolds) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto *FooVal = cast(Env.getValue(*FooDecl, SkipPast::None)); + auto *FooVal = cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(*FooVal)); }; @@ -189,7 +189,7 @@ TEST(ChromiumCheckModelTest, UnrelatedCheckIgnored) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto *FooVal = cast(Env.getValue(*FooDecl, SkipPast::None)); + auto *FooVal = cast(Env.getValue(*FooDecl)); EXPECT_FALSE(Env.flowConditionImplies(*FooVal)); }; diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp index 2f874b44c49bf..1c78dd380c774 100644 --- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp @@ -124,7 +124,7 @@ TEST_F(EnvironmentTest, InitGlobalVarsFun) { // Verify the global variable is populated when we analyze `Target`. Environment Env(DAContext, *Fun); - EXPECT_THAT(Env.getValue(*Var, SkipPast::None), NotNull()); + EXPECT_THAT(Env.getValue(*Var), NotNull()); } // Tests that fields mentioned only in default member initializers are included @@ -255,7 +255,7 @@ TEST_F(EnvironmentTest, InitGlobalVarsConstructor) { // Verify the global variable is populated when we analyze `Target`. Environment Env(DAContext, *Ctor); - EXPECT_THAT(Env.getValue(*Var, SkipPast::None), NotNull()); + EXPECT_THAT(Env.getValue(*Var), NotNull()); } } // namespace diff --git a/clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp index 9a5a7fd0b5532..325ffe1af9914 100644 --- a/clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp @@ -109,7 +109,7 @@ getValueAndSignProperties(const UnaryOperator *UO, // The DeclRefExpr refers to this variable in the operand. const auto *OperandVar = M.Nodes.getNodeAs(kVar); assert(OperandVar != nullptr); - const auto *OperandValue = State.Env.getValue(*OperandVar, SkipPast::None); + const auto *OperandValue = State.Env.getValue(*OperandVar); if (!OperandValue) return {nullptr, {}, {}}; diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h index ef67dc98790c0..ff7d27d6540cc 100644 --- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h +++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h @@ -242,7 +242,7 @@ checkDataflow(AnalysisInputs AI, // Build the control flow graph for the target function. auto MaybeCFCtx = - ControlFlowContext::build(Target, *Target->getBody(), Context); + ControlFlowContext::build(*Target, *Target->getBody(), Context); if (!MaybeCFCtx) return MaybeCFCtx.takeError(); auto &CFCtx = *MaybeCFCtx; @@ -400,7 +400,7 @@ ValueT &getValueForDecl(ASTContext &ASTCtx, const Environment &Env, llvm::StringRef Name) { const ValueDecl *VD = findValueDecl(ASTCtx, Name); assert(VD != nullptr); - return *cast(Env.getValue(*VD, SkipPast::None)); + return *cast(Env.getValue(*VD)); } /// Creates and owns constraints which are boolean values. diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index d2e86c5211975..7c2a7014354aa 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -39,12 +39,16 @@ using ::testing::UnorderedElementsAre; using BuiltinOptions = DataflowAnalysisContext::Options; template -void runDataflow(llvm::StringRef Code, Matcher Match, - DataflowAnalysisOptions Options, - LangStandard::Kind Std = LangStandard::lang_cxx17, - llvm::StringRef TargetFun = "target") { +llvm::Error +runDataflowReturnError(llvm::StringRef Code, Matcher Match, + DataflowAnalysisOptions Options, + LangStandard::Kind Std = LangStandard::lang_cxx17, + llvm::StringRef TargetFun = "target") { using ast_matchers::hasName; llvm::SmallVector ASTBuildArgs = { + // -fnodelayed-template-parsing is the default everywhere but on Windows. + // Set it explicitly so that tests behave the same on Windows as on other + // platforms. "-fsyntax-only", "-fno-delayed-template-parsing", "-std=" + std::string(LangStandard::getLangStandardForKind(Std).getName())}; @@ -61,13 +65,21 @@ void runDataflow(llvm::StringRef Code, Matcher Match, AI.ASTBuildArgs = ASTBuildArgs; if (Options.BuiltinOpts) AI.BuiltinOptions = *Options.BuiltinOpts; + return checkDataflow( + std::move(AI), + /*VerifyResults=*/ + [&Match]( + const llvm::StringMap> &Results, + const AnalysisOutputs &AO) { Match(Results, AO.ASTCtx); }); +} + +template +void runDataflow(llvm::StringRef Code, Matcher Match, + DataflowAnalysisOptions Options, + LangStandard::Kind Std = LangStandard::lang_cxx17, + llvm::StringRef TargetFun = "target") { ASSERT_THAT_ERROR( - checkDataflow( - std::move(AI), - /*VerifyResults=*/ - [&Match](const llvm::StringMap> - &Results, - const AnalysisOutputs &AO) { Match(Results, AO.ASTCtx); }), + runDataflowReturnError(Code, Match, Options, Std, TargetFun), llvm::Succeeded()); } @@ -173,8 +185,7 @@ TEST(TransferTest, StructIncomplete) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto *FooValue = dyn_cast_or_null( - Env.getValue(*FooDecl, SkipPast::None)); + auto *FooValue = dyn_cast_or_null(Env.getValue(*FooDecl)); ASSERT_THAT(FooValue, NotNull()); EXPECT_TRUE(isa(FooValue->getPointeeLoc())); @@ -234,7 +245,7 @@ TEST(TransferTest, StructFieldUnmodeled) { const ValueDecl *ZabDecl = findValueDecl(ASTCtx, "Zab"); ASSERT_THAT(ZabDecl, NotNull()); - EXPECT_THAT(Env.getValue(*ZabDecl, SkipPast::None), NotNull()); + EXPECT_THAT(Env.getValue(*ZabDecl), NotNull()); }); } @@ -788,13 +799,13 @@ TEST(TransferTest, BinaryOperatorAssign) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); + const Value *FooVal = Env.getValue(*FooDecl); ASSERT_TRUE(isa_and_nonnull(FooVal)); const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal); + EXPECT_EQ(Env.getValue(*BarDecl), FooVal); }); } @@ -816,13 +827,13 @@ TEST(TransferTest, VarDeclInitAssign) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); + const Value *FooVal = Env.getValue(*FooDecl); ASSERT_TRUE(isa_and_nonnull(FooVal)); const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal); + EXPECT_EQ(Env.getValue(*BarDecl), FooVal); }); } @@ -845,7 +856,7 @@ TEST(TransferTest, VarDeclInitAssignChained) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); + const Value *FooVal = Env.getValue(*FooDecl); ASSERT_TRUE(isa_and_nonnull(FooVal)); const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); @@ -854,8 +865,8 @@ TEST(TransferTest, VarDeclInitAssignChained) { const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal); - EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal); + EXPECT_EQ(Env.getValue(*BarDecl), FooVal); + EXPECT_EQ(Env.getValue(*BazDecl), FooVal); }); } @@ -879,20 +890,19 @@ TEST(TransferTest, VarDeclInitAssignPtrDeref) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); + const Value *FooVal = Env.getValue(*FooDecl); ASSERT_TRUE(isa_and_nonnull(FooVal)); const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - const auto *BarVal = - cast(Env.getValue(*BarDecl, SkipPast::None)); + const auto *BarVal = cast(Env.getValue(*BarDecl)); EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal); const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal); + EXPECT_EQ(Env.getValue(*BazDecl), FooVal); }); } @@ -920,30 +930,30 @@ TEST(TransferTest, AssignToAndFromReference) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const Value *FooVal = Env1.getValue(*FooDecl, SkipPast::None); + const Value *FooVal = Env1.getValue(*FooDecl); ASSERT_TRUE(isa_and_nonnull(FooVal)); const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - const Value *BarVal = Env1.getValue(*BarDecl, SkipPast::None); + const Value *BarVal = Env1.getValue(*BarDecl); ASSERT_TRUE(isa_and_nonnull(BarVal)); const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - EXPECT_EQ(Env1.getValue(*BazDecl, SkipPast::Reference), FooVal); + EXPECT_EQ(Env1.getValue(*BazDecl), FooVal); - EXPECT_EQ(Env2.getValue(*BazDecl, SkipPast::Reference), BarVal); - EXPECT_EQ(Env2.getValue(*FooDecl, SkipPast::None), BarVal); + EXPECT_EQ(Env2.getValue(*BazDecl), BarVal); + EXPECT_EQ(Env2.getValue(*FooDecl), BarVal); const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); ASSERT_THAT(QuxDecl, NotNull()); - EXPECT_EQ(Env2.getValue(*QuxDecl, SkipPast::None), BarVal); + EXPECT_EQ(Env2.getValue(*QuxDecl), BarVal); const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); ASSERT_THAT(QuuxDecl, NotNull()); - EXPECT_EQ(Env2.getValue(*QuuxDecl, SkipPast::Reference), BarVal); + EXPECT_EQ(Env2.getValue(*QuuxDecl), BarVal); }); } @@ -1126,7 +1136,7 @@ TEST(TransferTest, StructMember) { const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal); + EXPECT_EQ(Env.getValue(*BazDecl), BarVal); }); } @@ -1396,7 +1406,7 @@ TEST(TransferTest, ClassMember) { const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal); + EXPECT_EQ(Env.getValue(*BazDecl), BarVal); }); } @@ -1488,7 +1498,7 @@ TEST(TransferTest, ReferenceMember) { const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarReferentVal); + EXPECT_EQ(Env.getValue(*BazDecl), BarReferentVal); }); } @@ -1533,7 +1543,7 @@ TEST(TransferTest, StructThisMember) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal); + EXPECT_EQ(Env.getValue(*FooDecl), BarVal); const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); ASSERT_THAT(QuxDecl, NotNull()); @@ -1563,7 +1573,7 @@ TEST(TransferTest, StructThisMember) { const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); ASSERT_THAT(QuuxDecl, NotNull()); - EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal); + EXPECT_EQ(Env.getValue(*QuuxDecl), BazVal); }); } @@ -1608,7 +1618,7 @@ TEST(TransferTest, ClassThisMember) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal); + EXPECT_EQ(Env.getValue(*FooDecl), BarVal); const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); ASSERT_THAT(QuxDecl, NotNull()); @@ -1638,7 +1648,7 @@ TEST(TransferTest, ClassThisMember) { const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); ASSERT_THAT(QuuxDecl, NotNull()); - EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal); + EXPECT_EQ(Env.getValue(*QuuxDecl), BazVal); }); } @@ -1726,7 +1736,7 @@ TEST(TransferTest, StructThisInLambda) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal); + EXPECT_EQ(Env.getValue(*FooDecl), BarVal); }, LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()"); @@ -1765,7 +1775,7 @@ TEST(TransferTest, StructThisInLambda) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal); + EXPECT_EQ(Env.getValue(*FooDecl), BarVal); }, LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()"); @@ -1815,12 +1825,11 @@ TEST(TransferTest, ConstructorInitializer) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const auto *FooVal = - cast(Env.getValue(*FooDecl, SkipPast::None)); + const auto *FooVal = cast(Env.getValue(*FooDecl)); const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); ASSERT_THAT(QuxDecl, NotNull()); - EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal); + EXPECT_EQ(Env.getValue(*QuxDecl), FooVal); }); } @@ -1850,12 +1859,11 @@ TEST(TransferTest, DefaultInitializer) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const auto *FooVal = - cast(Env.getValue(*FooDecl, SkipPast::None)); + const auto *FooVal = cast(Env.getValue(*FooDecl)); const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); ASSERT_THAT(QuxDecl, NotNull()); - EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal); + EXPECT_EQ(Env.getValue(*QuxDecl), FooVal); }); } @@ -2275,10 +2283,8 @@ TEST(TransferTest, BindTemporary) { const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - const auto &FooVal = - *cast(Env.getValue(*FooDecl, SkipPast::None)); - const auto *BarVal = - cast(Env.getValue(*BarDecl, SkipPast::None)); + const auto &FooVal = *cast(Env.getValue(*FooDecl)); + const auto *BarVal = cast(Env.getValue(*BarDecl)); EXPECT_EQ(BarVal, FooVal.getChild(*BazDecl)); }); } @@ -2303,8 +2309,8 @@ TEST(TransferTest, StaticCast) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None); - const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None); + const auto *FooVal = Env.getValue(*FooDecl); + const auto *BarVal = Env.getValue(*BarDecl); EXPECT_TRUE(isa(FooVal)); EXPECT_TRUE(isa(BarVal)); EXPECT_EQ(FooVal, BarVal); @@ -2331,8 +2337,8 @@ TEST(TransferTest, IntegralCast) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None); - const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None); + const auto *FooVal = Env.getValue(*FooDecl); + const auto *BarVal = Env.getValue(*BarDecl); EXPECT_TRUE(isa(FooVal)); EXPECT_TRUE(isa(BarVal)); EXPECT_EQ(FooVal, BarVal); @@ -2359,8 +2365,8 @@ TEST(TransferTest, IntegraltoBooleanCast) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None); - const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None); + const auto *FooVal = Env.getValue(*FooDecl); + const auto *BarVal = Env.getValue(*BarDecl); EXPECT_TRUE(isa(FooVal)); EXPECT_TRUE(isa(BarVal)); }); @@ -2387,8 +2393,8 @@ TEST(TransferTest, IntegralToBooleanCastFromBool) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None); - const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None); + const auto *FooVal = Env.getValue(*FooDecl); + const auto *BarVal = Env.getValue(*BarDecl); EXPECT_TRUE(isa(FooVal)); EXPECT_TRUE(isa(BarVal)); EXPECT_EQ(FooVal, BarVal); @@ -2430,16 +2436,11 @@ TEST(TransferTest, NullToPointerCast) { const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null"); ASSERT_THAT(NullDecl, NotNull()); - const auto *FooXVal = - cast(Env.getValue(*FooXDecl, SkipPast::None)); - const auto *FooYVal = - cast(Env.getValue(*FooYDecl, SkipPast::None)); - const auto *BarVal = - cast(Env.getValue(*BarDecl, SkipPast::None)); - const auto *BazVal = - cast(Env.getValue(*BazDecl, SkipPast::None)); - const auto *NullVal = - cast(Env.getValue(*NullDecl, SkipPast::None)); + const auto *FooXVal = cast(Env.getValue(*FooXDecl)); + const auto *FooYVal = cast(Env.getValue(*FooYDecl)); + const auto *BarVal = cast(Env.getValue(*BarDecl)); + const auto *BazVal = cast(Env.getValue(*BazDecl)); + const auto *NullVal = cast(Env.getValue(*NullDecl)); EXPECT_EQ(FooXVal, FooYVal); EXPECT_NE(FooXVal, BarVal); @@ -2483,8 +2484,8 @@ TEST(TransferTest, NullToMemberPointerCast) { findValueDecl(ASTCtx, "MemberPointer"); ASSERT_THAT(MemberPointerDecl, NotNull()); - const auto *MemberPointerVal = cast( - Env.getValue(*MemberPointerDecl, SkipPast::None)); + const auto *MemberPointerVal = + cast(Env.getValue(*MemberPointerDecl)); const StorageLocation &MemberLoc = MemberPointerVal->getPointeeLoc(); EXPECT_THAT(Env.getValue(MemberLoc), IsNull()); @@ -2514,8 +2515,7 @@ TEST(TransferTest, AddrOfValue) { const auto *FooLoc = cast(Env.getStorageLocation(*FooDecl)); - const auto *BarVal = - cast(Env.getValue(*BarDecl, SkipPast::None)); + const auto *BarVal = cast(Env.getValue(*BarDecl)); EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); }); } @@ -2540,40 +2540,40 @@ TEST(TransferTest, AddrOfReference) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - const auto *FooVal = - cast(Env.getValue(*FooDecl, SkipPast::None)); - const auto *BarVal = - cast(Env.getValue(*BarDecl, SkipPast::None)); + const auto *FooVal = cast(Env.getValue(*FooDecl)); + const auto *BarVal = cast(Env.getValue(*BarDecl)); EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc()); }); } -TEST(TransferTest, DerefDependentPtr) { +TEST(TransferTest, CannotAnalyzeFunctionTemplate) { std::string Code = R"( template - void target(T *Foo) { - T &Bar = *Foo; - /*[[p]]*/ - } + void target() {} )"; - runDataflow( - Code, - [](const llvm::StringMap> &Results, - ASTContext &ASTCtx) { - ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); - const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); - - const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); - ASSERT_THAT(FooDecl, NotNull()); - - const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); - ASSERT_THAT(BarDecl, NotNull()); + ASSERT_THAT_ERROR( + runDataflowReturnError( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) {}, + {BuiltinOptions()}), + llvm::FailedWithMessage("Cannot analyze templated declarations")); +} - const auto *FooVal = - cast(Env.getValue(*FooDecl, SkipPast::None)); - const auto *BarLoc = Env.getStorageLocation(*BarDecl); - EXPECT_EQ(BarLoc, &FooVal->getPointeeLoc()); - }); +TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) { + std::string Code = R"( + template + struct A { + void target() {} + }; + )"; + ASSERT_THAT_ERROR( + runDataflowReturnError( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) {}, + {BuiltinOptions()}), + llvm::FailedWithMessage("Cannot analyze templated declarations")); } TEST(TransferTest, VarDeclInitAssignConditionalOperator) { @@ -2601,13 +2601,10 @@ TEST(TransferTest, VarDeclInitAssignConditionalOperator) { const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - const auto *FooVal = - cast(Env.getValue(*FooDecl, SkipPast::None)); - const auto *BarVal = - cast(Env.getValue(*BarDecl, SkipPast::None)); + const auto *FooVal = cast(Env.getValue(*FooDecl)); + const auto *BarVal = cast(Env.getValue(*BarDecl)); - const auto *BazVal = - dyn_cast(Env.getValue(*BazDecl, SkipPast::None)); + const auto *BazVal = dyn_cast(Env.getValue(*BazDecl)); ASSERT_THAT(BazVal, NotNull()); EXPECT_NE(BazVal, FooVal); @@ -2739,15 +2736,11 @@ TEST(TransferTest, AggregateInitialization) { const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); ASSERT_THAT(QuuxDecl, NotNull()); - const auto *FooArgVal = - cast(Env.getValue(*FooArgDecl, SkipPast::None)); - const auto *BarArgVal = - cast(Env.getValue(*BarArgDecl, SkipPast::None)); - const auto *QuxArgVal = - cast(Env.getValue(*QuxArgDecl, SkipPast::None)); + const auto *FooArgVal = cast(Env.getValue(*FooArgDecl)); + const auto *BarArgVal = cast(Env.getValue(*BarArgDecl)); + const auto *QuxArgVal = cast(Env.getValue(*QuxArgDecl)); - const auto *QuuxVal = - cast(Env.getValue(*QuuxDecl, SkipPast::None)); + const auto *QuuxVal = cast(Env.getValue(*QuuxDecl)); ASSERT_THAT(QuuxVal, NotNull()); const auto *BazVal = cast(QuuxVal->getChild(*BazDecl)); @@ -2832,15 +2825,15 @@ TEST(TransferTest, AssignFromBoolLiteral) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const auto *FooVal = dyn_cast_or_null( - Env.getValue(*FooDecl, SkipPast::None)); + const auto *FooVal = + dyn_cast_or_null(Env.getValue(*FooDecl)); ASSERT_THAT(FooVal, NotNull()); const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - const auto *BarVal = dyn_cast_or_null( - Env.getValue(*BarDecl, SkipPast::None)); + const auto *BarVal = + dyn_cast_or_null(Env.getValue(*BarDecl)); ASSERT_THAT(BarVal, NotNull()); EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true)); @@ -2866,29 +2859,29 @@ TEST(TransferTest, AssignFromCompositeBoolExpression) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const auto *FooVal = dyn_cast_or_null( - Env.getValue(*FooDecl, SkipPast::None)); + const auto *FooVal = + dyn_cast_or_null(Env.getValue(*FooDecl)); ASSERT_THAT(FooVal, NotNull()); const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - const auto *BarVal = dyn_cast_or_null( - Env.getValue(*BarDecl, SkipPast::None)); + const auto *BarVal = + dyn_cast_or_null(Env.getValue(*BarDecl)); ASSERT_THAT(BarVal, NotNull()); const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); ASSERT_THAT(QuxDecl, NotNull()); - const auto *QuxVal = dyn_cast_or_null( - Env.getValue(*QuxDecl, SkipPast::None)); + const auto *QuxVal = + dyn_cast_or_null(Env.getValue(*QuxDecl)); ASSERT_THAT(QuxVal, NotNull()); const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - const auto *BazVal = dyn_cast_or_null( - Env.getValue(*BazDecl, SkipPast::None)); + const auto *BazVal = + dyn_cast_or_null(Env.getValue(*BazDecl)); ASSERT_THAT(BazVal, NotNull()); EXPECT_EQ(&BazVal->getLeftSubValue(), FooVal); @@ -2916,29 +2909,29 @@ TEST(TransferTest, AssignFromCompositeBoolExpression) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const auto *FooVal = dyn_cast_or_null( - Env.getValue(*FooDecl, SkipPast::None)); + const auto *FooVal = + dyn_cast_or_null(Env.getValue(*FooDecl)); ASSERT_THAT(FooVal, NotNull()); const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - const auto *BarVal = dyn_cast_or_null( - Env.getValue(*BarDecl, SkipPast::None)); + const auto *BarVal = + dyn_cast_or_null(Env.getValue(*BarDecl)); ASSERT_THAT(BarVal, NotNull()); const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); ASSERT_THAT(QuxDecl, NotNull()); - const auto *QuxVal = dyn_cast_or_null( - Env.getValue(*QuxDecl, SkipPast::None)); + const auto *QuxVal = + dyn_cast_or_null(Env.getValue(*QuxDecl)); ASSERT_THAT(QuxVal, NotNull()); const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - const auto *BazVal = dyn_cast_or_null( - Env.getValue(*BazDecl, SkipPast::None)); + const auto *BazVal = + dyn_cast_or_null(Env.getValue(*BazDecl)); ASSERT_THAT(BazVal, NotNull()); const auto *BazLeftSubValVal = @@ -2967,36 +2960,32 @@ TEST(TransferTest, AssignFromCompositeBoolExpression) { const ValueDecl *ADecl = findValueDecl(ASTCtx, "A"); ASSERT_THAT(ADecl, NotNull()); - const auto *AVal = - dyn_cast_or_null(Env.getValue(*ADecl, SkipPast::None)); + const auto *AVal = dyn_cast_or_null(Env.getValue(*ADecl)); ASSERT_THAT(AVal, NotNull()); const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); ASSERT_THAT(BDecl, NotNull()); - const auto *BVal = - dyn_cast_or_null(Env.getValue(*BDecl, SkipPast::None)); + const auto *BVal = dyn_cast_or_null(Env.getValue(*BDecl)); ASSERT_THAT(BVal, NotNull()); const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); ASSERT_THAT(CDecl, NotNull()); - const auto *CVal = - dyn_cast_or_null(Env.getValue(*CDecl, SkipPast::None)); + const auto *CVal = dyn_cast_or_null(Env.getValue(*CDecl)); ASSERT_THAT(CVal, NotNull()); const ValueDecl *DDecl = findValueDecl(ASTCtx, "D"); ASSERT_THAT(DDecl, NotNull()); - const auto *DVal = - dyn_cast_or_null(Env.getValue(*DDecl, SkipPast::None)); + const auto *DVal = dyn_cast_or_null(Env.getValue(*DDecl)); ASSERT_THAT(DVal, NotNull()); const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const auto *FooVal = dyn_cast_or_null( - Env.getValue(*FooDecl, SkipPast::None)); + const auto *FooVal = + dyn_cast_or_null(Env.getValue(*FooDecl)); ASSERT_THAT(FooVal, NotNull()); const auto &FooLeftSubVal = @@ -3029,15 +3018,15 @@ TEST(TransferTest, AssignFromBoolNegation) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const auto *FooVal = dyn_cast_or_null( - Env.getValue(*FooDecl, SkipPast::None)); + const auto *FooVal = + dyn_cast_or_null(Env.getValue(*FooDecl)); ASSERT_THAT(FooVal, NotNull()); const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - const auto *BarVal = dyn_cast_or_null( - Env.getValue(*BarDecl, SkipPast::None)); + const auto *BarVal = + dyn_cast_or_null(Env.getValue(*BarDecl)); ASSERT_THAT(BarVal, NotNull()); EXPECT_EQ(&BarVal->getSubVal(), FooVal); @@ -3064,8 +3053,7 @@ TEST(TransferTest, BuiltinExpect) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), - Env.getValue(*BarDecl, SkipPast::None)); + EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); }); } @@ -3092,8 +3080,7 @@ TEST(TransferTest, BuiltinExpectBoolArg) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), - Env.getValue(*BarDecl, SkipPast::None)); + EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); }); } @@ -3125,8 +3112,7 @@ TEST(TransferTest, BuiltinUnreachable) { // `__builtin_unreachable` promises that the code is // unreachable, so the compiler treats the "then" branch as the // only possible predecessor of this statement. - EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), - Env.getValue(*BarDecl, SkipPast::None)); + EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); }); } @@ -3157,8 +3143,7 @@ TEST(TransferTest, BuiltinTrap) { // `__builtin_trap` ensures program termination, so only the // "then" branch is a predecessor of this statement. - EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), - Env.getValue(*BarDecl, SkipPast::None)); + EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); }); } @@ -3188,8 +3173,7 @@ TEST(TransferTest, BuiltinDebugTrap) { ASSERT_THAT(BarDecl, NotNull()); // `__builtin_debugtrap` doesn't ensure program termination. - EXPECT_NE(Env.getValue(*FooDecl, SkipPast::None), - Env.getValue(*BarDecl, SkipPast::None)); + EXPECT_NE(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); }); } @@ -3278,10 +3262,8 @@ TEST(TransferTest, GlobalIntVarDecl) { const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - const Value *BarVal = - cast(Env.getValue(*BarDecl, SkipPast::None)); - const Value *BazVal = - cast(Env.getValue(*BazDecl, SkipPast::None)); + const Value *BarVal = cast(Env.getValue(*BarDecl)); + const Value *BazVal = cast(Env.getValue(*BazDecl)); EXPECT_EQ(BarVal, BazVal); }); } @@ -3311,10 +3293,8 @@ TEST(TransferTest, StaticMemberIntVarDecl) { const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - const Value *BarVal = - cast(Env.getValue(*BarDecl, SkipPast::None)); - const Value *BazVal = - cast(Env.getValue(*BazDecl, SkipPast::None)); + const Value *BarVal = cast(Env.getValue(*BarDecl)); + const Value *BazVal = cast(Env.getValue(*BazDecl)); EXPECT_EQ(BarVal, BazVal); }); } @@ -3344,10 +3324,8 @@ TEST(TransferTest, StaticMemberRefVarDecl) { const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - const Value *BarVal = - cast(Env.getValue(*BarDecl, SkipPast::None)); - const Value *BazVal = - cast(Env.getValue(*BazDecl, SkipPast::None)); + const Value *BarVal = cast(Env.getValue(*BarDecl)); + const Value *BazVal = cast(Env.getValue(*BazDecl)); EXPECT_EQ(BarVal, BazVal); }); } @@ -3386,11 +3364,9 @@ TEST(TransferTest, AssignMemberBeforeCopy) { const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2"); ASSERT_THAT(A2Decl, NotNull()); - const auto *BarVal = - cast(Env.getValue(*BarDecl, SkipPast::None)); + const auto *BarVal = cast(Env.getValue(*BarDecl)); - const auto *A2Val = - cast(Env.getValue(*A2Decl, SkipPast::None)); + const auto *A2Val = cast(Env.getValue(*A2Decl)); EXPECT_EQ(A2Val->getChild(*FooDecl), BarVal); }); } @@ -3421,12 +3397,10 @@ TEST(TransferTest, BooleanEquality) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - auto &BarValThen = - *cast(EnvThen.getValue(*BarDecl, SkipPast::None)); + auto &BarValThen = *cast(EnvThen.getValue(*BarDecl)); EXPECT_TRUE(EnvThen.flowConditionImplies(BarValThen)); - auto &BarValElse = - *cast(EnvElse.getValue(*BarDecl, SkipPast::None)); + auto &BarValElse = *cast(EnvElse.getValue(*BarDecl)); EXPECT_FALSE(EnvElse.flowConditionImplies(BarValElse)); }); } @@ -3457,12 +3431,10 @@ TEST(TransferTest, BooleanInequality) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - auto &BarValThen = - *cast(EnvThen.getValue(*BarDecl, SkipPast::None)); + auto &BarValThen = *cast(EnvThen.getValue(*BarDecl)); EXPECT_FALSE(EnvThen.flowConditionImplies(BarValThen)); - auto &BarValElse = - *cast(EnvElse.getValue(*BarDecl, SkipPast::None)); + auto &BarValElse = *cast(EnvElse.getValue(*BarDecl)); EXPECT_TRUE(EnvElse.flowConditionImplies(BarValElse)); }); } @@ -3498,20 +3470,20 @@ TEST(TransferTest, CorrelatedBranches) { const Environment &Env = getEnvironmentAtAnnotation(Results, "p0"); const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); ASSERT_THAT(BDecl, NotNull()); - auto &BVal = *cast(Env.getValue(*BDecl, SkipPast::None)); + auto &BVal = *cast(Env.getValue(*BDecl)); EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BVal))); } { const Environment &Env = getEnvironmentAtAnnotation(Results, "p1"); - auto &CVal = *cast(Env.getValue(*CDecl, SkipPast::None)); + auto &CVal = *cast(Env.getValue(*CDecl)); EXPECT_TRUE(Env.flowConditionImplies(CVal)); } { const Environment &Env = getEnvironmentAtAnnotation(Results, "p2"); - auto &CVal = *cast(Env.getValue(*CDecl, SkipPast::None)); + auto &CVal = *cast(Env.getValue(*CDecl)); EXPECT_TRUE(Env.flowConditionImplies(CVal)); } }); @@ -3543,7 +3515,7 @@ TEST(TransferTest, LoopWithAssignmentConverges) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - auto &BarVal = *cast(Env.getValue(*BarDecl, SkipPast::None)); + auto &BarVal = *cast(Env.getValue(*BarDecl)); EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BarVal))); }); } @@ -3575,8 +3547,8 @@ TEST(TransferTest, LoopWithStagedAssignments) { const ValueDecl *ErrDecl = findValueDecl(ASTCtx, "Err"); ASSERT_THAT(ErrDecl, NotNull()); - auto &BarVal = *cast(Env.getValue(*BarDecl, SkipPast::None)); - auto &ErrVal = *cast(Env.getValue(*ErrDecl, SkipPast::None)); + auto &BarVal = *cast(Env.getValue(*BarDecl)); + auto &ErrVal = *cast(Env.getValue(*ErrDecl)); EXPECT_TRUE(Env.flowConditionImplies(BarVal)); // An unsound analysis, for example only evaluating the loop once, can // conclude that `Err` is false. So, we test that this conclusion is not @@ -3610,8 +3582,7 @@ TEST(TransferTest, LoopWithReferenceAssignmentConverges) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - auto &BarVal = - *cast(Env.getValue(*BarDecl, SkipPast::Reference)); + auto &BarVal = *cast(Env.getValue(*BarDecl)); EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BarVal))); }); } @@ -3652,16 +3623,14 @@ TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) { ASSERT_THAT(LDecl, NotNull()); // Inner. - auto *LVal = - dyn_cast(InnerEnv.getValue(*LDecl, SkipPast::None)); + auto *LVal = dyn_cast(InnerEnv.getValue(*LDecl)); ASSERT_THAT(LVal, NotNull()); EXPECT_EQ(&LVal->getPointeeLoc(), InnerEnv.getStorageLocation(*ValDecl)); // Outer. - LVal = - dyn_cast(OuterEnv.getValue(*LDecl, SkipPast::None)); + LVal = dyn_cast(OuterEnv.getValue(*LDecl)); ASSERT_THAT(LVal, NotNull()); // The loop body may not have been executed, so we should not conclude @@ -3738,7 +3707,7 @@ TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) { const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); ASSERT_THAT(BarRefLoc, NotNull()); - const Value *QuxVal = Env.getValue(*QuxDecl, SkipPast::None); + const Value *QuxVal = Env.getValue(*QuxDecl); ASSERT_THAT(QuxVal, NotNull()); const StorageLocation *BoundFooRefLoc = @@ -3749,7 +3718,7 @@ TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) { Env.getStorageLocation(*BoundBarRefDecl); EXPECT_EQ(BoundBarRefLoc, BarRefLoc); - EXPECT_EQ(Env.getValue(*BoundFooRefDecl, SkipPast::Reference), QuxVal); + EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); }); } @@ -3797,7 +3766,7 @@ TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) { const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); ASSERT_THAT(BarRefLoc, NotNull()); - const Value *QuxVal = Env.getValue(*QuxDecl, SkipPast::None); + const Value *QuxVal = Env.getValue(*QuxDecl); ASSERT_THAT(QuxVal, NotNull()); const StorageLocation *BoundFooRefLoc = @@ -3808,7 +3777,7 @@ TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) { Env.getStorageLocation(*BoundBarRefDecl); EXPECT_EQ(BoundBarRefLoc, BarRefLoc); - EXPECT_EQ(Env.getValue(*BoundFooRefDecl, SkipPast::Reference), QuxVal); + EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); }); } @@ -3857,7 +3826,7 @@ TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) { const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); ASSERT_THAT(BarRefLoc, NotNull()); - const Value *QuxVal = Env.getValue(*QuxDecl, SkipPast::None); + const Value *QuxVal = Env.getValue(*QuxDecl); ASSERT_THAT(QuxVal, NotNull()); const StorageLocation *BoundFooLoc = @@ -3868,7 +3837,7 @@ TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) { Env.getStorageLocation(*BoundBarDecl); EXPECT_NE(BoundBarLoc, BarRefLoc); - EXPECT_EQ(Env.getValue(*BoundFooDecl, SkipPast::Reference), QuxVal); + EXPECT_EQ(Env.getValue(*BoundFooDecl), QuxVal); }); } @@ -3934,24 +3903,22 @@ TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) { // BindingDecls always map to references -- either lvalue or rvalue, so // we still need to skip here. - const Value *BoundFooValue = - Env1.getValue(*BoundFooDecl, SkipPast::Reference); + const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); ASSERT_THAT(BoundFooValue, NotNull()); EXPECT_TRUE(isa(BoundFooValue)); - const Value *BoundBarValue = - Env1.getValue(*BoundBarDecl, SkipPast::Reference); + const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); ASSERT_THAT(BoundBarValue, NotNull()); EXPECT_TRUE(isa(BoundBarValue)); // Test that a `DeclRefExpr` to a `BindingDecl` works as expected. - EXPECT_EQ(Env1.getValue(*BazDecl, SkipPast::None), BoundFooValue); + EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); // Test that `BoundFooDecl` retains the value we expect, after the join. - BoundFooValue = Env2.getValue(*BoundFooDecl, SkipPast::Reference); - EXPECT_EQ(Env2.getValue(*BazDecl, SkipPast::None), BoundFooValue); + BoundFooValue = Env2.getValue(*BoundFooDecl); + EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); }); } @@ -4015,13 +3982,11 @@ TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) { const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - const Value *BoundFooValue = - Env1.getValue(*BoundFooDecl, SkipPast::Reference); + const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); ASSERT_THAT(BoundFooValue, NotNull()); EXPECT_TRUE(isa(BoundFooValue)); - const Value *BoundBarValue = - Env1.getValue(*BoundBarDecl, SkipPast::Reference); + const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); ASSERT_THAT(BoundBarValue, NotNull()); EXPECT_TRUE(isa(BoundBarValue)); @@ -4029,13 +3994,13 @@ TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) { // works as expected. We don't test aliasing properties of the // reference, because we don't model `std::get` and so have no way to // equate separate references into the tuple. - EXPECT_EQ(Env1.getValue(*BazDecl, SkipPast::None), BoundFooValue); + EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); // Test that `BoundFooDecl` retains the value we expect, after the join. - BoundFooValue = Env2.getValue(*BoundFooDecl, SkipPast::Reference); - EXPECT_EQ(Env2.getValue(*BazDecl, SkipPast::None), BoundFooValue); + BoundFooValue = Env2.getValue(*BoundFooDecl); + EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); }); } @@ -4092,12 +4057,10 @@ TEST(TransferTest, IfStmtBranchExtendsFlowCondition) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - BoolValue &ThenFooVal = - *cast(ThenEnv.getValue(*FooDecl, SkipPast::None)); + BoolValue &ThenFooVal = *cast(ThenEnv.getValue(*FooDecl)); EXPECT_TRUE(ThenEnv.flowConditionImplies(ThenFooVal)); - BoolValue &ElseFooVal = - *cast(ElseEnv.getValue(*FooDecl, SkipPast::None)); + BoolValue &ElseFooVal = *cast(ElseEnv.getValue(*FooDecl)); EXPECT_TRUE(ElseEnv.flowConditionImplies(ElseEnv.makeNot(ElseFooVal))); }); } @@ -4128,11 +4091,11 @@ TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) { ASSERT_THAT(FooDecl, NotNull()); BoolValue &LoopBodyFooVal = - *cast(LoopBodyEnv.getValue(*FooDecl, SkipPast::None)); + *cast(LoopBodyEnv.getValue(*FooDecl)); EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal)); BoolValue &AfterLoopFooVal = - *cast(AfterLoopEnv.getValue(*FooDecl, SkipPast::None)); + *cast(AfterLoopEnv.getValue(*FooDecl)); EXPECT_TRUE(AfterLoopEnv.flowConditionImplies( AfterLoopEnv.makeNot(AfterLoopFooVal))); }); @@ -4169,16 +4132,16 @@ TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) { ASSERT_THAT(BarDecl, NotNull()); BoolValue &LoopBodyFooVal = - *cast(LoopBodyEnv.getValue(*FooDecl, SkipPast::None)); + *cast(LoopBodyEnv.getValue(*FooDecl)); BoolValue &LoopBodyBarVal = - *cast(LoopBodyEnv.getValue(*BarDecl, SkipPast::None)); + *cast(LoopBodyEnv.getValue(*BarDecl)); EXPECT_TRUE(LoopBodyEnv.flowConditionImplies( LoopBodyEnv.makeOr(LoopBodyBarVal, LoopBodyFooVal))); BoolValue &AfterLoopFooVal = - *cast(AfterLoopEnv.getValue(*FooDecl, SkipPast::None)); + *cast(AfterLoopEnv.getValue(*FooDecl)); BoolValue &AfterLoopBarVal = - *cast(AfterLoopEnv.getValue(*BarDecl, SkipPast::None)); + *cast(AfterLoopEnv.getValue(*BarDecl)); EXPECT_TRUE(AfterLoopEnv.flowConditionImplies( AfterLoopEnv.makeNot(AfterLoopFooVal))); EXPECT_TRUE(AfterLoopEnv.flowConditionImplies( @@ -4212,11 +4175,11 @@ TEST(TransferTest, ForStmtBranchExtendsFlowCondition) { ASSERT_THAT(FooDecl, NotNull()); BoolValue &LoopBodyFooVal = - *cast(LoopBodyEnv.getValue(*FooDecl, SkipPast::None)); + *cast(LoopBodyEnv.getValue(*FooDecl)); EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal)); BoolValue &AfterLoopFooVal = - *cast(AfterLoopEnv.getValue(*FooDecl, SkipPast::None)); + *cast(AfterLoopEnv.getValue(*FooDecl)); EXPECT_TRUE(AfterLoopEnv.flowConditionImplies( AfterLoopEnv.makeNot(AfterLoopFooVal))); }); @@ -4243,7 +4206,7 @@ TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) { ASSERT_THAT(FooDecl, NotNull()); BoolValue &LoopBodyFooVal = - *cast(LoopBodyEnv.getValue(*FooDecl, SkipPast::None)); + *cast(LoopBodyEnv.getValue(*FooDecl)); EXPECT_FALSE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal)); }); } @@ -4269,7 +4232,7 @@ TEST(TransferTest, ContextSensitiveOptionDisabled) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_FALSE(Env.flowConditionImplies(FooVal)); EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal))); }, @@ -4326,7 +4289,7 @@ TEST(TransferTest, ContextSensitiveDepthZero) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_FALSE(Env.flowConditionImplies(FooVal)); EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal))); }, @@ -4354,7 +4317,7 @@ TEST(TransferTest, ContextSensitiveSetTrue) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); }, {BuiltinOptions{ContextSensitiveOptions{}}}); @@ -4381,7 +4344,7 @@ TEST(TransferTest, ContextSensitiveSetFalse) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(FooVal))); }, {BuiltinOptions{ContextSensitiveOptions{}}}); @@ -4413,11 +4376,11 @@ TEST(TransferTest, ContextSensitiveSetBothTrueAndFalse) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal))); - auto &BarVal = *cast(Env.getValue(*BarDecl, SkipPast::None)); + auto &BarVal = *cast(Env.getValue(*BarDecl)); EXPECT_FALSE(Env.flowConditionImplies(BarVal)); EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BarVal))); }, @@ -4446,7 +4409,7 @@ TEST(TransferTest, ContextSensitiveSetTwoLayersDepthOne) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_FALSE(Env.flowConditionImplies(FooVal)); EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal))); }, @@ -4475,7 +4438,7 @@ TEST(TransferTest, ContextSensitiveSetTwoLayersDepthTwo) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); }, {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); @@ -4504,7 +4467,7 @@ TEST(TransferTest, ContextSensitiveSetThreeLayersDepthTwo) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_FALSE(Env.flowConditionImplies(FooVal)); EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal))); }, @@ -4534,7 +4497,7 @@ TEST(TransferTest, ContextSensitiveSetThreeLayersDepthThree) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); }, {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/3}}}); @@ -4576,7 +4539,7 @@ TEST(TransferTest, ContextSensitiveMutualRecursion) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); // ... but it also can't prove anything here. EXPECT_FALSE(Env.flowConditionImplies(FooVal)); EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal))); @@ -4611,11 +4574,11 @@ TEST(TransferTest, ContextSensitiveSetMultipleLines) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal))); - auto &BarVal = *cast(Env.getValue(*BarDecl, SkipPast::None)); + auto &BarVal = *cast(Env.getValue(*BarDecl)); EXPECT_FALSE(Env.flowConditionImplies(BarVal)); EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BarVal))); }, @@ -4653,11 +4616,11 @@ TEST(TransferTest, ContextSensitiveSetMultipleBlocks) { const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - auto &BarVal = *cast(Env.getValue(*BarDecl, SkipPast::None)); + auto &BarVal = *cast(Env.getValue(*BarDecl)); EXPECT_FALSE(Env.flowConditionImplies(BarVal)); EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BarVal))); - auto &BazVal = *cast(Env.getValue(*BazDecl, SkipPast::None)); + auto &BazVal = *cast(Env.getValue(*BazDecl)); EXPECT_TRUE(Env.flowConditionImplies(BazVal)); EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(BazVal))); }, @@ -4702,7 +4665,7 @@ TEST(TransferTest, ContextSensitiveReturnTrue) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); }, {BuiltinOptions{ContextSensitiveOptions{}}}); @@ -4727,7 +4690,7 @@ TEST(TransferTest, ContextSensitiveReturnFalse) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(FooVal))); }, {BuiltinOptions{ContextSensitiveOptions{}}}); @@ -4755,7 +4718,7 @@ TEST(TransferTest, ContextSensitiveReturnArg) { const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - auto &BazVal = *cast(Env.getValue(*BazDecl, SkipPast::None)); + auto &BazVal = *cast(Env.getValue(*BazDecl)); EXPECT_TRUE(Env.flowConditionImplies(BazVal)); }, {BuiltinOptions{ContextSensitiveOptions{}}}); @@ -4803,7 +4766,7 @@ TEST(TransferTest, ContextSensitiveMethodLiteral) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); }, {BuiltinOptions{ContextSensitiveOptions{}}}); @@ -4835,7 +4798,7 @@ TEST(TransferTest, ContextSensitiveMethodGetter) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); }, {BuiltinOptions{ContextSensitiveOptions{}}}); @@ -4867,7 +4830,7 @@ TEST(TransferTest, ContextSensitiveMethodSetter) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); }, {BuiltinOptions{ContextSensitiveOptions{}}}); @@ -4901,7 +4864,7 @@ TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); }, {BuiltinOptions{ContextSensitiveOptions{}}}); @@ -4936,7 +4899,7 @@ TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); }, {BuiltinOptions{ContextSensitiveOptions{}}}); @@ -4970,7 +4933,7 @@ TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); }, {BuiltinOptions{ContextSensitiveOptions{}}}); @@ -5001,7 +4964,7 @@ TEST(TransferTest, ContextSensitiveConstructorBody) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); }, {BuiltinOptions{ContextSensitiveOptions{}}}); @@ -5032,7 +4995,7 @@ TEST(TransferTest, ContextSensitiveConstructorInitializer) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); }, {BuiltinOptions{ContextSensitiveOptions{}}}); @@ -5063,7 +5026,7 @@ TEST(TransferTest, ContextSensitiveConstructorDefault) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto &FooVal = *cast(Env.getValue(*FooDecl, SkipPast::None)); + auto &FooVal = *cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(FooVal)); }, {BuiltinOptions{ContextSensitiveOptions{}}}); diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index 57ab1c652d602..30aef86e7a26e 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -68,7 +68,7 @@ runAnalysis(llvm::StringRef Code, AnalysisT (*MakeAnalysis)(ASTContext &)) { assert(Body != nullptr); auto CFCtx = llvm::cantFail( - ControlFlowContext::build(nullptr, *Body, AST->getASTContext())); + ControlFlowContext::build(*Func, *Body, AST->getASTContext())); AnalysisT Analysis = MakeAnalysis(AST->getASTContext()); DataflowAnalysisContext DACtx(std::make_unique()); @@ -372,8 +372,7 @@ class SpecialBoolAnalysis final auto *Object = E->getImplicitObjectArgument(); assert(Object != nullptr); - auto *ObjectLoc = - Env.getStorageLocation(*Object, SkipPast::ReferenceThenPointer); + auto *ObjectLoc = getImplicitObjectLocation(*E, Env); assert(ObjectLoc != nullptr); auto &ConstructorVal = *Env.createValue(Object->getType()); @@ -489,8 +488,7 @@ TEST_F(JoinFlowConditionsTest, JoinDistinctButProvablyEquivalentValues) { ASSERT_THAT(FooDecl, NotNull()); auto GetFooValue = [FooDecl](const Environment &Env) { - return cast( - Env.getValue(*FooDecl, SkipPast::None)->getProperty("is_set")); + return cast(Env.getValue(*FooDecl)->getProperty("is_set")); }; EXPECT_FALSE(Env1.flowConditionImplies(*GetFooValue(Env1))); @@ -533,8 +531,7 @@ class OptionalIntAnalysis final auto *Object = E->getArg(0); assert(Object != nullptr); - auto *ObjectLoc = - Env.getStorageLocation(*Object, SkipPast::ReferenceThenPointer); + auto *ObjectLoc = Env.getStorageLocation(*Object, SkipPast::Reference); assert(ObjectLoc != nullptr); auto &ConstructorVal = *Env.createValue(Object->getType()); @@ -640,7 +637,7 @@ TEST_F(WideningTest, JoinDistinctValuesWithDistinctProperties) { ASSERT_THAT(FooDecl, NotNull()); auto GetFooValue = [FooDecl](const Environment &Env) { - return Env.getValue(*FooDecl, SkipPast::None); + return Env.getValue(*FooDecl); }; EXPECT_EQ(GetFooValue(Env1)->getProperty("has_value"), @@ -685,7 +682,7 @@ TEST_F(WideningTest, JoinDistinctValuesWithSameProperties) { ASSERT_THAT(FooDecl, NotNull()); auto GetFooValue = [FooDecl](const Environment &Env) { - return Env.getValue(*FooDecl, SkipPast::None); + return Env.getValue(*FooDecl); }; EXPECT_EQ(GetFooValue(Env1)->getProperty("has_value"), @@ -725,8 +722,7 @@ TEST_F(WideningTest, DistinctPointersToTheSameLocationAreEquivalent) { const auto *FooLoc = cast(Env.getStorageLocation(*FooDecl)); - const auto *BarVal = - cast(Env.getValue(*BarDecl, SkipPast::None)); + const auto *BarVal = cast(Env.getValue(*BarDecl)); EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); }); } @@ -755,7 +751,7 @@ TEST_F(WideningTest, DistinctValuesWithSamePropertiesAreEquivalent) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None); + const auto *FooVal = Env.getValue(*FooDecl); EXPECT_EQ(FooVal->getProperty("has_value"), &Env.getBoolLiteralValue(true)); }); @@ -804,13 +800,11 @@ TEST_F(FlowConditionTest, IfStmtSingleVar) { ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); - auto *FooVal1 = - cast(Env1.getValue(*FooDecl, SkipPast::None)); + auto *FooVal1 = cast(Env1.getValue(*FooDecl)); EXPECT_TRUE(Env1.flowConditionImplies(*FooVal1)); const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); - auto *FooVal2 = - cast(Env2.getValue(*FooDecl, SkipPast::None)); + auto *FooVal2 = cast(Env2.getValue(*FooDecl)); EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2)); }); } @@ -837,13 +831,11 @@ TEST_F(FlowConditionTest, IfStmtSingleNegatedVar) { ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); - auto *FooVal1 = - cast(Env1.getValue(*FooDecl, SkipPast::None)); + auto *FooVal1 = cast(Env1.getValue(*FooDecl)); EXPECT_FALSE(Env1.flowConditionImplies(*FooVal1)); const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); - auto *FooVal2 = - cast(Env2.getValue(*FooDecl, SkipPast::None)); + auto *FooVal2 = cast(Env2.getValue(*FooDecl)); EXPECT_TRUE(Env2.flowConditionImplies(*FooVal2)); }); } @@ -867,7 +859,7 @@ TEST_F(FlowConditionTest, WhileStmt) { ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); - auto *FooVal = cast(Env.getValue(*FooDecl, SkipPast::None)); + auto *FooVal = cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(*FooVal)); }); } @@ -896,14 +888,14 @@ TEST_F(FlowConditionTest, Conjunction) { ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); - auto *FooVal1 = cast(Env1.getValue(*FooDecl, SkipPast::None)); - auto *BarVal1 = cast(Env1.getValue(*BarDecl, SkipPast::None)); + auto *FooVal1 = cast(Env1.getValue(*FooDecl)); + auto *BarVal1 = cast(Env1.getValue(*BarDecl)); EXPECT_TRUE(Env1.flowConditionImplies(*FooVal1)); EXPECT_TRUE(Env1.flowConditionImplies(*BarVal1)); const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); - auto *FooVal2 = cast(Env2.getValue(*FooDecl, SkipPast::None)); - auto *BarVal2 = cast(Env2.getValue(*BarDecl, SkipPast::None)); + auto *FooVal2 = cast(Env2.getValue(*FooDecl)); + auto *BarVal2 = cast(Env2.getValue(*BarDecl)); EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2)); EXPECT_FALSE(Env2.flowConditionImplies(*BarVal2)); }); @@ -933,14 +925,14 @@ TEST_F(FlowConditionTest, Disjunction) { ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); - auto *FooVal1 = cast(Env1.getValue(*FooDecl, SkipPast::None)); - auto *BarVal1 = cast(Env1.getValue(*BarDecl, SkipPast::None)); + auto *FooVal1 = cast(Env1.getValue(*FooDecl)); + auto *BarVal1 = cast(Env1.getValue(*BarDecl)); EXPECT_FALSE(Env1.flowConditionImplies(*FooVal1)); EXPECT_FALSE(Env1.flowConditionImplies(*BarVal1)); const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); - auto *FooVal2 = cast(Env2.getValue(*FooDecl, SkipPast::None)); - auto *BarVal2 = cast(Env2.getValue(*BarDecl, SkipPast::None)); + auto *FooVal2 = cast(Env2.getValue(*FooDecl)); + auto *BarVal2 = cast(Env2.getValue(*BarDecl)); EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2)); EXPECT_FALSE(Env2.flowConditionImplies(*BarVal2)); }); @@ -970,14 +962,14 @@ TEST_F(FlowConditionTest, NegatedConjunction) { ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); - auto *FooVal1 = cast(Env1.getValue(*FooDecl, SkipPast::None)); - auto *BarVal1 = cast(Env1.getValue(*BarDecl, SkipPast::None)); + auto *FooVal1 = cast(Env1.getValue(*FooDecl)); + auto *BarVal1 = cast(Env1.getValue(*BarDecl)); EXPECT_FALSE(Env1.flowConditionImplies(*FooVal1)); EXPECT_FALSE(Env1.flowConditionImplies(*BarVal1)); const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); - auto *FooVal2 = cast(Env2.getValue(*FooDecl, SkipPast::None)); - auto *BarVal2 = cast(Env2.getValue(*BarDecl, SkipPast::None)); + auto *FooVal2 = cast(Env2.getValue(*FooDecl)); + auto *BarVal2 = cast(Env2.getValue(*BarDecl)); EXPECT_TRUE(Env2.flowConditionImplies(*FooVal2)); EXPECT_TRUE(Env2.flowConditionImplies(*BarVal2)); }); @@ -1007,14 +999,14 @@ TEST_F(FlowConditionTest, DeMorgan) { ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); - auto *FooVal1 = cast(Env1.getValue(*FooDecl, SkipPast::None)); - auto *BarVal1 = cast(Env1.getValue(*BarDecl, SkipPast::None)); + auto *FooVal1 = cast(Env1.getValue(*FooDecl)); + auto *BarVal1 = cast(Env1.getValue(*BarDecl)); EXPECT_TRUE(Env1.flowConditionImplies(*FooVal1)); EXPECT_TRUE(Env1.flowConditionImplies(*BarVal1)); const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); - auto *FooVal2 = cast(Env2.getValue(*FooDecl, SkipPast::None)); - auto *BarVal2 = cast(Env2.getValue(*BarDecl, SkipPast::None)); + auto *FooVal2 = cast(Env2.getValue(*FooDecl)); + auto *BarVal2 = cast(Env2.getValue(*BarDecl)); EXPECT_FALSE(Env2.flowConditionImplies(*FooVal2)); EXPECT_FALSE(Env2.flowConditionImplies(*BarVal2)); }); @@ -1044,7 +1036,7 @@ TEST_F(FlowConditionTest, Join) { ASSERT_THAT(FooDecl, NotNull()); const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); - auto *FooVal = cast(Env.getValue(*FooDecl, SkipPast::None)); + auto *FooVal = cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(*FooVal)); }); } @@ -1077,8 +1069,7 @@ TEST_F(FlowConditionTest, OpaqueFlowConditionMergesToOpaqueBool) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - auto &BarVal = - *cast(Env.getValue(*BarDecl, SkipPast::Reference)); + auto &BarVal = *cast(Env.getValue(*BarDecl)); EXPECT_FALSE(Env.flowConditionImplies(BarVal)); }); @@ -1119,8 +1110,7 @@ TEST_F(FlowConditionTest, OpaqueFieldFlowConditionMergesToOpaqueBool) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - auto &BarVal = - *cast(Env.getValue(*BarDecl, SkipPast::Reference)); + auto &BarVal = *cast(Env.getValue(*BarDecl)); EXPECT_FALSE(Env.flowConditionImplies(BarVal)); }); @@ -1154,8 +1144,7 @@ TEST_F(FlowConditionTest, OpaqueFlowConditionInsideBranchMergesToOpaqueBool) { const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - auto &BarVal = - *cast(Env.getValue(*BarDecl, SkipPast::Reference)); + auto &BarVal = *cast(Env.getValue(*BarDecl)); EXPECT_FALSE(Env.flowConditionImplies(BarVal)); }); @@ -1184,13 +1173,11 @@ TEST_F(FlowConditionTest, PointerToBoolImplicitCast) { ASSERT_THAT(FooDecl, NotNull()); const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); - auto &FooVal1 = - *cast(Env1.getValue(*FooDecl, SkipPast::Reference)); + auto &FooVal1 = *cast(Env1.getValue(*FooDecl)); EXPECT_TRUE(Env1.flowConditionImplies(FooVal1)); const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); - auto &FooVal2 = - *cast(Env2.getValue(*FooDecl, SkipPast::Reference)); + auto &FooVal2 = *cast(Env2.getValue(*FooDecl)); EXPECT_FALSE(Env2.flowConditionImplies(FooVal2)); }); } @@ -1267,9 +1254,8 @@ TEST_F(TopTest, UnusedTopInitializer) { const ValueDecl *FooDecl = findValueDecl(AO.ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto GetFooValue = [FooDecl](const Environment &Env) { - return Env.getValue(*FooDecl, SkipPast::None); + return Env.getValue(*FooDecl); }; Value *FooVal1 = GetFooValue(Env1); @@ -1313,9 +1299,8 @@ TEST_F(TopTest, UnusedTopAssignment) { const ValueDecl *FooDecl = findValueDecl(AO.ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); - auto GetFooValue = [FooDecl](const Environment &Env) { - return Env.getValue(*FooDecl, SkipPast::None); + return Env.getValue(*FooDecl); }; Value *FooVal1 = GetFooValue(Env1); @@ -1366,7 +1351,7 @@ TEST_F(TopTest, UnusedTopJoinsToTop) { ASSERT_THAT(FooDecl, NotNull()); auto GetFooValue = [FooDecl](const Environment &Env) { - return Env.getValue(*FooDecl, SkipPast::None); + return Env.getValue(*FooDecl); }; Value *FooVal1 = GetFooValue(Env1); @@ -1421,7 +1406,7 @@ TEST_F(TopTest, TopUsedBeforeBranchJoinsToSameAtomicBool) { ASSERT_THAT(FooDecl, NotNull()); auto GetFooValue = [FooDecl](const Environment &Env) { - return Env.getValue(*FooDecl, SkipPast::None); + return Env.getValue(*FooDecl); }; Value *FooVal0 = GetFooValue(Env0); @@ -1477,7 +1462,7 @@ TEST_F(TopTest, TopUsedInBothBranchesJoinsToAtomic) { ASSERT_THAT(FooDecl, NotNull()); auto GetFooValue = [FooDecl](const Environment &Env) { - return Env.getValue(*FooDecl, SkipPast::None); + return Env.getValue(*FooDecl); }; Value *FooVal1 = GetFooValue(Env1); @@ -1525,12 +1510,10 @@ TEST_F(TopTest, TopUsedInBothBranchesWithoutPrecisionLoss) { const ValueDecl *BarDecl = findValueDecl(AO.ASTCtx, "Bar"); ASSERT_THAT(BarDecl, NotNull()); - auto *FooVal = - dyn_cast_or_null(Env.getValue(*FooDecl, SkipPast::None)); + auto *FooVal = dyn_cast_or_null(Env.getValue(*FooDecl)); ASSERT_THAT(FooVal, NotNull()); - auto *BarVal = - dyn_cast_or_null(Env.getValue(*BarDecl, SkipPast::None)); + auto *BarVal = dyn_cast_or_null(Env.getValue(*BarDecl)); ASSERT_THAT(BarVal, NotNull()); EXPECT_TRUE(Env.flowConditionImplies(Env.makeIff(*FooVal, *BarVal))); @@ -1570,7 +1553,7 @@ TEST_F(TopTest, TopUnusedBeforeLoopHeadJoinsToTop) { ASSERT_THAT(FooDecl, NotNull()); auto GetFooValue = [FooDecl](const Environment &Env) { - return Env.getValue(*FooDecl, SkipPast::None); + return Env.getValue(*FooDecl); }; Value *FooVal1 = GetFooValue(Env1); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 099a5cb913643..dc673934a3f1b 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -6367,6 +6367,51 @@ TEST_F(FormatTest, FormatAlignInsidePreprocessorElseBlock) { "#endif\n" "}", Style); + + verifyFormat("#if FOO\n" + "int a = 1;\n" + "#else\n" + "int ab = 2;\n" + "#endif\n" + "#ifdef BAR\n" + "int abc = 3;\n" + "#elifdef BAZ\n" + "int abcd = 4;\n" + "#endif", + Style); + + verifyFormat("void f() {\n" + " if (foo) {\n" + "#if FOO\n" + " int a = 1;\n" + "#else\n" + " bool a = true;\n" + "#endif\n" + " int abc = 3;\n" + "#ifndef BAR\n" + " int abcd = 4;\n" + "#elif BAZ\n" + " bool abcd = true;\n" + "#endif\n" + " }\n" + "}", + Style); + + verifyFormat("void f() {\n" + "#if FOO\n" + " a = 1;\n" + "#else\n" + " ab = 2;\n" + "#endif\n" + "}\n" + "void g() {\n" + "#if BAR\n" + " abc = 3;\n" + "#elifndef BAZ\n" + " abcd = 4;\n" + "#endif\n" + "}", + Style); } TEST_F(FormatTest, FormatHashIfNotAtStartOfLine) { diff --git a/clang/unittests/Format/FormatTestComments.cpp b/clang/unittests/Format/FormatTestComments.cpp index 60e045059be86..0cf7aaaa4bdb2 100644 --- a/clang/unittests/Format/FormatTestComments.cpp +++ b/clang/unittests/Format/FormatTestComments.cpp @@ -2759,7 +2759,7 @@ TEST_F(FormatTestComments, AlignTrailingComments) { // Checks an edge case in preprocessor handling. // These comments should *not* be aligned - EXPECT_NE( // change for EQ when fixed + EXPECT_EQ( "#if FOO\n" "#else\n" "long a; // Line about a\n" diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index 6f07d8b084f56..ce81bd5d2f044 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -1476,6 +1476,17 @@ TEST_F(FormatTestJS, ImportExportASI) { " export class Y {}"); } +TEST_F(FormatTestJS, ImportExportType) { + verifyFormat("import type {x, y} from 'y';\n" + "import type * as x from 'y';\n" + "import type x from 'y';\n" + "import {x, type yu, z} from 'y';\n"); + verifyFormat("export type {x, y} from 'y';\n" + "export {x, type yu, z} from 'y';\n" + "export type {x, y};\n" + "export {x, type yu, z};\n"); +} + TEST_F(FormatTestJS, ClosureStyleCasts) { verifyFormat("var x = /** @type {foo} */ (bar);"); } diff --git a/clang/unittests/Format/SortImportsTestJS.cpp b/clang/unittests/Format/SortImportsTestJS.cpp index 1c7e508630360..2778d6efcdf9a 100644 --- a/clang/unittests/Format/SortImportsTestJS.cpp +++ b/clang/unittests/Format/SortImportsTestJS.cpp @@ -465,6 +465,55 @@ TEST_F(SortImportsTestJS, ImportEqAliases) { "console.log(Z);\n"); } +TEST_F(SortImportsTestJS, ImportExportType) { + verifySort("import type {sym} from 'a';\n" + "import {type sym} from 'b';\n" + "import {sym} from 'c';\n" + "import type sym from 'd';\n" + "import type * as sym from 'e';\n" + "\n" + "let x = 1;", + "import {sym} from 'c';\n" + "import type {sym} from 'a';\n" + "import type * as sym from 'e';\n" + "import type sym from 'd';\n" + "import {type sym} from 'b';\n" + "let x = 1;"); + + // Symbols within import statement + verifySort("import {type sym1, type sym2 as a, sym3} from 'b';\n", + "import {type sym2 as a, type sym1, sym3} from 'b';\n"); + + // Merging + verifySort("import {X, type Z} from 'a';\n" + "import type {Y} from 'a';\n" + "\n" + "X + Y + Z;\n", + "import {X} from 'a';\n" + "import {type Z} from 'a';\n" + "import type {Y} from 'a';\n" + "\n" + "X + Y + Z;\n"); + + // Merging: empty imports + verifySort("import type {A} from 'foo';\n", "import type {} from 'foo';\n" + "import type {A} from 'foo';"); + + // Merging: exports + verifySort("export {A, type B} from 'foo';\n", + "export {A} from 'foo';\n" + "export {type B} from 'foo';"); + + // `export type X = Y;` should terminate import sorting. The following export + // statements should therefore not merge. + verifySort("export type A = B;\n" + "export {X};\n" + "export {Y};\n", + "export type A = B;\n" + "export {X};\n" + "export {Y};\n"); +} + } // end namespace } // end namespace format } // end namespace clang diff --git a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp index 2f8804784a2e4..bc4eee73c1c29 100644 --- a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp +++ b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp @@ -503,6 +503,92 @@ TEST(MinimizeSourceToDependencyDirectivesTest, Pragma) { EXPECT_STREQ("#pragma clang module import\n", Out.data()); } +TEST(MinimizeSourceToDependencyDirectivesTest, UnderscorePragma) { + SmallVector Out; + + ASSERT_FALSE(minimizeSourceToDependencyDirectives(R"(_)", Out)); + EXPECT_STREQ("\n", Out.data()); + ASSERT_FALSE(minimizeSourceToDependencyDirectives(R"(_Pragma)", Out)); + EXPECT_STREQ("\n", Out.data()); + ASSERT_FALSE(minimizeSourceToDependencyDirectives(R"(_Pragma()", Out)); + EXPECT_STREQ("\n", Out.data()); + ASSERT_FALSE(minimizeSourceToDependencyDirectives(R"(_Pragma())", Out)); + EXPECT_STREQ("\n", Out.data()); + ASSERT_FALSE(minimizeSourceToDependencyDirectives(R"(_Pragma(")", Out)); + EXPECT_STREQ("\n", Out.data()); + ASSERT_FALSE(minimizeSourceToDependencyDirectives(R"(_Pragma("A"))", Out)); + EXPECT_STREQ("\n", Out.data()); + + ASSERT_FALSE(minimizeSourceToDependencyDirectives( + R"x(_Pragma("push_macro(\"MACRO\")"))x", Out)); + EXPECT_STREQ(R"x(_Pragma("push_macro(\"MACRO\")"))x" + "\n", + Out.data()); + + ASSERT_FALSE(minimizeSourceToDependencyDirectives( + R"x(_Pragma("pop_macro(\"MACRO\")"))x", Out)); + EXPECT_STREQ(R"x(_Pragma("pop_macro(\"MACRO\")"))x" + "\n", + Out.data()); + + ASSERT_FALSE(minimizeSourceToDependencyDirectives( + R"x(_Pragma("include_alias(\"A\", \"B\")"))x", Out)); + EXPECT_STREQ(R"x(_Pragma("include_alias(\"A\", \"B\")"))x" + "\n", + Out.data()); + + ASSERT_FALSE(minimizeSourceToDependencyDirectives( + R"x(_Pragma("include_alias(, )"))x", Out)); + EXPECT_STREQ(R"x(_Pragma("include_alias(, )"))x" + "\n", + Out.data()); + + ASSERT_FALSE( + minimizeSourceToDependencyDirectives(R"(_Pragma("clang"))", Out)); + EXPECT_STREQ("\n", Out.data()); + + ASSERT_FALSE( + minimizeSourceToDependencyDirectives(R"(_Pragma("clang module"))", Out)); + EXPECT_STREQ("\n", Out.data()); + + ASSERT_FALSE(minimizeSourceToDependencyDirectives( + R"(_Pragma("clang module impor"))", Out)); + EXPECT_STREQ("\n", Out.data()); + + ASSERT_FALSE(minimizeSourceToDependencyDirectives( + R"(_Pragma("clang module import"))", Out)); + EXPECT_STREQ(R"(_Pragma("clang module import"))" + "\n", + Out.data()); + + ASSERT_FALSE(minimizeSourceToDependencyDirectives( + R"(_Pragma("clang \ + module \ + import"))", + Out)); + EXPECT_STREQ(R"(_Pragma("clang \ + module \ + import"))" + "\n", + Out.data()); + + ASSERT_FALSE(minimizeSourceToDependencyDirectives( + R"(_Pragma(L"clang module import"))", Out)); + EXPECT_STREQ(R"(_Pragma(L"clang module import"))" + "\n", + Out.data()); + + // FIXME: u"" strings depend on using C11 language mode + ASSERT_FALSE(minimizeSourceToDependencyDirectives( + R"(_Pragma(u"clang module import"))", Out)); + EXPECT_STREQ("\n", Out.data()); + + // FIXME: R"()" strings depend on using C++ 11 language mode + ASSERT_FALSE(minimizeSourceToDependencyDirectives( + R"(_Pragma(R"abc(clang module import)abc"))", Out)); + EXPECT_STREQ("\n", Out.data()); +} + TEST(MinimizeSourceToDependencyDirectivesTest, Include) { SmallVector Out; @@ -757,20 +843,26 @@ TEST(MinimizeSourceToDependencyDirectivesTest, PragmaOnce) { #pragma once // another comment #include +_Pragma("once") )"; ASSERT_FALSE( minimizeSourceToDependencyDirectives(Source, Out, Tokens, Directives)); - EXPECT_STREQ("#pragma once\n#include \n", Out.data()); - ASSERT_EQ(Directives.size(), 3u); + EXPECT_STREQ("#pragma once\n#include \n_Pragma(\"once\")\n", + Out.data()); + ASSERT_EQ(Directives.size(), 4u); EXPECT_EQ(Directives[0].Kind, dependency_directives_scan::pp_pragma_once); + EXPECT_EQ(Directives[2].Kind, dependency_directives_scan::pp_pragma_once); Source = R"(// comment #pragma once extra tokens // another comment #include + _Pragma("once") extra tokens )"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out)); - EXPECT_STREQ("#pragma once extra tokens\n#include \n", Out.data()); + EXPECT_STREQ("#pragma once extra tokens\n#include " + "\n_Pragma(\"once\")\n", + Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, diff --git a/clang/utils/ClangVisualizers/clang.natvis b/clang/utils/ClangVisualizers/clang.natvis index 3e6148cd5e05c..ff949ce490d19 100644 --- a/clang/utils/ClangVisualizers/clang.natvis +++ b/clang/utils/ClangVisualizers/clang.natvis @@ -25,11 +25,16 @@ For later versions of Visual Studio, no setup is required--> {*(clang::BuiltinType *)this} {*(clang::PointerType *)this} + {*(clang::ParenType *)this} + {(clang::BitIntType *)this} {*(clang::LValueReferenceType *)this} {*(clang::RValueReferenceType *)this} {(clang::ConstantArrayType *)this,na} {(clang::ConstantArrayType *)this,view(left)na} {(clang::ConstantArrayType *)this,view(right)na} + {(clang::VariableArrayType *)this,na} + {(clang::VariableArrayType *)this,view(left)na} + {(clang::VariableArrayType *)this,view(right)na} {(clang::IncompleteArrayType *)this,na} {(clang::IncompleteArrayType *)this,view(left)na} {(clang::IncompleteArrayType *)this,view(right)na} @@ -39,6 +44,9 @@ For later versions of Visual Studio, no setup is required--> {(clang::DecayedType *)this,na} {(clang::DecayedType *)this,view(left)na} {(clang::DecayedType *)this,view(right)na} + {(clang::ElaboratedType *)this,na} + {(clang::ElaboratedType *)this,view(left)na} + {(clang::ElaboratedType *)this,view(right)na} {*(clang::TemplateTypeParmType *)this} {*(clang::TemplateTypeParmType *)this,view(cpp)} {*(clang::SubstTemplateTypeParmType *)this} @@ -59,25 +67,17 @@ For later versions of Visual Studio, no setup is required--> {*this,view(cpp)} No visualizer yet for {(clang::Type::TypeClass)TypeBits.TC,en}Type - Dependent{" ",sb} - - InstantiationDependent{" ",sb} - - VariablyModified{" ",sb} - - ContainsUnexpandedParameterPack{" ",sb} - + Dependence{" ",en} + CachedLinkage: {(clang::Linkage)TypeBits.CachedLinkage,en} CachedLocalOrUnnamed CachedLinkage: {(clang::Linkage)TypeBits.CachedLinkage,en}{" ",sb} FromAST - + No TypeBits set beyond TypeClass - -{*this, view(Dependent)}{*this, view(InstantiationDependent)}{*this, view(VariablyModified)} -{*this, view(ContainsUnexpandedParameterPack)}{*this, view(Cache)}{*this, view(FromAST)} + {*this, view(Dependence)}{*this, view(Cache)}{*this, view(FromAST)} {*this,view(cmn)} {{{*this,view(poly)}}} (clang::Type::TypeClass)TypeBits.TC @@ -85,12 +85,16 @@ For later versions of Visual Studio, no setup is required--> CanonicalType *(clang::BuiltinType *)this *(clang::PointerType *)this + *(clang::ParenType*)this + *(clang::BitIntType*)this *(clang::LValueReferenceType *)this *(clang::RValueReferenceType *)this (clang::ConstantArrayType *)this + (clang::VariableArrayType *)this (clang::IncompleteArrayType *)this *(clang::AttributedType *)this (clang::DecayedType *)this + (clang::ElaboratedType *)this (clang::TemplateTypeParmType *)this (clang::SubstTemplateTypeParmType *)this (clang::RecordType *)this @@ -125,6 +129,15 @@ For later versions of Visual Studio, no setup is required--> (clang::ArrayType *)this + + {ElementType,view(cpp)} + [*] + {ElementType,view(cpp)}[*] + + (clang::Expr *)SizeExpr + (clang::ArrayType *)this + + {Decl,view(name)nd} {Decl} @@ -140,6 +153,21 @@ For later versions of Visual Studio, no setup is required--> *(clang::Type *)this, view(cmn) + + {Inner, view(cpp)} + + Inner + *(clang::Type *)this, view(cmn) + + + + signed _BitInt({NumBits}) + unsigned _BitInt({NumBits})( + + NumBits + (clang::Type *)this, view(cmn) + + @@ -171,7 +199,7 @@ For later versions of Visual Studio, no setup is required--> FirstDecl - (clang::Decl *)(NextInContextAndBits.Value & ~3) + (clang::Decl *)(*(intptr_t *)NextInContextAndBits.Value.Data & ~3) *this @@ -213,15 +241,15 @@ For later versions of Visual Studio, no setup is required--> - {(clang::TypeSourceInfo *)(MaybeModedTInfo.Value & ~7LL),view(cpp)na} - {(clang::TypedefNameDecl::ModedTInfo *)(MaybeModedTInfo.Value & ~7LL),view(cpp)na} + {(clang::TypeSourceInfo *)(*(uintptr_t *)MaybeModedTInfo.Value.Data & ~7LL),view(cpp)na} + {(clang::TypedefNameDecl::ModedTInfo *)(*(uintptr_t *)MaybeModedTInfo.Value.Data & ~7LL),view(cpp)na} {(TypeDecl *)this,view(cpp)nand} typedef {this,view(type)na} {this,view(name)na}; - "Not yet calculated",sb - (bool)(MaybeModedTInfo.Value & 2) - (clang::TypeSourceInfo *)(MaybeModedTInfo.Value & ~7LL) - (clang::TypedefNameDecl::ModedTInfo *)(MaybeModedTInfo.Value & ~7LL) + "Not yet calculated",sb + (bool)(*(uintptr_t *)MaybeModedTInfo.Value.Data & 2) + (clang::TypeSourceInfo *)(*(uintptr_t *)MaybeModedTInfo.Value.Data & ~7LL) + (clang::TypedefNameDecl::ModedTInfo *)(*(uintptr_t *)MaybeModedTInfo.Value.Data & ~7LL) (TypeDecl *)this,nd @@ -400,6 +428,16 @@ For later versions of Visual Studio, no setup is required--> (clang::AdjustedType *)this + + {NamedType,view(left)} + {NamedType,view(right)} + {NamedType} + + (clang::ElaboratedTypeKeyword)TypeWithKeywordBits.Keyword + NNS + NamedType,view(cmn) + + {TTPDecl->Name,view(cpp)} Non-canonical: {*TTPDecl} @@ -426,11 +464,11 @@ For later versions of Visual Studio, no setup is required--> - {(IdentifierInfo*)Specifier,view(cpp)na}:: - {(NamedDecl*)Specifier,view(cpp)na}:: - {(Type*)Specifier,view(cpp)na}:: + {(IdentifierInfo*)Specifier,view(cpp)na}:: + {(NamedDecl*)Specifier,view(cpp)na}:: + {(Type*)Specifier,view(cpp)na}:: - (NestedNameSpecifier::StoredSpecifierKind)((Prefix.Value>>1)&3) + (NestedNameSpecifier::StoredSpecifierKind)((*(uintptr_t *)Prefix.Value.Data>>1)&3) @@ -442,28 +480,28 @@ For later versions of Visual Studio, no setup is required--> - - {*((clang::ExtQualsTypeCommonBase *)(((uintptr_t)Value.Value) & ~(uintptr_t)((1 << 4) - 1)))->BaseType,view(poly)}{*this,view(fastQuals)} - {*((clang::ExtQualsTypeCommonBase *)(((uintptr_t)Value.Value) & ~(uintptr_t)((1 << 4) - 1)))->BaseType,view(cpp)}{*this,view(fastQuals)} - {*((clang::ExtQualsTypeCommonBase *)(((uintptr_t)Value.Value) & ~(uintptr_t)((1 << 4) - 1)))->BaseType,view(left)}{*this,view(fastQuals)} - {*((clang::ExtQualsTypeCommonBase *)(((uintptr_t)Value.Value) & ~(uintptr_t)((1 << 4) - 1)))->BaseType,view(right)}{*this,view(fastQuals)} + {((clang::ExtQualsTypeCommonBase *)((*(uintptr_t *)Value.Value.Data) & ~(uintptr_t)((1U << clang::TypeAlignmentInBits) - 1U)))->BaseType,view(poly)}{*this,view(fastQuals)} + {((clang::ExtQualsTypeCommonBase *)((*(uintptr_t *)Value.Value.Data) & ~(uintptr_t)((1U << clang::TypeAlignmentInBits) - 1U)))->BaseType,view(cpp)}{*this,view(fastQuals)} + {((clang::ExtQualsTypeCommonBase *)((*(uintptr_t *)Value.Value.Data) & ~(uintptr_t)((1U << clang::TypeAlignmentInBits) - 1U)))->BaseType,view(left)}{*this,view(fastQuals)} + {((clang::ExtQualsTypeCommonBase *)((*(uintptr_t *)Value.Value.Data) & ~(uintptr_t)((1U << clang::TypeAlignmentInBits) - 1U)))->BaseType,view(right)}{*this,view(fastQuals)} - - {" ",sb}const - {" ",sb}restrict - {" ",sb}const restrict - {" ",sb}volatile - {" ",sb}const volatile - {" ",sb}volatile restrict - {" ",sb}const volatile restrict + + {" ",sb}const + {" ",sb}restrict + {" ",sb}const restrict + {" ",sb}volatile + {" ",sb}const volatile + {" ",sb}volatile restrict + {" ",sb}const volatile restrict Cannot visualize non-fast qualifiers - Null - {((clang::ExtQualsTypeCommonBase *)(((uintptr_t)Value.Value) & ~(uintptr_t)((1 << 4) - 1)))->BaseType,na}{*this,view(fastQuals)} + Null + {((clang::ExtQualsTypeCommonBase *)((*(uintptr_t *)Value.Value.Data) & ~(uintptr_t)((1U << clang::TypeAlignmentInBits) - 1U)))->BaseType,na}{*this,view(fastQuals)} *this,view(fastQuals) - ((clang::ExtQualsTypeCommonBase *)(((uintptr_t)Value.Value) & ~(uintptr_t)((1 << 4) - 1)))->BaseType + ((clang::ExtQualsTypeCommonBase *)((*(uintptr_t *)Value.Value.Data) & ~(uintptr_t)((1U << clang::TypeAlignmentInBits) - 1U)))->BaseType + {DeclInfo,view(cpp)na} @@ -889,31 +927,31 @@ For later versions of Visual Studio, no setup is required--> - {((clang::FunctionProtoType *)((clang::ExtQualsTypeCommonBase *)(((uintptr_t)DeclType.Value.Value) & ~15))->BaseType)->ResultType,view(cpp)} - + {((clang::FunctionProtoType *)((clang::ExtQualsTypeCommonBase *)((*(uintptr_t *)DeclType.Value.Value.Data) & ~15))->BaseType)->ResultType,view(cpp)} + {ParamInfo[0],na}{*this,view(parm1)nd} - + , {ParamInfo[1],na}{*this,view(parm2)nd} - + , {ParamInfo[2],na}{*this,view(parm3)nd} - + , {ParamInfo[3],na}{*this,view(parm4)nd} - + , {ParamInfo[4],na}{*this,view(parm5)nd} - + , /* expand for more params */ - - auto {Name,view(cpp)nd}({*this,view(parm0)nd}) -> {((clang::FunctionProtoType *)((clang::ExtQualsTypeCommonBase *)(((uintptr_t)DeclType.Value.Value) & ~15))->BaseType)->ResultType,view(cpp)} + + auto {Name,view(cpp)nd}({*this,view(parm0)nd}) -> {((clang::FunctionProtoType *)((clang::ExtQualsTypeCommonBase *)((*(uintptr_t *)DeclType.Value.Value.Data) & ~15))->BaseType)->ResultType,view(cpp)} {this,view(retType)nand} {Name,view(cpp)nd}({*this,view(parm0)nd}) (clang::DeclaratorDecl *)this,nd - ((clang::FunctionProtoType *)((clang::ExtQualsTypeCommonBase *)(((uintptr_t)DeclType.Value.Value) & ~15))->BaseType)->ResultType + ((clang::FunctionProtoType *)((clang::ExtQualsTypeCommonBase *)((*(uintptr_t *)DeclType.Value.Value.Data) & ~15))->BaseType)->ResultType {*this,view(parm0)nd} - ((clang::FunctionProtoType *)((clang::ExtQualsTypeCommonBase *)(((uintptr_t)DeclType.Value.Value) & ~15))->BaseType)->FunctionTypeBits.NumParams + ((clang::FunctionProtoType *)((clang::ExtQualsTypeCommonBase *)((*(uintptr_t *)DeclType.Value.Value.Data) & ~15))->BaseType)->FunctionTypeBits.NumParams ParamInfo diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp index d5d3f5fe558a8..d7f1e5af4db26 100644 --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -299,6 +299,7 @@ class SVEEmitter { if (It != FlagTypes.end()) { uint64_t Mask = It->getValue(); unsigned Shift = llvm::countr_zero(Mask); + assert(Shift < 64 && "Mask value produced an invalid shift value"); return (V << Shift) & Mask; } llvm_unreachable("Unsupported flag"); diff --git a/clang/utils/perf-training/CMakeLists.txt b/clang/utils/perf-training/CMakeLists.txt index 0d551baba2ccf..c6d51863fb1b5 100644 --- a/clang/utils/perf-training/CMakeLists.txt +++ b/clang/utils/perf-training/CMakeLists.txt @@ -61,3 +61,26 @@ if(APPLE AND DTRACE AND NOT LLVM_TOOL_LLVM_DRIVER_BUILD) COMMENT "Generating order file" DEPENDS generate-dtrace-logs) endif() + +if(CLANG_BOLT_INSTRUMENT AND NOT LLVM_BUILD_INSTRUMENTED) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/bolt.lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/bolt-fdata/lit.site.cfg + ) + + add_lit_testsuite(generate-bolt-fdata "Generating BOLT profile for Clang" + ${CMAKE_CURRENT_BINARY_DIR}/bolt-fdata/ + EXCLUDE_FROM_CHECK_ALL + DEPENDS clang-instrumented clear-bolt-fdata + ) + + add_custom_target(clear-bolt-fdata + COMMAND "${Python3_EXECUTABLE}" ${CMAKE_CURRENT_SOURCE_DIR}/perf-helper.py clean ${CMAKE_CURRENT_BINARY_DIR} fdata + COMMENT "Clearing old BOLT fdata") + + # Merge profiles into one using merge-fdata + add_custom_target(clang-bolt-profile + COMMAND "${Python3_EXECUTABLE}" ${CMAKE_CURRENT_SOURCE_DIR}/perf-helper.py merge-fdata $ ${CMAKE_CURRENT_BINARY_DIR}/prof.fdata ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Merging BOLT fdata" + DEPENDS merge-fdata generate-bolt-fdata) +endif() diff --git a/clang/utils/perf-training/bolt.lit.cfg b/clang/utils/perf-training/bolt.lit.cfg new file mode 100644 index 0000000000000..234ac855bd67c --- /dev/null +++ b/clang/utils/perf-training/bolt.lit.cfg @@ -0,0 +1,20 @@ +# -*- Python -*- + +from lit import Test +import lit.formats +import lit.util +import os +import subprocess + +config.clang = os.path.realpath(lit.util.which('clang-bolt.inst', config.clang_tools_dir)).replace('\\', '/') + +config.name = 'Clang Perf Training' +config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl', '.s', '.S', '.modulemap', '.test'] + +use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") +config.test_format = lit.formats.ShTest(use_lit_shell == "0") +config.substitutions.append( ('%clang_cpp_skip_driver', ' %s --driver-mode=g++ ' % (config.clang))) +config.substitutions.append( ('%clang_cpp', ' %s --driver-mode=g++ ' % (config.clang))) +config.substitutions.append( ('%clang_skip_driver', ' %s ' % (config.clang))) +config.substitutions.append( ('%clang', ' %s ' % (config.clang) ) ) +config.substitutions.append( ('%test_root', config.test_exec_root ) ) diff --git a/clang/utils/perf-training/bolt.lit.site.cfg.in b/clang/utils/perf-training/bolt.lit.site.cfg.in new file mode 100644 index 0000000000000..3029319673fc2 --- /dev/null +++ b/clang/utils/perf-training/bolt.lit.site.cfg.in @@ -0,0 +1,14 @@ +@LIT_SITE_CFG_IN_HEADER@ + +import sys + +config.clang_tools_dir = lit_config.substitute("@CURRENT_TOOLS_DIR@") +config.perf_helper_dir = "@CMAKE_CURRENT_SOURCE_DIR@" +config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" +config.test_source_root = "@CLANG_PGO_TRAINING_DATA@" +config.target_triple = "@LLVM_TARGET_TRIPLE@" +config.python_exe = "@Python3_EXECUTABLE@" +config.clang_obj_root = path(r"@CLANG_BINARY_DIR@") + +# Let the main config do the real work. +lit_config.load_config(config, "@CLANG_SOURCE_DIR@/utils/perf-training/bolt.lit.cfg") diff --git a/clang/www/OpenProjects.html b/clang/www/OpenProjects.html index d3aedd281121c..7a8bdbd3dbbc8 100755 --- a/clang/www/OpenProjects.html +++ b/clang/www/OpenProjects.html @@ -123,7 +123,7 @@

Open Clang Projects

-
  • Continue work on C++20, C++23, and C2x support: +
  • Continue work on C++20, C++23, C++2c, and C2x support: There are still several C++20 features to complete, and work has begun on supporting the latest language standards. Please see the C++ status report page to find out what is diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index e4ecb5f832e93..564c3d6a8c48c 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -65,6 +65,11 @@

    C++ Support in Clang

    -std=c++23 Partial + + C++2c + -std=c++2c + Partial +

    The Clang community is continually striving to improve C++ standards @@ -1024,11 +1029,7 @@

    C++20 implementation status

    Lambdas in unevaluated contexts P0315R4 - -
    Partial - temp.deduct/9 is not implemented yet. -
    - + Clang 17 @@ -1484,7 +1485,7 @@

    C++23 implementation status

    Clang 17 (Partial) We do not support outside of defaulted special memeber functions the change that constexpr functions no longer have to be constexpr compatible but rather support a less restricted requirements for constexpr - functions. Which include allowing non-literal types as return values and paremeters, allow calling of + functions. Which include allowing non-literal types as return values and parameters, allow calling of non-constexpr functions and constructors.
    @@ -1564,6 +1565,25 @@

    C++23 implementation status

    +

    C++2c implementation status

    + + +

    Clang has support for some of the features of the C++ standard following +C++23, informally referred to as C++26.

    + +

    You can use Clang in C++2c mode with the -std=c++2c option.

    + +
    +List of features and minimum Clang version with support + + + + + + +
    Language FeatureC++26 ProposalAvailable in Clang?
    +
    +

    Defect reports

    Clang generally aims to implement resolutions to Defect Reports (bug fixes diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt index c5a7b2478e504..8485fe9232d00 100644 --- a/compiler-rt/CMakeLists.txt +++ b/compiler-rt/CMakeLists.txt @@ -3,20 +3,13 @@ # An important constraint of the build is that it only produces libraries # based on the ability of the host toolchain to target various platforms. -cmake_minimum_required(VERSION 3.13.4) +cmake_minimum_required(VERSION 3.20.0) # Check if compiler-rt is built as a standalone project. if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR COMPILER_RT_STANDALONE_BUILD) project(CompilerRT C CXX ASM) set(COMPILER_RT_STANDALONE_BUILD TRUE) set_property(GLOBAL PROPERTY USE_FOLDERS ON) - if ("${CMAKE_VERSION}" VERSION_LESS "3.20.0") - message(WARNING - "Your CMake version is ${CMAKE_VERSION}. Starting with LLVM 17.0.0, the " - "minimum version of CMake required to build LLVM will become 3.20.0, and " - "using an older CMake will become an error. Please upgrade your CMake to " - "at least 3.20.0 now to avoid issues in the future!") - endif() endif() set(LLVM_COMMON_CMAKE_UTILS "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake index 99d672de4e882..3892dd7a6f453 100644 --- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake +++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake @@ -38,7 +38,8 @@ else() endif() if(OS_NAME MATCHES "Linux") - set(ALL_FUZZER_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${S390X}) + set(ALL_FUZZER_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${S390X} + ${RISCV64}) elseif (OS_NAME MATCHES "Windows") set(ALL_FUZZER_SUPPORTED_ARCH ${X86} ${X86_64}) elseif(OS_NAME MATCHES "Android") diff --git a/compiler-rt/lib/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt index 08fd68ab7acbc..1bfc6f0c5e37d 100644 --- a/compiler-rt/lib/asan/CMakeLists.txt +++ b/compiler-rt/lib/asan/CMakeLists.txt @@ -46,7 +46,7 @@ set(ASAN_STATIC_SOURCES asan_rtl_static.cpp ) -if (NOT WIN32 AND NOT APPLE) +if (ASAN_SUPPORTED_ARCH STREQUAL "x86_64" AND NOT WIN32 AND NOT APPLE) list(APPEND ASAN_STATIC_SOURCES asan_rtl_x86_64.S ) diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index 2df596ed7fe15..2595a6adda061 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -23,6 +23,7 @@ #include "asan_suppressions.h" #include "asan_thread.h" #include "lsan/lsan_common.h" +#include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_libc.h" // There is no general interception at all on Fuchsia. @@ -198,11 +199,16 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { AsanThread *t = (AsanThread *)arg; SetCurrentThread(t); - return t->ThreadStart(GetTid()); + auto self = GetThreadSelf(); + auto args = asanThreadArgRetval().GetArgs(self); + thread_return_t retval = t->ThreadStart(GetTid()); + asanThreadArgRetval().Finish(self, retval); + CHECK_EQ(args.arg_retval, t->get_arg()); + return retval; } -INTERCEPTOR(int, pthread_create, void *thread, - void *attr, void *(*start_routine)(void*), void *arg) { +INTERCEPTOR(int, pthread_create, void *thread, void *attr, + void *(*start_routine)(void *), void *arg) { EnsureMainThreadIDIsCorrect(); // Strict init-order checking is thread-hostile. if (flags()->strict_init_order) @@ -222,10 +228,13 @@ INTERCEPTOR(int, pthread_create, void *thread, // stored by pthread for future reuse even after thread destruction, and // the linked list it's stored in doesn't even hold valid pointers to the // objects, the latter are calculated by obscure pointer arithmetic. -#if CAN_SANITIZE_LEAKS +# if CAN_SANITIZE_LEAKS __lsan::ScopedInterceptorDisabler disabler; -#endif - result = REAL(pthread_create)(thread, attr, asan_thread_start, t); +# endif + asanThreadArgRetval().Create(detached, {start_routine, arg}, [&]() -> uptr { + result = REAL(pthread_create)(thread, attr, asan_thread_start, t); + return result ? 0 : *(uptr *)(thread); + }); } if (result != 0) { // If the thread didn't start delete the AsanThread to avoid leaking it. @@ -237,27 +246,48 @@ INTERCEPTOR(int, pthread_create, void *thread, } INTERCEPTOR(int, pthread_join, void *thread, void **retval) { - return REAL(pthread_join)(thread, retval); + int result; + asanThreadArgRetval().Join((uptr)thread, [&]() { + result = REAL(pthread_join)(thread, retval); + return !result; + }); + return result; } INTERCEPTOR(int, pthread_detach, void *thread) { - return REAL(pthread_detach)(thread); + int result; + asanThreadArgRetval().Detach((uptr)thread, [&](){ + result = REAL(pthread_detach)(thread); + return !result; + }); + return result; } INTERCEPTOR(int, pthread_exit, void *retval) { + asanThreadArgRetval().Finish(GetThreadSelf(), retval); return REAL(pthread_exit)(retval); } # if ASAN_INTERCEPT_TRYJOIN INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) { - return REAL(pthread_tryjoin_np)(thread, ret); + int result; + asanThreadArgRetval().Join((uptr)thread, [&]() { + result = REAL(pthread_tryjoin_np)(thread, ret); + return !result; + }); + return result; } # endif # if ASAN_INTERCEPT_TIMEDJOIN INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, const struct timespec *abstime) { - return REAL(pthread_timedjoin_np)(thread, ret, abstime); + int result; + asanThreadArgRetval().Join((uptr)thread, [&]() { + result = REAL(pthread_timedjoin_np)(thread, ret, abstime); + return !result; + }); + return result; } # endif diff --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp index 8d4b5c80f76ec..343fd079fa025 100644 --- a/compiler-rt/lib/asan/asan_thread.cpp +++ b/compiler-rt/lib/asan/asan_thread.cpp @@ -40,10 +40,8 @@ void AsanThreadContext::OnFinished() { thread = nullptr; } -// MIPS requires aligned address -static ALIGNED(alignof( - ThreadRegistry)) char thread_registry_placeholder[sizeof(ThreadRegistry)]; static ThreadRegistry *asan_thread_registry; +static ThreadArgRetval *thread_data; static Mutex mu_for_thread_context; static LowLevelAllocator allocator_for_thread_context; @@ -63,8 +61,16 @@ static void InitThreads() { // in TSD and can't reliably tell when no more TSD destructors will // be called. It would be wrong to reuse AsanThreadContext for another // thread before all TSD destructors will be called for it. + + // MIPS requires aligned address + static ALIGNED(alignof( + ThreadRegistry)) char thread_registry_placeholder[sizeof(ThreadRegistry)]; + static ALIGNED(alignof( + ThreadArgRetval)) char thread_data_placeholder[sizeof(ThreadArgRetval)]; + asan_thread_registry = new (thread_registry_placeholder) ThreadRegistry(GetAsanThreadContext); + thread_data = new (thread_data_placeholder) ThreadArgRetval(); initialized = true; } @@ -73,6 +79,11 @@ ThreadRegistry &asanThreadRegistry() { return *asan_thread_registry; } +ThreadArgRetval &asanThreadArgRetval() { + InitThreads(); + return *thread_data; +} + AsanThreadContext *GetThreadContextByTidLocked(u32 tid) { return static_cast( asanThreadRegistry().GetThreadLocked(tid)); @@ -483,9 +494,15 @@ __asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) { // --- Implementation of LSan-specific functions --- {{{1 namespace __lsan { -void LockThreadRegistry() { __asan::asanThreadRegistry().Lock(); } +void LockThreadRegistry() { + __asan::asanThreadRegistry().Lock(); + __asan::asanThreadArgRetval().Lock(); +} -void UnlockThreadRegistry() { __asan::asanThreadRegistry().Unlock(); } +void UnlockThreadRegistry() { + __asan::asanThreadArgRetval().Unlock(); + __asan::asanThreadRegistry().Unlock(); +} static ThreadRegistry *GetAsanThreadRegistryLocked() { __asan::asanThreadRegistry().CheckLocked(); @@ -540,33 +557,7 @@ void GetThreadExtraStackRangesLocked(InternalMmapVector *ranges) { } void GetAdditionalThreadContextPtrsLocked(InternalMmapVector *ptrs) { - GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked( - [](ThreadContextBase *tctx, void *ptrs) { - // Look for the arg pointer of threads that have been created or are - // running. This is necessary to prevent false positive leaks due to the - // AsanThread holding the only live reference to a heap object. This - // can happen because the `pthread_create()` interceptor doesn't wait - // for the child thread to start before returning and thus loosing the - // the only live reference to the heap object on the stack. - - __asan::AsanThreadContext *atctx = - static_cast<__asan::AsanThreadContext *>(tctx); - - // Note ThreadStatusRunning is required because there is a small window - // where the thread status switches to `ThreadStatusRunning` but the - // `arg` pointer still isn't on the stack yet. - if (atctx->status != ThreadStatusCreated && - atctx->status != ThreadStatusRunning) - return; - - uptr thread_arg = reinterpret_cast(atctx->thread->get_arg()); - if (!thread_arg) - return; - - auto ptrsVec = reinterpret_cast *>(ptrs); - ptrsVec->push_back(thread_arg); - }, - ptrs); + __asan::asanThreadArgRetval().GetAllPtrsLocked(ptrs); } void GetRunningThreadsLocked(InternalMmapVector *threads) { diff --git a/compiler-rt/lib/asan/asan_thread.h b/compiler-rt/lib/asan/asan_thread.h index dff1a0fd85d5d..c131dd40d8647 100644 --- a/compiler-rt/lib/asan/asan_thread.h +++ b/compiler-rt/lib/asan/asan_thread.h @@ -20,6 +20,7 @@ #include "asan_stats.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_thread_arg_retval.h" #include "sanitizer_common/sanitizer_thread_registry.h" namespace __sanitizer { @@ -171,6 +172,7 @@ class AsanThread { // Returns a single instance of registry. ThreadRegistry &asanThreadRegistry(); +ThreadArgRetval &asanThreadArgRetval(); // Must be called under ThreadRegistryLock. AsanThreadContext *GetThreadContextByTidLocked(u32 tid); diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index a302306cc3021..c3e22a8f354fc 100644 --- a/compiler-rt/lib/builtins/CMakeLists.txt +++ b/compiler-rt/lib/builtins/CMakeLists.txt @@ -3,14 +3,7 @@ # architecture-specific code in various subdirectories. if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - cmake_minimum_required(VERSION 3.13.4) - if ("${CMAKE_VERSION}" VERSION_LESS "3.20.0") - message(WARNING - "Your CMake version is ${CMAKE_VERSION}. Starting with LLVM 17.0.0, the " - "minimum version of CMake required to build LLVM will become 3.20.0, and " - "using an older CMake will become an error. Please upgrade your CMake to " - "at least 3.20.0 now to avoid issues in the future!") - endif() + cmake_minimum_required(VERSION 3.20.0) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) project(CompilerRTBuiltins C ASM) diff --git a/compiler-rt/lib/builtins/os_version_check.c b/compiler-rt/lib/builtins/os_version_check.c index ebfb2dfc72ddd..182eabe7a6ae2 100644 --- a/compiler-rt/lib/builtins/os_version_check.c +++ b/compiler-rt/lib/builtins/os_version_check.c @@ -86,6 +86,10 @@ typedef Boolean (*CFStringGetCStringFuncTy)(CFStringRef, char *, CFIndex, CFStringEncoding); typedef void (*CFReleaseFuncTy)(CFTypeRef); +extern __attribute__((weak_import)) +bool _availability_version_check(uint32_t count, + dyld_build_version_t versions[]); + static void _initializeAvailabilityCheck(bool LoadPlist) { if (AvailabilityVersionCheck && !LoadPlist) { // New API is supported and we're not being asked to load the plist, @@ -94,8 +98,8 @@ static void _initializeAvailabilityCheck(bool LoadPlist) { } // Use the new API if it's is available. - AvailabilityVersionCheck = (AvailabilityVersionCheckFuncTy)dlsym( - RTLD_DEFAULT, "_availability_version_check"); + if (_availability_version_check) + AvailabilityVersionCheck = &_availability_version_check; if (AvailabilityVersionCheck && !LoadPlist) { // New API is supported and we're not being asked to load the plist, diff --git a/compiler-rt/lib/crt/CMakeLists.txt b/compiler-rt/lib/crt/CMakeLists.txt index 771652f438f81..32fd61b1fa11e 100644 --- a/compiler-rt/lib/crt/CMakeLists.txt +++ b/compiler-rt/lib/crt/CMakeLists.txt @@ -1,12 +1,5 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - cmake_minimum_required(VERSION 3.13.4) - if ("${CMAKE_VERSION}" VERSION_LESS "3.20.0") - message(WARNING - "Your CMake version is ${CMAKE_VERSION}. Starting with LLVM 17.0.0, the " - "minimum version of CMake required to build LLVM will become 3.20.0, and " - "using an older CMake will become an error. Please upgrade your CMake to " - "at least 3.20.0 now to avoid issues in the future!") - endif() + cmake_minimum_required(VERSION 3.20.0) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) project(CompilerRTCRT C) diff --git a/compiler-rt/lib/dfsan/dfsan_custom.cpp b/compiler-rt/lib/dfsan/dfsan_custom.cpp index 8bb5d39ee8f24..e63e68084fa32 100644 --- a/compiler-rt/lib/dfsan/dfsan_custom.cpp +++ b/compiler-rt/lib/dfsan/dfsan_custom.cpp @@ -535,6 +535,36 @@ SANITIZER_INTERFACE_ATTRIBUTE size_t __dfso_strlen(const char *s, return ret; } +SANITIZER_INTERFACE_ATTRIBUTE size_t __dfsw_strnlen(const char *s, + size_t maxlen, + dfsan_label s_label, + dfsan_label maxlen_label, + dfsan_label *ret_label) { + size_t ret = strnlen(s, maxlen); + if (flags().strict_data_dependencies) { + *ret_label = 0; + } else { + size_t full_len = strlen(s); + size_t covered_len = maxlen > (full_len + 1) ? (full_len + 1) : maxlen; + *ret_label = dfsan_union(maxlen_label, dfsan_read_label(s, covered_len)); + } + return ret; +} + +SANITIZER_INTERFACE_ATTRIBUTE size_t __dfso_strnlen( + const char *s, size_t maxlen, dfsan_label s_label, dfsan_label maxlen_label, + dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin maxlen_origin, + dfsan_origin *ret_origin) { + size_t ret = __dfsw_strnlen(s, maxlen, s_label, maxlen_label, ret_label); + if (!flags().strict_data_dependencies) { + size_t full_len = strlen(s); + size_t covered_len = maxlen > (full_len + 1) ? (full_len + 1) : maxlen; + dfsan_origin o = dfsan_read_origin_of_first_taint(s, covered_len); + *ret_origin = o ? o : maxlen_origin; + } + return ret; +} + static void *dfsan_memmove(void *dest, const void *src, size_t n) { dfsan_label *sdest = shadow_for(dest); const dfsan_label *ssrc = shadow_for(src); diff --git a/compiler-rt/lib/dfsan/done_abilist.txt b/compiler-rt/lib/dfsan/done_abilist.txt index 88ec5cf504bae..cc3578b95cd49 100644 --- a/compiler-rt/lib/dfsan/done_abilist.txt +++ b/compiler-rt/lib/dfsan/done_abilist.txt @@ -278,6 +278,7 @@ fun:strcasecmp=custom fun:strchr=custom fun:strcmp=custom fun:strlen=custom +fun:strnlen=custom fun:strncasecmp=custom fun:strncmp=custom fun:strpbrk=custom diff --git a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp index d5866b8b94b05..f87e6a2ba44cb 100644 --- a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp +++ b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp @@ -17,6 +17,7 @@ #include "hwasan.h" #include "hwasan_checks.h" #include "hwasan_thread.h" +#include "hwasan_thread_list.h" #include "interception/interception.h" #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stackdepot.h" @@ -25,21 +26,7 @@ using namespace __hwasan; -#if HWASAN_WITH_INTERCEPTORS - -struct ThreadStartArg { - thread_callback_t callback; - void *param; - __sanitizer_sigset_t starting_sigset_; -}; - -static void *HwasanThreadStartFunc(void *arg) { - __hwasan_thread_enter(); - ThreadStartArg A = *reinterpret_cast(arg); - SetSigProcMask(&A.starting_sigset_, nullptr); - UnmapOrDie(arg, GetPageSizeCached()); - return A.callback(A.param); -} +# if HWASAN_WITH_INTERCEPTORS # define COMMON_SYSCALL_PRE_READ_RANGE(p, s) __hwasan_loadN((uptr)p, (uptr)s) # define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \ @@ -57,42 +44,91 @@ static void *HwasanThreadStartFunc(void *arg) { # include "sanitizer_common/sanitizer_common_syscalls.inc" # include "sanitizer_common/sanitizer_syscalls_netbsd.inc" -INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*), - void * param) { +struct ThreadStartArg { + __sanitizer_sigset_t starting_sigset_; +}; + +static void *HwasanThreadStartFunc(void *arg) { + __hwasan_thread_enter(); + ThreadStartArg A = *reinterpret_cast(arg); + SetSigProcMask(&A.starting_sigset_, nullptr); + InternalFree(arg); + auto self = GetThreadSelf(); + auto args = hwasanThreadArgRetval().GetArgs(self); + void *retval = (*args.routine)(args.arg_retval); + hwasanThreadArgRetval().Finish(self, retval); + return retval; +} + +extern "C" { +int pthread_attr_getdetachstate(void *attr, int *v); +} + +INTERCEPTOR(int, pthread_create, void *thread, void *attr, + void *(*callback)(void *), void *param) { EnsureMainThreadIDIsCorrect(); ScopedTaggingDisabler tagging_disabler; - ThreadStartArg *A = reinterpret_cast (MmapOrDie( - GetPageSizeCached(), "pthread_create")); - A->callback = callback; - A->param = param; + int detached = 0; + if (attr) + pthread_attr_getdetachstate(attr, &detached); + ThreadStartArg *A = (ThreadStartArg *)InternalAlloc(sizeof(ThreadStartArg)); ScopedBlockSignals block(&A->starting_sigset_); // ASAN uses the same approach to disable leaks from pthread_create. # if CAN_SANITIZE_LEAKS __lsan::ScopedInterceptorDisabler lsan_disabler; # endif - return REAL(pthread_create)(th, attr, &HwasanThreadStartFunc, A); + + int result; + hwasanThreadArgRetval().Create(detached, {callback, param}, [&]() -> uptr { + result = REAL(pthread_create)(thread, attr, &HwasanThreadStartFunc, A); + return result ? 0 : *(uptr *)(thread); + }); + if (result != 0) + InternalFree(A); + return result; } -INTERCEPTOR(int, pthread_join, void *t, void **arg) { - return REAL(pthread_join)(t, arg); +INTERCEPTOR(int, pthread_join, void *thread, void **retval) { + int result; + hwasanThreadArgRetval().Join((uptr)thread, [&]() { + result = REAL(pthread_join)(thread, retval); + return !result; + }); + return result; } INTERCEPTOR(int, pthread_detach, void *thread) { - return REAL(pthread_detach)(thread); + int result; + hwasanThreadArgRetval().Detach((uptr)thread, [&]() { + result = REAL(pthread_detach)(thread); + return !result; + }); + return result; } INTERCEPTOR(int, pthread_exit, void *retval) { + hwasanThreadArgRetval().Finish(GetThreadSelf(), retval); return REAL(pthread_exit)(retval); } # if SANITIZER_GLIBC INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) { - return REAL(pthread_tryjoin_np)(thread, ret); + int result; + hwasanThreadArgRetval().Join((uptr)thread, [&]() { + result = REAL(pthread_tryjoin_np)(thread, ret); + return !result; + }); + return result; } INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, const struct timespec *abstime) { - return REAL(pthread_timedjoin_np)(thread, ret, abstime); + int result; + hwasanThreadArgRetval().Join((uptr)thread, [&]() { + result = REAL(pthread_timedjoin_np)(thread, ret, abstime); + return !result; + }); + return result; } # endif @@ -104,13 +140,13 @@ DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork) // Get and/or change the set of blocked signals. extern "C" int sigprocmask(int __how, const __hw_sigset_t *__restrict __set, __hw_sigset_t *__restrict __oset); -#define SIG_BLOCK 0 -#define SIG_SETMASK 2 +# define SIG_BLOCK 0 +# define SIG_SETMASK 2 extern "C" int __sigjmp_save(__hw_sigjmp_buf env, int savemask) { env[0].__magic = kHwJmpBufMagic; env[0].__mask_was_saved = - (savemask && sigprocmask(SIG_BLOCK, (__hw_sigset_t *)0, - &env[0].__saved_mask) == 0); + (savemask && + sigprocmask(SIG_BLOCK, (__hw_sigset_t *)0, &env[0].__saved_mask) == 0); return 0; } @@ -139,26 +175,27 @@ InternalLongjmp(__hw_register_buf env, int retval) { # if defined(__aarch64__) register long int retval_tmp asm("x1") = retval; register void *env_address asm("x0") = &env[0]; - asm volatile("ldp x19, x20, [%0, #0<<3];" - "ldp x21, x22, [%0, #2<<3];" - "ldp x23, x24, [%0, #4<<3];" - "ldp x25, x26, [%0, #6<<3];" - "ldp x27, x28, [%0, #8<<3];" - "ldp x29, x30, [%0, #10<<3];" - "ldp d8, d9, [%0, #14<<3];" - "ldp d10, d11, [%0, #16<<3];" - "ldp d12, d13, [%0, #18<<3];" - "ldp d14, d15, [%0, #20<<3];" - "ldr x5, [%0, #13<<3];" - "mov sp, x5;" - // Return the value requested to return through arguments. - // This should be in x1 given what we requested above. - "cmp %1, #0;" - "mov x0, #1;" - "csel x0, %1, x0, ne;" - "br x30;" - : "+r"(env_address) - : "r"(retval_tmp)); + asm volatile( + "ldp x19, x20, [%0, #0<<3];" + "ldp x21, x22, [%0, #2<<3];" + "ldp x23, x24, [%0, #4<<3];" + "ldp x25, x26, [%0, #6<<3];" + "ldp x27, x28, [%0, #8<<3];" + "ldp x29, x30, [%0, #10<<3];" + "ldp d8, d9, [%0, #14<<3];" + "ldp d10, d11, [%0, #16<<3];" + "ldp d12, d13, [%0, #18<<3];" + "ldp d14, d15, [%0, #20<<3];" + "ldr x5, [%0, #13<<3];" + "mov sp, x5;" + // Return the value requested to return through arguments. + // This should be in x1 given what we requested above. + "cmp %1, #0;" + "mov x0, #1;" + "csel x0, %1, x0, ne;" + "br x30;" + : "+r"(env_address) + : "r"(retval_tmp)); # elif defined(__x86_64__) register long int retval_tmp asm("%rsi") = retval; register void *env_address asm("%rdi") = &env[0]; @@ -234,8 +271,7 @@ INTERCEPTOR(void, siglongjmp, __hw_sigjmp_buf env, int val) { if (env[0].__mask_was_saved) // Restore the saved signal mask. - (void)sigprocmask(SIG_SETMASK, &env[0].__saved_mask, - (__hw_sigset_t *)0); + (void)sigprocmask(SIG_SETMASK, &env[0].__saved_mask, (__hw_sigset_t *)0); InternalLongjmp(env[0].__jmpbuf, val); } @@ -257,8 +293,8 @@ INTERCEPTOR(void, longjmp, __hw_jmp_buf env, int val) { } InternalLongjmp(env[0].__jmpbuf, val); } -#undef SIG_BLOCK -#undef SIG_SETMASK +# undef SIG_BLOCK +# undef SIG_SETMASK # endif // HWASAN_WITH_INTERCEPTORS @@ -273,7 +309,7 @@ int OnExit() { return 0; } -} // namespace __hwasan +} // namespace __hwasan namespace __hwasan { @@ -300,6 +336,6 @@ void InitializeInterceptors() { inited = 1; } -} // namespace __hwasan +} // namespace __hwasan #endif // #if !SANITIZER_FUCHSIA diff --git a/compiler-rt/lib/hwasan/hwasan_linux.cpp b/compiler-rt/lib/hwasan/hwasan_linux.cpp index abf92d290c846..6f5e9432974ef 100644 --- a/compiler-rt/lib/hwasan/hwasan_linux.cpp +++ b/compiler-rt/lib/hwasan/hwasan_linux.cpp @@ -302,8 +302,15 @@ extern "C" void __hwasan_thread_exit() { Thread *t = GetCurrentThread(); // Make sure that signal handler can not see a stale current thread pointer. atomic_signal_fence(memory_order_seq_cst); - if (t) + if (t) { + // Block async signals on the thread as the handler can be instrumented. + // After this point instrumented code can't access essential data from TLS + // and will crash. + // Bionic already calls __hwasan_thread_exit with blocked signals. + if (SANITIZER_GLIBC) + BlockSignals(); hwasanThreadList().ReleaseThread(t); + } } # if HWASAN_WITH_INTERCEPTORS diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp index 3375782ef29b4..5faa899541854 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp @@ -173,9 +173,15 @@ static __hwasan::Thread *GetThreadByOsIDLocked(tid_t os_id) { [os_id](__hwasan::Thread *t) { return t->os_id() == os_id; }); } -void LockThreadRegistry() { __hwasan::hwasanThreadList().Lock(); } +void LockThreadRegistry() { + __hwasan::hwasanThreadList().Lock(); + __hwasan::hwasanThreadArgRetval().Lock(); +} -void UnlockThreadRegistry() { __hwasan::hwasanThreadList().Unlock(); } +void UnlockThreadRegistry() { + __hwasan::hwasanThreadArgRetval().Unlock(); + __hwasan::hwasanThreadList().Unlock(); +} void EnsureMainThreadIDIsCorrect() { __hwasan::EnsureMainThreadIDIsCorrect(); } @@ -202,7 +208,10 @@ void GetThreadExtraStackRangesLocked(tid_t os_id, InternalMmapVector *ranges) {} void GetThreadExtraStackRangesLocked(InternalMmapVector *ranges) {} -void GetAdditionalThreadContextPtrsLocked(InternalMmapVector *ptrs) {} +void GetAdditionalThreadContextPtrsLocked(InternalMmapVector *ptrs) { + __hwasan::hwasanThreadArgRetval().GetAllPtrsLocked(ptrs); +} + void GetRunningThreadsLocked(InternalMmapVector *threads) {} } // namespace __lsan diff --git a/compiler-rt/lib/hwasan/hwasan_thread_list.cpp b/compiler-rt/lib/hwasan/hwasan_thread_list.cpp index d528f520cc9eb..7df4dd3d78518 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread_list.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread_list.cpp @@ -1,15 +1,28 @@ #include "hwasan_thread_list.h" +#include "sanitizer_common/sanitizer_thread_arg_retval.h" + namespace __hwasan { -static ALIGNED(16) char thread_list_placeholder[sizeof(HwasanThreadList)]; + static HwasanThreadList *hwasan_thread_list; +static ThreadArgRetval *thread_data; HwasanThreadList &hwasanThreadList() { return *hwasan_thread_list; } +ThreadArgRetval &hwasanThreadArgRetval() { return *thread_data; } void InitThreadList(uptr storage, uptr size) { CHECK_EQ(hwasan_thread_list, nullptr); + + static ALIGNED(alignof( + HwasanThreadList)) char thread_list_placeholder[sizeof(HwasanThreadList)]; hwasan_thread_list = new (thread_list_placeholder) HwasanThreadList(storage, size); + + CHECK_EQ(thread_data, nullptr); + + static ALIGNED(alignof( + ThreadArgRetval)) char thread_data_placeholder[sizeof(ThreadArgRetval)]; + thread_data = new (thread_data_placeholder) ThreadArgRetval(); } -} // namespace __hwasan +} // namespace __hwasan diff --git a/compiler-rt/lib/hwasan/hwasan_thread_list.h b/compiler-rt/lib/hwasan/hwasan_thread_list.h index 0400499f93d5c..82f6c70a03f80 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread_list.h +++ b/compiler-rt/lib/hwasan/hwasan_thread_list.h @@ -47,8 +47,8 @@ #include "hwasan_allocator.h" #include "hwasan_flags.h" #include "hwasan_thread.h" - #include "sanitizer_common/sanitizer_placement_new.h" +#include "sanitizer_common/sanitizer_thread_arg_retval.h" namespace __hwasan { @@ -222,5 +222,6 @@ class SANITIZER_MUTEX HwasanThreadList { void InitThreadList(uptr storage, uptr size); HwasanThreadList &hwasanThreadList(); +ThreadArgRetval &hwasanThreadArgRetval(); } // namespace __hwasan diff --git a/compiler-rt/lib/lsan/lsan_interceptors.cpp b/compiler-rt/lib/lsan/lsan_interceptors.cpp index dc601cd646cf3..2a35572edfec0 100644 --- a/compiler-rt/lib/lsan/lsan_interceptors.cpp +++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -415,16 +415,10 @@ INTERCEPTOR(char *, strerror, int errnum) { #if SANITIZER_POSIX -struct ThreadParam { - void *(*callback)(void *arg); - void *param; - atomic_uintptr_t tid; -}; - -extern "C" void *__lsan_thread_start_func(void *arg) { - ThreadParam *p = (ThreadParam*)arg; - void* (*callback)(void *arg) = p->callback; - void *param = p->param; +template +static void *ThreadStartFunc(void *arg) { + u32 parent_tid = (uptr)arg; + uptr tid = ThreadCreate(parent_tid, Detached); // Wait until the last iteration to maximize the chance that we are the last // destructor to run. #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD @@ -433,13 +427,13 @@ extern "C" void *__lsan_thread_start_func(void *arg) { Report("LeakSanitizer: failed to set thread key.\n"); Die(); } -#endif - int tid = 0; - while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) - internal_sched_yield(); +# endif ThreadStart(tid, GetTid()); - atomic_store(&p->tid, 0, memory_order_release); - return callback(param); + auto self = GetThreadSelf(); + auto args = GetThreadArgRetval().GetArgs(self); + void *retval = (*args.routine)(args.arg_retval); + GetThreadArgRetval().Finish(self, retval); + return retval; } INTERCEPTOR(int, pthread_create, void *th, void *attr, @@ -454,46 +448,59 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, AdjustStackSize(attr); int detached = 0; pthread_attr_getdetachstate(attr, &detached); - ThreadParam p; - p.callback = callback; - p.param = param; - atomic_store(&p.tid, 0, memory_order_relaxed); - int res; + uptr this_tid = GetCurrentThreadId(); + int result; { // Ignore all allocations made by pthread_create: thread stack/TLS may be // stored by pthread for future reuse even after thread destruction, and // the linked list it's stored in doesn't even hold valid pointers to the // objects, the latter are calculated by obscure pointer arithmetic. ScopedInterceptorDisabler disabler; - res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p); - } - if (res == 0) { - int tid = ThreadCreate(GetCurrentThreadId(), IsStateDetached(detached)); - CHECK_NE(tid, kMainTid); - atomic_store(&p.tid, tid, memory_order_release); - while (atomic_load(&p.tid, memory_order_acquire) != 0) - internal_sched_yield(); + GetThreadArgRetval().Create(detached, {callback, param}, [&]() -> uptr { + result = REAL(pthread_create)(th, attr, + IsStateDetached(detached) + ? ThreadStartFunc + : ThreadStartFunc, + (void *)this_tid); + return result ? 0 : *(uptr *)(th); + }); } if (attr == &myattr) pthread_attr_destroy(&myattr); - return res; + return result; } INTERCEPTOR(int, pthread_join, void *thread, void **retval) { - return REAL(pthread_join)(thread, retval); + int result; + GetThreadArgRetval().Join((uptr)thread, [&]() { + result = REAL(pthread_join)(thread, retval); + return !result; + }); + return result; } INTERCEPTOR(int, pthread_detach, void *thread) { - return REAL(pthread_detach)(thread); + int result; + GetThreadArgRetval().Detach((uptr)thread, [&]() { + result = REAL(pthread_detach)(thread); + return !result; + }); + return result; } INTERCEPTOR(int, pthread_exit, void *retval) { + GetThreadArgRetval().Finish(GetThreadSelf(), retval); return REAL(pthread_exit)(retval); } # if SANITIZER_INTERCEPT_TRYJOIN INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) { - return REAL(pthread_tryjoin_np)(thread, ret); + int result; + GetThreadArgRetval().Join((uptr)thread, [&]() { + result = REAL(pthread_tryjoin_np)(thread, ret); + return !result; + }); + return result; } # define LSAN_MAYBE_INTERCEPT_TRYJOIN INTERCEPT_FUNCTION(pthread_tryjoin_np) # else @@ -503,7 +510,12 @@ INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) { # if SANITIZER_INTERCEPT_TIMEDJOIN INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, const struct timespec *abstime) { - return REAL(pthread_timedjoin_np)(thread, ret, abstime); + int result; + GetThreadArgRetval().Join((uptr)thread, [&]() { + result = REAL(pthread_timedjoin_np)(thread, ret, abstime); + return !result; + }); + return result; } # define LSAN_MAYBE_INTERCEPT_TIMEDJOIN \ INTERCEPT_FUNCTION(pthread_timedjoin_np) diff --git a/compiler-rt/lib/lsan/lsan_thread.cpp b/compiler-rt/lib/lsan/lsan_thread.cpp index 5a00973ef8026..e0ea622fa33c1 100644 --- a/compiler-rt/lib/lsan/lsan_thread.cpp +++ b/compiler-rt/lib/lsan/lsan_thread.cpp @@ -24,6 +24,7 @@ namespace __lsan { static ThreadRegistry *thread_registry; +static ThreadArgRetval *thread_arg_retval; static Mutex mu_for_thread_context; static LowLevelAllocator allocator_for_thread_context; @@ -34,11 +35,18 @@ static ThreadContextBase *CreateThreadContext(u32 tid) { } void InitializeThreadRegistry() { - static ALIGNED(64) char thread_registry_placeholder[sizeof(ThreadRegistry)]; + static ALIGNED(alignof( + ThreadRegistry)) char thread_registry_placeholder[sizeof(ThreadRegistry)]; thread_registry = new (thread_registry_placeholder) ThreadRegistry(CreateThreadContext); + + static ALIGNED(alignof(ThreadArgRetval)) char + thread_arg_retval_placeholder[sizeof(ThreadArgRetval)]; + thread_arg_retval = new (thread_arg_retval_placeholder) ThreadArgRetval(); } +ThreadArgRetval &GetThreadArgRetval() { return *thread_arg_retval; } + ThreadContextLsanBase::ThreadContextLsanBase(int tid) : ThreadContextBase(tid) {} @@ -72,9 +80,15 @@ void GetThreadExtraStackRangesLocked(tid_t os_id, InternalMmapVector *ranges) {} void GetThreadExtraStackRangesLocked(InternalMmapVector *ranges) {} -void LockThreadRegistry() { thread_registry->Lock(); } +void LockThreadRegistry() { + thread_registry->Lock(); + thread_arg_retval->Lock(); +} -void UnlockThreadRegistry() { thread_registry->Unlock(); } +void UnlockThreadRegistry() { + thread_arg_retval->Unlock(); + thread_registry->Unlock(); +} ThreadRegistry *GetLsanThreadRegistryLocked() { thread_registry->CheckLocked(); @@ -93,12 +107,7 @@ void GetRunningThreadsLocked(InternalMmapVector *threads) { } void GetAdditionalThreadContextPtrsLocked(InternalMmapVector *ptrs) { - // This function can be used to treat memory reachable from `tctx` as live. - // This is useful for threads that have been created but not yet started. - - // This is currently a no-op because the LSan `pthread_create()` interceptor - // blocks until the child thread starts which keeps the thread's `arg` pointer - // live. + GetThreadArgRetval().GetAllPtrsLocked(ptrs); } } // namespace __lsan diff --git a/compiler-rt/lib/lsan/lsan_thread.h b/compiler-rt/lib/lsan/lsan_thread.h index 709a02915c2d9..afe83fb93401f 100644 --- a/compiler-rt/lib/lsan/lsan_thread.h +++ b/compiler-rt/lib/lsan/lsan_thread.h @@ -14,6 +14,7 @@ #ifndef LSAN_THREAD_H #define LSAN_THREAD_H +#include "sanitizer_common/sanitizer_thread_arg_retval.h" #include "sanitizer_common/sanitizer_thread_registry.h" namespace __lsan { @@ -47,6 +48,7 @@ void InitializeThreadRegistry(); void InitializeMainThread(); ThreadRegistry *GetLsanThreadRegistryLocked(); +ThreadArgRetval &GetThreadArgRetval(); u32 ThreadCreate(u32 tid, bool detached, void *arg = nullptr); void ThreadFinish(); diff --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp index 757dc46739bea..8cf724b3949f2 100644 --- a/compiler-rt/lib/msan/msan_interceptors.cpp +++ b/compiler-rt/lib/msan/msan_interceptors.cpp @@ -1112,14 +1112,32 @@ INTERCEPTOR(int, __libc_thr_keycreate, __sanitizer_pthread_key_t *m, ALIAS(WRAPPER_NAME(pthread_key_create)); #endif -INTERCEPTOR(int, pthread_join, void *th, void **retval) { +INTERCEPTOR(int, pthread_join, void *thread, void **retval) { ENSURE_MSAN_INITED(); - int res = REAL(pthread_join)(th, retval); + int res = REAL(pthread_join)(thread, retval); if (!res && retval) __msan_unpoison(retval, sizeof(*retval)); return res; } +#if SANITIZER_GLIBC +INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **retval) { + ENSURE_MSAN_INITED(); + int res = REAL(pthread_tryjoin_np)(thread, retval); + if (!res && retval) + __msan_unpoison(retval, sizeof(*retval)); + return res; +} + +INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **retval, + const struct timespec *abstime) { + int res = REAL(pthread_timedjoin_np)(thread, retval, abstime); + if (!res && retval) + __msan_unpoison(retval, sizeof(*retval)); + return res; +} +#endif + DEFINE_REAL_PTHREAD_FUNCTIONS extern char *tzname[2]; @@ -1777,6 +1795,10 @@ void InitializeInterceptors() { #endif INTERCEPT_FUNCTION(pthread_join); INTERCEPT_FUNCTION(pthread_key_create); +#if SANITIZER_GLIBC + INTERCEPT_FUNCTION(pthread_tryjoin_np); + INTERCEPT_FUNCTION(pthread_timedjoin_np); +#endif #if SANITIZER_NETBSD INTERCEPT_FUNCTION(__libc_thr_keycreate); diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt index 9bc93abc553a1..614e63d5f9eb5 100644 --- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt +++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt @@ -37,6 +37,7 @@ set(SANITIZER_SOURCES_NOTERMINATION sanitizer_stoptheworld_win.cpp sanitizer_suppressions.cpp sanitizer_tls_get_addr.cpp + sanitizer_thread_arg_retval.cpp sanitizer_thread_registry.cpp sanitizer_type_traits.cpp sanitizer_win.cpp diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 490a8b12d8b17..bc31627ccca59 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -4404,12 +4404,16 @@ INTERCEPTOR(int, pthread_sigmask, int how, __sanitizer_sigset_t *set, INTERCEPTOR(int, backtrace, void **buffer, int size) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, backtrace, buffer, size); - // FIXME: under ASan the call below may write to freed memory and corrupt - // its metadata. See - // https://github.com/google/sanitizers/issues/321. - int res = REAL(backtrace)(buffer, size); - if (res && buffer) + // 'buffer' might be freed memory, hence it is unsafe to directly call + // REAL(backtrace)(buffer, size). Instead, we use our own known-good + // scratch buffer. + void **scratch = (void**)InternalAlloc(sizeof(void*) * size); + int res = REAL(backtrace)(scratch, size); + if (res && buffer) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buffer, res * sizeof(*buffer)); + internal_memcpy(buffer, scratch, res * sizeof(*buffer)); + } + InternalFree(scratch); return res; } @@ -4418,9 +4422,8 @@ INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) { COMMON_INTERCEPTOR_ENTER(ctx, backtrace_symbols, buffer, size); if (buffer && size) COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, size * sizeof(*buffer)); - // FIXME: under ASan the call below may write to freed memory and corrupt - // its metadata. See - // https://github.com/google/sanitizers/issues/321. + // The COMMON_INTERCEPTOR_READ_RANGE above ensures that 'buffer' is + // valid for reading. char **res = REAL(backtrace_symbols)(buffer, size); if (res && size) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, size * sizeof(*res)); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index 24c6acaa9e5a4..d2b3b63f3a7a3 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -156,11 +156,11 @@ const int FUTEX_WAKE_PRIVATE = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; namespace __sanitizer { -void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *old) { - CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, old)); +void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { + CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, oldset)); } -ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) { +void BlockSignals(__sanitizer_sigset_t *oldset) { __sanitizer_sigset_t set; internal_sigfillset(&set); # if SANITIZER_LINUX && !SANITIZER_ANDROID @@ -175,7 +175,11 @@ ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) { // hang. internal_sigdelset(&set, 31); # endif - SetSigProcMask(&set, &saved_); + SetSigProcMask(&set, oldset); +} + +ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) { + BlockSignals(&saved_); if (copy) internal_memcpy(copy, &saved_, sizeof(saved_)); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h index c84c04a877594..7454369fa4192 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h @@ -51,6 +51,7 @@ uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset); void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset); +void BlockSignals(__sanitizer_sigset_t *oldset = nullptr); struct ScopedBlockSignals { explicit ScopedBlockSignals(__sanitizer_sigset_t *copy); ~ScopedBlockSignals(); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp index 37b2b57c0c844..42013f4718705 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp @@ -148,7 +148,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, pthread_attr_t attr; pthread_attr_init(&attr); CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); - my_pthread_attr_getstack(&attr, &stackaddr, &stacksize); + internal_pthread_attr_getstack(&attr, &stackaddr, &stacksize); pthread_attr_destroy(&attr); #endif // SANITIZER_SOLARIS diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_posix.h index f91e26e74b87c..76b4174e927e8 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.h @@ -90,7 +90,7 @@ int real_pthread_join(void *th, void **ret); } \ } // namespace __sanitizer -int my_pthread_attr_getstack(void *attr, void **addr, uptr *size); +int internal_pthread_attr_getstack(void *attr, void **addr, uptr *size); // A routine named real_sigaction() must be implemented by each sanitizer in // order for internal_sigaction() to bypass interceptors. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index 46e41c669738c..e88e654eec5a1 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -383,7 +383,7 @@ SANITIZER_WEAK_ATTRIBUTE int real_pthread_attr_getstack(void *attr, void **addr, size_t *size); } // extern "C" -int my_pthread_attr_getstack(void *attr, void **addr, uptr *size) { +int internal_pthread_attr_getstack(void *attr, void **addr, uptr *size) { #if !SANITIZER_GO && !SANITIZER_APPLE if (&real_pthread_attr_getstack) return real_pthread_attr_getstack((pthread_attr_t *)attr, addr, @@ -397,7 +397,7 @@ void AdjustStackSize(void *attr_) { pthread_attr_t *attr = (pthread_attr_t *)attr_; uptr stackaddr = 0; uptr stacksize = 0; - my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize); + internal_pthread_attr_getstack(attr, (void **)&stackaddr, &stacksize); // GLibC will return (0 - stacksize) as the stack address in the case when // stacksize is set, but stackaddr is not. bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_thread_arg_retval.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_thread_arg_retval.cpp new file mode 100644 index 0000000000000..bddb285214085 --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_thread_arg_retval.cpp @@ -0,0 +1,94 @@ +//===-- sanitizer_thread_arg_retval.cpp -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizer tools. +// +// Tracks thread arguments and return value for leak checking. +//===----------------------------------------------------------------------===// + +#include "sanitizer_thread_arg_retval.h" + +#include "sanitizer_placement_new.h" + +namespace __sanitizer { + +void ThreadArgRetval::CreateLocked(uptr thread, bool detached, + const Args& args) { + CheckLocked(); + Data& t = data_[thread]; + t = {}; + t.gen = gen_++; + t.detached = detached; + t.args = args; +} + +ThreadArgRetval::Args ThreadArgRetval::GetArgs(uptr thread) const { + __sanitizer::Lock lock(&mtx_); + auto t = data_.find(thread); + CHECK(t); + if (t->second.done) + return {}; + return t->second.args; +} + +void ThreadArgRetval::Finish(uptr thread, void* retval) { + __sanitizer::Lock lock(&mtx_); + auto t = data_.find(thread); + if (!t) + return; + if (t->second.detached) { + // Retval of detached thread connot be retrieved. + data_.erase(t); + return; + } + t->second.done = true; + t->second.args.arg_retval = retval; +} + +u32 ThreadArgRetval::BeforeJoin(uptr thread) const { + __sanitizer::Lock lock(&mtx_); + auto t = data_.find(thread); + CHECK(t); + CHECK(!t->second.detached); + return t->second.gen; +} + +void ThreadArgRetval::AfterJoin(uptr thread, u32 gen) { + __sanitizer::Lock lock(&mtx_); + auto t = data_.find(thread); + if (!t || gen != t->second.gen) { + // Thread was reused and erased by any other event. + return; + } + CHECK(!t->second.detached); + data_.erase(t); +} + +void ThreadArgRetval::DetachLocked(uptr thread) { + CheckLocked(); + auto t = data_.find(thread); + CHECK(t); + CHECK(!t->second.detached); + if (t->second.done) { + // We can't retrive retval after detached thread finished. + data_.erase(t); + return; + } + t->second.detached = true; +} + +void ThreadArgRetval::GetAllPtrsLocked(InternalMmapVector* ptrs) { + CheckLocked(); + CHECK(ptrs); + data_.forEach([&](DenseMap::value_type& kv) -> bool { + ptrs->push_back((uptr)kv.second.args.arg_retval); + return true; + }); +} + +} // namespace __sanitizer diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_thread_arg_retval.h b/compiler-rt/lib/sanitizer_common/sanitizer_thread_arg_retval.h new file mode 100644 index 0000000000000..c77021beb67d1 --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_thread_arg_retval.h @@ -0,0 +1,116 @@ +//===-- sanitizer_thread_arg_retval.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 +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizer tools. +// +// Tracks thread arguments and return value for leak checking. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_THREAD_ARG_RETVAL_H +#define SANITIZER_THREAD_ARG_RETVAL_H + +#include "sanitizer_common.h" +#include "sanitizer_dense_map.h" +#include "sanitizer_list.h" +#include "sanitizer_mutex.h" + +namespace __sanitizer { + +// Primary goal of the class is to keep alive arg and retval pointer for leak +// checking. However it can be used to pass those pointer into wrappers used by +// interceptors. The difference from ThreadRegistry/ThreadList is that this +// class keeps data up to the detach or join, as exited thread still can be +// joined to retrive retval. ThreadRegistry/ThreadList can discard exited +// threads immediately. +class SANITIZER_MUTEX ThreadArgRetval { + public: + struct Args { + void* (*routine)(void*); + void* arg_retval; // Either arg or retval. + }; + void Lock() SANITIZER_ACQUIRE() { mtx_.Lock(); } + void CheckLocked() const SANITIZER_CHECK_LOCKED() { mtx_.CheckLocked(); } + void Unlock() SANITIZER_RELEASE() { mtx_.Unlock(); } + + // Wraps pthread_create or similar. We need to keep object locked, to + // prevent child thread from proceeding without thread handle. + template + void Create(bool detached, const Args& args, const CreateFn& fn) { + // No need to track detached threads with no args, but we will to do as it's + // not expensive and less edge-cases. + __sanitizer::Lock lock(&mtx_); + if (uptr thread = fn()) + CreateLocked(thread, detached, args); + } + + // Returns thread arg and routine. + Args GetArgs(uptr thread) const; + + // Mark thread as done and stores retval or remove if detached. Should be + // called by the thread. + void Finish(uptr thread, void* retval); + + // Mark thread as detached or remove if done. + template + void Detach(uptr thread, const DetachFn& fn) { + // Lock to prevent re-use of the thread between fn() and DetachLocked() + // calls. + __sanitizer::Lock lock(&mtx_); + if (fn()) + DetachLocked(thread); + } + + // Joins the thread. + template + void Join(uptr thread, const JoinFn& fn) { + // Remember internal id of the thread to prevent re-use of the thread + // between fn() and AfterJoin() calls. Locking JoinFn, like in + // Detach(), implementation can cause deadlock. + auto gen = BeforeJoin(thread); + if (fn()) + AfterJoin(thread, gen); + } + + // Returns all arg and retval which are considered alive. + void GetAllPtrsLocked(InternalMmapVector* ptrs); + + uptr size() const { + __sanitizer::Lock lock(&mtx_); + return data_.size(); + } + + // FIXME: Add fork support. Expected users of the class are sloppy with forks + // anyway. We likely should lock/unlock the object to avoid deadlocks, and + // erase all but the current threads, so we can detect leaked arg or retval in + // child process. + + // FIXME: Add cancelation support. Now if a thread was canceled, the class + // will keep pointers alive forever, missing leaks caused by cancelation. + + private: + struct Data { + Args args; + u32 gen; // Avoid collision if thread id re-used. + bool detached; + bool done; + }; + + void CreateLocked(uptr thread, bool detached, const Args& args); + u32 BeforeJoin(uptr thread) const; + void AfterJoin(uptr thread, u32 gen); + void DetachLocked(uptr thread); + + mutable Mutex mtx_; + + DenseMap data_; + u32 gen_ = 0; +}; + +} // namespace __sanitizer + +#endif // SANITIZER_THREAD_ARG_RETVAL_H diff --git a/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt index 22bad618a8ff3..40aa8e703b6c7 100644 --- a/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt +++ b/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt @@ -46,6 +46,7 @@ set(SANITIZER_UNITTESTS sanitizer_suppressions_test.cpp sanitizer_symbolizer_test.cpp sanitizer_test_main.cpp + sanitizer_thread_arg_retval_test.cpp sanitizer_thread_registry_test.cpp sanitizer_type_traits_test.cpp sanitizer_vector_test.cpp diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_arg_retval_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_arg_retval_test.cpp new file mode 100644 index 0000000000000..31507c8df19cf --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_arg_retval_test.cpp @@ -0,0 +1,158 @@ +//===-- sanitizer_thread_registry_test.cpp --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of shared sanitizer runtime. +// +//===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_thread_arg_retval.h" + +#include "gtest/gtest.h" +#include "sanitizer_mutex.h" + +namespace __sanitizer { + +static int t; +static void* arg = &t; +static void* (*routine)(void*) = [](void*) { return arg; }; +static void* retval = (&t) + 1; + +TEST(ThreadArgRetvalTest, CreateFail) { + ThreadArgRetval td; + td.Create(false, {routine, arg}, []() { return 0; }); + EXPECT_EQ(0u, td.size()); +} + +TEST(ThreadArgRetvalTest, CreateRunJoin) { + ThreadArgRetval td; + td.Create(false, {routine, arg}, []() { return 1; }); + EXPECT_EQ(1u, td.size()); + + EXPECT_EQ(arg, td.GetArgs(1).arg_retval); + EXPECT_EQ(routine, td.GetArgs(1).routine); + EXPECT_EQ(1u, td.size()); + + td.Finish(1, retval); + EXPECT_EQ(1u, td.size()); + + td.Join(1, []() { return false; }); + EXPECT_EQ(1u, td.size()); + + td.Join(1, []() { return true; }); + EXPECT_EQ(0u, td.size()); +} + +TEST(ThreadArgRetvalTest, CreateJoinRun) { + ThreadArgRetval td; + td.Create(false, {routine, arg}, []() { return 1; }); + EXPECT_EQ(1u, td.size()); + + td.Join(1, []() { return false; }); + EXPECT_EQ(1u, td.size()); + + td.Join(1, [&]() { + // Expected to happen on another thread. + EXPECT_EQ(1u, td.size()); + + EXPECT_EQ(arg, td.GetArgs(1).arg_retval); + EXPECT_EQ(routine, td.GetArgs(1).routine); + EXPECT_EQ(1u, td.size()); + + td.Finish(1, retval); + EXPECT_EQ(1u, td.size()); + return true; + }); + EXPECT_EQ(0u, td.size()); +} + +TEST(ThreadArgRetvalTest, CreateRunDetach) { + ThreadArgRetval td; + td.Create(false, {routine, arg}, []() { return 1; }); + EXPECT_EQ(1u, td.size()); + + EXPECT_EQ(arg, td.GetArgs(1).arg_retval); + EXPECT_EQ(routine, td.GetArgs(1).routine); + EXPECT_EQ(1u, td.size()); + + td.Finish(1, retval); + EXPECT_EQ(1u, td.size()); + + td.Detach(1, []() { return false; }); + EXPECT_EQ(1u, td.size()); + + td.Detach(1, []() { return true; }); + EXPECT_EQ(0u, td.size()); +} + +TEST(ThreadArgRetvalTest, CreateDetachRun) { + ThreadArgRetval td; + td.Create(false, {routine, arg}, []() { return 1; }); + EXPECT_EQ(1u, td.size()); + + td.Detach(1, []() { return true; }); + EXPECT_EQ(1u, td.size()); + + EXPECT_EQ(arg, td.GetArgs(1).arg_retval); + EXPECT_EQ(routine, td.GetArgs(1).routine); + EXPECT_EQ(1u, td.size()); + + td.Finish(1, retval); + EXPECT_EQ(0u, td.size()); +} + +TEST(ThreadArgRetvalTest, CreateRunJoinReuse) { + ThreadArgRetval td; + td.Create(false, {routine, arg}, []() { return 1; }); + EXPECT_EQ(1u, td.size()); + + td.Finish(1, retval); + EXPECT_EQ(1u, td.size()); + + td.Join(1, [&]() { + // Reuse thread id. + td.Create(false, {routine, arg}, []() { return 1; }); + EXPECT_EQ(1u, td.size()); + return true; + }); + // Even if JoinFn succeeded, we can't erase mismatching thread. + EXPECT_EQ(1u, td.size()); + + // Now we can join another one. + td.Join(1, []() { return true; }); + EXPECT_EQ(0u, td.size()); +} + +TEST(ThreadArgRetvalTest, GetAllPtrsLocked) { + ThreadArgRetval td; + td.Create(false, {routine, arg}, []() { return 1; }); + { + GenericScopedLock lock(&td); + InternalMmapVector ptrs; + td.GetAllPtrsLocked(&ptrs); + EXPECT_EQ(1u, ptrs.size()); + EXPECT_EQ((uptr)arg, ptrs[0]); + } + + td.Finish(1, retval); + { + GenericScopedLock lock(&td); + InternalMmapVector ptrs; + td.GetAllPtrsLocked(&ptrs); + EXPECT_EQ(1u, ptrs.size()); + EXPECT_EQ((uptr)retval, ptrs[0]); + } + + td.Join(1, []() { return true; }); + { + GenericScopedLock lock(&td); + InternalMmapVector ptrs; + td.GetAllPtrsLocked(&ptrs); + EXPECT_TRUE(ptrs.empty()); + } +} + +} // namespace __sanitizer diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h index d5365b689aa8d..006605659bfd9 100644 --- a/compiler-rt/lib/scudo/standalone/combined.h +++ b/compiler-rt/lib/scudo/standalone/combined.h @@ -239,6 +239,7 @@ class Allocator { } TSDRegistryT *getTSDRegistry() { return &TSDRegistry; } + QuarantineT *getQuarantine() { return &Quarantine; } // The Cache must be provided zero-initialized. void initCache(CacheT *Cache) { Cache->init(&Stats, &Primary); } @@ -254,6 +255,13 @@ class Allocator { TSD->getCache().destroy(&Stats); } + void drainCache(TSD *TSD) { + Quarantine.drainAndRecycle(&TSD->getQuarantineCache(), + QuarantineCallback(*this, TSD->getCache())); + TSD->getCache().drain(); + } + void drainCaches() { TSDRegistry.drainCaches(this); } + ALWAYS_INLINE void *getHeaderTaggedPointer(void *Ptr) { if (!allocatorSupportsMemoryTagging()) return Ptr; @@ -747,6 +755,8 @@ class Allocator { void releaseToOS(ReleaseToOS ReleaseType) { initThreadMaybe(); + if (ReleaseType == ReleaseToOS::ForceAll) + drainCaches(); Primary.releaseToOS(ReleaseType); Secondary.releaseToOS(); } diff --git a/compiler-rt/lib/scudo/standalone/primary32.h b/compiler-rt/lib/scudo/standalone/primary32.h index 7ac8df9dd95e4..726db754f245e 100644 --- a/compiler-rt/lib/scudo/standalone/primary32.h +++ b/compiler-rt/lib/scudo/standalone/primary32.h @@ -737,6 +737,9 @@ template class SizeClassAllocator32 { Sci->AllocatedUser - (Sci->Stats.PoppedBlocks - Sci->Stats.PushedBlocks) * BlockSize; + if (UNLIKELY(BytesInFreeList == 0)) + return 0; + bool MaySkip = false; if (BytesInFreeList <= Sci->ReleaseInfo.BytesInFreeListAtLastCheckpoint) { diff --git a/compiler-rt/lib/scudo/standalone/primary64.h b/compiler-rt/lib/scudo/standalone/primary64.h index b954b7c0bf2ae..39248376eaac7 100644 --- a/compiler-rt/lib/scudo/standalone/primary64.h +++ b/compiler-rt/lib/scudo/standalone/primary64.h @@ -845,6 +845,9 @@ template class SizeClassAllocator64 { Region->AllocatedUser - (Region->Stats.PoppedBlocks - Region->Stats.PushedBlocks) * BlockSize; + if (UNLIKELY(BytesInFreeList == 0)) + return 0; + bool MaySkip = false; // Always update `BytesInFreeListAtLastCheckpoint` with the smallest value diff --git a/compiler-rt/lib/scudo/standalone/quarantine.h b/compiler-rt/lib/scudo/standalone/quarantine.h index e65a733ced7b8..b5f8db0e87c23 100644 --- a/compiler-rt/lib/scudo/standalone/quarantine.h +++ b/compiler-rt/lib/scudo/standalone/quarantine.h @@ -192,6 +192,12 @@ template class GlobalQuarantine { uptr getMaxSize() const { return atomic_load_relaxed(&MaxSize); } uptr getCacheSize() const { return atomic_load_relaxed(&MaxCacheSize); } + // This is supposed to be used in test only. + bool isEmpty() { + ScopedLock L(CacheMutex); + return Cache.getSize() == 0U; + } + void put(CacheT *C, Callback Cb, Node *Ptr, uptr Size) { C->enqueue(Cb, Ptr, Size); if (C->getSize() > getCacheSize()) diff --git a/compiler-rt/lib/scudo/standalone/secondary.h b/compiler-rt/lib/scudo/standalone/secondary.h index 935b48914d00c..94009f5fa9c65 100644 --- a/compiler-rt/lib/scudo/standalone/secondary.h +++ b/compiler-rt/lib/scudo/standalone/secondary.h @@ -522,13 +522,12 @@ void *MapAllocator::allocate(Options Options, uptr Size, uptr Alignment, if (FillContents && !Zeroed) memset(Ptr, FillContents == ZeroFill ? 0 : PatternFillByte, BlockEnd - PtrInt); - const uptr BlockSize = BlockEnd - HInt; { ScopedLock L(Mutex); InUseBlocks.push_back(H); - AllocatedBytes += BlockSize; + AllocatedBytes += H->CommitSize; NumberOfAllocs++; - Stats.add(StatAllocated, BlockSize); + Stats.add(StatAllocated, H->CommitSize); Stats.add(StatMapped, H->MemMap.getCapacity()); } return Ptr; diff --git a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp index 33a309e42d656..44ba639f7aa24 100644 --- a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp @@ -457,6 +457,28 @@ SCUDO_TYPED_TEST(ScudoCombinedTest, CacheDrain) NO_THREAD_SAFETY_ANALYSIS { TSD->unlock(); } +SCUDO_TYPED_TEST(ScudoCombinedTest, ForceCacheDrain) NO_THREAD_SAFETY_ANALYSIS { + auto *Allocator = this->Allocator.get(); + + std::vector V; + for (scudo::uptr I = 0; I < 64U; I++) + V.push_back(Allocator->allocate( + rand() % (TypeParam::Primary::SizeClassMap::MaxSize / 2U), Origin)); + for (auto P : V) + Allocator->deallocate(P, Origin); + + // `ForceAll` will also drain the caches. + Allocator->releaseToOS(scudo::ReleaseToOS::ForceAll); + + bool UnlockRequired; + auto *TSD = Allocator->getTSDRegistry()->getTSDAndLock(&UnlockRequired); + EXPECT_TRUE(TSD->getCache().isEmpty()); + EXPECT_EQ(TSD->getQuarantineCache().getSize(), 0U); + EXPECT_TRUE(Allocator->getQuarantine()->isEmpty()); + if (UnlockRequired) + TSD->unlock(); +} + SCUDO_TYPED_TEST(ScudoCombinedTest, ThreadedCombined) { std::mutex Mutex; std::condition_variable Cv; diff --git a/compiler-rt/lib/scudo/standalone/tsd_exclusive.h b/compiler-rt/lib/scudo/standalone/tsd_exclusive.h index aca9fc9b4e802..238367420238d 100644 --- a/compiler-rt/lib/scudo/standalone/tsd_exclusive.h +++ b/compiler-rt/lib/scudo/standalone/tsd_exclusive.h @@ -59,6 +59,15 @@ template struct TSDRegistryExT { Initialized = false; } + void drainCaches(Allocator *Instance) { + // We don't have a way to iterate all thread local `ThreadTSD`s. Simply + // drain the `ThreadTSD` of current thread and `FallbackTSD`. + Instance->drainCache(&ThreadTSD); + FallbackTSD.lock(); + Instance->drainCache(&FallbackTSD); + FallbackTSD.unlock(); + } + ALWAYS_INLINE void initThreadMaybe(Allocator *Instance, bool MinimalInit) { if (LIKELY(State.InitState != ThreadState::NotInitialized)) return; diff --git a/compiler-rt/lib/scudo/standalone/tsd_shared.h b/compiler-rt/lib/scudo/standalone/tsd_shared.h index e193281fc7343..dcb0948ad78fa 100644 --- a/compiler-rt/lib/scudo/standalone/tsd_shared.h +++ b/compiler-rt/lib/scudo/standalone/tsd_shared.h @@ -54,6 +54,15 @@ struct TSDRegistrySharedT { Initialized = false; } + void drainCaches(Allocator *Instance) { + ScopedLock L(MutexTSDs); + for (uptr I = 0; I < NumberOfTSDs; ++I) { + TSDs[I].lock(); + Instance->drainCache(&TSDs[I]); + TSDs[I].unlock(); + } + } + ALWAYS_INLINE void initThreadMaybe(Allocator *Instance, UNUSED bool MinimalInit) { if (LIKELY(getCurrentTSD())) diff --git a/compiler-rt/test/asan/TestCases/backtrace_interceptor.cpp b/compiler-rt/test/asan/TestCases/backtrace_interceptor.cpp new file mode 100644 index 0000000000000..f1ce7d18c0b8a --- /dev/null +++ b/compiler-rt/test/asan/TestCases/backtrace_interceptor.cpp @@ -0,0 +1,30 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +// Windows does not have execinfo.h. For now, be conservative and +// restrict the test to glibc. +// REQUIRES: glibc-2.27 + +// Test the backtrace() interceptor. + +#include +#include +#include +#include +#include + +#define MAX_BT 100 + +int main() { + void **buffer = (void **)malloc(sizeof(void *) * MAX_BT); + assert(buffer != NULL); + free(buffer); + + // Deliberate use-after-free of 'buffer'. We expect ASan to + // catch this, without triggering internal sanitizer errors. + int numEntries = backtrace(buffer, MAX_BT); + printf("backtrace returned %d entries\n", numEntries); + + // CHECK: use-after-free + // CHECK: SUMMARY + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/backtrace_symbols_interceptor.cpp b/compiler-rt/test/asan/TestCases/backtrace_symbols_interceptor.cpp new file mode 100644 index 0000000000000..c896208350395 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/backtrace_symbols_interceptor.cpp @@ -0,0 +1,40 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +// Windows does not have execinfo.h. For now, be conservative and +// restrict the test to glibc. +// REQUIRES: glibc-2.27 + +// Test the backtrace_symbols() interceptor. + +#include +#include +#include +#include +#include + +#define MAX_BT 100 + +int main() { + void **buffer = (void **)malloc(sizeof(void *) * MAX_BT); + assert(buffer != NULL); + + int numEntries = backtrace(buffer, MAX_BT); + printf("backtrace returned %d entries\n", numEntries); + + free(buffer); + + // Deliberate use-after-free of 'buffer'. We expect ASan to + // catch this, without triggering internal sanitizer errors. + char **strings = backtrace_symbols(buffer, numEntries); + assert(strings != NULL); + + for (int i = 0; i < numEntries; i++) { + printf("%s\n", strings[i]); + } + + free(strings); + + // CHECK: use-after-free + // CHECK: SUMMARY + return 0; +} diff --git a/compiler-rt/test/asan/lit.cfg.py b/compiler-rt/test/asan/lit.cfg.py index e8c96f9b58d0e..9a8e513521a33 100644 --- a/compiler-rt/test/asan/lit.cfg.py +++ b/compiler-rt/test/asan/lit.cfg.py @@ -3,18 +3,10 @@ import os import platform import re +import shlex import lit.formats -# Get shlex.quote if available (added in 3.3), and fall back to pipes.quote if -# it's not available. -try: - import shlex - sh_quote = shlex.quote -except: - import pipes - sh_quote = pipes.quote - def get_required_attr(config, attr_name): attr_value = getattr(config, attr_name, None) if attr_value == None: @@ -182,7 +174,7 @@ def build_invocation(compile_flags): # FIXME: De-hardcode this path. asan_source_dir = os.path.join( get_required_attr(config, "compiler_rt_src_root"), "lib", "asan") -python_exec = sh_quote(get_required_attr(config, "python_executable")) +python_exec = shlex.quote(get_required_attr(config, "python_executable")) # Setup path to asan_symbolize.py script. asan_symbolize = os.path.join(asan_source_dir, "scripts", "asan_symbolize.py") if not os.path.exists(asan_symbolize): diff --git a/compiler-rt/test/dfsan/custom.cpp b/compiler-rt/test/dfsan/custom.cpp index 6dbf0d71c9663..62483c1ed96f2 100644 --- a/compiler-rt/test/dfsan/custom.cpp +++ b/compiler-rt/test/dfsan/custom.cpp @@ -381,6 +381,34 @@ void test_strlen() { #endif } +void test_strnlen() { + char str1[] = "str1"; + dfsan_set_label(i_label, &str1[3], 1); + + int maxlen = 4; + dfsan_set_label(j_label, &maxlen, sizeof(maxlen)); + + int rv = strnlen(str1, maxlen); + assert(rv == 4); +#ifdef STRICT_DATA_DEPENDENCIES + ASSERT_ZERO_LABEL(rv); +#else + ASSERT_LABEL(rv, dfsan_union(i_label, j_label)); + ASSERT_EQ_ORIGIN(rv, str1[3]); +#endif + + maxlen = 2; + dfsan_set_label(j_label, &maxlen, sizeof(maxlen)); + rv = strnlen(str1, maxlen); + assert(rv == 2); +#ifdef STRICT_DATA_DEPENDENCIES + ASSERT_ZERO_LABEL(rv); +#else + ASSERT_LABEL(rv, j_label); + ASSERT_EQ_ORIGIN(rv, maxlen); +#endif +} + void test_strdup() { char str1[] = "str1"; dfsan_set_label(i_label, &str1[3], 1); @@ -2085,6 +2113,7 @@ int main(void) { test_strcpy(); test_strdup(); test_strlen(); + test_strnlen(); test_strncasecmp(); test_strncmp(); test_strncpy(); diff --git a/compiler-rt/test/hwasan/TestCases/global-with-reduction.c b/compiler-rt/test/hwasan/TestCases/global-with-reduction.c index de682030ee883..b93e976c6f3ff 100644 --- a/compiler-rt/test/hwasan/TestCases/global-with-reduction.c +++ b/compiler-rt/test/hwasan/TestCases/global-with-reduction.c @@ -22,29 +22,36 @@ // REQUIRES: pointer-tagging +#include #include +struct data { + uint64_t x; + uint64_t y; +}; + // GlobalOpt may replace the current GV with a new boolean-typed GV. Previously, // this resulted in the "nosanitize" getting dropped because while the data/code // references to the GV were updated, the old metadata references weren't. -int* f() { +struct data *f() { #ifdef USE_NOSANITIZE -__attribute__((no_sanitize("hwaddress"))) static int x = 1; + __attribute__((no_sanitize("hwaddress"))) static struct data x = {1, 0}; #else // USE_NOSANITIZE - static int x = 1; + static struct data x = {1, 0}; #endif // USE_NOSANITIZE - if (x == 1) x = 0; + if (x.x == 1) + x.x = 0; return &x; } int main(int argc, char **argv) { // CHECK: Cause: global-overflow - // RSYM: is located 0 bytes after a 4-byte global variable f.x {{.*}} in {{.*}}global-with-reduction.c.tmp - // RNOSYM: is located after a 4-byte global variable in + // RSYM: is located 0 bytes after a 16-byte global variable f.x {{.*}} in {{.*}}global-with-reduction.c.tmp + // RNOSYM: is located after a 16-byte global variable in // RNOSYM-NEXT: #0 0x{{.*}} ({{.*}}global-with-reduction.c.tmp+{{.*}}) - // LSYM: is located 4 bytes before a 4-byte global variable f.x {{.*}} in {{.*}}global-with-reduction.c.tmp - // LNOSYM: is located before a 4-byte global variable in + // LSYM: is located 16 bytes before a 16-byte global variable f.x {{.*}} in {{.*}}global-with-reduction.c.tmp + // LNOSYM: is located before a 16-byte global variable in // LNOSYM-NEXT: #0 0x{{.*}} ({{.*}}global-with-reduction.c.tmp+{{.*}}) // CHECK-NOT: can not describe - f()[atoi(argv[1])] = 1; + f()[atoi(argv[1])].x = 1; } diff --git a/compiler-rt/test/lit.common.cfg.py b/compiler-rt/test/lit.common.cfg.py index 0608b08f09deb..432f738895843 100644 --- a/compiler-rt/test/lit.common.cfg.py +++ b/compiler-rt/test/lit.common.cfg.py @@ -6,21 +6,13 @@ import os import platform import re +import shlex import subprocess import json import lit.formats import lit.util -# Get shlex.quote if available (added in 3.3), and fall back to pipes.quote if -# it's not available. -try: - import shlex - sh_quote = shlex.quote -except: - import pipes - sh_quote = pipes.quote - def find_compiler_libdir(): """ Returns the path to library resource directory used @@ -730,15 +722,15 @@ def is_windows_lto_supported(): config.substitutions.append(( "%get_pid_from_output", "{} {}/get_pid_from_output.py".format( - sh_quote(config.python_executable), - sh_quote(get_ios_commands_dir()) + shlex.quote(config.python_executable), + shlex.quote(get_ios_commands_dir()) )) ) config.substitutions.append( ("%print_crashreport_for_pid", "{} {}/print_crashreport_for_pid.py".format( - sh_quote(config.python_executable), - sh_quote(get_ios_commands_dir()) + shlex.quote(config.python_executable), + shlex.quote(get_ios_commands_dir()) )) ) diff --git a/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp b/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp index 14acd1472bfda..92e70b2e37c3d 100644 --- a/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp +++ b/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp @@ -4,11 +4,7 @@ // RUN: %run not %t 10 1 0 0 2>&1 | FileCheck %s --check-prefixes=LEAK,LEAK123 // RUN: %run not %t 10 0 1 0 2>&1 | FileCheck %s --check-prefixes=LEAK,LEAK234 // RUN: %run not %t 10 0 0 1 2>&1 | FileCheck %s --check-prefixes=LEAK,LEAK234 - -// FIXME: Remove "not". There is no leak. -// False LEAK123 is broken for HWASAN. -// False LEAK234 is broken for ASAN, HWASAN, LSAN. -// RUN: %run %if asan %{ not %} %if hwasan %{ not %} %if lsan-standalone %{ not %} %t 10 0 0 0 +// RUN: %run %t 10 0 0 0 #include #include diff --git a/compiler-rt/test/memprof/lit.cfg.py b/compiler-rt/test/memprof/lit.cfg.py index e472101b1f16e..80a325a38e40d 100644 --- a/compiler-rt/test/memprof/lit.cfg.py +++ b/compiler-rt/test/memprof/lit.cfg.py @@ -6,15 +6,6 @@ import lit.formats -# Get shlex.quote if available (added in 3.3), and fall back to pipes.quote if -# it's not available. -try: - import shlex - sh_quote = shlex.quote -except: - import pipes - sh_quote = pipes.quote - def get_required_attr(config, attr_name): attr_value = getattr(config, attr_name, None) if attr_value == None: diff --git a/compiler-rt/test/orc/TestCases/Darwin/arm64/objc-cross-file-method-call.S b/compiler-rt/test/orc/TestCases/Darwin/arm64/objc-cross-file-method-call.S index 0d0d2debd4679..ef2ed8b8968f0 100644 --- a/compiler-rt/test/orc/TestCases/Darwin/arm64/objc-cross-file-method-call.S +++ b/compiler-rt/test/orc/TestCases/Darwin/arm64/objc-cross-file-method-call.S @@ -3,6 +3,8 @@ // RUN: %clang -c -o %t.o %s // RUN: %clang -c -o %t.aux.o %S/Inputs/objc-Foo-foo-class-method.S // RUN: %llvm_jitlink -preload libobjc.A.dylib %t.o %t.aux.o +// +// REQUIRES: jit-compatible-osx-swift-runtime .section __TEXT,__text,regular,pure_instructions .build_version macos, 14, 0 sdk_version 14, 0 diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/pthread_join.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/pthread_join.cpp index 2b35b163b1430..212a28dd3985b 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/pthread_join.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/pthread_join.cpp @@ -4,8 +4,6 @@ // FIXME: Crashes on some bots in pthread_exit. // RUN: %run %t %if tsan %{ 0 %} %else %{ 1 %} -// XFAIL: msan - // REQUIRES: glibc #include diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/create_thread_loop.cpp b/compiler-rt/test/sanitizer_common/TestCases/Posix/create_thread_loop.cpp index 46bc1b52af447..6b7ee913cc992 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Posix/create_thread_loop.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/create_thread_loop.cpp @@ -2,6 +2,9 @@ // RUN: %clangxx -O3 -pthread %s -o %t && %run %t 1000 +// Inconsistently fails on Android. +// UNSUPPORTED: android + #include #include diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/create_thread_loop2.cpp b/compiler-rt/test/sanitizer_common/TestCases/Posix/create_thread_loop2.cpp index afc4c769bead7..fdbc5712d83de 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Posix/create_thread_loop2.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/create_thread_loop2.cpp @@ -2,6 +2,9 @@ // RUN: %clangxx -O3 -pthread %s -o %t && %run %t 10 +// Crashes on Android. +// UNSUPPORTED: android + #include #include #include diff --git a/flang/CMakeLists.txt b/flang/CMakeLists.txt index ab254871fbb48..66a09703c87d3 100644 --- a/flang/CMakeLists.txt +++ b/flang/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.13.4) +cmake_minimum_required(VERSION 3.20.0) if(NOT DEFINED LLVM_COMMON_CMAKE_UTILS) set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) @@ -39,13 +39,6 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) message("Building Flang as a standalone project.") project(Flang) set(FLANG_STANDALONE_BUILD ON) - if ("${CMAKE_VERSION}" VERSION_LESS "3.20.0") - message(WARNING - "Your CMake version is ${CMAKE_VERSION}. Starting with LLVM 17.0.0, the " - "minimum version of CMake required to build LLVM will become 3.20.0, and " - "using an older CMake will become an error. Please upgrade your CMake to " - "at least 3.20.0 now to avoid issues in the future!") - endif() else() set(FLANG_STANDALONE_BUILD OFF) endif() diff --git a/flang/docs/OpenMP-semantics.md b/flang/docs/OpenMP-semantics.md index 579c40692ba4b..6f42b44726e93 100644 --- a/flang/docs/OpenMP-semantics.md +++ b/flang/docs/OpenMP-semantics.md @@ -418,6 +418,16 @@ More details are listed in the following table: OmpUseDevicePtr + + use_device_addr + + Yes + + New Symbol + + OmpUseDeviceAddr + + To determine the right data-sharing attribute, @@ -535,6 +545,11 @@ use_device_ptr clause are privatized and the device pointers to the corresponding list items in the device data environment are assigned into the private versions so it is best to follow the representation for privatised variables i.e represent them with a new Symbol and `OmpUseDevicePtr` flag. +If a list item that appears in a use_device_addr clause has corresponding +storage in the device data environment, references to the list item in the +associated structured block are converted into references to the corresponding +list item so following the same i.e. represent them with a new Symbol and +`OmpUseDeviceAddr` flag. The basic steps to determine the data-mapping attribute are: diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp index 5efda806856f6..a93c1b19ea688 100644 --- a/flang/examples/FeatureList/FeatureList.cpp +++ b/flang/examples/FeatureList/FeatureList.cpp @@ -474,6 +474,7 @@ struct NodeVisitor { READ_FEATURE(OmpDependenceType::Type) READ_FEATURE(OmpDependSinkVec) READ_FEATURE(OmpDependSinkVecLength) + READ_FEATURE(OmpEndAllocators) READ_FEATURE(OmpEndAtomic) READ_FEATURE(OmpEndBlockDirective) READ_FEATURE(OmpEndCriticalDirective) @@ -506,7 +507,10 @@ struct NodeVisitor { READ_FEATURE(OmpReductionInitializerClause) READ_FEATURE(OmpReductionOperator) READ_FEATURE(OmpAllocateClause) - READ_FEATURE(OmpAllocateClause::Allocator) + READ_FEATURE(OmpAllocateClause::AllocateModifier) + READ_FEATURE(OmpAllocateClause::AllocateModifier::Allocator) + READ_FEATURE(OmpAllocateClause::AllocateModifier::ComplexModifier) + READ_FEATURE(OmpAllocateClause::AllocateModifier::Align) READ_FEATURE(OmpScheduleClause) READ_FEATURE(OmpScheduleClause::ScheduleType) READ_FEATURE(OmpDeviceClause) @@ -553,6 +557,7 @@ struct NodeVisitor { READ_FEATURE(OpenMPFlushConstruct) READ_FEATURE(OpenMPLoopConstruct) READ_FEATURE(OpenMPExecutableAllocate) + READ_FEATURE(OpenMPAllocatorsConstruct) READ_FEATURE(OpenMPRequiresConstruct) READ_FEATURE(OpenMPSimpleStandaloneConstruct) READ_FEATURE(OpenMPStandaloneConstruct) diff --git a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp index d78f898d499e4..7382e99de1ab8 100644 --- a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp +++ b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp @@ -128,6 +128,10 @@ std::string OpenMPCounterVisitor::getName(const OpenMPConstruct &c) { const CharBlock &source{std::get<0>(c.t).source}; return normalize_construct_name(source.ToString()); }, + [&](const OpenMPAllocatorsConstruct &c) -> std::string { + const CharBlock &source{std::get<0>(c.t).source}; + return normalize_construct_name(source.ToString()); + }, [&](const OpenMPAtomicConstruct &c) -> std::string { return std::visit( [&](const auto &c) { diff --git a/flang/include/flang/Evaluate/constant.h b/flang/include/flang/Evaluate/constant.h index 46c2f59f15537..611ee7772d2a1 100644 --- a/flang/include/flang/Evaluate/constant.h +++ b/flang/include/flang/Evaluate/constant.h @@ -165,7 +165,8 @@ class Constant> : public ConstantBounds { ~Constant(); bool operator==(const Constant &that) const { - return shape() == that.shape() && values_ == that.values_; + return LEN() == that.LEN() && shape() == that.shape() && + values_ == that.values_; } bool empty() const; std::size_t size() const; diff --git a/flang/include/flang/Evaluate/type.h b/flang/include/flang/Evaluate/type.h index 4b13a3155ab00..2183b0dad5d1a 100644 --- a/flang/include/flang/Evaluate/type.h +++ b/flang/include/flang/Evaluate/type.h @@ -472,7 +472,8 @@ int SelectedCharKind(const std::string &, int defaultKind); std::optional ComparisonType( const DynamicType &, const DynamicType &); -bool IsInteroperableIntrinsicType(const DynamicType &); +bool IsInteroperableIntrinsicType( + const DynamicType &, bool checkCharLength = true); // Determine whether two derived type specs are sufficiently identical // to be considered the "same" type even if declared separately. diff --git a/flang/include/flang/Lower/AbstractConverter.h b/flang/include/flang/Lower/AbstractConverter.h index 8c428da37dc87..7452f71d8083b 100644 --- a/flang/include/flang/Lower/AbstractConverter.h +++ b/flang/include/flang/Lower/AbstractConverter.h @@ -115,6 +115,17 @@ class AbstractConverter { Fortran::semantics::Symbol::Flag flag, bool collectSymbols = true, bool collectHostAssociatedSymbols = false) = 0; + /// For the given literal constant \p expression, returns a unique name + /// that can be used to create a global object to represent this + /// literal constant. It will return the same name for equivalent + /// literal constant expressions. \p eleTy specifies the data type + /// of the constant elements. For array constants it specifies + /// the array's element type. + virtual llvm::StringRef + getUniqueLitName(mlir::Location loc, + std::unique_ptr expression, + mlir::Type eleTy) = 0; + //===--------------------------------------------------------------------===// // Expressions //===--------------------------------------------------------------------===// diff --git a/flang/include/flang/Lower/ConvertExprToHLFIR.h b/flang/include/flang/Lower/ConvertExprToHLFIR.h index 0acb713cd04c5..42ce7b6edd747 100644 --- a/flang/include/flang/Lower/ConvertExprToHLFIR.h +++ b/flang/include/flang/Lower/ConvertExprToHLFIR.h @@ -27,6 +27,10 @@ namespace mlir { class Location; } // namespace mlir +namespace hlfir { +class ElementalAddrOp; +} + namespace Fortran::lower { class AbstractConverter; @@ -115,6 +119,19 @@ fir::MutableBoxValue convertExprToMutableBox(mlir::Location loc, Fortran::lower::AbstractConverter &, const Fortran::lower::SomeExpr &, Fortran::lower::SymMap &); +/// Lower a designator containing vector subscripts into an +/// hlfir::ElementalAddrOp that will allow looping on the elements to assign +/// them values. This only intends to cover the cases where such designator +/// appears on the left-hand side of an assignment or appears in an input IO +/// statement. These are the only contexts in Fortran where a vector subscripted +/// entity may be modified. Otherwise, there is no need to do anything special +/// about vector subscripts, they are automatically turned into array expression +/// values via an hlfir.elemental in the convertExprToXXX calls. +hlfir::ElementalAddrOp convertVectorSubscriptedExprToElementalAddr( + mlir::Location loc, Fortran::lower::AbstractConverter &, + const Fortran::lower::SomeExpr &, Fortran::lower::SymMap &, + Fortran::lower::StatementContext &); + } // namespace Fortran::lower #endif // FORTRAN_LOWER_CONVERTEXPRTOHLFIR_H diff --git a/flang/include/flang/Lower/IterationSpace.h b/flang/include/flang/Lower/IterationSpace.h index f05a23ba3e33e..1359e22e23edd 100644 --- a/flang/include/flang/Lower/IterationSpace.h +++ b/flang/include/flang/Lower/IterationSpace.h @@ -37,30 +37,9 @@ using FrontEndSymbol = const semantics::Symbol *; class AbstractConverter; -unsigned getHashValue(FrontEndExpr x); -bool isEqual(FrontEndExpr x, FrontEndExpr y); } // namespace lower } // namespace Fortran -namespace llvm { -template <> -struct DenseMapInfo { - static inline Fortran::lower::FrontEndExpr getEmptyKey() { - return reinterpret_cast(~0); - } - static inline Fortran::lower::FrontEndExpr getTombstoneKey() { - return reinterpret_cast(~0 - 1); - } - static unsigned getHashValue(Fortran::lower::FrontEndExpr v) { - return Fortran::lower::getHashValue(v); - } - static bool isEqual(Fortran::lower::FrontEndExpr lhs, - Fortran::lower::FrontEndExpr rhs) { - return Fortran::lower::isEqual(lhs, rhs); - } -}; -} // namespace llvm - namespace Fortran::lower { /// Abstraction of the iteration space for building the elemental compute loop diff --git a/flang/include/flang/Lower/Mangler.h b/flang/include/flang/Lower/Mangler.h index 9e6f82bc19598..e32132a6692a7 100644 --- a/flang/include/flang/Lower/Mangler.h +++ b/flang/include/flang/Lower/Mangler.h @@ -54,7 +54,7 @@ std::string mangleName(const semantics::DerivedTypeSpec &, ScopeBlockIdMap &); std::string demangleName(llvm::StringRef name); std::string -mangleArrayLiteral(const uint8_t *addr, size_t size, +mangleArrayLiteral(size_t size, const Fortran::evaluate::ConstantSubscripts &shape, Fortran::common::TypeCategory cat, int kind = 0, Fortran::common::ConstantSubscript charLen = -1, @@ -64,9 +64,8 @@ template std::string mangleArrayLiteral( mlir::Type, const Fortran::evaluate::Constant> &x) { - return mangleArrayLiteral( - reinterpret_cast(x.values().data()), - x.values().size() * sizeof(x.values()[0]), x.shape(), TC, KIND); + return mangleArrayLiteral(x.values().size() * sizeof(x.values()[0]), + x.shape(), TC, KIND); } template @@ -74,25 +73,18 @@ std::string mangleArrayLiteral(mlir::Type, const Fortran::evaluate::Constant> &x) { - return mangleArrayLiteral( - reinterpret_cast(x.values().data()), - x.values().size() * sizeof(x.values()[0]), x.shape(), - Fortran::common::TypeCategory::Character, KIND, x.LEN()); + return mangleArrayLiteral(x.values().size() * sizeof(x.values()[0]), + x.shape(), Fortran::common::TypeCategory::Character, + KIND, x.LEN()); } -// FIXME: derived type mangling is safe but not reproducible between two -// compilation of a same file because `values().data()` is a nontrivial compile -// time data structure containing pointers and vectors. In particular, this -// means that similar structure constructors are not "combined" into the same -// global constant by lowering. inline std::string mangleArrayLiteral( mlir::Type eleTy, const Fortran::evaluate::Constant &x) { - return mangleArrayLiteral( - reinterpret_cast(x.values().data()), - x.values().size() * sizeof(x.values()[0]), x.shape(), - Fortran::common::TypeCategory::Derived, /*kind=*/0, /*charLen=*/-1, - eleTy.cast().getName()); + return mangleArrayLiteral(x.values().size() * sizeof(x.values()[0]), + x.shape(), Fortran::common::TypeCategory::Derived, + /*kind=*/0, /*charLen=*/-1, + eleTy.cast().getName()); } /// Return the compiler-generated name of a static namelist variable descriptor. diff --git a/flang/include/flang/Lower/Support/Utils.h b/flang/include/flang/Lower/Support/Utils.h index c84dd93c7d0cb..9ab00dad51d39 100644 --- a/flang/include/flang/Lower/Support/Utils.h +++ b/flang/include/flang/Lower/Support/Utils.h @@ -24,7 +24,7 @@ namespace Fortran::lower { using SomeExpr = Fortran::evaluate::Expr; -} +} // end namespace Fortran::lower //===----------------------------------------------------------------------===// // Small inline helper functions to deal with repetitive, clumsy conversions. @@ -85,4 +85,582 @@ A flatZip(const A &container1, const A &container2) { return result; } +namespace Fortran::lower { +// Fortran::evaluate::Expr are functional values organized like an AST. A +// Fortran::evaluate::Expr is meant to be moved and cloned. Using the front end +// tools can often cause copies and extra wrapper classes to be added to any +// Fortran::evalute::Expr. These values should not be assumed or relied upon to +// have an *object* identity. They are deeply recursive, irregular structures +// built from a large number of classes which do not use inheritance and +// necessitate a large volume of boilerplate code as a result. +// +// Contrastingly, LLVM data structures make ubiquitous assumptions about an +// object's identity via pointers to the object. An object's location in memory +// is thus very often an identifying relation. + +// This class defines a hash computation of a Fortran::evaluate::Expr tree value +// so it can be used with llvm::DenseMap. The Fortran::evaluate::Expr need not +// have the same address. +class HashEvaluateExpr { +public: + // A Se::Symbol is the only part of an Fortran::evaluate::Expr with an + // identity property. + static unsigned getHashValue(const Fortran::semantics::Symbol &x) { + return static_cast(reinterpret_cast(&x)); + } + template + static unsigned getHashValue(const Fortran::common::Indirection &x) { + return getHashValue(x.value()); + } + template + static unsigned getHashValue(const std::optional &x) { + if (x.has_value()) + return getHashValue(x.value()); + return 0u; + } + static unsigned getHashValue(const Fortran::evaluate::Subscript &x) { + return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); + } + static unsigned getHashValue(const Fortran::evaluate::Triplet &x) { + return getHashValue(x.lower()) - getHashValue(x.upper()) * 5u - + getHashValue(x.stride()) * 11u; + } + static unsigned getHashValue(const Fortran::evaluate::Component &x) { + return getHashValue(x.base()) * 83u - getHashValue(x.GetLastSymbol()); + } + static unsigned getHashValue(const Fortran::evaluate::ArrayRef &x) { + unsigned subs = 1u; + for (const Fortran::evaluate::Subscript &v : x.subscript()) + subs -= getHashValue(v); + return getHashValue(x.base()) * 89u - subs; + } + static unsigned getHashValue(const Fortran::evaluate::CoarrayRef &x) { + unsigned subs = 1u; + for (const Fortran::evaluate::Subscript &v : x.subscript()) + subs -= getHashValue(v); + unsigned cosubs = 3u; + for (const Fortran::evaluate::Expr &v : + x.cosubscript()) + cosubs -= getHashValue(v); + unsigned syms = 7u; + for (const Fortran::evaluate::SymbolRef &v : x.base()) + syms += getHashValue(v); + return syms * 97u - subs - cosubs + getHashValue(x.stat()) + 257u + + getHashValue(x.team()); + } + static unsigned getHashValue(const Fortran::evaluate::NamedEntity &x) { + if (x.IsSymbol()) + return getHashValue(x.GetFirstSymbol()) * 11u; + return getHashValue(x.GetComponent()) * 13u; + } + static unsigned getHashValue(const Fortran::evaluate::DataRef &x) { + return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); + } + static unsigned getHashValue(const Fortran::evaluate::ComplexPart &x) { + return getHashValue(x.complex()) - static_cast(x.part()); + } + template + static unsigned getHashValue( + const Fortran::evaluate::Convert, TC2> + &x) { + return getHashValue(x.left()) - (static_cast(TC1) + 2u) - + (static_cast(KIND) + 5u); + } + template + static unsigned + getHashValue(const Fortran::evaluate::ComplexComponent &x) { + return getHashValue(x.left()) - + (static_cast(x.isImaginaryPart) + 1u) * 3u; + } + template + static unsigned getHashValue(const Fortran::evaluate::Parentheses &x) { + return getHashValue(x.left()) * 17u; + } + template + static unsigned getHashValue( + const Fortran::evaluate::Negate> &x) { + return getHashValue(x.left()) - (static_cast(TC) + 5u) - + (static_cast(KIND) + 7u); + } + template + static unsigned getHashValue( + const Fortran::evaluate::Add> &x) { + return (getHashValue(x.left()) + getHashValue(x.right())) * 23u + + static_cast(TC) + static_cast(KIND); + } + template + static unsigned getHashValue( + const Fortran::evaluate::Subtract> &x) { + return (getHashValue(x.left()) - getHashValue(x.right())) * 19u + + static_cast(TC) + static_cast(KIND); + } + template + static unsigned getHashValue( + const Fortran::evaluate::Multiply> &x) { + return (getHashValue(x.left()) + getHashValue(x.right())) * 29u + + static_cast(TC) + static_cast(KIND); + } + template + static unsigned getHashValue( + const Fortran::evaluate::Divide> &x) { + return (getHashValue(x.left()) - getHashValue(x.right())) * 31u + + static_cast(TC) + static_cast(KIND); + } + template + static unsigned getHashValue( + const Fortran::evaluate::Power> &x) { + return (getHashValue(x.left()) - getHashValue(x.right())) * 37u + + static_cast(TC) + static_cast(KIND); + } + template + static unsigned getHashValue( + const Fortran::evaluate::Extremum> &x) { + return (getHashValue(x.left()) + getHashValue(x.right())) * 41u + + static_cast(TC) + static_cast(KIND) + + static_cast(x.ordering) * 7u; + } + template + static unsigned getHashValue( + const Fortran::evaluate::RealToIntPower> + &x) { + return (getHashValue(x.left()) - getHashValue(x.right())) * 43u + + static_cast(TC) + static_cast(KIND); + } + template + static unsigned + getHashValue(const Fortran::evaluate::ComplexConstructor &x) { + return (getHashValue(x.left()) - getHashValue(x.right())) * 47u + + static_cast(KIND); + } + template + static unsigned getHashValue(const Fortran::evaluate::Concat &x) { + return (getHashValue(x.left()) - getHashValue(x.right())) * 53u + + static_cast(KIND); + } + template + static unsigned getHashValue(const Fortran::evaluate::SetLength &x) { + return (getHashValue(x.left()) - getHashValue(x.right())) * 59u + + static_cast(KIND); + } + static unsigned getHashValue(const Fortran::semantics::SymbolRef &sym) { + return getHashValue(sym.get()); + } + static unsigned getHashValue(const Fortran::evaluate::Substring &x) { + return 61u * std::visit([&](const auto &p) { return getHashValue(p); }, + x.parent()) - + getHashValue(x.lower()) - (getHashValue(x.lower()) + 1u); + } + static unsigned + getHashValue(const Fortran::evaluate::StaticDataObject::Pointer &x) { + return llvm::hash_value(x->name()); + } + static unsigned getHashValue(const Fortran::evaluate::SpecificIntrinsic &x) { + return llvm::hash_value(x.name); + } + template + static unsigned getHashValue(const Fortran::evaluate::Constant &x) { + // FIXME: Should hash the content. + return 103u; + } + static unsigned getHashValue(const Fortran::evaluate::ActualArgument &x) { + if (const Fortran::evaluate::Symbol *sym = x.GetAssumedTypeDummy()) + return getHashValue(*sym); + return getHashValue(*x.UnwrapExpr()); + } + static unsigned + getHashValue(const Fortran::evaluate::ProcedureDesignator &x) { + return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); + } + static unsigned getHashValue(const Fortran::evaluate::ProcedureRef &x) { + unsigned args = 13u; + for (const std::optional &v : + x.arguments()) + args -= getHashValue(v); + return getHashValue(x.proc()) * 101u - args; + } + template + static unsigned + getHashValue(const Fortran::evaluate::ArrayConstructor &x) { + // FIXME: hash the contents. + return 127u; + } + static unsigned getHashValue(const Fortran::evaluate::ImpliedDoIndex &x) { + return llvm::hash_value(toStringRef(x.name).str()) * 131u; + } + static unsigned getHashValue(const Fortran::evaluate::TypeParamInquiry &x) { + return getHashValue(x.base()) * 137u - getHashValue(x.parameter()) * 3u; + } + static unsigned getHashValue(const Fortran::evaluate::DescriptorInquiry &x) { + return getHashValue(x.base()) * 139u - + static_cast(x.field()) * 13u + + static_cast(x.dimension()); + } + static unsigned + getHashValue(const Fortran::evaluate::StructureConstructor &x) { + // FIXME: hash the contents. + return 149u; + } + template + static unsigned getHashValue(const Fortran::evaluate::Not &x) { + return getHashValue(x.left()) * 61u + static_cast(KIND); + } + template + static unsigned + getHashValue(const Fortran::evaluate::LogicalOperation &x) { + unsigned result = getHashValue(x.left()) + getHashValue(x.right()); + return result * 67u + static_cast(x.logicalOperator) * 5u; + } + template + static unsigned getHashValue( + const Fortran::evaluate::Relational> + &x) { + return (getHashValue(x.left()) + getHashValue(x.right())) * 71u + + static_cast(TC) + static_cast(KIND) + + static_cast(x.opr) * 11u; + } + template + static unsigned getHashValue(const Fortran::evaluate::Expr &x) { + return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); + } + static unsigned getHashValue( + const Fortran::evaluate::Relational &x) { + return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); + } + template + static unsigned getHashValue(const Fortran::evaluate::Designator &x) { + return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); + } + template + static unsigned + getHashValue(const Fortran::evaluate::value::Integer &x) { + return static_cast(x.ToSInt()); + } + static unsigned getHashValue(const Fortran::evaluate::NullPointer &x) { + return ~179u; + } +}; + +// Define the is equals test for using Fortran::evaluate::Expr values with +// llvm::DenseMap. +class IsEqualEvaluateExpr { +public: + // A Se::Symbol is the only part of an Fortran::evaluate::Expr with an + // identity property. + static bool isEqual(const Fortran::semantics::Symbol &x, + const Fortran::semantics::Symbol &y) { + return isEqual(&x, &y); + } + static bool isEqual(const Fortran::semantics::Symbol *x, + const Fortran::semantics::Symbol *y) { + return x == y; + } + template + static bool isEqual(const Fortran::common::Indirection &x, + const Fortran::common::Indirection &y) { + return isEqual(x.value(), y.value()); + } + template + static bool isEqual(const std::optional &x, const std::optional &y) { + if (x.has_value() && y.has_value()) + return isEqual(x.value(), y.value()); + return !x.has_value() && !y.has_value(); + } + template + static bool isEqual(const std::vector &x, const std::vector &y) { + if (x.size() != y.size()) + return false; + const std::size_t size = x.size(); + for (std::remove_const_t i = 0; i < size; ++i) + if (!isEqual(x[i], y[i])) + return false; + return true; + } + static bool isEqual(const Fortran::evaluate::Subscript &x, + const Fortran::evaluate::Subscript &y) { + return std::visit( + [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); + } + static bool isEqual(const Fortran::evaluate::Triplet &x, + const Fortran::evaluate::Triplet &y) { + return isEqual(x.lower(), y.lower()) && isEqual(x.upper(), y.upper()) && + isEqual(x.stride(), y.stride()); + } + static bool isEqual(const Fortran::evaluate::Component &x, + const Fortran::evaluate::Component &y) { + return isEqual(x.base(), y.base()) && + isEqual(x.GetLastSymbol(), y.GetLastSymbol()); + } + static bool isEqual(const Fortran::evaluate::ArrayRef &x, + const Fortran::evaluate::ArrayRef &y) { + return isEqual(x.base(), y.base()) && isEqual(x.subscript(), y.subscript()); + } + static bool isEqual(const Fortran::evaluate::CoarrayRef &x, + const Fortran::evaluate::CoarrayRef &y) { + return isEqual(x.base(), y.base()) && + isEqual(x.subscript(), y.subscript()) && + isEqual(x.cosubscript(), y.cosubscript()) && + isEqual(x.stat(), y.stat()) && isEqual(x.team(), y.team()); + } + static bool isEqual(const Fortran::evaluate::NamedEntity &x, + const Fortran::evaluate::NamedEntity &y) { + if (x.IsSymbol() && y.IsSymbol()) + return isEqual(x.GetFirstSymbol(), y.GetFirstSymbol()); + return !x.IsSymbol() && !y.IsSymbol() && + isEqual(x.GetComponent(), y.GetComponent()); + } + static bool isEqual(const Fortran::evaluate::DataRef &x, + const Fortran::evaluate::DataRef &y) { + return std::visit( + [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); + } + static bool isEqual(const Fortran::evaluate::ComplexPart &x, + const Fortran::evaluate::ComplexPart &y) { + return isEqual(x.complex(), y.complex()) && x.part() == y.part(); + } + template + static bool isEqual(const Fortran::evaluate::Convert &x, + const Fortran::evaluate::Convert &y) { + return isEqual(x.left(), y.left()); + } + template + static bool isEqual(const Fortran::evaluate::ComplexComponent &x, + const Fortran::evaluate::ComplexComponent &y) { + return isEqual(x.left(), y.left()) && + x.isImaginaryPart == y.isImaginaryPart; + } + template + static bool isEqual(const Fortran::evaluate::Parentheses &x, + const Fortran::evaluate::Parentheses &y) { + return isEqual(x.left(), y.left()); + } + template + static bool isEqual(const Fortran::evaluate::Negate &x, + const Fortran::evaluate::Negate &y) { + return isEqual(x.left(), y.left()); + } + template + static bool isBinaryEqual(const A &x, const A &y) { + return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right()); + } + template + static bool isEqual(const Fortran::evaluate::Add &x, + const Fortran::evaluate::Add &y) { + return isBinaryEqual(x, y); + } + template + static bool isEqual(const Fortran::evaluate::Subtract &x, + const Fortran::evaluate::Subtract &y) { + return isBinaryEqual(x, y); + } + template + static bool isEqual(const Fortran::evaluate::Multiply &x, + const Fortran::evaluate::Multiply &y) { + return isBinaryEqual(x, y); + } + template + static bool isEqual(const Fortran::evaluate::Divide &x, + const Fortran::evaluate::Divide &y) { + return isBinaryEqual(x, y); + } + template + static bool isEqual(const Fortran::evaluate::Power &x, + const Fortran::evaluate::Power &y) { + return isBinaryEqual(x, y); + } + template + static bool isEqual(const Fortran::evaluate::Extremum &x, + const Fortran::evaluate::Extremum &y) { + return isBinaryEqual(x, y); + } + template + static bool isEqual(const Fortran::evaluate::RealToIntPower &x, + const Fortran::evaluate::RealToIntPower &y) { + return isBinaryEqual(x, y); + } + template + static bool isEqual(const Fortran::evaluate::ComplexConstructor &x, + const Fortran::evaluate::ComplexConstructor &y) { + return isBinaryEqual(x, y); + } + template + static bool isEqual(const Fortran::evaluate::Concat &x, + const Fortran::evaluate::Concat &y) { + return isBinaryEqual(x, y); + } + template + static bool isEqual(const Fortran::evaluate::SetLength &x, + const Fortran::evaluate::SetLength &y) { + return isBinaryEqual(x, y); + } + static bool isEqual(const Fortran::semantics::SymbolRef &x, + const Fortran::semantics::SymbolRef &y) { + return isEqual(x.get(), y.get()); + } + static bool isEqual(const Fortran::evaluate::Substring &x, + const Fortran::evaluate::Substring &y) { + return std::visit( + [&](const auto &p, const auto &q) { return isEqual(p, q); }, + x.parent(), y.parent()) && + isEqual(x.lower(), y.lower()) && isEqual(x.lower(), y.lower()); + } + static bool isEqual(const Fortran::evaluate::StaticDataObject::Pointer &x, + const Fortran::evaluate::StaticDataObject::Pointer &y) { + return x->name() == y->name(); + } + static bool isEqual(const Fortran::evaluate::SpecificIntrinsic &x, + const Fortran::evaluate::SpecificIntrinsic &y) { + return x.name == y.name; + } + template + static bool isEqual(const Fortran::evaluate::Constant &x, + const Fortran::evaluate::Constant &y) { + return x == y; + } + static bool isEqual(const Fortran::evaluate::ActualArgument &x, + const Fortran::evaluate::ActualArgument &y) { + if (const Fortran::evaluate::Symbol *xs = x.GetAssumedTypeDummy()) { + if (const Fortran::evaluate::Symbol *ys = y.GetAssumedTypeDummy()) + return isEqual(*xs, *ys); + return false; + } + return !y.GetAssumedTypeDummy() && + isEqual(*x.UnwrapExpr(), *y.UnwrapExpr()); + } + static bool isEqual(const Fortran::evaluate::ProcedureDesignator &x, + const Fortran::evaluate::ProcedureDesignator &y) { + return std::visit( + [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); + } + static bool isEqual(const Fortran::evaluate::ProcedureRef &x, + const Fortran::evaluate::ProcedureRef &y) { + return isEqual(x.proc(), y.proc()) && isEqual(x.arguments(), y.arguments()); + } + template + static bool isEqual(const Fortran::evaluate::ArrayConstructor &x, + const Fortran::evaluate::ArrayConstructor &y) { + llvm::report_fatal_error("not implemented"); + } + static bool isEqual(const Fortran::evaluate::ImpliedDoIndex &x, + const Fortran::evaluate::ImpliedDoIndex &y) { + return toStringRef(x.name) == toStringRef(y.name); + } + static bool isEqual(const Fortran::evaluate::TypeParamInquiry &x, + const Fortran::evaluate::TypeParamInquiry &y) { + return isEqual(x.base(), y.base()) && isEqual(x.parameter(), y.parameter()); + } + static bool isEqual(const Fortran::evaluate::DescriptorInquiry &x, + const Fortran::evaluate::DescriptorInquiry &y) { + return isEqual(x.base(), y.base()) && x.field() == y.field() && + x.dimension() == y.dimension(); + } + static bool isEqual(const Fortran::evaluate::StructureConstructor &x, + const Fortran::evaluate::StructureConstructor &y) { + const auto &xValues = x.values(); + const auto &yValues = y.values(); + if (xValues.size() != yValues.size()) + return false; + if (x.derivedTypeSpec() != y.derivedTypeSpec()) + return false; + for (const auto &[xSymbol, xValue] : xValues) { + auto yIt = yValues.find(xSymbol); + // This should probably never happen, since the derived type + // should be the same. + if (yIt == yValues.end()) + return false; + if (!isEqual(xValue, yIt->second)) + return false; + } + return true; + } + template + static bool isEqual(const Fortran::evaluate::Not &x, + const Fortran::evaluate::Not &y) { + return isEqual(x.left(), y.left()); + } + template + static bool isEqual(const Fortran::evaluate::LogicalOperation &x, + const Fortran::evaluate::LogicalOperation &y) { + return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right()); + } + template + static bool isEqual(const Fortran::evaluate::Relational &x, + const Fortran::evaluate::Relational &y) { + return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right()); + } + template + static bool isEqual(const Fortran::evaluate::Expr &x, + const Fortran::evaluate::Expr &y) { + return std::visit( + [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); + } + static bool + isEqual(const Fortran::evaluate::Relational &x, + const Fortran::evaluate::Relational &y) { + return std::visit( + [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); + } + template + static bool isEqual(const Fortran::evaluate::Designator &x, + const Fortran::evaluate::Designator &y) { + return std::visit( + [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); + } + template + static bool isEqual(const Fortran::evaluate::value::Integer &x, + const Fortran::evaluate::value::Integer &y) { + return x == y; + } + static bool isEqual(const Fortran::evaluate::NullPointer &x, + const Fortran::evaluate::NullPointer &y) { + return true; + } + template , bool> = true> + static bool isEqual(const A &, const B &) { + return false; + } +}; + +static inline unsigned getHashValue(const Fortran::lower::SomeExpr *x) { + return HashEvaluateExpr::getHashValue(*x); +} + +static bool isEqual(const Fortran::lower::SomeExpr *x, + const Fortran::lower::SomeExpr *y); +} // end namespace Fortran::lower + +// DenseMapInfo for pointers to Fortran::lower::SomeExpr. +namespace llvm { +template <> +struct DenseMapInfo { + static inline const Fortran::lower::SomeExpr *getEmptyKey() { + return reinterpret_cast(~0); + } + static inline const Fortran::lower::SomeExpr *getTombstoneKey() { + return reinterpret_cast(~0 - 1); + } + static unsigned getHashValue(const Fortran::lower::SomeExpr *v) { + return Fortran::lower::getHashValue(v); + } + static bool isEqual(const Fortran::lower::SomeExpr *lhs, + const Fortran::lower::SomeExpr *rhs) { + return Fortran::lower::isEqual(lhs, rhs); + } +}; +} // namespace llvm + +namespace Fortran::lower { +static inline bool isEqual(const Fortran::lower::SomeExpr *x, + const Fortran::lower::SomeExpr *y) { + const auto *empty = + llvm::DenseMapInfo::getEmptyKey(); + const auto *tombstone = + llvm::DenseMapInfo::getTombstoneKey(); + if (x == empty || y == empty || x == tombstone || y == tombstone) + return x == y; + return x == y || IsEqualEvaluateExpr::isEqual(*x, *y); +} +} // end namespace Fortran::lower + #endif // FORTRAN_LOWER_SUPPORT_UTILS_H diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h index 2cc797f9b3f2a..0d32976b6f606 100644 --- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h +++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h @@ -98,6 +98,11 @@ mlir::Value genMax(fir::FirOpBuilder &, mlir::Location, mlir::Value genMin(fir::FirOpBuilder &, mlir::Location, llvm::ArrayRef args); +/// Generate Complex divide with the given expected +/// result type. +mlir::Value genDivC(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Type resultType, mlir::Value x, mlir::Value y); + /// Generate power function x**y with the given expected /// result type. mlir::Value genPow(fir::FirOpBuilder &, mlir::Location, mlir::Type resultType, diff --git a/flang/include/flang/Optimizer/Builder/MutableBox.h b/flang/include/flang/Optimizer/Builder/MutableBox.h index f763d29c40a11..9056f8ddd29fc 100644 --- a/flang/include/flang/Optimizer/Builder/MutableBox.h +++ b/flang/include/flang/Optimizer/Builder/MutableBox.h @@ -168,6 +168,12 @@ mlir::Value genIsNotAllocatedOrAssociatedTest(fir::FirOpBuilder &builder, mlir::Location loc, const fir::MutableBoxValue &box); +/// Generate an unallocated box of the given \p boxTy +/// and store it into a temporary storage. +/// Return address of the temporary storage. +mlir::Value genNullBoxStorage(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Type boxTy); + } // namespace fir::factory #endif // FORTRAN_OPTIMIZER_BUILDER_MUTABLEBOX_H diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h index 0386b37dbda34..0ccab339fa958 100644 --- a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h +++ b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h @@ -73,6 +73,7 @@ bool isFortranScalarNumericalType(mlir::Type); bool isFortranNumericalArrayObject(mlir::Type); bool isFortranNumericalOrLogicalArrayObject(mlir::Type); bool isFortranArrayObject(mlir::Type); +bool isFortranLogicalArrayObject(mlir::Type); bool isPassByRefOrIntegerType(mlir::Type); bool isI1Type(mlir::Type); // scalar i1 or logical, or sequence of logical (via (boxed?) array or expr) diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td b/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td index 2c620af80bfeb..5d37bd50c4b56 100644 --- a/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td @@ -133,4 +133,9 @@ def IsMaskArgumentPred def AnyFortranLogicalOrI1ArrayObject : Type; +def IsFortranLogicalArrayPred + : CPred<"::hlfir::isFortranLogicalArrayObject($_self)">; +def AnyFortranLogicalArrayObject : Type; + #endif // FORTRAN_DIALECT_HLFIR_OP_BASE diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td index 87136197851a0..924e868d32afd 100644 --- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td @@ -317,6 +317,28 @@ def hlfir_ConcatOp : hlfir_Op<"concat", []> { let hasVerifier = 1; } +def hlfir_AnyOp : hlfir_Op<"any", []> { + let summary = "ANY transformational intrinsic"; + let description = [{ + Takes a logical array MASK as argument, optionally along a particular dimension, + and returns true if any element of MASK is true. + }]; + + let arguments = (ins + AnyFortranLogicalArrayObject:$mask, + Optional:$dim + ); + + let results = (outs hlfir_ExprType); + + let assemblyFormat = [{ + $mask (`dim` $dim^)? attr-dict `:` functional-type(operands, results) + }]; + + let hasVerifier = 1; +} + + def hlfir_ProductOp : hlfir_Op<"product", [AttrSizedOperandSegments, DeclareOpInterfaceMethods]> { let summary = "PRODUCT transformational intrinsic"; diff --git a/flang/include/flang/Optimizer/Transforms/Passes.h b/flang/include/flang/Optimizer/Transforms/Passes.h index 863e0df1e7373..93f78f0646e00 100644 --- a/flang/include/flang/Optimizer/Transforms/Passes.h +++ b/flang/include/flang/Optimizer/Transforms/Passes.h @@ -72,7 +72,6 @@ std::unique_ptr createAlgebraicSimplificationPass(); std::unique_ptr createAlgebraicSimplificationPass(const mlir::GreedyRewriteConfig &config); std::unique_ptr createPolymorphicOpConversionPass(); -std::unique_ptr createOpenACCDataOperandConversionPass(); // declarative passes #define GEN_PASS_REGISTRATION diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td index e7a7c61b47972..b4cae024248ba 100644 --- a/flang/include/flang/Optimizer/Transforms/Passes.td +++ b/flang/include/flang/Optimizer/Transforms/Passes.td @@ -286,16 +286,6 @@ def PolymorphicOpConversion : Pass<"fir-polymorphic-op", "::mlir::func::FuncOp"> ]; } -def OpenACCDataOperandConversion : Pass<"fir-openacc-data-operand-conversion", "::mlir::func::FuncOp"> { - let summary = "Convert the FIR operands in OpenACC ops to LLVM dialect"; - let dependentDialects = ["mlir::LLVM::LLVMDialect"]; - let options = [ - Option<"useOpaquePointers", "use-opaque-pointers", "bool", - /*default=*/"true", "Generate LLVM IR using opaque pointers " - "instead of typed pointers">, - ]; -} - def LoopVersioning : Pass<"loop-versioning", "mlir::func::FuncOp"> { let summary = "Loop Versioning"; let description = [{ diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index 7bc1d08c1d5ab..5b680ea3403d0 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -490,6 +490,7 @@ class ParseTreeDumper { NODE_ENUM(OmpDependenceType, Type) NODE(parser, OmpDependSinkVec) NODE(parser, OmpDependSinkVecLength) + NODE(parser, OmpEndAllocators) NODE(parser, OmpEndAtomic) NODE(parser, OmpEndBlockDirective) NODE(parser, OmpEndCriticalDirective) @@ -527,7 +528,10 @@ class ParseTreeDumper { NODE(parser, OmpReductionInitializerClause) NODE(parser, OmpReductionOperator) NODE(parser, OmpAllocateClause) - NODE(OmpAllocateClause, Allocator) + NODE(OmpAllocateClause, AllocateModifier) + NODE(OmpAllocateClause::AllocateModifier, Allocator) + NODE(OmpAllocateClause::AllocateModifier, ComplexModifier) + NODE(OmpAllocateClause::AllocateModifier, Align) NODE(parser, OmpScheduleClause) NODE_ENUM(OmpScheduleClause, ScheduleType) NODE(parser, OmpDeviceClause) @@ -574,6 +578,7 @@ class ParseTreeDumper { NODE(parser, OpenMPFlushConstruct) NODE(parser, OpenMPLoopConstruct) NODE(parser, OpenMPExecutableAllocate) + NODE(parser, OpenMPAllocatorsConstruct) NODE(parser, OpenMPRequiresConstruct) NODE(parser, OpenMPSimpleStandaloneConstruct) NODE(parser, OpenMPStandaloneConstruct) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index d729f444ef959..9059cfbe7f8c8 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3482,10 +3482,23 @@ struct OmpInReductionClause { }; // OMP 5.0 2.11.4 allocate-clause -> ALLOCATE ([allocator:] variable-name-list) +// OMP 5.2 2.13.4 allocate-clause -> ALLOCATE ([allocate-modifier [, +// allocate-modifier] :] +// variable-name-list) +// allocate-modifier -> allocator | align struct OmpAllocateClause { TUPLE_CLASS_BOILERPLATE(OmpAllocateClause); - WRAPPER_CLASS(Allocator, ScalarIntExpr); - std::tuple, OmpObjectList> t; + struct AllocateModifier { + UNION_CLASS_BOILERPLATE(AllocateModifier); + WRAPPER_CLASS(Allocator, ScalarIntExpr); + WRAPPER_CLASS(Align, ScalarIntExpr); + struct ComplexModifier { + TUPLE_CLASS_BOILERPLATE(ComplexModifier); + std::tuple t; + }; + std::variant u; + }; + std::tuple, OmpObjectList> t; }; // 2.13.9 depend-vec-length -> +/- non-negative-constant @@ -3703,6 +3716,20 @@ struct OpenMPExecutableAllocate { t; }; +EMPTY_CLASS(OmpEndAllocators); + +// 6.7 Allocators construct [OpenMP 5.2] +// allocators-construct -> ALLOCATORS [allocate-clause [,]] +// allocate-stmt +// [omp-end-allocators-construct] +struct OpenMPAllocatorsConstruct { + TUPLE_CLASS_BOILERPLATE(OpenMPAllocatorsConstruct); + CharBlock source; + std::tuple, + std::optional> + t; +}; + // 2.17.7 Atomic construct/2.17.8 Flush construct [OpenMP 5.0] // memory-order-clause -> acq_rel // release @@ -3889,7 +3916,8 @@ struct OpenMPConstruct { std::variant + OpenMPExecutableAllocate, OpenMPAllocatorsConstruct, + OpenMPCriticalConstruct> u; }; diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h index 41a03a2b6a949..3e029c98fc2e1 100644 --- a/flang/include/flang/Semantics/symbol.h +++ b/flang/include/flang/Semantics/symbol.h @@ -560,7 +560,7 @@ class Symbol { OmpShared, OmpPrivate, OmpLinear, OmpFirstPrivate, OmpLastPrivate, // OpenMP data-mapping attribute OmpMapTo, OmpMapFrom, OmpMapAlloc, OmpMapRelease, OmpMapDelete, - OmpUseDevicePtr, + OmpUseDevicePtr, OmpUseDeviceAddr, // OpenMP data-copying attribute OmpCopyIn, OmpCopyPrivate, // OpenMP miscellaneous flags diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h index 4a78b31c5a792..ee62b66d54b0f 100644 --- a/flang/include/flang/Semantics/tools.h +++ b/flang/include/flang/Semantics/tools.h @@ -117,7 +117,7 @@ bool CanBeTypeBoundProc(const Symbol &); bool HasDeclarationInitializer(const Symbol &); // Is the symbol explicitly or implicitly initialized in any way? bool IsInitialized(const Symbol &, bool ignoreDATAstatements = false, - bool ignoreAllocatable = false); + bool ignoreAllocatable = false, bool ignorePointer = true); // Is the symbol a component subject to deallocation or finalization? bool IsDestructible(const Symbol &, const Symbol *derivedType = nullptr); bool HasIntrinsicTypeName(const Symbol &); diff --git a/flang/include/flang/Semantics/type.h b/flang/include/flang/Semantics/type.h index 76866c8e994b0..3fcd438eaf134 100644 --- a/flang/include/flang/Semantics/type.h +++ b/flang/include/flang/Semantics/type.h @@ -266,7 +266,8 @@ class DerivedTypeSpec { bool MightBeParameterized() const; bool IsForwardReferenced() const; - bool HasDefaultInitialization(bool ignoreAllocatable = false) const; + bool HasDefaultInitialization( + bool ignoreAllocatable = false, bool ignorePointer = true) const; bool HasDestruction() const; // The "raw" type parameter list is a simple transcription from the diff --git a/flang/lib/Decimal/CMakeLists.txt b/flang/lib/Decimal/CMakeLists.txt index a81d329b4a5de..3116ff68ea262 100644 --- a/flang/lib/Decimal/CMakeLists.txt +++ b/flang/lib/Decimal/CMakeLists.txt @@ -1,5 +1,5 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - cmake_minimum_required(VERSION 3.13.4) + cmake_minimum_required(VERSION 3.20.0) project(FortranDecimal C CXX) diff --git a/flang/lib/Evaluate/characteristics.cpp b/flang/lib/Evaluate/characteristics.cpp index b8cb822866dbf..62b1573010f95 100644 --- a/flang/lib/Evaluate/characteristics.cpp +++ b/flang/lib/Evaluate/characteristics.cpp @@ -149,7 +149,13 @@ std::optional TypeAndShape::Characterize( std::optional TypeAndShape::Characterize( const ActualArgument &arg, FoldingContext &context) { - return Characterize(arg.UnwrapExpr(), context); + if (const auto *expr{arg.UnwrapExpr()}) { + return Characterize(*expr, context); + } else if (const Symbol * assumed{arg.GetAssumedTypeDummy()}) { + return Characterize(*assumed, context); + } else { + return std::nullopt; + } } bool TypeAndShape::IsCompatibleWith(parser::ContextualMessages &messages, diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp index d307af6a9e14c..206e9578a28b8 100644 --- a/flang/lib/Evaluate/check-expression.cpp +++ b/flang/lib/Evaluate/check-expression.cpp @@ -819,10 +819,21 @@ class IsContiguousHelper characteristics::Procedure::Characterize(x.proc(), context_)}) { if (chars->functionResult) { const auto &result{*chars->functionResult}; - return !result.IsProcedurePointer() && - result.attrs.test(characteristics::FunctionResult::Attr::Pointer) && - result.attrs.test( - characteristics::FunctionResult::Attr::Contiguous); + if (!result.IsProcedurePointer()) { + if (result.attrs.test( + characteristics::FunctionResult::Attr::Contiguous)) { + return true; + } + if (!result.attrs.test( + characteristics::FunctionResult::Attr::Pointer)) { + return true; + } + if (const auto *type{result.GetTypeAndShape()}; + type && type->Rank() == 0) { + return true; // pointer to scalar + } + // Must be non-CONTIGUOUS pointer to array + } } } return std::nullopt; diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp index 649d46886e98d..7b7ce78e9cbe8 100644 --- a/flang/lib/Evaluate/intrinsics.cpp +++ b/flang/lib/Evaluate/intrinsics.cpp @@ -2410,6 +2410,8 @@ class IntrinsicProcTable::Implementation { SpecificCall HandleNull(ActualArguments &, FoldingContext &) const; std::optional HandleC_F_Pointer( ActualArguments &, FoldingContext &) const; + std::optional HandleC_Loc( + ActualArguments &, FoldingContext &) const; const std::string &ResolveAlias(const std::string &name) const { auto iter{aliases_.find(name)}; return iter == aliases_.end() ? name : iter->second; @@ -2435,7 +2437,7 @@ bool IntrinsicProcTable::Implementation::IsIntrinsicFunction( return true; } // special cases - return name == "null"; + return name == "__builtin_c_loc" || name == "null"; } bool IntrinsicProcTable::Implementation::IsIntrinsicSubroutine( const std::string &name) const { @@ -2691,6 +2693,78 @@ IntrinsicProcTable::Implementation::HandleC_F_Pointer( } } +static bool CheckForCoindexedObject(FoldingContext &context, + const std::optional &arg, const std::string &procName, + const std::string &argName) { + bool ok{true}; + if (arg) { + if (ExtractCoarrayRef(arg->UnwrapExpr())) { + ok = false; + context.messages().Say(arg->sourceLocation(), + "'%s' argument to '%s' may not be a coindexed object"_err_en_US, + argName, procName); + } + } + return ok; +} + +// Function C_LOC(X) from intrinsic module ISO_C_BINDING (18.2.3.6) +std::optional IntrinsicProcTable::Implementation::HandleC_Loc( + ActualArguments &arguments, FoldingContext &context) const { + static const char *const keywords[]{"x", nullptr}; + if (CheckAndRearrangeArguments(arguments, context.messages(), keywords)) { + CHECK(arguments.size() == 1); + CheckForCoindexedObject(context, arguments[0], "c_loc", "x"); + const auto *expr{arguments[0].value().UnwrapExpr()}; + if (expr && + !(IsObjectPointer(*expr, context) || + (IsVariable(*expr) && GetLastTarget(GetSymbolVector(*expr))))) { + context.messages().Say(arguments[0]->sourceLocation(), + "C_LOC() argument must be a data pointer or target"_err_en_US); + } + if (auto typeAndShape{characteristics::TypeAndShape::Characterize( + arguments[0], context)}) { + if (expr && !IsContiguous(*expr, context).value_or(true)) { + context.messages().Say(arguments[0]->sourceLocation(), + "C_LOC() argument must be contiguous"_err_en_US); + } + if (auto constExtents{AsConstantExtents(context, typeAndShape->shape())}; + constExtents && GetSize(*constExtents) == 0) { + context.messages().Say(arguments[0]->sourceLocation(), + "C_LOC() argument may not be a zero-sized array"_err_en_US); + } + if (!(typeAndShape->type().category() != TypeCategory::Derived || + typeAndShape->type().IsAssumedType() || + (!typeAndShape->type().IsPolymorphic() && + CountNonConstantLenParameters( + typeAndShape->type().GetDerivedTypeSpec()) == 0))) { + context.messages().Say(arguments[0]->sourceLocation(), + "C_LOC() argument must have an intrinsic type, assumed type, or non-polymorphic derived type with no non-constant length parameter"_err_en_US); + } else if (typeAndShape->type().knownLength().value_or(1) == 0) { + context.messages().Say(arguments[0]->sourceLocation(), + "C_LOC() argument may not be zero-length character"_err_en_US); + } else if (typeAndShape->type().category() != TypeCategory::Derived && + !IsInteroperableIntrinsicType(typeAndShape->type())) { + context.messages().Say(arguments[0]->sourceLocation(), + "C_LOC() argument has non-interoperable intrinsic type, kind, or length"_warn_en_US); + } + + return SpecificCall{SpecificIntrinsic{"__builtin_c_loc"s, + characteristics::Procedure{ + characteristics::FunctionResult{ + DynamicType{GetBuiltinDerivedType( + builtinsScope_, "__builtin_c_ptr")}}, + characteristics::DummyArguments{ + characteristics::DummyArgument{"x"s, + characteristics::DummyDataObject{ + std::move(*typeAndShape)}}}, + characteristics::Procedure::Attrs{}}}, + std::move(arguments)}; + } + } + return std::nullopt; +} + static bool CheckForNonPositiveValues(FoldingContext &context, const ActualArgument &arg, const std::string &procName, const std::string &argName) { @@ -2751,21 +2825,6 @@ static bool CheckDimAgainstCorank(SpecificCall &call, FoldingContext &context) { return ok; } -static bool CheckForCoindexedObject(FoldingContext &context, - const std::optional &arg, const std::string &procName, - const std::string &argName) { - bool ok{true}; - if (arg) { - if (ExtractCoarrayRef(arg->UnwrapExpr())) { - ok = false; - context.messages().Say(arg->sourceLocation(), - "'%s' argument to '%s' may not be a coindexed object"_err_en_US, - argName, procName); - } - } - return ok; -} - static bool CheckAtomicDefineAndRef(FoldingContext &context, const std::optional &atomArg, const std::optional &valueArg, @@ -3013,8 +3072,12 @@ std::optional IntrinsicProcTable::Implementation::Probe( "RANDOM_SEED must have either 1 or no arguments"_err_en_US); } } - } else if (call.name == "null") { - return HandleNull(arguments, context); + } else { // function + if (call.name == "__builtin_c_loc") { + return HandleC_Loc(arguments, context); + } else if (call.name == "null") { + return HandleNull(arguments, context); + } } if (call.isSubroutineCall) { diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp index 5d7129b32fc0b..b9fb511b47cba 100644 --- a/flang/lib/Evaluate/tools.cpp +++ b/flang/lib/Evaluate/tools.cpp @@ -1555,9 +1555,11 @@ bool IsBuiltinDerivedType(const DerivedTypeSpec *derived, const char *name) { } bool IsBuiltinCPtr(const Symbol &symbol) { - if (const DeclTypeSpec *declType = symbol.GetType()) - if (const DerivedTypeSpec *derived = declType->AsDerived()) + if (const DeclTypeSpec *declType = symbol.GetType()) { + if (const DerivedTypeSpec *derived = declType->AsDerived()) { return IsIsoCType(derived); + } + } return false; } diff --git a/flang/lib/Evaluate/type.cpp b/flang/lib/Evaluate/type.cpp index a8d0fca70c0c1..0b9292a18d3fa 100644 --- a/flang/lib/Evaluate/type.cpp +++ b/flang/lib/Evaluate/type.cpp @@ -47,23 +47,13 @@ static bool IsDescriptor(const ObjectEntityDetails &details) { return false; } -static bool IsDescriptor(const ProcEntityDetails &details) { - // TODO: refine this placeholder; procedure pointers and dummy - // procedures should now be simple addresses (possibly of thunks) - return details.HasExplicitInterface(); -} - bool IsDescriptor(const Symbol &symbol) { return common::visit( common::visitors{ [&](const ObjectEntityDetails &d) { return IsAllocatableOrPointer(symbol) || IsDescriptor(d); }, - [&](const ProcEntityDetails &d) { - return (symbol.attrs().test(Attr::POINTER) || - symbol.attrs().test(Attr::EXTERNAL)) && - IsDescriptor(d); - }, + [&](const ProcEntityDetails &d) { return false; }, [&](const EntityDetails &d) { return IsDescriptor(d.type()); }, [](const AssocEntityDetails &d) { if (const auto &expr{d.expr()}) { @@ -744,7 +734,8 @@ std::optional ComparisonType( } } -bool IsInteroperableIntrinsicType(const DynamicType &type) { +bool IsInteroperableIntrinsicType( + const DynamicType &type, bool checkCharLength) { switch (type.category()) { case TypeCategory::Integer: return true; @@ -754,7 +745,10 @@ bool IsInteroperableIntrinsicType(const DynamicType &type) { case TypeCategory::Logical: return type.kind() == 1; // C_BOOL case TypeCategory::Character: - return type.kind() == 1 /* C_CHAR */ && type.knownLength().value_or(0) == 1; + if (checkCharLength && type.knownLength().value_or(0) != 1) { + return false; + } + return type.kind() == 1 /* C_CHAR */; default: // Derived types are tested in Semantics/check-declarations.cpp return false; diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index fdc6649972471..c1dbac108b887 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -791,6 +791,40 @@ class FirConverter : public Fortran::lower::AbstractConverter { dispatchTableConverter.registerTypeSpec(*this, loc, typeSpec); } + llvm::StringRef + getUniqueLitName(mlir::Location loc, + std::unique_ptr expr, + mlir::Type eleTy) override final { + std::string namePrefix = + getConstantExprManglePrefix(loc, *expr.get(), eleTy); + auto [it, inserted] = literalNamesMap.try_emplace( + expr.get(), namePrefix + std::to_string(uniqueLitId)); + const auto &name = it->second; + if (inserted) { + // Keep ownership of the expr key. + literalExprsStorage.push_back(std::move(expr)); + + // If we've just added a new name, we have to make sure + // there is no global object with the same name in the module. + fir::GlobalOp global = builder->getNamedGlobal(name); + if (global) + fir::emitFatalError(loc, llvm::Twine("global object with name '") + + llvm::Twine(name) + + llvm::Twine("' already exists")); + ++uniqueLitId; + return name; + } + + // The name already exists. Verify that the prefix is the same. + if (!llvm::StringRef(name).starts_with(namePrefix)) + fir::emitFatalError(loc, llvm::Twine("conflicting prefixes: '") + + llvm::Twine(name) + + llvm::Twine("' does not start with '") + + llvm::Twine(namePrefix) + llvm::Twine("'")); + + return name; + } + private: FirConverter() = delete; FirConverter(const FirConverter &) = delete; @@ -1937,7 +1971,8 @@ class FirConverter : public Fortran::lower::AbstractConverter { } void genFIR(const Fortran::parser::EndForallStmt &) { - cleanupExplicitSpace(); + if (!lowerToHighLevelFIR()) + cleanupExplicitSpace(); } template @@ -1956,11 +1991,24 @@ class FirConverter : public Fortran::lower::AbstractConverter { /// Generate FIR for a FORALL statement. void genFIR(const Fortran::parser::ForallStmt &stmt) { + const auto &concurrentHeader = + std::get< + Fortran::common::Indirection>( + stmt.t) + .value(); + if (lowerToHighLevelFIR()) { + mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint(); + localSymbols.pushScope(); + genForallNest(concurrentHeader); + genFIR(std::get>(stmt.t) + .statement); + localSymbols.popScope(); + builder->restoreInsertionPoint(insertPt); + return; + } prepareExplicitSpace(stmt); - genFIR(std::get< - Fortran::common::Indirection>( - stmt.t) - .value()); + genFIR(concurrentHeader); genFIR(std::get>(stmt.t) .statement); @@ -1969,7 +2017,11 @@ class FirConverter : public Fortran::lower::AbstractConverter { /// Generate FIR for a FORALL construct. void genFIR(const Fortran::parser::ForallConstruct &forall) { - prepareExplicitSpace(forall); + mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint(); + if (lowerToHighLevelFIR()) + localSymbols.pushScope(); + else + prepareExplicitSpace(forall); genNestedStatement( std::get< Fortran::parser::Statement>( @@ -1987,14 +2039,101 @@ class FirConverter : public Fortran::lower::AbstractConverter { genNestedStatement( std::get>( forall.t)); + if (lowerToHighLevelFIR()) { + localSymbols.popScope(); + builder->restoreInsertionPoint(insertPt); + } } /// Lower the concurrent header specification. void genFIR(const Fortran::parser::ForallConstructStmt &stmt) { - genFIR(std::get< - Fortran::common::Indirection>( - stmt.t) - .value()); + const auto &concurrentHeader = + std::get< + Fortran::common::Indirection>( + stmt.t) + .value(); + if (lowerToHighLevelFIR()) + genForallNest(concurrentHeader); + else + genFIR(concurrentHeader); + } + + /// Generate hlfir.forall and hlfir.forall_mask nest given a Forall + /// concurrent header + void genForallNest(const Fortran::parser::ConcurrentHeader &header) { + mlir::Location loc = getCurrentLocation(); + const bool isOutterForall = !isInsideHlfirForallOrWhere(); + hlfir::ForallOp outerForall; + auto evaluateControl = [&](const auto &parserExpr, mlir::Region ®ion, + bool isMask = false) { + if (region.empty()) + builder->createBlock(®ion); + Fortran::lower::StatementContext localStmtCtx; + const Fortran::semantics::SomeExpr *anlalyzedExpr = + Fortran::semantics::GetExpr(parserExpr); + assert(anlalyzedExpr && "expression semantics failed"); + // Generate the controls of outer forall outside of the hlfir.forall + // region. They do not depend on any previous forall indices (C1123) and + // no assignment has been made yet that could modify their value. This + // will simplify hlfir.forall analysis because the SSA integer value + // yielded will obviously not depend on any variable modified by the + // forall when produced outside of it. + // This is not done for the mask because it may (and in usual code, does) + // depend on the forall indices that have just been defined as + // hlfir.forall block arguments. + mlir::OpBuilder::InsertPoint innerInsertionPoint; + if (outerForall && !isMask) { + innerInsertionPoint = builder->saveInsertionPoint(); + builder->setInsertionPoint(outerForall); + } + mlir::Value exprVal = + fir::getBase(genExprValue(*anlalyzedExpr, localStmtCtx, &loc)); + localStmtCtx.finalizeAndPop(); + if (isMask) + exprVal = builder->createConvert(loc, builder->getI1Type(), exprVal); + if (innerInsertionPoint.isSet()) + builder->restoreInsertionPoint(innerInsertionPoint); + builder->create(loc, exprVal); + }; + for (const Fortran::parser::ConcurrentControl &control : + std::get>(header.t)) { + auto forallOp = builder->create(loc); + if (isOutterForall && !outerForall) + outerForall = forallOp; + evaluateControl(std::get<1>(control.t), forallOp.getLbRegion()); + evaluateControl(std::get<2>(control.t), forallOp.getUbRegion()); + if (const auto &optionalStep = + std::get>( + control.t)) + evaluateControl(*optionalStep, forallOp.getStepRegion()); + // Create block argument and map it to a symbol via an hlfir.forall_index + // op (symbols must be mapped to in memory values). + const Fortran::semantics::Symbol *controlVar = + std::get(control.t).symbol; + assert(controlVar && "symbol analysis failed"); + mlir::Type controlVarType = genType(*controlVar); + mlir::Block *forallBody = builder->createBlock(&forallOp.getBody(), {}, + {controlVarType}, {loc}); + auto forallIndex = builder->create( + loc, fir::ReferenceType::get(controlVarType), + forallBody->getArguments()[0], + builder->getStringAttr(controlVar->name().ToString())); + localSymbols.addVariableDefinition(*controlVar, forallIndex, + /*force=*/true); + auto end = builder->create(loc); + builder->setInsertionPoint(end); + } + + if (const auto &maskExpr = + std::get>( + header.t)) { + // Create hlfir.forall_mask and set insertion point in its body. + auto forallMaskOp = builder->create(loc); + evaluateControl(*maskExpr, forallMaskOp.getMaskRegion(), /*isMask=*/true); + builder->createBlock(&forallMaskOp.getBody()); + auto end = builder->create(loc); + builder->setInsertionPoint(end); + } } void genFIR(const Fortran::parser::CompilerDirective &) { @@ -2991,13 +3130,14 @@ class FirConverter : public Fortran::lower::AbstractConverter { /// DestroyOp in case the returned value has hlfir::ExprType. mlir::Value genImplicitLogicalConvert(const Fortran::evaluate::Assignment &assign, - hlfir::Entity lhs, hlfir::Entity rhs) { + hlfir::Entity rhs, + Fortran::lower::StatementContext &stmtCtx) { mlir::Type fromTy = rhs.getFortranElementType(); - mlir::Type toTy = lhs.getFortranElementType(); - if (fromTy == toTy) + if (!fromTy.isa()) return nullptr; - if (!fromTy.isa()) + mlir::Type toTy = hlfir::getFortranElementType(genType(assign.lhs)); + if (fromTy == toTy) return nullptr; if (!toTy.isa()) return nullptr; @@ -3015,76 +3155,149 @@ class FirConverter : public Fortran::lower::AbstractConverter { auto val = hlfir::loadTrivialScalar(loc, builder, elementPtr); return hlfir::EntityWithAttributes{builder.createConvert(loc, toTy, val)}; }; - return hlfir::genElementalOp(loc, builder, toTy, shape, /*typeParams=*/{}, - genKernel); + mlir::Value convertedRhs = hlfir::genElementalOp( + loc, builder, toTy, shape, /*typeParams=*/{}, genKernel); + fir::FirOpBuilder *bldr = &builder; + stmtCtx.attachCleanup([loc, bldr, convertedRhs]() { + bldr->create(loc, convertedRhs); + }); + return convertedRhs; + } + + static void + genCleanUpInRegionIfAny(mlir::Location loc, fir::FirOpBuilder &builder, + mlir::Region ®ion, + Fortran::lower::StatementContext &context) { + if (!context.hasCode()) + return; + mlir::OpBuilder::InsertPoint insertPt = builder.saveInsertionPoint(); + if (region.empty()) + builder.createBlock(®ion); + else + builder.setInsertionPointToEnd(®ion.front()); + context.finalizeAndPop(); + hlfir::YieldOp::ensureTerminator(region, builder, loc); + builder.restoreInsertionPoint(insertPt); + } + + void genDataAssignment( + const Fortran::evaluate::Assignment &assign, + const Fortran::evaluate::ProcedureRef *userDefinedAssignment) { + mlir::Location loc = getCurrentLocation(); + fir::FirOpBuilder &builder = getFirOpBuilder(); + // Gather some information about the assignment that will impact how it is + // lowered. + const bool isWholeAllocatableAssignment = + !userDefinedAssignment && !isInsideHlfirWhere() && + Fortran::lower::isWholeAllocatable(assign.lhs); + std::optional lhsType = + assign.lhs.GetType(); + const bool keepLhsLengthInAllocatableAssignment = + isWholeAllocatableAssignment && lhsType.has_value() && + lhsType->category() == Fortran::common::TypeCategory::Character && + !lhsType->HasDeferredTypeParameter(); + const bool lhsHasVectorSubscripts = + Fortran::evaluate::HasVectorSubscript(assign.lhs); + + // Helper to generate the code evaluating the right-hand side. + auto evaluateRhs = [&](Fortran::lower::StatementContext &stmtCtx) { + hlfir::Entity rhs = Fortran::lower::convertExprToHLFIR( + loc, *this, assign.rhs, localSymbols, stmtCtx); + // Load trivial scalar RHS to allow the loads to be hoisted outside of + // loops early if possible. This also dereferences pointer and + // allocatable RHS: the target is being assigned from. + rhs = hlfir::loadTrivialScalar(loc, builder, rhs); + // In intrinsic assignments, Logical<->Integer assignments are allowed as + // an extension, but there is no explicit Convert expression for the RHS. + // Recognize the type mismatch here and insert explicit scalar convert or + // ElementalOp for array assignment. + if (!userDefinedAssignment) + if (mlir::Value conversion = + genImplicitLogicalConvert(assign, rhs, stmtCtx)) + rhs = hlfir::Entity{conversion}; + return rhs; + }; + + // Helper to generate the code evaluating the left-hand side. + auto evaluateLhs = [&](Fortran::lower::StatementContext &stmtCtx) { + hlfir::Entity lhs = Fortran::lower::convertExprToHLFIR( + loc, *this, assign.lhs, localSymbols, stmtCtx); + // Dereference pointer LHS: the target is being assigned to. + // Same for allocatables outside of whole allocatable assignments. + if (!isWholeAllocatableAssignment) + lhs = hlfir::derefPointersAndAllocatables(loc, builder, lhs); + return lhs; + }; + + if (!isInsideHlfirForallOrWhere() && !lhsHasVectorSubscripts && + !userDefinedAssignment) { + Fortran::lower::StatementContext localStmtCtx; + hlfir::Entity rhs = evaluateRhs(localStmtCtx); + hlfir::Entity lhs = evaluateLhs(localStmtCtx); + builder.create(loc, rhs, lhs, + isWholeAllocatableAssignment, + keepLhsLengthInAllocatableAssignment); + return; + } + // Assignments inside Forall, Where, or assignments to a vector subscripted + // left-hand side requires using an hlfir.region_assign in HLFIR. The + // right-hand side and left-hand side must be evaluated inside the + // hlfir.region_assign regions. + auto regionAssignOp = builder.create(loc); + + // Lower RHS in its own region. + builder.createBlock(®ionAssignOp.getRhsRegion()); + Fortran::lower::StatementContext rhsContext; + hlfir::Entity rhs = evaluateRhs(rhsContext); + auto rhsYieldOp = builder.create(loc, rhs); + genCleanUpInRegionIfAny(loc, builder, rhsYieldOp.getCleanup(), rhsContext); + // Lower LHS in its own region. + builder.createBlock(®ionAssignOp.getLhsRegion()); + Fortran::lower::StatementContext lhsContext; + if (!lhsHasVectorSubscripts) { + hlfir::Entity lhs = evaluateLhs(lhsContext); + auto lhsYieldOp = builder.create(loc, lhs); + genCleanUpInRegionIfAny(loc, builder, lhsYieldOp.getCleanup(), + lhsContext); + } else { + hlfir::ElementalAddrOp elementalAddr = + Fortran::lower::convertVectorSubscriptedExprToElementalAddr( + loc, *this, assign.lhs, localSymbols, lhsContext); + genCleanUpInRegionIfAny(loc, builder, elementalAddr.getCleanup(), + lhsContext); + } + + // Add "realloc" flag to hlfir.region_assign. + if (isWholeAllocatableAssignment) + TODO(loc, "assignment to a whole allocatable inside FORALL"); + // Generate the hlfir.region_assign userDefinedAssignment region. + if (userDefinedAssignment) + TODO(loc, "HLFIR user defined assignment"); + + builder.setInsertionPointAfter(regionAssignOp); } /// Shared for both assignments and pointer assignments. void genAssignment(const Fortran::evaluate::Assignment &assign) { mlir::Location loc = toLocation(); if (lowerToHighLevelFIR()) { - if (explicitIterationSpace() || !implicitIterSpace.empty()) - TODO(loc, "HLFIR assignment inside FORALL or WHERE"); - auto &builder = getFirOpBuilder(); std::visit( Fortran::common::visitors{ - // [1] Plain old assignment. [&](const Fortran::evaluate::Assignment::Intrinsic &) { - if (Fortran::evaluate::HasVectorSubscript(assign.lhs)) - TODO(loc, "assignment to vector subscripted entity"); - Fortran::lower::StatementContext stmtCtx; - hlfir::Entity rhs = Fortran::lower::convertExprToHLFIR( - loc, *this, assign.rhs, localSymbols, stmtCtx); - // Load trivial scalar LHS to allow the loads to be hoisted - // outside of loops early if possible. This also dereferences - // pointer and allocatable RHS: the target is being assigned - // from. - rhs = hlfir::loadTrivialScalar(loc, builder, rhs); - hlfir::Entity lhs = Fortran::lower::convertExprToHLFIR( - loc, *this, assign.lhs, localSymbols, stmtCtx); - bool isWholeAllocatableAssignment = false; - bool keepLhsLengthInAllocatableAssignment = false; - if (Fortran::lower::isWholeAllocatable(assign.lhs)) { - isWholeAllocatableAssignment = true; - if (std::optional lhsType = - assign.lhs.GetType()) - keepLhsLengthInAllocatableAssignment = - lhsType->category() == - Fortran::common::TypeCategory::Character && - !lhsType->HasDeferredTypeParameter(); - } else { - // Dereference pointer LHS: the target is being assigned to. - lhs = hlfir::derefPointersAndAllocatables(loc, builder, lhs); - } - - // Logical<->Integer assignments are allowed as an extension, - // but there is no explicit Convert expression for the RHS. - // Recognize the type mismatch here and insert explicit - // scalar convert or ElementalOp for array assignment. - mlir::Value logicalConvert = - genImplicitLogicalConvert(assign, lhs, rhs); - if (logicalConvert) - rhs = hlfir::EntityWithAttributes{logicalConvert}; - - builder.create( - loc, rhs, lhs, isWholeAllocatableAssignment, - keepLhsLengthInAllocatableAssignment); - - // Mark the end of life range of the ElementalOp's result. - if (logicalConvert && - logicalConvert.getType().isa()) - builder.create(loc, rhs); + genDataAssignment(assign, /*userDefinedAssignment=*/nullptr); }, - // [2] User defined assignment. If the context is a scalar - // expression then call the procedure. [&](const Fortran::evaluate::ProcedureRef &procRef) { - TODO(loc, "HLFIR user defined assignment"); + genDataAssignment(assign, /*userDefinedAssignment=*/&procRef); }, [&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) { + if (isInsideHlfirForallOrWhere()) + TODO(loc, "pointer assignment inside FORALL"); genPointerAssignment(loc, assign, lbExprs); }, [&](const Fortran::evaluate::Assignment::BoundsRemapping &boundExprs) { + if (isInsideHlfirForallOrWhere()) + TODO(loc, "pointer assignment inside FORALL"); genPointerAssignment(loc, assign, boundExprs); }, }, @@ -3275,12 +3488,47 @@ class FirConverter : public Fortran::lower::AbstractConverter { Fortran::lower::createArrayMergeStores(*this, explicitIterSpace); } + // Is the insertion point of the builder directly or indirectly set + // inside any operation of type "Op"? + template + bool isInsideOp() const { + mlir::Block *block = builder->getInsertionBlock(); + mlir::Operation *op = block ? block->getParentOp() : nullptr; + while (op) { + if (mlir::isa(op)) + return true; + op = op->getParentOp(); + } + return false; + } + bool isInsideHlfirForallOrWhere() const { + return isInsideOp(); + } + bool isInsideHlfirWhere() const { return isInsideOp(); } + void genFIR(const Fortran::parser::WhereConstruct &c) { - implicitIterSpace.growStack(); + mlir::Location loc = getCurrentLocation(); + hlfir::WhereOp whereOp; + + if (!lowerToHighLevelFIR()) { + implicitIterSpace.growStack(); + } else { + whereOp = builder->create(loc); + builder->createBlock(&whereOp.getMaskRegion()); + } + + // Lower the where mask. For HLFIR, this is done in the hlfir.where mask + // region. genNestedStatement( std::get< Fortran::parser::Statement>( c.t)); + + // Lower WHERE body. For HLFIR, this is done in the hlfir.where body + // region. + if (whereOp) + builder->createBlock(&whereOp.getBody()); + for (const auto &body : std::get>(c.t)) genFIR(body); @@ -3296,6 +3544,13 @@ class FirConverter : public Fortran::lower::AbstractConverter { genNestedStatement( std::get>( c.t)); + + if (whereOp) { + // For HLFIR, create fir.end terminator in the last hlfir.elsewhere, or + // in the hlfir.where if it had no elsewhere. + builder->create(loc); + builder->setInsertionPointAfter(whereOp); + } } void genFIR(const Fortran::parser::WhereBodyConstruct &body) { std::visit( @@ -3311,24 +3566,61 @@ class FirConverter : public Fortran::lower::AbstractConverter { }, body.u); } + + /// Lower a Where or Elsewhere mask into an hlfir mask region. + void lowerWhereMaskToHlfir(mlir::Location loc, + const Fortran::semantics::SomeExpr *maskExpr) { + assert(maskExpr && "mask semantic analysis failed"); + Fortran::lower::StatementContext maskContext; + hlfir::Entity mask = Fortran::lower::convertExprToHLFIR( + loc, *this, *maskExpr, localSymbols, maskContext); + mask = hlfir::loadTrivialScalar(loc, *builder, mask); + auto yieldOp = builder->create(loc, mask); + genCleanUpInRegionIfAny(loc, *builder, yieldOp.getCleanup(), maskContext); + } void genFIR(const Fortran::parser::WhereConstructStmt &stmt) { - implicitIterSpace.append(Fortran::semantics::GetExpr( - std::get(stmt.t))); + const Fortran::semantics::SomeExpr *maskExpr = Fortran::semantics::GetExpr( + std::get(stmt.t)); + if (lowerToHighLevelFIR()) + lowerWhereMaskToHlfir(getCurrentLocation(), maskExpr); + else + implicitIterSpace.append(maskExpr); } void genFIR(const Fortran::parser::WhereConstruct::MaskedElsewhere &ew) { + mlir::Location loc = getCurrentLocation(); + hlfir::ElseWhereOp elsewhereOp; + if (lowerToHighLevelFIR()) { + elsewhereOp = builder->create(loc); + // Lower mask in the mask region. + builder->createBlock(&elsewhereOp.getMaskRegion()); + } genNestedStatement( std::get< Fortran::parser::Statement>( ew.t)); + + // For HLFIR, lower the body in the hlfir.elsewhere body region. + if (elsewhereOp) + builder->createBlock(&elsewhereOp.getBody()); + for (const auto &body : std::get>(ew.t)) genFIR(body); } void genFIR(const Fortran::parser::MaskedElsewhereStmt &stmt) { - implicitIterSpace.append(Fortran::semantics::GetExpr( - std::get(stmt.t))); + const auto *maskExpr = Fortran::semantics::GetExpr( + std::get(stmt.t)); + if (lowerToHighLevelFIR()) + lowerWhereMaskToHlfir(getCurrentLocation(), maskExpr); + else + implicitIterSpace.append(maskExpr); } void genFIR(const Fortran::parser::WhereConstruct::Elsewhere &ew) { + if (lowerToHighLevelFIR()) { + auto elsewhereOp = + builder->create(getCurrentLocation()); + builder->createBlock(&elsewhereOp.getBody()); + } genNestedStatement( std::get>( ew.t)); @@ -3337,18 +3629,32 @@ class FirConverter : public Fortran::lower::AbstractConverter { genFIR(body); } void genFIR(const Fortran::parser::ElsewhereStmt &stmt) { - implicitIterSpace.append(nullptr); + if (!lowerToHighLevelFIR()) + implicitIterSpace.append(nullptr); } void genFIR(const Fortran::parser::EndWhereStmt &) { - implicitIterSpace.shrinkStack(); + if (!lowerToHighLevelFIR()) + implicitIterSpace.shrinkStack(); } void genFIR(const Fortran::parser::WhereStmt &stmt) { Fortran::lower::StatementContext stmtCtx; const auto &assign = std::get(stmt.t); + const auto *mask = Fortran::semantics::GetExpr( + std::get(stmt.t)); + if (lowerToHighLevelFIR()) { + mlir::Location loc = getCurrentLocation(); + auto whereOp = builder->create(loc); + builder->createBlock(&whereOp.getMaskRegion()); + lowerWhereMaskToHlfir(loc, mask); + builder->createBlock(&whereOp.getBody()); + genAssignment(*assign.typedAssignment->v); + builder->create(loc); + builder->setInsertionPointAfter(whereOp); + return; + } implicitIterSpace.growStack(); - implicitIterSpace.append(Fortran::semantics::GetExpr( - std::get(stmt.t))); + implicitIterSpace.append(mask); genAssignment(*assign.typedAssignment->v); implicitIterSpace.shrinkStack(); } @@ -4125,6 +4431,49 @@ class FirConverter : public Fortran::lower::AbstractConverter { return bridge.getLoweringOptions().getLowerToHighLevelFIR(); } + // Returns the mangling prefix for the given constant expression. + std::string getConstantExprManglePrefix(mlir::Location loc, + const Fortran::lower::SomeExpr &expr, + mlir::Type eleTy) { + return std::visit( + [&](const auto &x) -> std::string { + using T = std::decay_t; + if constexpr (Fortran::common::HasMember< + T, Fortran::lower::CategoryExpression>) { + if constexpr (T::Result::category == + Fortran::common::TypeCategory::Derived) { + if (const auto *constant = + std::get_if>(&x.u)) + return Fortran::lower::mangle::mangleArrayLiteral(eleTy, + *constant); + fir::emitFatalError(loc, + "non a constant derived type expression"); + } else { + return std::visit( + [&](const auto &someKind) -> std::string { + using T = std::decay_t; + using TK = Fortran::evaluate::Type; + if (const auto *constant = + std::get_if>( + &someKind.u)) { + return Fortran::lower::mangle::mangleArrayLiteral( + nullptr, *constant); + } + fir::emitFatalError( + loc, "not a Fortran::evaluate::Constant expression"); + return {}; + }, + x.u); + } + } else { + fir::emitFatalError(loc, "unexpected expression"); + } + }, + expr.u); + } + //===--------------------------------------------------------------------===// Fortran::lower::LoweringBridge &bridge; @@ -4151,6 +4500,23 @@ class FirConverter : public Fortran::lower::AbstractConverter { /// Tuple of host associated variables mlir::Value hostAssocTuple; + + /// A map of unique names for constant expressions. + /// The names are used for representing the constant expressions + /// with global constant initialized objects. + /// The names are usually prefixed by a mangling string based + /// on the element type of the constant expression, but the element + /// type is not used as a key into the map (so the assumption is that + /// the equivalent constant expressions are prefixed using the same + /// element type). + llvm::DenseMap literalNamesMap; + + /// Storage for Constant expressions used as keys for literalNamesMap. + llvm::SmallVector> + literalExprsStorage; + + /// A counter for uniquing names in `literalNamesMap`. + std::uint64_t uniqueLitId = 0; }; } // namespace diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp index 35e34511d5425..674e2c8c3ae96 100644 --- a/flang/lib/Lower/ConvertCall.cpp +++ b/flang/lib/Lower/ConvertCall.cpp @@ -1135,11 +1135,10 @@ genUserCall(PreparedActualArguments &loweredActuals, // callee side, and it is illegal to use NULL without a MOLD if any // dummy length parameters are assumed. mlir::Type boxTy = fir::dyn_cast_ptrEleTy(argTy); - assert(boxTy && boxTy.isa() && "must be a fir.box type"); - mlir::Value boxStorage = builder.createTemporary(loc, boxTy); - mlir::Value nullBox = fir::factory::createUnallocatedBox( - builder, loc, boxTy, /*nonDeferredParams=*/{}); - builder.create(loc, nullBox, boxStorage); + assert(boxTy && boxTy.isa() && + "must be a fir.box type"); + mlir::Value boxStorage = + fir::factory::genNullBoxStorage(builder, loc, boxTy); caller.placeInput(arg, boxStorage); continue; } @@ -1237,6 +1236,26 @@ genIntrinsicRefCore(PreparedActualArguments &loweredActuals, loc, converter, actual, stmtCtx, getActualFortranElementType())); continue; case fir::LowerIntrinsicArgAs::Inquired: + if (const Fortran::lower::SomeExpr *expr = + callContext.procRef.UnwrapArgExpr(arg.index())) { + if (Fortran::evaluate::UnwrapExpr( + *expr)) { + // NULL() pointer without a MOLD must be passed as a deallocated + // pointer (see table 16.5 in Fortran 2018 standard). + // !fir.box> should always be valid in this context. + mlir::Type noneTy = mlir::NoneType::get(builder.getContext()); + mlir::Type nullPtrTy = fir::PointerType::get(noneTy); + mlir::Type boxTy = fir::BoxType::get(nullPtrTy); + mlir::Value boxStorage = + fir::factory::genNullBoxStorage(builder, loc, boxTy); + hlfir::EntityWithAttributes nullBoxEntity = + extendedValueToHlfirEntity(loc, builder, boxStorage, + ".tmp.null_box"); + operands.emplace_back(Fortran::lower::translateToExtendedValue( + loc, builder, nullBoxEntity, stmtCtx)); + continue; + } + } // Place hlfir.expr in memory, and unbox fir.boxchar. Other entities // are translated to fir::ExtendedValue without transformation (notably, // pointers/allocatable are not dereferenced). @@ -1257,8 +1276,8 @@ genIntrinsicRefCore(PreparedActualArguments &loweredActuals, scalarResultType = hlfir::getFortranElementType(*callContext.resultType); const std::string intrinsicName = callContext.getProcedureName(); // Let the intrinsic library lower the intrinsic procedure call. - auto [resultExv, mustBeFreed] = genIntrinsicCall( - callContext.getBuilder(), loc, intrinsicName, scalarResultType, operands); + auto [resultExv, mustBeFreed] = + genIntrinsicCall(builder, loc, intrinsicName, scalarResultType, operands); if (!fir::getBase(resultExv)) return std::nullopt; hlfir::EntityWithAttributes resultEntity = extendedValueToHlfirEntity( @@ -1409,6 +1428,19 @@ genHLFIRIntrinsicRefCore(PreparedActualArguments &loweredActuals, return {hlfir::EntityWithAttributes{transposeOp.getResult()}}; } + if (intrinsicName == "any") { + llvm::SmallVector operands = getOperandVector(loweredActuals); + assert(operands.size() == 2); + // dim argument can be NULL if not given + mlir::Value mask = operands[0]; + mlir::Value dim = operands[1]; + if (dim) + dim = hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{dim}); + mlir::Type resultTy = computeResultType(mask, *callContext.resultType); + hlfir::AnyOp anyOp = builder.create(loc, resultTy, mask, dim); + + return {hlfir::EntityWithAttributes{anyOp.getResult()}}; + } // TODO add hlfir operations for other transformational intrinsics here diff --git a/flang/lib/Lower/ConvertConstant.cpp b/flang/lib/Lower/ConvertConstant.cpp index a391d71498e76..8e7c341cc2827 100644 --- a/flang/lib/Lower/ConvertConstant.cpp +++ b/flang/lib/Lower/ConvertConstant.cpp @@ -415,9 +415,10 @@ static mlir::Value genScalarLit( if (!outlineBigConstantsInReadOnlyMemory) return genInlinedStructureCtorLitImpl(converter, loc, value, eleTy); fir::FirOpBuilder &builder = converter.getFirOpBuilder(); - std::string globalName = Fortran::lower::mangle::mangleArrayLiteral( - eleTy, - Fortran::evaluate::Constant(value)); + auto expr = std::make_unique(toEvExpr( + Fortran::evaluate::Constant(value))); + llvm::StringRef globalName = + converter.getUniqueLitName(loc, std::move(expr), eleTy); fir::GlobalOp global = builder.getNamedGlobal(globalName); if (!global) { global = builder.createGlobalConstant( @@ -525,8 +526,9 @@ genOutlineArrayLit(Fortran::lower::AbstractConverter &converter, const Fortran::evaluate::Constant &constant) { fir::FirOpBuilder &builder = converter.getFirOpBuilder(); mlir::Type eleTy = arrayTy.cast().getEleTy(); - std::string globalName = - Fortran::lower::mangle::mangleArrayLiteral(eleTy, constant); + llvm::StringRef globalName = converter.getUniqueLitName( + loc, std::make_unique(toEvExpr(constant)), + eleTy); fir::GlobalOp global = builder.getNamedGlobal(globalName); if (!global) { // Using a dense attribute for the initial value instead of creating an diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp index 7f89fcf88f87d..47d5ed4c02e54 100644 --- a/flang/lib/Lower/ConvertExpr.cpp +++ b/flang/lib/Lower/ConvertExpr.cpp @@ -720,11 +720,8 @@ class ScalarExprLowering { mlir::Type noneTy = mlir::NoneType::get(builder.getContext()); mlir::Type polyRefTy = fir::PointerType::get(noneTy); mlir::Type boxType = fir::BoxType::get(polyRefTy); - mlir::Value nullConst = builder.createNullConstant(loc, polyRefTy); mlir::Value tempBox = - builder.createTemporary(loc, boxType, /*shape=*/mlir::ValueRange{}); - mlir::Value nullBox = builder.create(loc, boxType, nullConst); - builder.create(loc, nullBox, tempBox); + fir::factory::genNullBoxStorage(builder, loc, boxType); return fir::MutableBoxValue(tempBox, /*lenParameters=*/mlir::ValueRange{}, /*mutableProperties=*/{}); @@ -976,7 +973,12 @@ class ScalarExprLowering { /// Lowering of an ac-do-variable, which is not a Symbol. ExtValue genval(const Fortran::evaluate::ImpliedDoIndex &var) { - return converter.impliedDoBinding(toStringRef(var.name)); + mlir::Value value = converter.impliedDoBinding(toStringRef(var.name)); + // The index value generated by the implied-do has Index type, + // while computations based on it inside the loop body are using + // the original data type. So we need to cast it appropriately. + mlir::Type varTy = converter.genType(toEvExpr(var)); + return builder.createConvert(getLoc(), varTy, value); } ExtValue genval(const Fortran::evaluate::DescriptorInquiry &desc) { @@ -1075,7 +1077,16 @@ class ScalarExprLowering { GENBIN(Multiply, Complex, fir::MulcOp) GENBIN(Divide, Integer, mlir::arith::DivSIOp) GENBIN(Divide, Real, mlir::arith::DivFOp) - GENBIN(Divide, Complex, fir::DivcOp) + + template + ExtValue genval(const Fortran::evaluate::Divide> &op) { + mlir::Type ty = + converter.genType(Fortran::common::TypeCategory::Complex, KIND); + mlir::Value lhs = genunbox(op.left()); + mlir::Value rhs = genunbox(op.right()); + return fir::genDivC(builder, getLoc(), ty, lhs, rhs); + } template ExtValue genval( @@ -5077,7 +5088,21 @@ class ArrayExprLowering { GENBIN(Multiply, Complex, fir::MulcOp) GENBIN(Divide, Integer, mlir::arith::DivSIOp) GENBIN(Divide, Real, mlir::arith::DivFOp) - GENBIN(Divide, Complex, fir::DivcOp) + + template + CC genarr(const Fortran::evaluate::Divide> &x) { + mlir::Location loc = getLoc(); + mlir::Type ty = + converter.genType(Fortran::common::TypeCategory::Complex, KIND); + auto lf = genarr(x.left()); + auto rf = genarr(x.right()); + return [=](IterSpace iters) -> ExtValue { + mlir::Value lhs = fir::getBase(lf(iters)); + mlir::Value rhs = fir::getBase(rf(iters)); + return fir::genDivC(builder, loc, ty, lhs, rhs); + }; + } template CC genarr( diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp index b5bee6b94543e..bfa84be04637e 100644 --- a/flang/lib/Lower/ConvertExprToHLFIR.cpp +++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp @@ -47,6 +47,10 @@ class HlfirDesignatorBuilder { return result; } + hlfir::EntityWithAttributes + genDesignatorExpr(const Fortran::lower::SomeExpr &designatorExpr, + bool vectorSubscriptDesignatorToValue = true); + public: HlfirDesignatorBuilder(mlir::Location loc, Fortran::lower::AbstractConverter &converter, @@ -112,6 +116,11 @@ class HlfirDesignatorBuilder { vectorSubscriptDesignatorToValue); } + /// Public entry point to lower a vector subscripted designator to + /// an hlfir::ElementalAddrOp. + hlfir::ElementalAddrOp convertVectorSubscriptedExprToElementalAddr( + const Fortran::lower::SomeExpr &designatorExpr); + private: /// Struct that is filled while visiting a part-ref (in the "visit" member /// function) before the top level "gen" generates an hlfir.declare for the @@ -844,6 +853,67 @@ class HlfirDesignatorBuilder { mlir::Location loc; }; +hlfir::EntityWithAttributes HlfirDesignatorBuilder::genDesignatorExpr( + const Fortran::lower::SomeExpr &designatorExpr, + bool vectorSubscriptDesignatorToValue) { + // Expr plumbing to unwrap Designator and call + // gen(Designator.u). + return std::visit( + [&](const auto &x) -> hlfir::EntityWithAttributes { + using T = std::decay_t; + if constexpr (Fortran::common::HasMember< + T, Fortran::lower::CategoryExpression>) { + if constexpr (T::Result::category == + Fortran::common::TypeCategory::Derived) { + return gen(std::get>(x.u) + .u, + vectorSubscriptDesignatorToValue); + } else { + return std::visit( + [&](const auto &preciseKind) { + using TK = + typename std::decay_t::Result; + return gen( + std::get>(preciseKind.u) + .u, + vectorSubscriptDesignatorToValue); + }, + x.u); + } + } else { + fir::emitFatalError(loc, "unexpected typeless Designator"); + } + }, + designatorExpr.u); +} + +hlfir::ElementalAddrOp +HlfirDesignatorBuilder::convertVectorSubscriptedExprToElementalAddr( + const Fortran::lower::SomeExpr &designatorExpr) { + + hlfir::EntityWithAttributes elementAddrEntity = genDesignatorExpr( + designatorExpr, /*vectorSubscriptDesignatorToValue=*/false); + assert(getVectorSubscriptElementAddrOp().has_value() && + "expected vector subscripts"); + hlfir::ElementalAddrOp elementalAddrOp = *getVectorSubscriptElementAddrOp(); + // Now that the type parameters have been computed, add then to the + // hlfir.elemental_addr. + fir::FirOpBuilder &builder = getBuilder(); + llvm::SmallVector lengths; + hlfir::genLengthParameters(loc, builder, elementAddrEntity, lengths); + if (!lengths.empty()) + elementalAddrOp.getTypeparamsMutable().assign(lengths); + // Create the hlfir.yield terminator inside the hlfir.elemental_body. + builder.setInsertionPointToEnd(&elementalAddrOp.getBody().front()); + builder.create(loc, elementAddrEntity); + builder.setInsertionPointAfter(elementalAddrOp); + // Reset the HlfirDesignatorBuilder state, in case it is used on a new + // designator. + setVectorSubscriptElementAddrOp(std::nullopt); + return elementalAddrOp; +} + //===--------------------------------------------------------------------===// // Binary Operation implementation //===--------------------------------------------------------------------===// @@ -878,7 +948,22 @@ GENBIN(Multiply, Real, mlir::arith::MulFOp) GENBIN(Multiply, Complex, fir::MulcOp) GENBIN(Divide, Integer, mlir::arith::DivSIOp) GENBIN(Divide, Real, mlir::arith::DivFOp) -GENBIN(Divide, Complex, fir::DivcOp) + +template +struct BinaryOp>> { + using Op = Fortran::evaluate::Divide< + Fortran::evaluate::Type>; + static hlfir::EntityWithAttributes gen(mlir::Location loc, + fir::FirOpBuilder &builder, const Op &, + hlfir::Entity lhs, hlfir::Entity rhs) { + mlir::Type ty = Fortran::lower::getFIRType( + builder.getContext(), Fortran::common::TypeCategory::Complex, KIND, + /*params=*/std::nullopt); + return hlfir::EntityWithAttributes{ + fir::genDivC(builder, loc, ty, lhs, rhs)}; + } +}; template struct BinaryOp>> { @@ -1488,7 +1573,13 @@ class HlfirBuilder { hlfir::EntityWithAttributes gen(const Fortran::evaluate::ImpliedDoIndex &var) { mlir::Value value = symMap.lookupImpliedDo(toStringRef(var.name)); - assert(value && "impled do was not mapped"); + if (!value) + fir::emitFatalError(getLoc(), "ac-do-variable has no binding"); + // The index value generated by the implied-do has Index type, + // while computations based on it inside the loop body are using + // the original data type. So we need to cast it appropriately. + mlir::Type varTy = getConverter().genType(toEvExpr(var)); + value = getBuilder().createConvert(getLoc(), varTy, value); return hlfir::EntityWithAttributes{value}; } @@ -1613,3 +1704,12 @@ fir::MutableBoxValue Fortran::lower::convertExprToMutableBox( assert(mutableBox && "expression could not be lowered to mutable box"); return *mutableBox; } + +hlfir::ElementalAddrOp +Fortran::lower::convertVectorSubscriptedExprToElementalAddr( + mlir::Location loc, Fortran::lower::AbstractConverter &converter, + const Fortran::lower::SomeExpr &designatorExpr, + Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) { + return HlfirDesignatorBuilder(loc, converter, symMap, stmtCtx) + .convertVectorSubscriptedExprToElementalAddr(designatorExpr); +} diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp index c0343356a84af..2204505571ce2 100644 --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -68,8 +68,21 @@ static bool hasDefaultInitialization(const Fortran::semantics::Symbol &sym) { if (!Fortran::semantics::IsAllocatableOrPointer(sym)) if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType()) if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec = - declTypeSpec->AsDerived()) - return derivedTypeSpec->HasDefaultInitialization(); + declTypeSpec->AsDerived()) { + // Pointer assignments in the runtime may hit undefined behaviors if + // the RHS contains garbage. Pointer objects are always established by + // lowering to NULL() (in Fortran::lower::createMutableBox). However, + // pointer components need special care here so that local and global + // derived type containing pointers are always initialized. + // Intent(out), however, do not need to be initialized since the + // related descriptor storage comes from a local or global that has + // been initialized (it may not be NULL() anymore, but the rank, type, + // and non deferred length parameters are still correct in a + // conformant program, and that is what matters). + const bool ignorePointer = Fortran::semantics::IsIntentOut(sym); + return derivedTypeSpec->HasDefaultInitialization( + /*ignoreAllocatable=*/false, ignorePointer); + } return false; } diff --git a/flang/lib/Lower/IterationSpace.cpp b/flang/lib/Lower/IterationSpace.cpp index 8c629d44962f2..6bf310b5cfb76 100644 --- a/flang/lib/Lower/IterationSpace.cpp +++ b/flang/lib/Lower/IterationSpace.cpp @@ -19,541 +19,12 @@ #define DEBUG_TYPE "flang-lower-iteration-space" -namespace { -// Fortran::evaluate::Expr are functional values organized like an AST. A -// Fortran::evaluate::Expr is meant to be moved and cloned. Using the front end -// tools can often cause copies and extra wrapper classes to be added to any -// Fortran::evalute::Expr. These values should not be assumed or relied upon to -// have an *object* identity. They are deeply recursive, irregular structures -// built from a large number of classes which do not use inheritance and -// necessitate a large volume of boilerplate code as a result. -// -// Contrastingly, LLVM data structures make ubiquitous assumptions about an -// object's identity via pointers to the object. An object's location in memory -// is thus very often an identifying relation. - -// This class defines a hash computation of a Fortran::evaluate::Expr tree value -// so it can be used with llvm::DenseMap. The Fortran::evaluate::Expr need not -// have the same address. -class HashEvaluateExpr { -public: - // A Se::Symbol is the only part of an Fortran::evaluate::Expr with an - // identity property. - static unsigned getHashValue(const Fortran::semantics::Symbol &x) { - return static_cast(reinterpret_cast(&x)); - } - template - static unsigned getHashValue(const Fortran::common::Indirection &x) { - return getHashValue(x.value()); - } - template - static unsigned getHashValue(const std::optional &x) { - if (x.has_value()) - return getHashValue(x.value()); - return 0u; - } - static unsigned getHashValue(const Fortran::evaluate::Subscript &x) { - return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); - } - static unsigned getHashValue(const Fortran::evaluate::Triplet &x) { - return getHashValue(x.lower()) - getHashValue(x.upper()) * 5u - - getHashValue(x.stride()) * 11u; - } - static unsigned getHashValue(const Fortran::evaluate::Component &x) { - return getHashValue(x.base()) * 83u - getHashValue(x.GetLastSymbol()); - } - static unsigned getHashValue(const Fortran::evaluate::ArrayRef &x) { - unsigned subs = 1u; - for (const Fortran::evaluate::Subscript &v : x.subscript()) - subs -= getHashValue(v); - return getHashValue(x.base()) * 89u - subs; - } - static unsigned getHashValue(const Fortran::evaluate::CoarrayRef &x) { - unsigned subs = 1u; - for (const Fortran::evaluate::Subscript &v : x.subscript()) - subs -= getHashValue(v); - unsigned cosubs = 3u; - for (const Fortran::evaluate::Expr &v : - x.cosubscript()) - cosubs -= getHashValue(v); - unsigned syms = 7u; - for (const Fortran::evaluate::SymbolRef &v : x.base()) - syms += getHashValue(v); - return syms * 97u - subs - cosubs + getHashValue(x.stat()) + 257u + - getHashValue(x.team()); - } - static unsigned getHashValue(const Fortran::evaluate::NamedEntity &x) { - if (x.IsSymbol()) - return getHashValue(x.GetFirstSymbol()) * 11u; - return getHashValue(x.GetComponent()) * 13u; - } - static unsigned getHashValue(const Fortran::evaluate::DataRef &x) { - return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); - } - static unsigned getHashValue(const Fortran::evaluate::ComplexPart &x) { - return getHashValue(x.complex()) - static_cast(x.part()); - } - template - static unsigned getHashValue( - const Fortran::evaluate::Convert, TC2> - &x) { - return getHashValue(x.left()) - (static_cast(TC1) + 2u) - - (static_cast(KIND) + 5u); - } - template - static unsigned - getHashValue(const Fortran::evaluate::ComplexComponent &x) { - return getHashValue(x.left()) - - (static_cast(x.isImaginaryPart) + 1u) * 3u; - } - template - static unsigned getHashValue(const Fortran::evaluate::Parentheses &x) { - return getHashValue(x.left()) * 17u; - } - template - static unsigned getHashValue( - const Fortran::evaluate::Negate> &x) { - return getHashValue(x.left()) - (static_cast(TC) + 5u) - - (static_cast(KIND) + 7u); - } - template - static unsigned getHashValue( - const Fortran::evaluate::Add> &x) { - return (getHashValue(x.left()) + getHashValue(x.right())) * 23u + - static_cast(TC) + static_cast(KIND); - } - template - static unsigned getHashValue( - const Fortran::evaluate::Subtract> &x) { - return (getHashValue(x.left()) - getHashValue(x.right())) * 19u + - static_cast(TC) + static_cast(KIND); - } - template - static unsigned getHashValue( - const Fortran::evaluate::Multiply> &x) { - return (getHashValue(x.left()) + getHashValue(x.right())) * 29u + - static_cast(TC) + static_cast(KIND); - } - template - static unsigned getHashValue( - const Fortran::evaluate::Divide> &x) { - return (getHashValue(x.left()) - getHashValue(x.right())) * 31u + - static_cast(TC) + static_cast(KIND); - } - template - static unsigned getHashValue( - const Fortran::evaluate::Power> &x) { - return (getHashValue(x.left()) - getHashValue(x.right())) * 37u + - static_cast(TC) + static_cast(KIND); - } - template - static unsigned getHashValue( - const Fortran::evaluate::Extremum> &x) { - return (getHashValue(x.left()) + getHashValue(x.right())) * 41u + - static_cast(TC) + static_cast(KIND) + - static_cast(x.ordering) * 7u; - } - template - static unsigned getHashValue( - const Fortran::evaluate::RealToIntPower> - &x) { - return (getHashValue(x.left()) - getHashValue(x.right())) * 43u + - static_cast(TC) + static_cast(KIND); - } - template - static unsigned - getHashValue(const Fortran::evaluate::ComplexConstructor &x) { - return (getHashValue(x.left()) - getHashValue(x.right())) * 47u + - static_cast(KIND); - } - template - static unsigned getHashValue(const Fortran::evaluate::Concat &x) { - return (getHashValue(x.left()) - getHashValue(x.right())) * 53u + - static_cast(KIND); - } - template - static unsigned getHashValue(const Fortran::evaluate::SetLength &x) { - return (getHashValue(x.left()) - getHashValue(x.right())) * 59u + - static_cast(KIND); - } - static unsigned getHashValue(const Fortran::semantics::SymbolRef &sym) { - return getHashValue(sym.get()); - } - static unsigned getHashValue(const Fortran::evaluate::Substring &x) { - return 61u * std::visit([&](const auto &p) { return getHashValue(p); }, - x.parent()) - - getHashValue(x.lower()) - (getHashValue(x.lower()) + 1u); - } - static unsigned - getHashValue(const Fortran::evaluate::StaticDataObject::Pointer &x) { - return llvm::hash_value(x->name()); - } - static unsigned getHashValue(const Fortran::evaluate::SpecificIntrinsic &x) { - return llvm::hash_value(x.name); - } - template - static unsigned getHashValue(const Fortran::evaluate::Constant &x) { - // FIXME: Should hash the content. - return 103u; - } - static unsigned getHashValue(const Fortran::evaluate::ActualArgument &x) { - if (const Fortran::evaluate::Symbol *sym = x.GetAssumedTypeDummy()) - return getHashValue(*sym); - return getHashValue(*x.UnwrapExpr()); - } - static unsigned - getHashValue(const Fortran::evaluate::ProcedureDesignator &x) { - return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); - } - static unsigned getHashValue(const Fortran::evaluate::ProcedureRef &x) { - unsigned args = 13u; - for (const std::optional &v : - x.arguments()) - args -= getHashValue(v); - return getHashValue(x.proc()) * 101u - args; - } - template - static unsigned - getHashValue(const Fortran::evaluate::ArrayConstructor &x) { - // FIXME: hash the contents. - return 127u; - } - static unsigned getHashValue(const Fortran::evaluate::ImpliedDoIndex &x) { - return llvm::hash_value(toStringRef(x.name).str()) * 131u; - } - static unsigned getHashValue(const Fortran::evaluate::TypeParamInquiry &x) { - return getHashValue(x.base()) * 137u - getHashValue(x.parameter()) * 3u; - } - static unsigned getHashValue(const Fortran::evaluate::DescriptorInquiry &x) { - return getHashValue(x.base()) * 139u - - static_cast(x.field()) * 13u + - static_cast(x.dimension()); - } - static unsigned - getHashValue(const Fortran::evaluate::StructureConstructor &x) { - // FIXME: hash the contents. - return 149u; - } - template - static unsigned getHashValue(const Fortran::evaluate::Not &x) { - return getHashValue(x.left()) * 61u + static_cast(KIND); - } - template - static unsigned - getHashValue(const Fortran::evaluate::LogicalOperation &x) { - unsigned result = getHashValue(x.left()) + getHashValue(x.right()); - return result * 67u + static_cast(x.logicalOperator) * 5u; - } - template - static unsigned getHashValue( - const Fortran::evaluate::Relational> - &x) { - return (getHashValue(x.left()) + getHashValue(x.right())) * 71u + - static_cast(TC) + static_cast(KIND) + - static_cast(x.opr) * 11u; - } - template - static unsigned getHashValue(const Fortran::evaluate::Expr &x) { - return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); - } - static unsigned getHashValue( - const Fortran::evaluate::Relational &x) { - return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); - } - template - static unsigned getHashValue(const Fortran::evaluate::Designator &x) { - return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); - } - template - static unsigned - getHashValue(const Fortran::evaluate::value::Integer &x) { - return static_cast(x.ToSInt()); - } - static unsigned getHashValue(const Fortran::evaluate::NullPointer &x) { - return ~179u; - } -}; -} // namespace - unsigned Fortran::lower::getHashValue( const Fortran::lower::ExplicitIterSpace::ArrayBases &x) { return std::visit( [&](const auto *p) { return HashEvaluateExpr::getHashValue(*p); }, x); } -unsigned Fortran::lower::getHashValue(Fortran::lower::FrontEndExpr x) { - return HashEvaluateExpr::getHashValue(*x); -} - -namespace { -// Define the is equals test for using Fortran::evaluate::Expr values with -// llvm::DenseMap. -class IsEqualEvaluateExpr { -public: - // A Se::Symbol is the only part of an Fortran::evaluate::Expr with an - // identity property. - static bool isEqual(const Fortran::semantics::Symbol &x, - const Fortran::semantics::Symbol &y) { - return isEqual(&x, &y); - } - static bool isEqual(const Fortran::semantics::Symbol *x, - const Fortran::semantics::Symbol *y) { - return x == y; - } - template - static bool isEqual(const Fortran::common::Indirection &x, - const Fortran::common::Indirection &y) { - return isEqual(x.value(), y.value()); - } - template - static bool isEqual(const std::optional &x, const std::optional &y) { - if (x.has_value() && y.has_value()) - return isEqual(x.value(), y.value()); - return !x.has_value() && !y.has_value(); - } - template - static bool isEqual(const std::vector &x, const std::vector &y) { - if (x.size() != y.size()) - return false; - const std::size_t size = x.size(); - for (std::remove_const_t i = 0; i < size; ++i) - if (!isEqual(x[i], y[i])) - return false; - return true; - } - static bool isEqual(const Fortran::evaluate::Subscript &x, - const Fortran::evaluate::Subscript &y) { - return std::visit( - [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); - } - static bool isEqual(const Fortran::evaluate::Triplet &x, - const Fortran::evaluate::Triplet &y) { - return isEqual(x.lower(), y.lower()) && isEqual(x.upper(), y.upper()) && - isEqual(x.stride(), y.stride()); - } - static bool isEqual(const Fortran::evaluate::Component &x, - const Fortran::evaluate::Component &y) { - return isEqual(x.base(), y.base()) && - isEqual(x.GetLastSymbol(), y.GetLastSymbol()); - } - static bool isEqual(const Fortran::evaluate::ArrayRef &x, - const Fortran::evaluate::ArrayRef &y) { - return isEqual(x.base(), y.base()) && isEqual(x.subscript(), y.subscript()); - } - static bool isEqual(const Fortran::evaluate::CoarrayRef &x, - const Fortran::evaluate::CoarrayRef &y) { - return isEqual(x.base(), y.base()) && - isEqual(x.subscript(), y.subscript()) && - isEqual(x.cosubscript(), y.cosubscript()) && - isEqual(x.stat(), y.stat()) && isEqual(x.team(), y.team()); - } - static bool isEqual(const Fortran::evaluate::NamedEntity &x, - const Fortran::evaluate::NamedEntity &y) { - if (x.IsSymbol() && y.IsSymbol()) - return isEqual(x.GetFirstSymbol(), y.GetFirstSymbol()); - return !x.IsSymbol() && !y.IsSymbol() && - isEqual(x.GetComponent(), y.GetComponent()); - } - static bool isEqual(const Fortran::evaluate::DataRef &x, - const Fortran::evaluate::DataRef &y) { - return std::visit( - [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); - } - static bool isEqual(const Fortran::evaluate::ComplexPart &x, - const Fortran::evaluate::ComplexPart &y) { - return isEqual(x.complex(), y.complex()) && x.part() == y.part(); - } - template - static bool isEqual(const Fortran::evaluate::Convert &x, - const Fortran::evaluate::Convert &y) { - return isEqual(x.left(), y.left()); - } - template - static bool isEqual(const Fortran::evaluate::ComplexComponent &x, - const Fortran::evaluate::ComplexComponent &y) { - return isEqual(x.left(), y.left()) && - x.isImaginaryPart == y.isImaginaryPart; - } - template - static bool isEqual(const Fortran::evaluate::Parentheses &x, - const Fortran::evaluate::Parentheses &y) { - return isEqual(x.left(), y.left()); - } - template - static bool isEqual(const Fortran::evaluate::Negate &x, - const Fortran::evaluate::Negate &y) { - return isEqual(x.left(), y.left()); - } - template - static bool isBinaryEqual(const A &x, const A &y) { - return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right()); - } - template - static bool isEqual(const Fortran::evaluate::Add &x, - const Fortran::evaluate::Add &y) { - return isBinaryEqual(x, y); - } - template - static bool isEqual(const Fortran::evaluate::Subtract &x, - const Fortran::evaluate::Subtract &y) { - return isBinaryEqual(x, y); - } - template - static bool isEqual(const Fortran::evaluate::Multiply &x, - const Fortran::evaluate::Multiply &y) { - return isBinaryEqual(x, y); - } - template - static bool isEqual(const Fortran::evaluate::Divide &x, - const Fortran::evaluate::Divide &y) { - return isBinaryEqual(x, y); - } - template - static bool isEqual(const Fortran::evaluate::Power &x, - const Fortran::evaluate::Power &y) { - return isBinaryEqual(x, y); - } - template - static bool isEqual(const Fortran::evaluate::Extremum &x, - const Fortran::evaluate::Extremum &y) { - return isBinaryEqual(x, y); - } - template - static bool isEqual(const Fortran::evaluate::RealToIntPower &x, - const Fortran::evaluate::RealToIntPower &y) { - return isBinaryEqual(x, y); - } - template - static bool isEqual(const Fortran::evaluate::ComplexConstructor &x, - const Fortran::evaluate::ComplexConstructor &y) { - return isBinaryEqual(x, y); - } - template - static bool isEqual(const Fortran::evaluate::Concat &x, - const Fortran::evaluate::Concat &y) { - return isBinaryEqual(x, y); - } - template - static bool isEqual(const Fortran::evaluate::SetLength &x, - const Fortran::evaluate::SetLength &y) { - return isBinaryEqual(x, y); - } - static bool isEqual(const Fortran::semantics::SymbolRef &x, - const Fortran::semantics::SymbolRef &y) { - return isEqual(x.get(), y.get()); - } - static bool isEqual(const Fortran::evaluate::Substring &x, - const Fortran::evaluate::Substring &y) { - return std::visit( - [&](const auto &p, const auto &q) { return isEqual(p, q); }, - x.parent(), y.parent()) && - isEqual(x.lower(), y.lower()) && isEqual(x.lower(), y.lower()); - } - static bool isEqual(const Fortran::evaluate::StaticDataObject::Pointer &x, - const Fortran::evaluate::StaticDataObject::Pointer &y) { - return x->name() == y->name(); - } - static bool isEqual(const Fortran::evaluate::SpecificIntrinsic &x, - const Fortran::evaluate::SpecificIntrinsic &y) { - return x.name == y.name; - } - template - static bool isEqual(const Fortran::evaluate::Constant &x, - const Fortran::evaluate::Constant &y) { - return x == y; - } - static bool isEqual(const Fortran::evaluate::ActualArgument &x, - const Fortran::evaluate::ActualArgument &y) { - if (const Fortran::evaluate::Symbol *xs = x.GetAssumedTypeDummy()) { - if (const Fortran::evaluate::Symbol *ys = y.GetAssumedTypeDummy()) - return isEqual(*xs, *ys); - return false; - } - return !y.GetAssumedTypeDummy() && - isEqual(*x.UnwrapExpr(), *y.UnwrapExpr()); - } - static bool isEqual(const Fortran::evaluate::ProcedureDesignator &x, - const Fortran::evaluate::ProcedureDesignator &y) { - return std::visit( - [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); - } - static bool isEqual(const Fortran::evaluate::ProcedureRef &x, - const Fortran::evaluate::ProcedureRef &y) { - return isEqual(x.proc(), y.proc()) && isEqual(x.arguments(), y.arguments()); - } - template - static bool isEqual(const Fortran::evaluate::ArrayConstructor &x, - const Fortran::evaluate::ArrayConstructor &y) { - llvm::report_fatal_error("not implemented"); - } - static bool isEqual(const Fortran::evaluate::ImpliedDoIndex &x, - const Fortran::evaluate::ImpliedDoIndex &y) { - return toStringRef(x.name) == toStringRef(y.name); - } - static bool isEqual(const Fortran::evaluate::TypeParamInquiry &x, - const Fortran::evaluate::TypeParamInquiry &y) { - return isEqual(x.base(), y.base()) && isEqual(x.parameter(), y.parameter()); - } - static bool isEqual(const Fortran::evaluate::DescriptorInquiry &x, - const Fortran::evaluate::DescriptorInquiry &y) { - return isEqual(x.base(), y.base()) && x.field() == y.field() && - x.dimension() == y.dimension(); - } - static bool isEqual(const Fortran::evaluate::StructureConstructor &x, - const Fortran::evaluate::StructureConstructor &y) { - llvm::report_fatal_error("not implemented"); - } - template - static bool isEqual(const Fortran::evaluate::Not &x, - const Fortran::evaluate::Not &y) { - return isEqual(x.left(), y.left()); - } - template - static bool isEqual(const Fortran::evaluate::LogicalOperation &x, - const Fortran::evaluate::LogicalOperation &y) { - return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right()); - } - template - static bool isEqual(const Fortran::evaluate::Relational &x, - const Fortran::evaluate::Relational &y) { - return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right()); - } - template - static bool isEqual(const Fortran::evaluate::Expr &x, - const Fortran::evaluate::Expr &y) { - return std::visit( - [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); - } - static bool - isEqual(const Fortran::evaluate::Relational &x, - const Fortran::evaluate::Relational &y) { - return std::visit( - [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); - } - template - static bool isEqual(const Fortran::evaluate::Designator &x, - const Fortran::evaluate::Designator &y) { - return std::visit( - [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); - } - template - static bool isEqual(const Fortran::evaluate::value::Integer &x, - const Fortran::evaluate::value::Integer &y) { - return x == y; - } - static bool isEqual(const Fortran::evaluate::NullPointer &x, - const Fortran::evaluate::NullPointer &y) { - return true; - } - template , bool> = true> - static bool isEqual(const A &, const B &) { - return false; - } -}; -} // namespace - bool Fortran::lower::isEqual( const Fortran::lower::ExplicitIterSpace::ArrayBases &x, const Fortran::lower::ExplicitIterSpace::ArrayBases &y) { @@ -578,16 +49,6 @@ bool Fortran::lower::isEqual( x, y); } -bool Fortran::lower::isEqual(Fortran::lower::FrontEndExpr x, - Fortran::lower::FrontEndExpr y) { - auto empty = llvm::DenseMapInfo::getEmptyKey(); - auto tombstone = - llvm::DenseMapInfo::getTombstoneKey(); - if (x == empty || y == empty || x == tombstone || y == tombstone) - return x == y; - return x == y || IsEqualEvaluateExpr::isEqual(*x, *y); -} - namespace { /// This class can recover the base array in an expression that contains diff --git a/flang/lib/Lower/Mangler.cpp b/flang/lib/Lower/Mangler.cpp index 807d9ebff6c49..0f46458b7266e 100644 --- a/flang/lib/Lower/Mangler.cpp +++ b/flang/lib/Lower/Mangler.cpp @@ -236,8 +236,7 @@ static std::string typeToString(Fortran::common::TypeCategory cat, int kind, } std::string Fortran::lower::mangle::mangleArrayLiteral( - const uint8_t *addr, size_t size, - const Fortran::evaluate::ConstantSubscripts &shape, + size_t size, const Fortran::evaluate::ConstantSubscripts &shape, Fortran::common::TypeCategory cat, int kind, Fortran::common::ConstantSubscript charLen, llvm::StringRef derivedName) { std::string typeId; @@ -249,14 +248,8 @@ std::string Fortran::lower::mangle::mangleArrayLiteral( std::string name = fir::NameUniquer::doGenerated("ro."s.append(typeId).append(".")); if (!size) - return name += "null"; - llvm::MD5 hashValue{}; - hashValue.update(llvm::ArrayRef{addr, size}); - llvm::MD5::MD5Result hashResult; - hashValue.final(hashResult); - llvm::SmallString<32> hashString; - llvm::MD5::stringifyResult(hashResult, hashString); - return name += hashString.c_str(); + name += "null."; + return name; } std::string Fortran::lower::mangle::globalNamelistDescriptorName( diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp index d46c0c54ee460..fb6b71466021b 100644 --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -146,12 +146,10 @@ genBaseBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value baseLb = fir::factory::readLowerBound(builder, loc, dataExv, dim, one); mlir::Value ext = fir::factory::readExtent(builder, loc, dataExv, dim); - mlir::Value lb = - baseLb == one ? builder.createIntegerConstant(loc, idxTy, 0) : baseLb; + mlir::Value lb = builder.createIntegerConstant(loc, idxTy, 0); - // ub = baseLb + extent - 1 - mlir::Value lbExt = builder.create(loc, ext, baseLb); - mlir::Value ub = builder.create(loc, lbExt, one); + // ub = extent - 1 + mlir::Value ub = builder.create(loc, ext, one); mlir::Value bound = builder.create( loc, boundTy, lb, ub, mlir::Value(), one, false, baseLb); bounds.push_back(bound); @@ -904,10 +902,13 @@ createComputeOp(Fortran::lower::AbstractConverter &converter, } } else if (const auto *copyClause = std::get_if(&clause.u)) { + auto crtDataStart = dataClauseOperands.size(); genDataOperandOperations( copyClause->v, converter, semanticsContext, stmtCtx, - copyEntryOperands, mlir::acc::DataClause::acc_copy, + dataClauseOperands, mlir::acc::DataClause::acc_copy, /*structured=*/true); + copyEntryOperands.append(dataClauseOperands.begin() + crtDataStart, + dataClauseOperands.end()); } else if (const auto *copyinClause = std::get_if(&clause.u)) { genDataOperandOperationsWithModifier( &clause.u)) { + auto crtDataStart = dataClauseOperands.size(); genDataOperandOperationsWithModifier( copyoutClause, converter, semanticsContext, stmtCtx, Fortran::parser::AccDataModifier::Modifier::ReadOnly, - copyoutEntryOperands, mlir::acc::DataClause::acc_copyout, + dataClauseOperands, mlir::acc::DataClause::acc_copyout, mlir::acc::DataClause::acc_copyout_zero); + copyoutEntryOperands.append(dataClauseOperands.begin() + crtDataStart, + dataClauseOperands.end()); } else if (const auto *createClause = std::get_if(&clause.u)) { + auto crtDataStart = dataClauseOperands.size(); genDataOperandOperationsWithModifier( createClause, converter, semanticsContext, stmtCtx, - Fortran::parser::AccDataModifier::Modifier::Zero, createEntryOperands, + Fortran::parser::AccDataModifier::Modifier::Zero, dataClauseOperands, mlir::acc::DataClause::acc_create, mlir::acc::DataClause::acc_create_zero); + createEntryOperands.append(dataClauseOperands.begin() + crtDataStart, + dataClauseOperands.end()); } else if (const auto *noCreateClause = std::get_if( &clause.u)) { @@ -956,10 +963,13 @@ createComputeOp(Fortran::lower::AbstractConverter &converter, /*structured=*/true); } else if (const auto *attachClause = std::get_if(&clause.u)) { + auto crtDataStart = dataClauseOperands.size(); genDataOperandOperations( attachClause->v, converter, semanticsContext, stmtCtx, - attachEntryOperands, mlir::acc::DataClause::acc_attach, + dataClauseOperands, mlir::acc::DataClause::acc_attach, /*structured=*/true); + attachEntryOperands.append(dataClauseOperands.begin() + crtDataStart, + dataClauseOperands.end()); } else if (const auto *privateClause = std::get_if( &clause.u)) { @@ -975,11 +985,6 @@ createComputeOp(Fortran::lower::AbstractConverter &converter, } } - dataClauseOperands.append(attachEntryOperands); - dataClauseOperands.append(copyEntryOperands); - dataClauseOperands.append(copyoutEntryOperands); - dataClauseOperands.append(createEntryOperands); - // Prepare the operand segment size attribute and the operands value range. llvm::SmallVector operands; llvm::SmallVector operandSegments; @@ -992,10 +997,8 @@ createComputeOp(Fortran::lower::AbstractConverter &converter, } addOperand(operands, operandSegments, ifCond); addOperand(operands, operandSegments, selfCond); - if constexpr (!std::is_same_v) - addOperands(operands, operandSegments, reductionOperands); - operandSegments.append({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); if constexpr (!std::is_same_v) { + addOperands(operands, operandSegments, reductionOperands); addOperands(operands, operandSegments, privateOperands); addOperands(operands, operandSegments, firstprivateOperands); } @@ -1054,10 +1057,13 @@ static void genACCDataOp(Fortran::lower::AbstractConverter &converter, genIfClause(converter, clauseLocation, ifClause, ifCond, stmtCtx); } else if (const auto *copyClause = std::get_if(&clause.u)) { + auto crtDataStart = dataClauseOperands.size(); genDataOperandOperations( copyClause->v, converter, semanticsContext, stmtCtx, - copyEntryOperands, mlir::acc::DataClause::acc_copy, + dataClauseOperands, mlir::acc::DataClause::acc_copy, /*structured=*/true); + copyEntryOperands.append(dataClauseOperands.begin() + crtDataStart, + dataClauseOperands.end()); } else if (const auto *copyinClause = std::get_if(&clause.u)) { genDataOperandOperationsWithModifier( &clause.u)) { + auto crtDataStart = dataClauseOperands.size(); genDataOperandOperationsWithModifier( copyoutClause, converter, semanticsContext, stmtCtx, - Fortran::parser::AccDataModifier::Modifier::Zero, - copyoutEntryOperands, mlir::acc::DataClause::acc_copyout, + Fortran::parser::AccDataModifier::Modifier::Zero, dataClauseOperands, + mlir::acc::DataClause::acc_copyout, mlir::acc::DataClause::acc_copyout_zero); + copyoutEntryOperands.append(dataClauseOperands.begin() + crtDataStart, + dataClauseOperands.end()); } else if (const auto *createClause = std::get_if(&clause.u)) { + auto crtDataStart = dataClauseOperands.size(); genDataOperandOperationsWithModifier( createClause, converter, semanticsContext, stmtCtx, - Fortran::parser::AccDataModifier::Modifier::Zero, createEntryOperands, + Fortran::parser::AccDataModifier::Modifier::Zero, dataClauseOperands, mlir::acc::DataClause::acc_create, mlir::acc::DataClause::acc_create_zero); + createEntryOperands.append(dataClauseOperands.begin() + crtDataStart, + dataClauseOperands.end()); } else if (const auto *noCreateClause = std::get_if( &clause.u)) { @@ -1106,23 +1118,20 @@ static void genACCDataOp(Fortran::lower::AbstractConverter &converter, /*structured=*/true); } else if (const auto *attachClause = std::get_if(&clause.u)) { + auto crtDataStart = dataClauseOperands.size(); genDataOperandOperations( attachClause->v, converter, semanticsContext, stmtCtx, - attachEntryOperands, mlir::acc::DataClause::acc_attach, + dataClauseOperands, mlir::acc::DataClause::acc_attach, /*structured=*/true); + attachEntryOperands.append(dataClauseOperands.begin() + crtDataStart, + dataClauseOperands.end()); } } - dataClauseOperands.append(attachEntryOperands); - dataClauseOperands.append(copyEntryOperands); - dataClauseOperands.append(copyoutEntryOperands); - dataClauseOperands.append(createEntryOperands); - // Prepare the operand segment size attribute and the operands value range. llvm::SmallVector operands; llvm::SmallVector operandSegments; addOperand(operands, operandSegments, ifCond); - operandSegments.append({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); addOperands(operands, operandSegments, dataClauseOperands); auto dataOp = createRegionOp( @@ -1287,7 +1296,6 @@ genACCEnterDataOp(Fortran::lower::AbstractConverter &converter, addOperand(operands, operandSegments, async); addOperand(operands, operandSegments, waitDevnum); addOperands(operands, operandSegments, waitOperands); - operandSegments.append({0, 0, 0, 0}); addOperands(operands, operandSegments, dataClauseOperands); mlir::acc::EnterDataOp enterDataOp = createSimpleOp( @@ -1369,7 +1377,6 @@ genACCExitDataOp(Fortran::lower::AbstractConverter &converter, addOperand(operands, operandSegments, async); addOperand(operands, operandSegments, waitDevnum); addOperands(operands, operandSegments, waitOperands); - operandSegments.append({0, 0, 0}); addOperands(operands, operandSegments, dataClauseOperands); mlir::acc::ExitDataOp exitDataOp = createSimpleOp( @@ -1481,6 +1488,18 @@ genACCUpdateOp(Fortran::lower::AbstractConverter &converter, genDataOperandOperations( deviceClause->v, converter, semanticsContext, stmtCtx, dataClauseOperands, mlir::acc::DataClause::acc_update_device, false); + } else if (std::get_if(&clause.u)) { + addIfPresentAttr = true; + } else if (const auto *selfClause = + std::get_if(&clause.u)) { + const std::optional &accSelfClause = + selfClause->v; + const auto *accObjectList = + std::get_if(&(*accSelfClause).u); + assert(accObjectList && "expect AccObjectList"); + genDataOperandOperations( + *accObjectList, converter, semanticsContext, stmtCtx, + updateHostOperands, mlir::acc::DataClause::acc_update_self, false); } } diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp index 8ab9dc40a50b0..6b03a92c956c2 100644 --- a/flang/lib/Lower/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP.cpp @@ -881,15 +881,31 @@ genAllocateClause(Fortran::lower::AbstractConverter &converter, mlir::Value allocatorOperand; const Fortran::parser::OmpObjectList &ompObjectList = std::get(ompAllocateClause.t); - const auto &allocatorValue = - std::get>( - ompAllocateClause.t); + const auto &allocateModifier = std::get< + std::optional>( + ompAllocateClause.t); + + // If the allocate modifier is present, check if we only use the allocator + // submodifier. ALIGN in this context is unimplemented + const bool onlyAllocator = + allocateModifier && + std::holds_alternative< + Fortran::parser::OmpAllocateClause::AllocateModifier::Allocator>( + allocateModifier->u); + + if (allocateModifier && !onlyAllocator) { + TODO(converter.getCurrentLocation(), "OmpAllocateClause ALIGN modifier"); + } + // Check if allocate clause has allocator specified. If so, add it // to list of allocators, otherwise, add default allocator to // list of allocators. - if (allocatorValue) { + if (onlyAllocator) { + const auto &allocatorValue = std::get< + Fortran::parser::OmpAllocateClause::AllocateModifier::Allocator>( + allocateModifier->u); allocatorOperand = fir::getBase(converter.genExprValue( - *Fortran::semantics::GetExpr(allocatorValue->v), stmtCtx)); + *Fortran::semantics::GetExpr(allocatorValue.v), stmtCtx)); allocatorOperands.insert(allocatorOperands.end(), ompObjectList.v.size(), allocatorOperand); } else { @@ -2380,6 +2396,10 @@ void Fortran::lower::genOpenMPConstruct( &execAllocConstruct) { TODO(converter.getCurrentLocation(), "OpenMPExecutableAllocate"); }, + [&](const Fortran::parser::OpenMPAllocatorsConstruct + &allocsConstruct) { + TODO(converter.getCurrentLocation(), "OpenMPAllocatorsConstruct"); + }, [&](const Fortran::parser::OpenMPBlockConstruct &blockConstruct) { genOMP(converter, eval, blockConstruct); }, diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp index 8ffff7ad7809a..ae82a5afa2acb 100644 --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -999,7 +999,9 @@ fir::ExtendedValue fir::factory::createStringLiteral(fir::FirOpBuilder &builder, auto stringLitOp = builder.createStringLitOp(loc, str); builder.create(loc, stringLitOp); }, - builder.createLinkOnceLinkage()); + builder.createInternalLinkage()); + // TODO: This can be changed to linkonce linkage once we have support for + // generating comdat sections auto addr = builder.create(loc, global.resultType(), global.getSymbol()); auto len = builder.createIntegerConstant( diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp index d877be0cbc0ae..2ee6f404ceef1 100644 --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -1184,6 +1184,54 @@ static mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc, return libCall.getResult(0); } +static mlir::Value genLibSplitComplexArgsCall( + fir::FirOpBuilder &builder, mlir::Location loc, llvm::StringRef libFuncName, + mlir::FunctionType libFuncType, llvm::ArrayRef args) { + assert(args.size() == 2 && "Incorrect #args to genLibSplitComplexArgsCall"); + + auto getSplitComplexArgsType = [&builder, &args]() -> mlir::FunctionType { + mlir::Type ctype = args[0].getType(); + auto fKind = ctype.cast().getFKind(); + mlir::Type ftype; + + if (fKind == 2) + ftype = builder.getF16Type(); + else if (fKind == 3) + ftype = builder.getBF16Type(); + else if (fKind == 4) + ftype = builder.getF32Type(); + else if (fKind == 8) + ftype = builder.getF64Type(); + else if (fKind == 10) + ftype = builder.getF80Type(); + else if (fKind == 16) + ftype = builder.getF128Type(); + else + assert(0 && "Unsupported Complex Type"); + + return builder.getFunctionType({ftype, ftype, ftype, ftype}, {ctype}); + }; + + llvm::SmallVector splitArgs; + mlir::Value cplx1 = args[0]; + auto real1 = fir::factory::Complex{builder, loc}.extractComplexPart( + cplx1, /*isImagPart=*/false); + splitArgs.push_back(real1); + auto imag1 = fir::factory::Complex{builder, loc}.extractComplexPart( + cplx1, /*isImagPart=*/true); + splitArgs.push_back(imag1); + mlir::Value cplx2 = args[1]; + auto real2 = fir::factory::Complex{builder, loc}.extractComplexPart( + cplx2, /*isImagPart=*/false); + splitArgs.push_back(real2); + auto imag2 = fir::factory::Complex{builder, loc}.extractComplexPart( + cplx2, /*isImagPart=*/true); + splitArgs.push_back(imag2); + + return genLibCall(builder, loc, libFuncName, getSplitComplexArgsType(), + splitArgs); +} + template static mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc, llvm::StringRef mathLibFuncName, @@ -1345,6 +1393,22 @@ static constexpr MathOperation mathOperations[] = { {"cosh", "cosh", genF64F64FuncType, genLibCall}, {"cosh", "ccoshf", genComplexComplexFuncType<4>, genLibCall}, {"cosh", "ccosh", genComplexComplexFuncType<8>, genLibCall}, + {"divc", + {}, + genComplexComplexComplexFuncType<2>, + genComplexMathOp}, + {"divc", + {}, + genComplexComplexComplexFuncType<3>, + genComplexMathOp}, + {"divc", "__divsc3", genComplexComplexComplexFuncType<4>, + genLibSplitComplexArgsCall}, + {"divc", "__divdc3", genComplexComplexComplexFuncType<8>, + genLibSplitComplexArgsCall}, + {"divc", "__divxc3", genComplexComplexComplexFuncType<10>, + genLibSplitComplexArgsCall}, + {"divc", "__divtc3", genComplexComplexComplexFuncType<16>, + genLibSplitComplexArgsCall}, {"erf", "erff", genF32F32FuncType, genMathOp}, {"erf", "erf", genF64F64FuncType, genMathOp}, {"erfc", "erfcf", genF32F32FuncType, genLibCall}, @@ -4843,6 +4907,13 @@ IntrinsicLibrary::genSize(mlir::Type resultType, // Get the DIM argument. mlir::Value dim = fir::getBase(args[1]); + if (std::optional cstDim = fir::getIntIfConstant(dim)) { + // If it is a compile time constant, skip the runtime call. + return builder.createConvert(loc, resultType, + fir::factory::readExtent(builder, loc, + fir::BoxValue{array}, + cstDim.value() - 1)); + } if (!fir::isa_ref_type(dim.getType())) return builder.createConvert( loc, resultType, fir::runtime::genSizeDim(builder, loc, array, dim)); @@ -5661,6 +5732,11 @@ mlir::Value fir::genMin(fir::FirOpBuilder &builder, mlir::Location loc, args); } +mlir::Value fir::genDivC(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Type type, mlir::Value x, mlir::Value y) { + return IntrinsicLibrary{builder, loc}.genRuntimeCall("divc", type, {x, y}); +} + mlir::Value fir::genPow(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type type, mlir::Value x, mlir::Value y) { // TODO: since there is no libm version of pow with integer exponent, diff --git a/flang/lib/Optimizer/Builder/MutableBox.cpp b/flang/lib/Optimizer/Builder/MutableBox.cpp index 3c4169643e487..a673c441b25be 100644 --- a/flang/lib/Optimizer/Builder/MutableBox.cpp +++ b/flang/lib/Optimizer/Builder/MutableBox.cpp @@ -934,3 +934,13 @@ void fir::factory::syncMutableBoxFromIRBox(fir::FirOpBuilder &builder, const fir::MutableBoxValue &box) { MutablePropertyWriter{builder, loc, box}.syncMutablePropertiesFromIRBox(); } + +mlir::Value fir::factory::genNullBoxStorage(fir::FirOpBuilder &builder, + mlir::Location loc, + mlir::Type boxTy) { + mlir::Value boxStorage = builder.createTemporary(loc, boxTy); + mlir::Value nullBox = fir::factory::createUnallocatedBox( + builder, loc, boxTy, /*nonDeferredParams=*/{}); + builder.create(loc, nullBox, boxStorage); + return boxStorage; +} diff --git a/flang/lib/Optimizer/CodeGen/CMakeLists.txt b/flang/lib/Optimizer/CodeGen/CMakeLists.txt index 1d65e1de6df4c..016544ef870a5 100644 --- a/flang/lib/Optimizer/CodeGen/CMakeLists.txt +++ b/flang/lib/Optimizer/CodeGen/CMakeLists.txt @@ -23,7 +23,6 @@ add_flang_library(FIRCodeGen MLIRMathToFuncs MLIRMathToLLVM MLIRMathToLibm - MLIROpenACCToLLVM MLIROpenMPToLLVM MLIRBuiltinToLLVMIRTranslation MLIRLLVMToLLVMIRTranslation diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index c96ce573e9c4d..f3565c04abcb8 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -31,7 +31,6 @@ #include "mlir/Conversion/MathToFuncs/MathToFuncs.h" #include "mlir/Conversion/MathToLLVM/MathToLLVM.h" #include "mlir/Conversion/MathToLibm/MathToLibm.h" -#include "mlir/Conversion/OpenACCToLLVM/ConvertOpenACCToLLVM.h" #include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h" #include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" @@ -3690,7 +3689,6 @@ class FIRToLLVMLowering XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(typeConverter, options); mlir::populateFuncToLLVMConversionPatterns(typeConverter, pattern); - mlir::populateOpenACCToLLVMConversionPatterns(typeConverter, pattern); mlir::populateOpenMPToLLVMConversionPatterns(typeConverter, pattern); mlir::arith::populateArithToLLVMConversionPatterns(typeConverter, pattern); mlir::cf::populateControlFlowToLLVMConversionPatterns(typeConverter, diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp index cf6b332028c78..fda12d1ea8611 100644 --- a/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp +++ b/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp @@ -148,6 +148,17 @@ bool hlfir::isI1Type(mlir::Type type) { return false; } +bool hlfir::isFortranLogicalArrayObject(mlir::Type type) { + if (isBoxAddressType(type)) + return false; + if (auto arrayTy = + getFortranElementOrSequenceType(type).dyn_cast()) { + mlir::Type eleTy = arrayTy.getEleTy(); + return mlir::isa(eleTy); + } + return false; +} + bool hlfir::isMaskArgument(mlir::Type type) { if (isBoxAddressType(type)) return false; diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp index 7599b8d2756e0..b399a457d13df 100644 --- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp +++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp @@ -441,6 +441,44 @@ mlir::LogicalResult hlfir::ParentComponentOp::verify() { return mlir::success(); } +//===----------------------------------------------------------------------===// +// AnyOp +//===----------------------------------------------------------------------===// +mlir::LogicalResult hlfir::AnyOp::verify() { + mlir::Operation *op = getOperation(); + + auto results = op->getResultTypes(); + assert(results.size() == 1); + + mlir::Value mask = getMask(); + fir::SequenceType maskTy = + hlfir::getFortranElementOrSequenceType(mask.getType()) + .cast(); + mlir::Type logicalTy = maskTy.getEleTy(); + llvm::ArrayRef maskShape = maskTy.getShape(); + hlfir::ExprType resultTy = results[0].cast(); + + // Result is of the same type as MASK + if (resultTy.getElementType() != logicalTy) + return emitOpError( + "result must have the same element type as MASK argument"); + + if (resultTy.isArray()) { + // Result is of the same type as MASK + if (resultTy.getEleTy() != logicalTy) + return emitOpError( + "result must have the same element type as MASK argument"); + + llvm::ArrayRef resultShape = resultTy.getShape(); + + // Result has rank n-1 + if (resultShape.size() != (maskShape.size() - 1)) + return emitOpError("result rank must be one less than MASK"); + } + + return mlir::success(); +} + //===----------------------------------------------------------------------===// // ConcatOp //===----------------------------------------------------------------------===// diff --git a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp index 8d364eafb9391..7b12fad984f4e 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp @@ -215,8 +215,14 @@ struct ApplyOpConversion : public mlir::OpConversionPattern { mlir::Value result = rewriter.create( loc, resultType, bufferizedExpr, adaptor.getIndices(), adaptor.getTypeparams()); - if (fir::isa_trivial(apply.getType())) + if (fir::isa_trivial(apply.getType())) { result = rewriter.create(loc, result); + } else { + auto module = apply->getParentOfType(); + fir::FirOpBuilder builder(rewriter, fir::getKindMapping(module)); + result = + packageBufferizedExpr(loc, builder, hlfir::Entity{result}, false); + } rewriter.replaceOp(apply, result); return mlir::success(); } @@ -340,12 +346,32 @@ struct AssociateOpConversion auto replaceWith = [&](mlir::Value hlfirVar, mlir::Value firVar, mlir::Value flag) { - hlfirVar = - builder.createConvert(loc, associate.getResultTypes()[0], hlfirVar); + // 0-dim variables may need special handling: + // %0 = hlfir.as_expr %x move %true : + // (!fir.box>>, i1) -> + // !hlfir.expr> + // %1:3 = hlfir.associate %0 {uniq_name = "adapt.valuebyref"} : + // (!hlfir.expr>) -> + // (!fir.ref>, + // !fir.ref>, + // i1) + // + // !fir.box>> value must be propagated + // as the box address !fir.ref>. + mlir::Type associateHlfirVarType = associate.getResultTypes()[0]; + if (hlfirVar.getType().isa() && + !associateHlfirVarType.isa()) + hlfirVar = builder.create(loc, associateHlfirVarType, + hlfirVar); + else + hlfirVar = builder.createConvert(loc, associateHlfirVarType, hlfirVar); associate.getResult(0).replaceAllUsesWith(hlfirVar); + mlir::Type associateFirVarType = associate.getResultTypes()[1]; - if (firVar.getType().isa() && - !associateFirVarType.isa()) + if ((firVar.getType().isa() && + !associateFirVarType.isa()) || + (firVar.getType().isa() && + !associateFirVarType.isa())) firVar = builder.create(loc, associateFirVarType, firVar); else @@ -451,8 +477,20 @@ struct NoReassocOpConversion mlir::LogicalResult matchAndRewrite(hlfir::NoReassocOp noreassoc, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const override { - rewriter.replaceOpWithNewOp( - noreassoc, getBufferizedExprStorage(adaptor.getVal())); + mlir::Location loc = noreassoc->getLoc(); + auto module = noreassoc->getParentOfType(); + fir::FirOpBuilder builder(rewriter, fir::getKindMapping(module)); + mlir::Value bufferizedExpr = getBufferizedExprStorage(adaptor.getVal()); + mlir::Value result = + builder.create(loc, bufferizedExpr); + + if (!fir::isa_trivial(bufferizedExpr.getType())) { + // NoReassocOp should not be needed on the mustFree path. + mlir::Value mustFree = getBufferizedExprMustFreeFlag(adaptor.getVal()); + result = + packageBufferizedExpr(loc, builder, hlfir::Entity{result}, mustFree); + } + rewriter.replaceOp(noreassoc, result); return mlir::success(); } }; diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp index 0225ac3631b9e..ab1f7417531bd 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp @@ -42,13 +42,11 @@ static mlir::Value genAllocatableTempFromSourceBox(mlir::Location loc, // the RHS. // This has the huge benefit of dealing with all cases, including // polymorphic entities. - mlir::Type fromHeapType = fir::HeapType::get( - fir::unwrapRefType(sourceBox.getType().cast().getEleTy())); + mlir::Type fromHeapType = fir::HeapType::get(fir::unwrapRefType( + sourceBox.getType().cast().getEleTy())); mlir::Type fromBoxHeapType = fir::BoxType::get(fromHeapType); - auto fromMutableBox = builder.createTemporary(loc, fromBoxHeapType); - mlir::Value unallocatedBox = - fir::factory::createUnallocatedBox(builder, loc, fromBoxHeapType, {}); - builder.create(loc, unallocatedBox, fromMutableBox); + mlir::Value fromMutableBox = + fir::factory::genNullBoxStorage(builder, loc, fromBoxHeapType); fir::runtime::genAssign(builder, loc, fromMutableBox, sourceBox); mlir::Value copy = builder.create(loc, fromMutableBox); return copy; diff --git a/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp b/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp index fbf7670413df2..1cf3929c1c043 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp @@ -213,6 +213,38 @@ using SumOpConversion = HlfirReductionIntrinsicConversion; using ProductOpConversion = HlfirReductionIntrinsicConversion; +struct AnyOpConversion : public HlfirIntrinsicConversion { + using HlfirIntrinsicConversion::HlfirIntrinsicConversion; + + mlir::LogicalResult + matchAndRewrite(hlfir::AnyOp any, + mlir::PatternRewriter &rewriter) const override { + fir::KindMapping kindMapping{rewriter.getContext()}; + fir::FirOpBuilder builder{rewriter, kindMapping}; + const mlir::Location &loc = any->getLoc(); + + mlir::Type i32 = builder.getI32Type(); + mlir::Type logicalType = fir::LogicalType::get( + builder.getContext(), builder.getKindMap().defaultLogicalKind()); + llvm::SmallVector inArgs; + inArgs.push_back({any.getMask(), logicalType}); + inArgs.push_back({any.getDim(), i32}); + + auto *argLowering = fir::getIntrinsicArgumentLowering("any"); + llvm::SmallVector args = + this->lowerArguments(any, inArgs, rewriter, argLowering); + + mlir::Type resultType = hlfir::getFortranElementType(any.getType()); + + auto [resultExv, mustBeFreed] = + fir::genIntrinsicCall(builder, loc, "any", resultType, args); + + this->processReturnValue(any, resultExv, mustBeFreed, builder, rewriter); + + return mlir::success(); + } +}; + struct MatmulOpConversion : public HlfirIntrinsicConversion { using HlfirIntrinsicConversion::HlfirIntrinsicConversion; @@ -321,16 +353,15 @@ class LowerHLFIRIntrinsics mlir::ModuleOp module = this->getOperation(); mlir::MLIRContext *context = &getContext(); mlir::RewritePatternSet patterns(context); - patterns - .insert( - context); + patterns.insert(context); mlir::ConversionTarget target(*context); target.addLegalDialect(); target.addIllegalOp(); + hlfir::ProductOp, hlfir::TransposeOp, hlfir::AnyOp>(); target.markUnknownOpDynamicallyLegal( [](mlir::Operation *) { return true; }); if (mlir::failed( diff --git a/flang/lib/Optimizer/Transforms/CMakeLists.txt b/flang/lib/Optimizer/Transforms/CMakeLists.txt index 3f63035a92987..932914e12a231 100644 --- a/flang/lib/Optimizer/Transforms/CMakeLists.txt +++ b/flang/lib/Optimizer/Transforms/CMakeLists.txt @@ -15,7 +15,6 @@ add_flang_library(FIRTransforms SimplifyIntrinsics.cpp AddDebugFoundation.cpp PolymorphicOpConversion.cpp - OpenACC/OpenACCDataOperandConversion.cpp LoopVersioning.cpp DEPENDS diff --git a/flang/lib/Optimizer/Transforms/OpenACC/OpenACCDataOperandConversion.cpp b/flang/lib/Optimizer/Transforms/OpenACC/OpenACCDataOperandConversion.cpp deleted file mode 100644 index a612c4c4641ed..0000000000000 --- a/flang/lib/Optimizer/Transforms/OpenACC/OpenACCDataOperandConversion.cpp +++ /dev/null @@ -1,186 +0,0 @@ -//===- OpenACCDataOperandConversion.cpp - OpenACC data operand conversion -===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "flang/Optimizer/Dialect/FIRDialect.h" -#include "flang/Optimizer/Transforms/Passes.h" -#include "mlir/Conversion/LLVMCommon/Pattern.h" -#include "mlir/Conversion/OpenACCToLLVM/ConvertOpenACCToLLVM.h" -#include "mlir/Dialect/Func/IR/FuncOps.h" -#include "mlir/Dialect/LLVMIR/LLVMDialect.h" -#include "mlir/Dialect/OpenACC/OpenACC.h" -#include "mlir/IR/Builders.h" -#include "mlir/IR/BuiltinOps.h" -#include "mlir/Pass/Pass.h" - -namespace fir { -#define GEN_PASS_DEF_OPENACCDATAOPERANDCONVERSION -#include "flang/Optimizer/Transforms/Passes.h.inc" -} // namespace fir - -#define DEBUG_TYPE "flang-openacc-conversion" -#include "flang/Optimizer/CodeGen/TypeConverter.h" - -using namespace fir; -using namespace mlir; - -//===----------------------------------------------------------------------===// -// Conversion patterns -//===----------------------------------------------------------------------===// - -namespace { - -template -class LegalizeDataOpForLLVMTranslation : public ConvertOpToLLVMPattern { - using ConvertOpToLLVMPattern::ConvertOpToLLVMPattern; - - LogicalResult - matchAndRewrite(Op op, typename Op::Adaptor adaptor, - ConversionPatternRewriter &builder) const override { - Location loc = op.getLoc(); - fir::LLVMTypeConverter &converter = - *static_cast(this->getTypeConverter()); - - unsigned numDataOperands = op.getNumDataOperands(); - - // Keep the non data operands without modification. - auto nonDataOperands = adaptor.getOperands().take_front( - adaptor.getOperands().size() - numDataOperands); - SmallVector convertedOperands; - convertedOperands.append(nonDataOperands.begin(), nonDataOperands.end()); - - // Go over the data operand and legalize them for translation. - for (unsigned idx = 0; idx < numDataOperands; ++idx) { - Value originalDataOperand = op.getDataOperand(idx); - if (auto refTy = - originalDataOperand.getType().dyn_cast()) { - if (refTy.getEleTy().isa()) - return builder.notifyMatchFailure(op, "BaseBoxType not supported"); - mlir::Type convertedType = - converter.convertType(refTy).cast(); - mlir::Value castedOperand = - builder - .create(loc, convertedType, - originalDataOperand) - .getResult(0); - convertedOperands.push_back(castedOperand); - } else { - // Type not supported. - return builder.notifyMatchFailure(op, "expecting a reference type"); - } - } - - if constexpr (std::is_same_v || - std::is_same_v) { - auto newOp = - builder.create(op.getLoc(), TypeRange(), convertedOperands, - op.getOperation()->getAttrs()); - builder.inlineRegionBefore(op.getRegion(), newOp.getRegion(), - newOp.getRegion().end()); - if (failed(builder.convertRegionTypes(&newOp.getOperation()->getRegion(0), - *this->getTypeConverter()))) - return failure(); - builder.eraseOp(op); - } else { - builder.replaceOpWithNewOp(op, TypeRange(), convertedOperands, - op.getOperation()->getAttrs()); - } - - return success(); - } -}; -} // namespace - -namespace { -struct OpenACCDataOperandConversion - : public fir::impl::OpenACCDataOperandConversionBase< - OpenACCDataOperandConversion> { - using Base::Base; - - void runOnOperation() override; -}; -} // namespace - -void OpenACCDataOperandConversion::runOnOperation() { - auto op = getOperation(); - auto *context = op.getContext(); - - // Convert to OpenACC operations with LLVM IR dialect - RewritePatternSet patterns(context); - LowerToLLVMOptions options(context); - options.useOpaquePointers = useOpaquePointers; - fir::LLVMTypeConverter converter( - op.getOperation()->getParentOfType(), true); - patterns.add>(converter); - patterns.add>(converter); - patterns.add>(converter); - patterns.add>(converter); - - ConversionTarget target(*context); - target.addLegalDialect(); - target.addLegalDialect(); - target.addLegalOp(); - - auto allDataOperandsAreConverted = [](ValueRange operands) { - for (Value operand : operands) { - if (!operand.getType().isa()) - return false; - } - return true; - }; - - target.addDynamicallyLegalOp( - [allDataOperandsAreConverted](acc::DataOp op) { - return allDataOperandsAreConverted(op.getCopyOperands()) && - allDataOperandsAreConverted(op.getCopyinOperands()) && - allDataOperandsAreConverted(op.getCopyinReadonlyOperands()) && - allDataOperandsAreConverted(op.getCopyoutOperands()) && - allDataOperandsAreConverted(op.getCopyoutZeroOperands()) && - allDataOperandsAreConverted(op.getCreateOperands()) && - allDataOperandsAreConverted(op.getCreateZeroOperands()) && - allDataOperandsAreConverted(op.getNoCreateOperands()) && - allDataOperandsAreConverted(op.getPresentOperands()) && - allDataOperandsAreConverted(op.getDeviceptrOperands()) && - allDataOperandsAreConverted(op.getAttachOperands()); - }); - - target.addDynamicallyLegalOp( - [allDataOperandsAreConverted](acc::EnterDataOp op) { - return allDataOperandsAreConverted(op.getCopyinOperands()) && - allDataOperandsAreConverted(op.getCreateOperands()) && - allDataOperandsAreConverted(op.getCreateZeroOperands()) && - allDataOperandsAreConverted(op.getAttachOperands()); - }); - - target.addDynamicallyLegalOp( - [allDataOperandsAreConverted](acc::ExitDataOp op) { - return allDataOperandsAreConverted(op.getCopyoutOperands()) && - allDataOperandsAreConverted(op.getDeleteOperands()) && - allDataOperandsAreConverted(op.getDetachOperands()); - }); - - target.addDynamicallyLegalOp( - [allDataOperandsAreConverted](acc::ParallelOp op) { - return allDataOperandsAreConverted(op.getReductionOperands()) && - allDataOperandsAreConverted(op.getCopyOperands()) && - allDataOperandsAreConverted(op.getCopyinOperands()) && - allDataOperandsAreConverted(op.getCopyinReadonlyOperands()) && - allDataOperandsAreConverted(op.getCopyoutOperands()) && - allDataOperandsAreConverted(op.getCopyoutZeroOperands()) && - allDataOperandsAreConverted(op.getCreateOperands()) && - allDataOperandsAreConverted(op.getCreateZeroOperands()) && - allDataOperandsAreConverted(op.getNoCreateOperands()) && - allDataOperandsAreConverted(op.getPresentOperands()) && - allDataOperandsAreConverted(op.getDevicePtrOperands()) && - allDataOperandsAreConverted(op.getAttachOperands()) && - allDataOperandsAreConverted(op.getGangPrivateOperands()) && - allDataOperandsAreConverted(op.getGangFirstPrivateOperands()); - }); - - if (failed(applyPartialConversion(op, target, std::move(patterns)))) - signalPassFailure(); -} diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index cec08e18e44c5..6a5815236768c 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -140,9 +140,35 @@ TYPE_PARSER(construct( TYPE_PARSER(construct( Parser{} / ":", Parser{})) -// OMP 5.0 2.11.4 ALLOCATE ([allocator:] variable-name-list) +// OMP 5.0 2.11.4 allocate-clause -> ALLOCATE ([allocator:] variable-name-list) +// OMP 5.2 2.13.4 allocate-clause -> ALLOCATE ([allocate-modifier +// [, allocate-modifier] :] +// variable-name-list) +// allocate-modifier -> allocator | align TYPE_PARSER(construct( - maybe(construct(scalarIntExpr) / ":"), + maybe( + first( + construct("ALLOCATOR" >> + construct( + parenthesized(construct< + OmpAllocateClause::AllocateModifier::Allocator>( + scalarIntExpr)) / + ",", + "ALIGN" >> parenthesized(construct< + OmpAllocateClause::AllocateModifier::Align>( + scalarIntExpr)))), + construct("ALLOCATOR" >> + parenthesized( + construct( + scalarIntExpr))), + construct("ALIGN" >> + parenthesized( + construct( + scalarIntExpr))), + construct( + construct( + scalarIntExpr))) / + ":"), Parser{})) // 2.13.9 DEPEND (SOURCE | SINK : vec | (IN | OUT | INOUT) : list @@ -310,6 +336,9 @@ TYPE_PARSER( parenthesized(Parser{}))) || "USE_DEVICE_PTR" >> construct(construct( parenthesized(Parser{}))) || + "USE_DEVICE_ADDR" >> + construct(construct( + parenthesized(Parser{}))) || "UNIFIED_ADDRESS" >> construct(construct()) || "UNIFIED_SHARED_MEMORY" >> @@ -562,6 +591,16 @@ TYPE_PARSER( maybe(nonemptyList(Parser{})) / endOmpLine, statement(allocateStmt)))) +// 6.7 Allocators construct [OpenMP 5.2] +// allocators-construct -> ALLOCATORS [allocate-clause [,]] +// allocate-stmt +// [omp-end-allocators-construct] +TYPE_PARSER(sourced(construct( + verbatim("ALLOCATORS"_tok), Parser{} / endOmpLine, + statement(allocateStmt), maybe(Parser{} / endOmpLine)))) + +TYPE_PARSER(construct(startOmpLine >> "END ALLOCATORS"_tok)) + // 2.8.2 Declare Simd construct TYPE_PARSER( sourced(construct(verbatim("DECLARE SIMD"_tok), @@ -638,6 +677,7 @@ TYPE_CONTEXT_PARSER("OpenMP construct"_en_US, construct(Parser{}), construct(Parser{}), construct(Parser{}), + construct(Parser{}), construct(Parser{}), construct(Parser{}))) diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 3b34c4ec89cef..4490f7a7cc57b 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2042,10 +2042,35 @@ class UnparseVisitor { Walk(std::get(x.t)); } void Unparse(const OmpAllocateClause &x) { - Walk(std::get>(x.t)); - Put(":"); + Walk( + std::get>(x.t), ":"); Walk(std::get(x.t)); } + void Unparse(const OmpAllocateClause::AllocateModifier &x) { + common::visit( + common::visitors{ + [&](const OmpAllocateClause::AllocateModifier::Allocator &y) { + Walk(y); + }, + [&](const OmpAllocateClause::AllocateModifier::ComplexModifier &y) { + Word("ALLOCATOR("); + Walk(std::get( + y.t)); + Put(")"); + Put(","); + Walk(std::get(y.t)); + }, + [&](const OmpAllocateClause::AllocateModifier::Align &y) { + Walk(y); + }, + }, + x.u); + } + void Unparse(const OmpAllocateClause::AllocateModifier::Align &x) { + Word("ALIGN("); + Walk(x.v); + Put(")"); + } void Unparse(const OmpOrderClause &x) { Walk(std::get>(x.t), ":"); Walk(std::get(x.t)); @@ -2351,6 +2376,23 @@ class UnparseVisitor { Put("\n"); EndOpenMP(); } + void Unparse(const OmpEndAllocators &x) { + BeginOpenMP(); + Word("!$OMP END ALLOCATE"); + Put("\n"); + EndOpenMP(); + } + void Unparse(const OpenMPAllocatorsConstruct &x) { + BeginOpenMP(); + Word("!$OMP ALLOCATE"); + Walk(std::get(x.t)); + Put("\n"); + EndOpenMP(); + Walk(std::get>(x.t)); + if (const auto &end = std::get>(x.t)) { + Walk(*end); + } + } void Unparse(const OmpCriticalDirective &x) { BeginOpenMP(); Word("!$OMP CRITICAL"); diff --git a/flang/lib/Semantics/check-data.cpp b/flang/lib/Semantics/check-data.cpp index f33258ea7c19a..6916870907a63 100644 --- a/flang/lib/Semantics/check-data.cpp +++ b/flang/lib/Semantics/check-data.cpp @@ -63,7 +63,8 @@ class DataVarChecker : public evaluate::AllTraverse { : IsFunctionResult(symbol) ? "Function result" : IsAllocatable(symbol) ? "Allocatable" : IsInitialized(symbol, true /*ignore DATA*/, - true /*ignore allocatable components*/) + true /*ignore allocatable components*/, + true /*ignore uninitialized pointer components*/) ? "Default-initialized" : IsProcedure(symbol) && !IsPointer(symbol) ? "Procedure" // remaining checks don't apply to components diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index cd30441d5ad1e..eb8de20a6b8ba 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -2806,12 +2806,12 @@ const parser::OmpObjectList *OmpStructureChecker::GetOmpObjectList( const parser::OmpClause &clause) { // Clauses with OmpObjectList as its data member - using MemberObjectListClauses = - std::tuple; + using MemberObjectListClauses = std::tuple; // Clauses with OmpObjectList in the tuple using TupleObjectListClauses = std::tuple()) { - Say("'%s' is not a specific procedure"_err_en_US, symbol.name()); + Say("'%s' is not a specific procedure"_err_en_US, last.name()); } else { return Expr{ProcedureDesignator{symbol}}; } @@ -229,7 +229,7 @@ MaybeExpr ExpressionAnalyzer::Designate(DataRef &&ref) { return Expr{ProcedureDesignator{std::move(intrinsic)}}; } else { Say("'%s' is not an unrestricted specific intrinsic procedure"_err_en_US, - symbol.name()); + last.name()); } return std::nullopt; } else if (MaybeExpr result{AsGenericExpr(std::move(ref))}) { @@ -1475,7 +1475,20 @@ class ArrayConstructorContext { ArrayConstructor result{MakeSpecific(std::move(values_))}; if constexpr (T::category == TypeCategory::Character) { if (auto len{type_->LEN()}) { - if (IsConstantExpr(*len)) { + // The ac-do-variables may be treated as constant expressions, + // if some conditions on ac-implied-do-control hold (10.1.12 (12)). + // At the same time, they may be treated as constant expressions + // only in the context of the ac-implied-do, but setting + // the character length here may result in complete elimination + // of the ac-implied-do. For example: + // character(10) :: c + // ... len([(c(i:i), integer(8)::i = 1,4)]) + // would be evaulated into: + // ... int(max(0_8,i-i+1_8),kind=4) + // with a dangling reference to the ac-do-variable. + // Prevent this by checking for the ac-do-variable references + // in the 'len' expression. + if (!ContainsAnyImpliedDoIndex(*len) && IsConstantExpr(*len)) { result.set_LEN(std::move(*len)); } } @@ -2066,13 +2079,15 @@ MaybeExpr ExpressionAnalyzer::Analyze( if (!symbol.test(Symbol::Flag::ParentComp) && unavailable.find(symbol.name()) == unavailable.cend()) { if (IsAllocatable(symbol)) { - // Set all remaining allocatables to explicit NULL() + // Set all remaining allocatables to explicit NULL(). result.Add(symbol, Expr{NullPointer{}}); - } else if (const auto *details{ - symbol.detailsIf()}) { - if (details->init()) { - result.Add(symbol, common::Clone(*details->init())); - } else { // C799 + } else { + const auto *object{symbol.detailsIf()}; + if (object && object->init()) { + result.Add(symbol, common::Clone(*object->init())); + } else if (IsPointer(symbol)) { + result.Add(symbol, Expr{NullPointer{}}); + } else if (object) { // C799 AttachDeclaration(Say(typeName, "Structure constructor lacks a value for " "component '%s'"_err_en_US, diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index 1052c459632e6..c6cef99042a11 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -441,6 +441,11 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor { return false; } + bool Pre(const parser::OmpClause::UseDeviceAddr &x) { + ResolveOmpObjectList(x.v, Symbol::Flag::OmpUseDeviceAddr); + return false; + } + void Post(const parser::Name &); // Keep track of labels in the statements that causes jumps to target labels @@ -511,7 +516,8 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor { Symbol::Flag::OmpPrivate, Symbol::Flag::OmpLinear, Symbol::Flag::OmpFirstPrivate, Symbol::Flag::OmpLastPrivate, Symbol::Flag::OmpReduction, Symbol::Flag::OmpCriticalLock, - Symbol::Flag::OmpCopyIn, Symbol::Flag::OmpUseDevicePtr}; + Symbol::Flag::OmpCopyIn, Symbol::Flag::OmpUseDevicePtr, + Symbol::Flag::OmpUseDeviceAddr}; static constexpr Symbol::Flags ompFlagsRequireMark{ Symbol::Flag::OmpThreadprivate}; diff --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp index 15a2a67103236..acd3c49b39098 100644 --- a/flang/lib/Semantics/runtime-type-info.cpp +++ b/flang/lib/Semantics/runtime-type-info.cpp @@ -626,8 +626,8 @@ const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) { // instances without any initialized components, analyze the type // and set a flag if there's nothing to do for it at run time. AddValue(dtValues, derivedTypeSchema_, "noinitializationneeded"s, - IntExpr<1>( - derivedTypeSpec && !derivedTypeSpec->HasDefaultInitialization())); + IntExpr<1>(derivedTypeSpec && + !derivedTypeSpec->HasDefaultInitialization(false, false))); // Similarly, a flag to short-circuit destruction when not needed. AddValue(dtValues, derivedTypeSchema_, "nodestructionneeded"s, IntExpr<1>(isAbstractType || diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp index fb2710b54284c..711537ec4947b 100644 --- a/flang/lib/Semantics/tools.cpp +++ b/flang/lib/Semantics/tools.cpp @@ -642,21 +642,23 @@ bool HasDeclarationInitializer(const Symbol &symbol) { } } -bool IsInitialized( - const Symbol &symbol, bool ignoreDataStatements, bool ignoreAllocatable) { +bool IsInitialized(const Symbol &symbol, bool ignoreDataStatements, + bool ignoreAllocatable, bool ignorePointer) { if (!ignoreAllocatable && IsAllocatable(symbol)) { return true; } else if (!ignoreDataStatements && symbol.test(Symbol::Flag::InDataStmt)) { return true; } else if (HasDeclarationInitializer(symbol)) { return true; - } else if (IsNamedConstant(symbol) || IsFunctionResult(symbol) || - IsPointer(symbol)) { + } else if (IsPointer(symbol)) { + return !ignorePointer; + } else if (IsNamedConstant(symbol) || IsFunctionResult(symbol)) { return false; } else if (const auto *object{symbol.detailsIf()}) { if (!object->isDummy() && object->type()) { if (const auto *derived{object->type()->AsDerived()}) { - return derived->HasDefaultInitialization(ignoreAllocatable); + return derived->HasDefaultInitialization( + ignoreAllocatable, ignorePointer); } } } diff --git a/flang/lib/Semantics/type.cpp b/flang/lib/Semantics/type.cpp index d895f01dba2ea..667fdc453687a 100644 --- a/flang/lib/Semantics/type.cpp +++ b/flang/lib/Semantics/type.cpp @@ -179,11 +179,13 @@ bool DerivedTypeSpec::IsForwardReferenced() const { return typeSymbol_.get().isForwardReferenced(); } -bool DerivedTypeSpec::HasDefaultInitialization(bool ignoreAllocatable) const { +bool DerivedTypeSpec::HasDefaultInitialization( + bool ignoreAllocatable, bool ignorePointer) const { DirectComponentIterator components{*this}; return bool{std::find_if( components.begin(), components.end(), [&](const Symbol &component) { - return IsInitialized(component, true, ignoreAllocatable); + return IsInitialized(component, /*ignoreDataStatements=*/true, + ignoreAllocatable, ignorePointer); })}; } diff --git a/flang/module/__fortran_builtins.f90 b/flang/module/__fortran_builtins.f90 index a22aa4699f7ad..1dee77e3c10cf 100644 --- a/flang/module/__fortran_builtins.f90 +++ b/flang/module/__fortran_builtins.f90 @@ -12,6 +12,7 @@ ! standard names of the procedures. module __Fortran_builtins + intrinsic :: __builtin_c_loc intrinsic :: __builtin_c_f_pointer intrinsic :: sizeof ! extension @@ -42,8 +43,6 @@ integer, parameter :: __builtin_atomic_int_kind = selected_int_kind(18) integer, parameter :: __builtin_atomic_logical_kind = __builtin_atomic_int_kind - procedure(type(__builtin_c_ptr)) :: __builtin_c_loc - intrinsic :: __builtin_ieee_is_nan, __builtin_ieee_is_negative, & __builtin_ieee_is_normal intrinsic :: __builtin_ieee_next_after, __builtin_ieee_next_down, & diff --git a/flang/runtime/CMakeLists.txt b/flang/runtime/CMakeLists.txt index 2a7e74c175533..63d7f9bf2a9d6 100644 --- a/flang/runtime/CMakeLists.txt +++ b/flang/runtime/CMakeLists.txt @@ -7,14 +7,7 @@ #===------------------------------------------------------------------------===# if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - cmake_minimum_required(VERSION 3.13.4) - if ("${CMAKE_VERSION}" VERSION_LESS "3.20.0") - message(WARNING - "Your CMake version is ${CMAKE_VERSION}. Starting with LLVM 17.0.0, the " - "minimum version of CMake required to build LLVM will become 3.20.0, and " - "using an older CMake will become an error. Please upgrade your CMake to " - "at least 3.20.0 now to avoid issues in the future!") - endif() + cmake_minimum_required(VERSION 3.20.0) project(FlangRuntime C CXX) diff --git a/flang/runtime/assign.cpp b/flang/runtime/assign.cpp index 88f5500588bfa..f75fe94bf3009 100644 --- a/flang/runtime/assign.cpp +++ b/flang/runtime/assign.cpp @@ -129,9 +129,9 @@ static void MaximalByteOffsetRange( if (extent > 0) { auto sm{dim.ByteStride()}; if (sm < 0) { - least += extent * sm; + least += (extent - 1) * sm; } else { - most += extent * sm; + most += (extent - 1) * sm; } } } @@ -294,6 +294,10 @@ static void Assign( StaticDescriptor staticDesc; Descriptor &newFrom{staticDesc.descriptor()}; std::memcpy(&newFrom, &from, descBytes); + // Pretend the temporary descriptor is for an ALLOCATABLE + // entity, otherwise, the Deallocate() below will not + // free the descriptor memory. + newFrom.raw().attribute = CFI_attribute_allocatable; auto stat{ReturnError(terminator, newFrom.Allocate())}; if (stat == StatOk) { char *toAt{newFrom.OffsetElement()}; diff --git a/flang/runtime/derived.cpp b/flang/runtime/derived.cpp index 981ddb2a6e9d4..814fcfa1e1e7d 100644 --- a/flang/runtime/derived.cpp +++ b/flang/runtime/derived.cpp @@ -58,6 +58,16 @@ int Initialize(const Descriptor &instance, const typeInfo::DerivedType &derived, char *ptr{instance.ZeroBasedIndexedElement(j) + comp.offset()}; std::memcpy(ptr, init, bytes); } + } else if (comp.genre() == typeInfo::Component::Genre::Pointer) { + // Data pointers without explicit initialization are established + // so that they are valid right-hand side targets of pointer + // assignment statements. + for (std::size_t j{0}; j < elements; ++j) { + Descriptor &ptrDesc{*instance.OffsetElement( + j * byteStride + comp.offset())}; + comp.EstablishDescriptor(ptrDesc, instance, terminator); + ptrDesc.raw().attribute = CFI_attribute_pointer; + } } else if (comp.genre() == typeInfo::Component::Genre::Data && comp.derivedType() && !comp.derivedType()->noInitializationNeeded()) { // Default initialization of non-pointer non-allocatable/automatic diff --git a/flang/runtime/type-info.cpp b/flang/runtime/type-info.cpp index 84ec05d02705f..9b624a664a2f5 100644 --- a/flang/runtime/type-info.cpp +++ b/flang/runtime/type-info.cpp @@ -112,7 +112,7 @@ void Component::EstablishDescriptor(Descriptor &descriptor, } else { descriptor.Establish(cat, kind_, nullptr, rank_, nullptr, attribute); } - if (rank_ && genre_ != Genre::Allocatable) { + if (rank_ && genre_ != Genre::Allocatable && genre_ != Genre::Pointer) { const typeInfo::Value *boundValues{bounds()}; RUNTIME_CHECK(terminator, boundValues != nullptr); auto byteStride{static_cast(descriptor.ElementBytes())}; diff --git a/flang/test/Evaluate/rewrite01.f90 b/flang/test/Evaluate/rewrite01.f90 index cbcbfb97189c7..0fa3581a3799f 100644 --- a/flang/test/Evaluate/rewrite01.f90 +++ b/flang/test/Evaluate/rewrite01.f90 @@ -234,10 +234,13 @@ function return_allocatable() subroutine array_ctor_implied_do_index(x, j) integer :: x(:) integer(8) :: j + character(10) :: c !CHECK: PRINT *, size([INTEGER(4)::(x(1_8:i:1_8),INTEGER(8)::i=1_8,2_8,1_8)]) print *, size([(x(1:i), integer(8)::i=1,2)]) !CHECK: PRINT *, int(0_8+2_8*(0_8+max((j-1_8+1_8)/1_8,0_8)),kind=4) print *, size([(x(1:j), integer(8)::i=1,2)]) + !CHECK: PRINT *, len([(c(i:i),INTEGER(8)::i=1_8,4_8,1_8)]) + print *, len([(c(i:i), integer(8)::i = 1,4)]) end subroutine end module diff --git a/flang/test/HLFIR/any-lowering.fir b/flang/test/HLFIR/any-lowering.fir new file mode 100644 index 0000000000000..2c750ce35bd37 --- /dev/null +++ b/flang/test/HLFIR/any-lowering.fir @@ -0,0 +1,162 @@ +// Test hlfir.any operation lowering to fir runtime call +// RUN: fir-opt %s -lower-hlfir-intrinsics | FileCheck %s + +// one argument ANY +func.func @_QPany1(%arg0: !fir.box>> {fir.bindc_name = "a"}, %arg1: !fir.ref> {fir.bindc_name = "s"}) { + %0:2 = hlfir.declare %arg0 {uniq_name = "_QFany1Ea"} : (!fir.box>>) -> (!fir.box>>, !fir.box>>) + %1:2 = hlfir.declare %arg1 {uniq_name = "_QFany1Es"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) + %2 = hlfir.any %0#0 : (!fir.box>>) -> !hlfir.expr> + hlfir.assign %2 to %1#0 : !hlfir.expr>, !fir.ref> + hlfir.destroy %2 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPany1( +// CHECK: %[[ARG0:.*]]: !fir.box>> {fir.bindc_name = "a"} +// CHECK: %[[ARG1:.*]]: !fir.ref> +// CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG0]] +// CHECK-DAG: %[[RES:.*]]:2 = hlfir.declare %[[ARG1]] +// CHECK-DAG: %[[MASK_ARG:.*]] = fir.convert %[[MASK]]#1 : (!fir.box>>) -> !fir.box +// CHECK: %[[RET_ARG:.*]] = fir.call @_FortranAAny(%[[MASK_ARG]], %[[LOC_STR:.*]], %[[LOC_N:.*]], %[[C1:.*]]) : (!fir.box, !fir.ref, i32, i32) -> i1 +// CHECK-NEXT: %[[RET:.*]] = fir.convert %[[RET_ARG]] : (i1) -> !fir.logical<4> +// CHECK-NEXT: hlfir.assign %[[RET]] to %[[RES]]#0 : !fir.logical<4>, !fir.ref> +// CHECK-NEXT: return +// CHECK-NEXT: } + +// ANY with dim argument by-ref +func.func @_QPany2(%arg0: !fir.box>> {fir.bindc_name = "a"}, %arg1: !fir.box>> {fir.bindc_name = "s"}, %arg2: !fir.ref {fir.bindc_name = "d"}) { + %0:2 = hlfir.declare %arg0 {uniq_name = "_QFany2Ea"} : (!fir.box>>) -> (!fir.box>>, !fir.box>>) + %1:2 = hlfir.declare %arg2 {uniq_name = "_QFany2Ed"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %2:2 = hlfir.declare %arg1 {uniq_name = "_QFany2Es"} : (!fir.box>>) -> (!fir.box>>, !fir.box>>) + %3 = fir.load %1#0 : !fir.ref + %4 = hlfir.any %0#0 dim %3 : (!fir.box>>, i32) -> !hlfir.expr> + hlfir.assign %4 to %2#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %4 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPany2( +// CHECK: %[[ARG0:.*]]: !fir.box>> +// CHECK: %[[ARG1:.*]]: !fir.box>> +// CHECK: %[[ARG2:.*]]: !fir.ref +// CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG0]] +// CHECK-DAG: %[[DIM_VAR:.*]]:2 = hlfir.declare %[[ARG2]] +// CHECK-DAG: %[[RES:.*]]:2 = hlfir.declare %[[ARG1]] + +// CHECK-DAG: %[[RET_BOX:.*]] = fir.alloca !fir.box>>> +// CHECK-DAG: %[[RET_ADDR:.*]] = fir.zero_bits !fir.heap>> +// CHECK-DAG: %[[C0:.*]] = arith.constant 0 : index +// CHECK-DAG: %[[RET_SHAPE:.*]] = fir.shape %[[C0]] : (index) -> !fir.shape<1> +// CHECK-DAG: %[[RET_EMBOX:.*]] = fir.embox %[[RET_ADDR]](%[[RET_SHAPE]]) +// CHECK-DAG: fir.store %[[RET_EMBOX]] to %[[RET_BOX]] + +// CHECK-DAG: %[[DIM:.*]] = fir.load %[[DIM_VAR]]#0 : !fir.ref +// CHECK-DAG: %[[RET_ARG:.*]] = fir.convert %[[RET_BOX]] +// CHECK-DAG: %[[MASK_ARG:.*]] = fir.convert %[[MASK]]#1 + +// CHECK: %[[NONE:.*]] = fir.call @_FortranAAnyDim(%[[RET_ARG]], %[[MASK_ARG]], %[[DIM]], %[[LOC_STR:.*]], %[[LOC_N:.*]]) : (!fir.ref>, !fir.box, i32, !fir.ref, i32) -> none +// CHECK: %[[RET:.*]] = fir.load %[[RET_BOX]] +// CHECK: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[RET]] +// CHECK-NEXT: %[[ADDR:.*]] = fir.box_addr %[[RET]] +// CHECK-NEXT: %[[SHIFT:.*]] = fir.shape_shift %[[BOX_DIMS]]#0, %[[BOX_DIMS]]#1 +// CHECK-NEXT: %[[TMP:.*]]:2 = hlfir.declare %[[ADDR]](%[[SHIFT]]) {uniq_name = ".tmp.intrinsic_result"} +// CHECK: %[[TRUE:.*]] = arith.constant true +// CHECK: %[[EXPR:.*]] = hlfir.as_expr %[[TMP]]#0 move %[[TRUE]] : (!fir.box>>, i1) -> !hlfir.expr> +// CHECK: hlfir.assign %[[EXPR]] to %[[RES]]#0 +// CHECK: hlfir.destroy %[[EXPR]] +// CHECK-NEXT: return +// CHECK-NEXT: } + +// any with DIM argument by-val, mask isn't boxed +func.func @_QPany3(%arg0: !fir.ref>> {fir.bindc_name = "s"}) { + %0 = fir.address_of(@_QFany3Ea) : !fir.ref>> + %c2 = arith.constant 2 : index + %c2_0 = arith.constant 2 : index + %1 = fir.shape %c2, %c2_0 : (index, index) -> !fir.shape<2> + %2:2 = hlfir.declare %0(%1) {uniq_name = "_QFany3Ea"} : (!fir.ref>>, !fir.shape<2>) -> (!fir.ref>>, !fir.ref>>) + %c2_1 = arith.constant 2 : index + %3 = fir.shape %c2_1 : (index) -> !fir.shape<1> + %4:2 = hlfir.declare %arg0(%3) {uniq_name = "_QFany3Es"} : (!fir.ref>>, !fir.shape<1>) -> (!fir.ref>>, !fir.ref>>) + %c1_i32 = arith.constant 1 : i32 + %5 = hlfir.any %2#0 dim %c1_i32 : (!fir.ref>>, i32) -> !hlfir.expr<2x!fir.logical<4>> + hlfir.assign %5 to %4#0 : !hlfir.expr<2x!fir.logical<4>>, !fir.ref>> + hlfir.destroy %5 : !hlfir.expr<2x!fir.logical<4>> + return +} +// CHECK-LABEL: func.func @_QPany3( +// CHECK: %[[ARG0:.*]]: !fir.ref>> +// CHECK-DAG: %[[RET_BOX:.*]] = fir.alloca !fir.box>>> +// CHECK-DAG: %[[RET_ADDR:.*]] = fir.zero_bits !fir.heap>> +// CHECK-DAG: %[[C0:.*]] = arith.constant 0 : index +// CHECK-DAG: %[[RET_SHAPE:.*]] = fir.shape %[[C0]] : (index) -> !fir.shape<1> +// CHECK-DAG: %[[RET_EMBOX:.*]] = fir.embox %[[RET_ADDR]](%[[RET_SHAPE]]) +// CHECK-DAG: fir.store %[[RET_EMBOX]] to %[[RET_BOX]] +// CHECK-DAG: %[[RES:.*]]:2 = hlfir.declare %[[ARG0]](%[[RES_SHAPE:.*]]) + +// CHECK-DAG: %[[MASK_ADDR:.*]] = fir.address_of +// CHECK-DAG: %[[MASK_VAR:.*]]:2 = hlfir.declare %[[MASK_ADDR]](%[[MASK_SHAPE:.*]]) +// CHECK-DAG: %[[MASK_BOX:.*]] = fir.embox %[[MASK_VAR]]#1(%[[MASK_SHAPE:.*]]) + +// CHECK-DAG: %[[DIM:.*]] = arith.constant 1 : i32 + +// CHECK-DAG: %[[RET_ARG:.*]] = fir.convert %[[RET_BOX]] +// CHECK-DAG: %[[MASK_ARG:.*]] = fir.convert %[[MASK_BOX]] : (!fir.box>>) -> !fir.box +// CHECK: %[[NONE:.*]] = fir.call @_FortranAAnyDim(%[[RET_ARG]], %[[MASK_ARG]], %[[DIM]], %[[LOC_STR:.*]], %[[LOC_N:.*]]) +// CHECK: %[[RET:.*]] = fir.load %[[RET_BOX]] +// CHECK: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[RET]] +// CHECK-NEXT: %[[ADDR:.*]] = fir.box_addr %[[RET]] +// CHECK-NEXT: %[[SHIFT:.*]] = fir.shape_shift %[[BOX_DIMS]]#0, %[[BOX_DIMS]]#1 +// CHECK-NEXT: %[[TMP:.*]]:2 = hlfir.declare %[[ADDR]](%[[SHIFT]]) {uniq_name = ".tmp.intrinsic_result"} +// CHECK: %[[TRUE:.*]] = arith.constant true +// CHECK: %[[EXPR:.*]] = hlfir.as_expr %[[TMP]]#0 move %[[TRUE]] : (!fir.box>>, i1) -> !hlfir.expr> +// CHECK: hlfir.assign %[[EXPR]] to %[[RES]] +// CHECK: hlfir.destroy %[[EXPR]] +// CHECK-NEXT: return +// CHECK-NEXT: } + +// any with dim from pointer +func.func @_QPany4(%arg0: !fir.box>> {fir.bindc_name = "a"}, %arg1: !fir.box>> {fir.bindc_name = "s"}, %arg2: !fir.ref>> {fir.bindc_name = "d"}) { + %0:2 = hlfir.declare %arg0 {uniq_name = "_QFany4Ea"} : (!fir.box>>) -> (!fir.box>>, !fir.box>>) + %1:2 = hlfir.declare %arg2 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFany4Ed"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) + %2:2 = hlfir.declare %arg1 {uniq_name = "_QFany4Es"} : (!fir.box>>) -> (!fir.box>>, !fir.box>>) + %3 = fir.load %1#0 : !fir.ref>> + %4 = fir.box_addr %3 : (!fir.box>) -> !fir.ptr + %5 = fir.load %4 : !fir.ptr + %6 = hlfir.no_reassoc %5 : i32 + %7 = hlfir.any %0#0 dim %6 : (!fir.box>>, i32) -> !hlfir.expr> + hlfir.assign %7 to %2#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %7 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPany4( +// CHECK: %[[ARG0:.*]]: !fir.box>> +// CHECK: %[[ARG1:.*]]: !fir.box>> +// CHECK: %[[ARG2:.*]]: !fir.ref>> +// CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG0]] +// CHECK-DAG: %[[DIM_ARG:.*]]:2 = hlfir.declare %[[ARG2]] +// CHECK-DAG: %[[RES:.*]]:2 = hlfir.declare %[[ARG1]] + +// CHECK-DAG: %[[RET_BOX:.*]] = fir.alloca !fir.box>>> +// CHECK-DAG: %[[DIM_PTR:.*]] = fir.load %[[DIM_ARG]]#0 : !fir.ref>> +// CHECK-DAG: %[[DIM_ADDR:.*]] = fir.box_addr %[[DIM_PTR]] +// CHECK-DAG: %[[DIM_VAR:.*]] = fir.load %[[DIM_ADDR]] +// CHECK-DAG: %[[DIM:.*]] = hlfir.no_reassoc %[[DIM_VAR]] + +// CHECK-DAG: %[[C0:.*]] = arith.constant 0 : index +// CHECK-DAG: %[[RET_ADDR:.*]] = fir.zero_bits !fir.heap>> +// CHECK-DAG: %[[RET_SHAPE:.*]] = fir.shape %[[C0]] : (index) -> !fir.shape<1> +// CHECK-DAG: %[[RET_EMBOX:.*]] = fir.embox %[[RET_ADDR]](%[[RET_SHAPE]]) +// CHECK-DAG: fir.store %[[RET_EMBOX]] to %[[RET_BOX]] +// CHECK-DAG: %[[RET_ARG:.*]] = fir.convert %[[RET_BOX]] +// CHECK-DAG: %[[MASK_ARG:.*]] = fir.convert %[[MASK]]#1 + +// CHECK: %[[NONE:.*]] = fir.call @_FortranAAnyDim(%[[RET_ARG]], %[[MASK_ARG]], %[[DIM]], %[[LOC_STR:.*]], %[[LOC_N:.*]]) : (!fir.ref>, !fir.box, i32, !fir.ref, i32) -> none +// CHECK: %[[RET:.*]] = fir.load %[[RET_BOX]] +// CHECK: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[RET]] +// CHECK-NEXT: %[[ADDR:.*]] = fir.box_addr %[[RET]] +// CHECK-NEXT: %[[SHIFT:.*]] = fir.shape_shift %[[BOX_DIMS]]#0, %[[BOX_DIMS]]#1 +// CHECK-NEXT: %[[TMP:.*]]:2 = hlfir.declare %[[ADDR]](%[[SHIFT]]) {uniq_name = ".tmp.intrinsic_result"} +// CHECK: %[[TRUE:.*]] = arith.constant true +// CHECK: %[[EXPR:.*]] = hlfir.as_expr %[[TMP]]#0 move %[[TRUE]] : (!fir.box>>, i1) -> !hlfir.expr> +// CHECK: hlfir.assign %[[EXPR]] to %[[RES]] +// CHECK: hlfir.destroy %[[EXPR]] +// CHECK-NEXT: return +// CHECK-NEXT: } diff --git a/flang/test/HLFIR/any.fir b/flang/test/HLFIR/any.fir new file mode 100644 index 0000000000000..cccbf831f3061 --- /dev/null +++ b/flang/test/HLFIR/any.fir @@ -0,0 +1,113 @@ +// Test hlfir.product operation parse, verify (no errors), and unparse + +// RUN: fir-opt %s | fir-opt | FileCheck %s + +// mask is an expression of known shape +func.func @any0(%arg0: !hlfir.expr<2x!fir.logical<4>>) { + %any = hlfir.any %arg0 : (!hlfir.expr<2x!fir.logical<4>>) -> !hlfir.expr> + return +} +// CHECK: func.func @any0(%[[ARRAY:.*]]: !hlfir.expr<2x!fir.logical<4>>) { +// CHECK-NEXT: %[[ANY:.*]] = hlfir.any %[[ARRAY]] : (!hlfir.expr<2x!fir.logical<4>>) -> !hlfir.expr> +// CHECK-NEXT: return +// CHECK-NEXT: } + +// mask is an expression of assumed shape +func.func @any1(%arg0: !hlfir.expr>) { + %any = hlfir.any %arg0 : (!hlfir.expr>) -> !hlfir.expr> + return +} +// CHECK: func.func @any1(%[[ARRAY:.*]]: !hlfir.expr>) { +// CHECK-NEXT: %[[ANY:.*]] = hlfir.any %[[ARRAY]] : (!hlfir.expr>) -> !hlfir.expr> +// CHECK-NEXT: return +// CHECK-NEXT: } + +// mask is a boxed array +func.func @any2(%arg0: !fir.box>>) { + %any = hlfir.any %arg0 : (!fir.box>>) -> !hlfir.expr> + return +} +// CHECK: func.func @any2(%[[ARRAY:.*]]: !fir.box>>) { +// CHECK-NEXT: %[[ANY:.*]] = hlfir.any %[[ARRAY]] : (!fir.box>>) -> !hlfir.expr> +// CHECK-NEXT: return +// CHECK-NEXT: } + +// mask is an assumed shape boxed array +func.func @any3(%arg0: !fir.box>>){ + %any = hlfir.any %arg0 : (!fir.box>>) -> !hlfir.expr> + return +} +// CHECK: func.func @any3(%[[ARRAY:.*]]: !fir.box>>) { +// CHECK-NEXT: %[[ANY:.*]] = hlfir.any %[[ARRAY]] : (!fir.box>>) -> !hlfir.expr> +// CHECK-NEXT: return +// CHECK-NEXT: } + +// mask is a 2-dimensional array +func.func @any4(%arg0: !fir.box>>){ + %any = hlfir.any %arg0 : (!fir.box>>) -> !hlfir.expr> + return +} +// CHECK: func.func @any4(%[[ARRAY:.*]]: !fir.box>>) { +// CHECK-NEXT: %[[ANY:.*]] = hlfir.any %[[ARRAY]] : (!fir.box>>) -> !hlfir.expr> +// CHECK-NEXT: return +// CHECK-NEXT: } + +// mask and dim argument +func.func @any5(%arg0: !fir.box>>, %arg1: i32) { + %any = hlfir.any %arg0 dim %arg1 : (!fir.box>>, i32) -> !hlfir.expr> + return +} +// CHECK: func.func @any5(%[[ARRAY:.*]]: !fir.box>>, %[[DIM:.*]]: i32) { +// CHECK-NEXT: %[[ANY:.*]] = hlfir.any %[[ARRAY]] dim %[[DIM]] : (!fir.box>>, i32) -> !hlfir.expr> +// CHECK-NEXT: return +// CHECK-NEXT: } + +// hlfir.any with dim argument with an unusual type +func.func @any6(%arg0: !fir.box>>, %arg1: index) { + %any = hlfir.any %arg0 dim %arg1 : (!fir.box>>, index) -> !hlfir.expr> + return +} +// CHECK: func.func @any6(%[[ARRAY:.*]]: !fir.box>>, %[[DIM:.*]]: index) { +// CHECK-NEXT: %[[ANY:.*]] = hlfir.any %[[ARRAY]] dim %[[DIM]] : (!fir.box>>, index) -> !hlfir.expr> +// CHECK-NEXT: return +// CHECK-NEXT: } + +// mask is a 2 dimensional array with dim +func.func @any7(%arg0: !fir.box>>, %arg1: i32) { + %any = hlfir.any %arg0 dim %arg1 : (!fir.box>>, i32) -> !hlfir.expr> + return +} +// CHECK: func.func @any7(%[[ARRAY:.*]]: !fir.box>>, %[[DIM:.*]]: i32) { +// CHECK-NEXT: %[[ANY:.*]] = hlfir.any %[[ARRAY]] dim %[[DIM]] : (!fir.box>>, i32) -> !hlfir.expr> +// CHECK-NEXT: return +// CHECK-NEXT: } + +// known shape expr return +func.func @any8(%arg0: !fir.box>>, %arg1: i32) { + %any = hlfir.any %arg0 dim %arg1 : (!fir.box>>, i32) -> !hlfir.expr<2x!fir.logical<4>> + return +} +// CHECK: func.func @any8(%[[ARRAY:.*]]: !fir.box>>, %[[DIM:.*]]: i32) { +// CHECK-NEXT: %[[ANY:.*]] = hlfir.any %[[ARRAY]] dim %[[DIM]] : (!fir.box>>, i32) -> !hlfir.expr<2x!fir.logical<4>> +// CHECK-NEXT: return +// CHECK-NEXT: } + +// hlfir.any with mask argument of ref> type +func.func @any9(%arg0: !fir.ref>>) { + %any = hlfir.any %arg0 : (!fir.ref>>) -> !hlfir.expr> + return +} +// CHECK: func.func @any9(%[[ARRAY:.*]]: !fir.ref>>) { +// CHECK-NEXT: %[[ANY:.*]] = hlfir.any %[[ARRAY]] : (!fir.ref>>) -> !hlfir.expr> +// CHECK-NEXT: return +// CHECK-NEXT: } + +// hlfir.any with fir.logical<8> type +func.func @any10(%arg0: !fir.box>>) { + %any = hlfir.any %arg0 : (!fir.box>>) -> !hlfir.expr> + return +} +// CHECK: func.func @any10(%[[ARRAY:.*]]: !fir.box>>) { +// CHECK-NEXT: %[[ANY:.*]] = hlfir.any %[[ARRAY]] : (!fir.box>>) -> !hlfir.expr> +// CHECK-NEXT: return +// CHECK-NEXT: } diff --git a/flang/test/HLFIR/apply-codegen.fir b/flang/test/HLFIR/apply-codegen.fir index 400637dc99eb6..aebe2c0e410f0 100644 --- a/flang/test/HLFIR/apply-codegen.fir +++ b/flang/test/HLFIR/apply-codegen.fir @@ -25,3 +25,7 @@ func.func @character_apply(%arg0 : !fir.ref>>, %l: i // CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) typeparams %[[VAL_1:.*]] {uniq_name = ".tmp"} // CHECK: %[[VAL_11:.*]] = arith.constant 42 : index // CHECK: %[[VAL_12:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_11]]) typeparams %[[VAL_1]] : (!fir.box>>, index, index) -> !fir.boxchar<2> +// CHECK: %[[VAL_13:.*]] = arith.constant false +// CHECK: %[[VAL_14:.*]] = fir.undefined tuple, i1> +// CHECK: %[[VAL_15:.*]] = fir.insert_value %[[VAL_14]], %[[VAL_13]], [1 : index] : (tuple, i1>, i1) -> tuple, i1> +// CHECK: %[[VAL_16:.*]] = fir.insert_value %[[VAL_15]], %[[VAL_12]], [0 : index] : (tuple, i1>, !fir.boxchar<2>) -> tuple, i1> diff --git a/flang/test/HLFIR/associate-codegen.fir b/flang/test/HLFIR/associate-codegen.fir index a151e7ca5368c..5127f78e783cc 100644 --- a/flang/test/HLFIR/associate-codegen.fir +++ b/flang/test/HLFIR/associate-codegen.fir @@ -53,31 +53,61 @@ func.func @associate_logical() { func.func @associate_char(%arg0: !fir.boxchar<1> ) { + %c1 = arith.constant 1 : index %0:2 = fir.unboxchar %arg0 : (!fir.boxchar<1>) -> (!fir.ref>, index) %1:2 = hlfir.declare %0#0 typeparams %0#1 {uniq_name = "x"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) - %2 = arith.addi %0#1, %0#1 : index - %3 = hlfir.concat %1#0, %1#0 len %2 : (!fir.boxchar<1>, !fir.boxchar<1>, index) -> !hlfir.expr> - %4:3 = hlfir.associate %3 typeparams %2 {uniq_name = "x"} : (!hlfir.expr>, index) -> (!fir.boxchar<1>, !fir.ref>, i1) - fir.call @take_c(%4#0) : (!fir.boxchar<1>) -> () - hlfir.end_associate %4#1, %4#2 : !fir.ref>, i1 + %2 = arith.addi %0#1, %c1 : index + %3 = fir.undefined !fir.ref> + %4:2 = hlfir.declare %3 typeparams %c1 {fortran_attrs = #fir.var_attrs, uniq_name = "char_literal"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) + %5 = hlfir.concat %1#0, %4#0 len %2 : (!fir.boxchar<1>, !fir.ref>, index) -> !hlfir.expr> + %6 = hlfir.no_reassoc %5 : !hlfir.expr> + %7:3 = hlfir.associate %6 typeparams %2 {uniq_name = "x"} : (!hlfir.expr>, index) -> (!fir.boxchar<1>, !fir.ref>, i1) + fir.call @take_c(%7#0) : (!fir.boxchar<1>) -> () + hlfir.end_associate %7#1, %7#2 : !fir.ref>, i1 return } -// CHECK-LABEL: func.func @associate_char( -// CHECK-SAME: %[[VAL_0:.*]]: !fir.boxchar<1>) { -// CHECK: %[[VAL_1:.*]]:2 = fir.unboxchar %[[VAL_0]] : (!fir.boxchar<1>) -> (!fir.ref>, index) -// CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]]#0 typeparams %[[VAL_1]]#1 {uniq_name = "x"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) -// CHECK: %[[VAL_3:.*]] = arith.addi %[[VAL_1]]#1, %[[VAL_1]]#1 : index -// CHECK: %[[VAL_4:.*]] = arith.addi %[[VAL_1]]#1, %[[VAL_1]]#1 : index -// CHECK: %[[VAL_5:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_4]] : index) {bindc_name = ".chrtmp"} -// CHECK: fir.call @llvm.memmove.p0.p0.i64 -// CHECK: %[[VAL_21:.*]]:2 = hlfir.declare %[[VAL_5]] typeparams %[[VAL_4]] {uniq_name = "tmp"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) -// CHECK: %[[VAL_22:.*]] = arith.constant false -// CHECK: %[[VAL_23:.*]] = fir.undefined tuple, i1> -// CHECK: %[[VAL_24:.*]] = fir.insert_value %[[VAL_23]], %[[VAL_22]], [1 : index] : (tuple, i1>, i1) -> tuple, i1> -// CHECK: %[[VAL_25:.*]] = fir.insert_value %[[VAL_24]], %[[VAL_21]]#0, [0 : index] : (tuple, i1>, !fir.boxchar<1>) -> tuple, i1> -// CHECK: fir.call @take_c(%[[VAL_21]]#0) : (!fir.boxchar<1>) -> () -// CHECK-NOT: fir.freemem +// CHECK-LABEL: func.func @associate_char( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.boxchar<1>) { +// CHECK: %[[VAL_1:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_2:.*]]:2 = fir.unboxchar %[[VAL_0]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]]#0 typeparams %[[VAL_2]]#1 {uniq_name = "x"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) +// CHECK: %[[VAL_4:.*]] = arith.addi %[[VAL_2]]#1, %[[VAL_1]] : index +// CHECK: %[[VAL_5:.*]] = fir.undefined !fir.ref> +// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] typeparams %[[VAL_1]] {fortran_attrs = #fir.var_attrs, uniq_name = "char_literal"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +// CHECK: %[[VAL_7:.*]] = arith.addi %[[VAL_2]]#1, %[[VAL_1]] : index +// CHECK: %[[VAL_8:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_7]] : index) {bindc_name = ".chrtmp"} +// CHECK: %[[VAL_9:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_2]]#1 : (index) -> i64 +// CHECK: %[[VAL_11:.*]] = arith.muli %[[VAL_9]], %[[VAL_10]] : i64 +// CHECK: %[[VAL_12:.*]] = arith.constant false +// CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_8]] : (!fir.ref>) -> !fir.ref +// CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_3]]#1 : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @llvm.memmove.p0.p0.i64(%[[VAL_13]], %[[VAL_14]], %[[VAL_11]], %[[VAL_12]]) : (!fir.ref, !fir.ref, i64, i1) -> () +// CHECK: %[[VAL_15:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_16:.*]] = arith.subi %[[VAL_7]], %[[VAL_15]] : index +// CHECK: fir.do_loop %[[VAL_17:.*]] = %[[VAL_2]]#1 to %[[VAL_16]] step %[[VAL_15]] { +// CHECK: %[[VAL_18:.*]] = arith.subi %[[VAL_17]], %[[VAL_2]]#1 : index +// CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_6]]#1 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_20:.*]] = fir.coordinate_of %[[VAL_19]], %[[VAL_18]] : (!fir.ref>>, index) -> !fir.ref> +// CHECK: %[[VAL_21:.*]] = fir.load %[[VAL_20]] : !fir.ref> +// CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_8]] : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_23:.*]] = fir.coordinate_of %[[VAL_22]], %[[VAL_17]] : (!fir.ref>>, index) -> !fir.ref> +// CHECK: fir.store %[[VAL_21]] to %[[VAL_23]] : !fir.ref> +// CHECK: } +// CHECK: %[[VAL_24:.*]]:2 = hlfir.declare %[[VAL_8]] typeparams %[[VAL_7]] {uniq_name = "tmp"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) +// CHECK: %[[VAL_25:.*]] = arith.constant false +// CHECK: %[[VAL_26:.*]] = fir.undefined tuple, i1> +// CHECK: %[[VAL_27:.*]] = fir.insert_value %[[VAL_26]], %[[VAL_25]], [1 : index] : (tuple, i1>, i1) -> tuple, i1> +// CHECK: %[[VAL_28:.*]] = fir.insert_value %[[VAL_27]], %[[VAL_24]]#0, [0 : index] : (tuple, i1>, !fir.boxchar<1>) -> tuple, i1> +// CHECK: %[[VAL_29:.*]] = hlfir.no_reassoc %[[VAL_24]]#0 : !fir.boxchar<1> +// CHECK: %[[VAL_30:.*]] = fir.undefined tuple, i1> +// CHECK: %[[VAL_31:.*]] = fir.insert_value %[[VAL_30]], %[[VAL_25]], [1 : index] : (tuple, i1>, i1) -> tuple, i1> +// CHECK: %[[VAL_32:.*]] = fir.insert_value %[[VAL_31]], %[[VAL_29]], [0 : index] : (tuple, i1>, !fir.boxchar<1>) -> tuple, i1> +// CHECK: %[[VAL_33:.*]] = fir.box_addr %[[VAL_29]] : (!fir.boxchar<1>) -> !fir.ref> +// CHECK: fir.call @take_c(%[[VAL_29]]) : (!fir.boxchar<1>) -> () +// CHECK: return +// CHECK: } func.func @test_end_associate_box(%var: !fir.box>) { %true = arith.constant 1 : i1 @@ -143,6 +173,27 @@ func.func @test_result_convert(%x : !fir.heap>) { // CHECK: fir.call @bar2(%[[ADDR]]) : (!fir.ref>) -> () +func.func @test_0dim_box(%x : !fir.ref>>) { + %0 = fir.load %x : !fir.ref>> + %1:2 = hlfir.declare %0 {uniq_name = ".tmp.intrinsic_result"} : (!fir.box>) -> (!fir.box>, !fir.box>) + %true = arith.constant true + %2 = hlfir.as_expr %1#0 move %true : (!fir.box>, i1) -> !hlfir.expr + %3:3 = hlfir.associate %2 {uniq_name = "adapt.valuebyref"} : (!hlfir.expr) -> (!fir.ref, !fir.ref, i1) + return +} +// CHECK-LABEL: func.func @test_0dim_box( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>>) { +// CHECK: %[[VAL_1:.*]] = fir.load %[[VAL_0]] : !fir.ref>> +// CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = ".tmp.intrinsic_result"} : (!fir.box>) -> (!fir.box>, !fir.box>) +// CHECK: %[[VAL_3:.*]] = arith.constant true +// CHECK: %[[VAL_4:.*]] = fir.undefined tuple>, i1> +// CHECK: %[[VAL_5:.*]] = fir.insert_value %[[VAL_4]], %[[VAL_3]], [1 : index] : (tuple>, i1>, i1) -> tuple>, i1> +// CHECK: %[[VAL_6:.*]] = fir.insert_value %[[VAL_5]], %[[VAL_2]]#0, [0 : index] : (tuple>, i1>, !fir.box>) -> tuple>, i1> +// CHECK: %[[VAL_7:.*]] = fir.box_addr %[[VAL_2]]#0 : (!fir.box>) -> !fir.ref +// CHECK: %[[VAL_8:.*]] = fir.box_addr %[[VAL_2]]#1 : (!fir.box>) -> !fir.ref +// CHECK: return +// CHECK: } + func.func private @take_i4(!fir.ref) func.func private @take_r4(!fir.ref) func.func private @take_l4(!fir.ref>) diff --git a/flang/test/HLFIR/bufferize01.fir b/flang/test/HLFIR/bufferize01.fir new file mode 100644 index 0000000000000..81f8f2cd6a7e1 --- /dev/null +++ b/flang/test/HLFIR/bufferize01.fir @@ -0,0 +1,145 @@ +// RUN: fir-opt --bufferize-hlfir --split-input-file %s | FileCheck %s + +// ----- + +// Bufferization for hlfir.apply and hlfir.no_reassoc must establish +// the tuple properly, so that the users have +// access to both components. + +// CHECK-LABEL: func.func @_QPtest1() { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i32 +// CHECK: %[[VAL_1:.*]] = arith.constant 80 : i32 +// CHECK: %[[VAL_2:.*]] = arith.constant true +// CHECK: %[[VAL_3:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_5:.*]] = fir.alloca !fir.array<10xi64> {bindc_name = ".rt.arrayctor.vector"} +// CHECK: %[[VAL_6:.*]] = fir.alloca !fir.box>>> {bindc_name = ".tmp.arrayctor"} +// CHECK: %[[VAL_7:.*]] = fir.alloca !fir.box>> {bindc_name = "w", uniq_name = "_QFtest1Ew"} +// CHECK: %[[VAL_8:.*]] = fir.zero_bits !fir.heap> +// CHECK: %[[VAL_9:.*]] = fir.embox %[[VAL_8]] typeparams %[[VAL_4]] : (!fir.heap>, index) -> !fir.box>> +// CHECK: fir.store %[[VAL_9]] to %[[VAL_7]] : !fir.ref>>> +// CHECK: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_7]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest1Ew"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) +// CHECK: %[[VAL_11:.*]] = fir.zero_bits !fir.heap>> +// CHECK: %[[VAL_12:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_13:.*]] = fir.embox %[[VAL_11]](%[[VAL_12]]) typeparams %[[VAL_4]] : (!fir.heap>>, !fir.shape<1>, index) -> !fir.box>>> +// CHECK: fir.store %[[VAL_13]] to %[[VAL_6]] : !fir.ref>>>> +// CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_5]] : (!fir.ref>) -> !fir.llvm_ptr +// CHECK: %[[VAL_15:.*]] = fir.address_of(@_QQcl.ce30ef70ff16a711a97719fb946c0b3d) : !fir.ref> +// CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_6]] : (!fir.ref>>>>) -> !fir.ref> +// CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_15]] : (!fir.ref>) -> !fir.ref +// CHECK: %[[VAL_18:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_14]], %[[VAL_16]], %[[VAL_2]], %[[VAL_1]], %[[VAL_17]], %[[VAL_0]]) fastmath : (!fir.llvm_ptr, !fir.ref>, i1, i32, !fir.ref, i32) -> none +// CHECK: %[[VAL_19:.*]] = fir.load %[[VAL_10]]#0 : !fir.ref>>> +// CHECK: %[[VAL_20:.*]] = fir.box_addr %[[VAL_19]] : (!fir.box>>) -> !fir.heap> +// CHECK: %[[VAL_21:.*]] = fir.load %[[VAL_10]]#0 : !fir.ref>>> +// CHECK: %[[VAL_22:.*]] = fir.box_elesize %[[VAL_21]] : (!fir.box>>) -> index +// CHECK: %[[VAL_23:.*]] = fir.emboxchar %[[VAL_20]], %[[VAL_22]] : (!fir.heap>, index) -> !fir.boxchar<1> +// CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_10]]#0 : !fir.ref>>> +// CHECK: %[[VAL_25:.*]] = fir.box_elesize %[[VAL_24]] : (!fir.box>>) -> index +// CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_25]] : (index) -> i64 +// CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_26]] : (i64) -> index +// CHECK: %[[VAL_28:.*]] = arith.cmpi sgt, %[[VAL_27]], %[[VAL_4]] : index +// CHECK: %[[VAL_29:.*]] = arith.select %[[VAL_28]], %[[VAL_27]], %[[VAL_4]] : index +// CHECK: %[[VAL_30:.*]] = hlfir.designate %[[VAL_23]] substr %[[VAL_3]], %[[VAL_27]] typeparams %[[VAL_29]] : (!fir.boxchar<1>, index, index, index) -> !fir.boxchar<1> +// CHECK: %[[VAL_31:.*]]:2 = fir.unboxchar %[[VAL_30]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_32:.*]] = fir.embox %[[VAL_31]]#0 typeparams %[[VAL_29]] : (!fir.ref>, index) -> !fir.box> +// CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_34:.*]] = fir.call @_FortranAPushArrayConstructorValue(%[[VAL_14]], %[[VAL_33]]) fastmath : (!fir.llvm_ptr, !fir.box) -> none +// CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_6]] : !fir.ref>>>> +// CHECK: %[[VAL_36:.*]] = fir.undefined tuple>>>, i1> +// CHECK: %[[VAL_37:.*]] = fir.insert_value %[[VAL_36]], %[[VAL_2]], [1 : index] : (tuple>>>, i1>, i1) -> tuple>>>, i1> +// CHECK: %[[VAL_38:.*]] = fir.insert_value %[[VAL_37]], %[[VAL_35]], [0 : index] : (tuple>>>, i1>, !fir.box>>>) -> tuple>>>, i1> +// CHECK: %[[VAL_39:.*]] = fir.box_elesize %[[VAL_35]] : (!fir.box>>>) -> index +// CHECK: %[[VAL_40:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_41:.*]] = fir.allocmem !fir.array<1x!fir.char<1,?>>(%[[VAL_39]] : index) {bindc_name = ".tmp.array", uniq_name = ""} +// CHECK: %[[VAL_42:.*]]:2 = hlfir.declare %[[VAL_41]](%[[VAL_40]]) typeparams %[[VAL_39]] {uniq_name = ".tmp.array"} : (!fir.heap>>, !fir.shape<1>, index) -> (!fir.box>>, !fir.heap>>) +// CHECK: %[[VAL_43:.*]] = arith.constant true +// CHECK: %[[VAL_44:.*]] = arith.constant 1 : index +// CHECK: fir.do_loop %[[VAL_45:.*]] = %[[VAL_44]] to %[[VAL_3]] step %[[VAL_44]] { +// CHECK: %[[VAL_46:.*]] = fir.box_elesize %[[VAL_35]] : (!fir.box>>>) -> index +// CHECK: %[[VAL_47:.*]] = hlfir.designate %[[VAL_35]] (%[[VAL_45]]) typeparams %[[VAL_46]] : (!fir.box>>>, index, index) -> !fir.boxchar<1> +// CHECK: %[[VAL_48:.*]] = arith.constant false +// CHECK: %[[VAL_49:.*]] = fir.undefined tuple, i1> +// CHECK: %[[VAL_50:.*]] = fir.insert_value %[[VAL_49]], %[[VAL_48]], [1 : index] : (tuple, i1>, i1) -> tuple, i1> +// CHECK: %[[VAL_51:.*]] = fir.insert_value %[[VAL_50]], %[[VAL_47]], [0 : index] : (tuple, i1>, !fir.boxchar<1>) -> tuple, i1> +// CHECK: %[[VAL_52:.*]] = hlfir.no_reassoc %[[VAL_47]] : !fir.boxchar<1> +// CHECK: %[[VAL_53:.*]] = fir.undefined tuple, i1> +// CHECK: %[[VAL_54:.*]] = fir.insert_value %[[VAL_53]], %[[VAL_48]], [1 : index] : (tuple, i1>, i1) -> tuple, i1> +// CHECK: %[[VAL_55:.*]] = fir.insert_value %[[VAL_54]], %[[VAL_52]], [0 : index] : (tuple, i1>, !fir.boxchar<1>) -> tuple, i1> +// CHECK: %[[VAL_56:.*]] = hlfir.designate %[[VAL_42]]#0 (%[[VAL_45]]) typeparams %[[VAL_39]] : (!fir.box>>, index, index) -> !fir.boxchar<1> +// CHECK: hlfir.assign %[[VAL_52]] to %[[VAL_56]] : !fir.boxchar<1>, !fir.boxchar<1> +// CHECK: } +// CHECK: %[[VAL_57:.*]] = fir.undefined tuple>>, i1> +// CHECK: %[[VAL_58:.*]] = fir.insert_value %[[VAL_57]], %[[VAL_43]], [1 : index] : (tuple>>, i1>, i1) -> tuple>>, i1> +// CHECK: %[[VAL_59:.*]] = fir.insert_value %[[VAL_58]], %[[VAL_42]]#0, [0 : index] : (tuple>>, i1>, !fir.box>>) -> tuple>>, i1> +// CHECK: %[[VAL_60:.*]] = fir.convert %[[VAL_42]]#1 : (!fir.heap>>) -> !fir.ref>> +// CHECK: %[[VAL_61:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_62:.*]]:2 = hlfir.declare %[[VAL_60]](%[[VAL_61]]) typeparams %[[VAL_39]] {uniq_name = "_QFtest1Ey"} : (!fir.ref>>, !fir.shape<1>, index) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_63:.*]] = fir.convert %[[VAL_60]] : (!fir.ref>>) -> !fir.heap>> +// CHECK: fir.freemem %[[VAL_63]] : !fir.heap>> +// CHECK: %[[VAL_64:.*]] = fir.box_addr %[[VAL_35]] : (!fir.box>>>) -> !fir.heap>> +// CHECK: fir.freemem %[[VAL_64]] : !fir.heap>> +// CHECK: return +// CHECK: } +func.func @_QPtest1() { + %c1_i32 = arith.constant 1 : i32 + %c80_i32 = arith.constant 80 : i32 + %true = arith.constant true + %c1 = arith.constant 1 : index + %c0 = arith.constant 0 : index + %0 = fir.alloca !fir.array<10xi64> {bindc_name = ".rt.arrayctor.vector"} + %1 = fir.alloca !fir.box>>> {bindc_name = ".tmp.arrayctor"} + %2 = fir.alloca !fir.box>> {bindc_name = "w", uniq_name = "_QFtest1Ew"} + %3 = fir.zero_bits !fir.heap> + %4 = fir.embox %3 typeparams %c0 : (!fir.heap>, index) -> !fir.box>> + fir.store %4 to %2 : !fir.ref>>> + %5:2 = hlfir.declare %2 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest1Ew"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) + %6 = fir.zero_bits !fir.heap>> + %7 = fir.shape %c1 : (index) -> !fir.shape<1> + %8 = fir.embox %6(%7) typeparams %c0 : (!fir.heap>>, !fir.shape<1>, index) -> !fir.box>>> + fir.store %8 to %1 : !fir.ref>>>> + %9 = fir.convert %0 : (!fir.ref>) -> !fir.llvm_ptr + %10 = fir.address_of(@_QQcl.ce30ef70ff16a711a97719fb946c0b3d) : !fir.ref> + %11 = fir.convert %1 : (!fir.ref>>>>) -> !fir.ref> + %12 = fir.convert %10 : (!fir.ref>) -> !fir.ref + %13 = fir.call @_FortranAInitArrayConstructorVector(%9, %11, %true, %c80_i32, %12, %c1_i32) fastmath : (!fir.llvm_ptr, !fir.ref>, i1, i32, !fir.ref, i32) -> none + %14 = fir.load %5#0 : !fir.ref>>> + %15 = fir.box_addr %14 : (!fir.box>>) -> !fir.heap> + %16 = fir.load %5#0 : !fir.ref>>> + %17 = fir.box_elesize %16 : (!fir.box>>) -> index + %18 = fir.emboxchar %15, %17 : (!fir.heap>, index) -> !fir.boxchar<1> + %19 = fir.load %5#0 : !fir.ref>>> + %20 = fir.box_elesize %19 : (!fir.box>>) -> index + %21 = fir.convert %20 : (index) -> i64 + %22 = fir.convert %21 : (i64) -> index + %23 = arith.cmpi sgt, %22, %c0 : index + %24 = arith.select %23, %22, %c0 : index + %25 = hlfir.designate %18 substr %c1, %22 typeparams %24 : (!fir.boxchar<1>, index, index, index) -> !fir.boxchar<1> + %26:2 = fir.unboxchar %25 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %27 = fir.embox %26#0 typeparams %24 : (!fir.ref>, index) -> !fir.box> + %28 = fir.convert %27 : (!fir.box>) -> !fir.box + %29 = fir.call @_FortranAPushArrayConstructorValue(%9, %28) fastmath : (!fir.llvm_ptr, !fir.box) -> none + %30 = fir.load %1 : !fir.ref>>>> + %31 = hlfir.as_expr %30 move %true : (!fir.box>>>, i1) -> !hlfir.expr<1x!fir.char<1,?>> + %32 = fir.box_elesize %30 : (!fir.box>>>) -> index + %33 = fir.shape %c1 : (index) -> !fir.shape<1> + %34 = hlfir.elemental %33 typeparams %32 : (!fir.shape<1>, index) -> !hlfir.expr<1x!fir.char<1,?>> { + ^bb0(%arg0: index): + %38 = fir.box_elesize %30 : (!fir.box>>>) -> index + %39 = hlfir.apply %31, %arg0 typeparams %38 : (!hlfir.expr<1x!fir.char<1,?>>, index, index) -> !hlfir.expr> + %40 = hlfir.no_reassoc %39 : !hlfir.expr> + hlfir.yield_element %40 : !hlfir.expr> + } + %35:3 = hlfir.associate %34(%33) typeparams %32 {uniq_name = "adapt.valuebyref"} : (!hlfir.expr<1x!fir.char<1,?>>, !fir.shape<1>, index) -> (!fir.box>>, !fir.ref>>, i1) + %36 = fir.shape %c1 : (index) -> !fir.shape<1> + %37:2 = hlfir.declare %35#1(%36) typeparams %32 {uniq_name = "_QFtest1Ey"} : (!fir.ref>>, !fir.shape<1>, index) -> (!fir.box>>, !fir.ref>>) + hlfir.end_associate %35#1, %35#2 : !fir.ref>>, i1 + hlfir.destroy %34 : !hlfir.expr<1x!fir.char<1,?>> + hlfir.destroy %31 : !hlfir.expr<1x!fir.char<1,?>> + return +} +func.func private @_FortranAInitArrayConstructorVector(!fir.llvm_ptr, !fir.ref>, i1, i32, !fir.ref, i32) -> none attributes {fir.runtime} +fir.global linkonce @_QQcl.ce30ef70ff16a711a97719fb946c0b3d constant : !fir.char<1,1> { + %0 = fir.string_lit "\00"(1) : !fir.char<1,1> + fir.has_value %0 : !fir.char<1,1> +} +func.func private @_FortranAPushArrayConstructorValue(!fir.llvm_ptr, !fir.box) -> none attributes {fir.runtime} diff --git a/flang/test/HLFIR/copy-in-out-codegen.fir b/flang/test/HLFIR/copy-in-out-codegen.fir index b6c7a3c1f3789..71962d90f013a 100644 --- a/flang/test/HLFIR/copy-in-out-codegen.fir +++ b/flang/test/HLFIR/copy-in-out-codegen.fir @@ -94,3 +94,36 @@ func.func @test_copy_out_copy_back(%box: !fir.box>, %temp: !fi // CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box>) -> !fir.heap> // CHECK: fir.freemem %[[VAL_11]] : !fir.heap> // CHECK: } + +func.func @test_copy_in_poly(%poly : !fir.class>>) { + %0:2 = hlfir.copy_in %poly : (!fir.class>>) -> (!fir.class>>, i1) + return +} +// CHECK-LABEL: func.func @test_copy_in_poly( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.class>>) { +// CHECK: %[[VAL_1:.*]] = fir.alloca !fir.box>>> +// CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_0]] : (!fir.class>>) -> !fir.box +// CHECK: %[[VAL_3:.*]] = fir.call @_FortranAIsContiguous(%[[VAL_2]]) : (!fir.box) -> i1 +// CHECK: %[[VAL_4:.*]] = fir.if %[[VAL_3]] -> (!fir.class>>) { +// CHECK: fir.result %[[VAL_0]] : !fir.class>> +// CHECK: } else { +// CHECK: %[[VAL_5:.*]] = fir.zero_bits !fir.heap>> +// CHECK: %[[VAL_6:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_6]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_8:.*]] = fir.embox %[[VAL_5]](%[[VAL_7]]) : (!fir.heap>>, !fir.shape<1>) -> !fir.box>>> +// CHECK: fir.store %[[VAL_8]] to %[[VAL_1]] : !fir.ref>>>> +// CHECK: %[[VAL_9:.*]] = fir.address_of(@_QQcl.{{.*}}) : !fir.ref> +// CHECK: %[[VAL_10:.*]] = arith.constant {{.*}} : index +// CHECK: %[[VAL_11:.*]] = arith.constant {{.*}} : i32 +// CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>>>>) -> !fir.ref> +// CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_0]] : (!fir.class>>) -> !fir.box +// CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_9]] : (!fir.ref>) -> !fir.ref +// CHECK: %[[VAL_15:.*]] = fir.call @_FortranAAssign(%[[VAL_12]], %[[VAL_13]], %[[VAL_14]], %[[VAL_11]]) : (!fir.ref>, !fir.box, !fir.ref, i32) -> none +// CHECK: %[[VAL_16:.*]] = fir.load %[[VAL_1]] : !fir.ref>>>> +// CHECK: %[[VAL_17:.*]] = fir.rebox %[[VAL_16]] : (!fir.box>>>) -> !fir.class>> +// CHECK: fir.result %[[VAL_17]] : !fir.class>> +// CHECK: } +// CHECK: %[[VAL_18:.*]] = arith.constant false +// CHECK: %[[VAL_19:.*]] = arith.cmpi eq, %[[VAL_3]], %[[VAL_18]] : i1 +// CHECK: return +// CHECK: } diff --git a/flang/test/HLFIR/invalid.fir b/flang/test/HLFIR/invalid.fir index 6b3ed77eb1aa3..e4e9cd00b41ba 100644 --- a/flang/test/HLFIR/invalid.fir +++ b/flang/test/HLFIR/invalid.fir @@ -296,6 +296,25 @@ func.func @bad_concat_4(%arg0: !fir.ref>) { return } +// ----- +func.func @bad_any1(%arg0: !hlfir.expr>) { + // expected-error@+1 {{'hlfir.any' op result must have the same element type as MASK argument}} + %0 = hlfir.any %arg0 : (!hlfir.expr>) -> !hlfir.expr> +} + +// ----- +func.func @bad_any2(%arg0: !hlfir.expr>) { + // expected-error@+1 {{'hlfir.any' op result must have the same element type as MASK argument}} + %0 = hlfir.any %arg0 : (!hlfir.expr>) -> !hlfir.expr> +} + +// ----- +func.func @bad_any3(%arg0: !hlfir.expr>, %arg1: i32){ + // expected-error@+1 {{'hlfir.any' op result rank must be one less than MASK}} + %0 = hlfir.any %arg0 dim %arg1 : (!hlfir.expr>, i32) -> !hlfir.expr> +} + + // ----- func.func @bad_product1(%arg0: !hlfir.expr, %arg1: i32, %arg2: !fir.box>) { // expected-error@+1 {{'hlfir.product' op result must have the same element type as ARRAY argument}} diff --git a/flang/test/Lower/HLFIR/any.f90 b/flang/test/Lower/HLFIR/any.f90 new file mode 100644 index 0000000000000..f4e66cb571ea1 --- /dev/null +++ b/flang/test/Lower/HLFIR/any.f90 @@ -0,0 +1,80 @@ +! Test lowering of ANY intrinsic to HLFIR +! RUN: bbc -emit-fir -hlfir -o - %s 2>&1 | FileCheck %s +! simple 1 argument ANY +subroutine any1(a, s) + logical :: a(:), s + s = ANY(a) +end subroutine +! CHECK-LABEL: func.func @_QPany1( +! CHECK: %[[ARG0:.*]]: !fir.box>> +! CHECK: %[[ARG1:.*]]: !fir.ref> +! CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG0]] +! CHECK-DAG: %[[OUT:.*]]:2 = hlfir.declare %[[ARG1]] +! CHECK-NEXT: %[[EXPR:.*]] = hlfir.any %[[MASK]]#0 : (!fir.box>>) -> !hlfir.expr> +! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[OUT]]#0 : !hlfir.expr>, !fir.ref> +! CHECK-NEXT: hlfir.destroy %[[EXPR]] +! CHECK-NEXT: return +! CHECK-NEXT: } + +! any with by-ref DIM argument +subroutine any2(a, s, d) + logical :: a(:,:), s(:) + integer :: d + s = ANY(a, d) +end subroutine +! CHECK-LABEL: func.func @_QPany2( +! CHECK: %[[ARG0:.*]]: !fir.box>> {fir.bindc_name = "a"} +! CHECK: %[[ARG1:.*]]: !fir.box>> {fir.bindc_name = "s"} +! CHECK: %[[ARG2:.*]]: !fir.ref {fir.bindc_name = "d"} +! CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG0]] +! CHECK-DAG: %[[DIM_REF:.*]]:2 = hlfir.declare %[[ARG2]] +! CHECK-DAG: %[[OUT:.*]]:2 = hlfir.declare %[[ARG1]] +! CHECK-NEXT: %[[DIM:.*]] = fir.load %[[DIM_REF]]#0 : !fir.ref +! CHECK-NEXT: %[[EXPR:.*]] = hlfir.any %[[MASK]]#0 dim %[[DIM]] : (!fir.box>>, i32) -> !hlfir.expr> +! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[OUT]]#0 : !hlfir.expr>, !fir.box>> +! CHECK-NEXT: hlfir.destroy %[[EXPR]] +! CHECK-NEXT: return +! CHECK-NEXT: } + +! any with DIM argument by-val, mask isn't boxed +subroutine any3(s) + logical :: s(2) + logical :: a(2,2) = reshape((/.true.,.false.,.true.,.false./), shape(a)) + s = ANY(a, 1) +end subroutine +! CHECK-LABEL: func.func @_QPany3( +! CHECK: %[[ARG0:.*]]: !fir.ref>> {fir.bindc_name = "s"} +! CHECK-DAG: %[[ADDR:.*]] = fir.address_of{{.*}} : !fir.ref>> +! CHECK-DAG: %[[MASK_SHAPE:.*]] = fir.shape {{.*}} -> !fir.shape<2> +! CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ADDR]](%[[MASK_SHAPE]]) +! CHECK-DAG: %[[OUT_SHAPE:.*]] = fir.shape {{.*}} -> !fir.shape<1> +! CHECK-DAG: %[[OUT:.*]]:2 = hlfir.declare %[[ARG0]](%[[OUT_SHAPE]]) +! CHECK-DAG: %[[C1:.*]] = arith.constant 1 : i32 +! CHECK-DAG: %[[EXPR:.*]] = hlfir.any %[[MASK]]#0 dim %[[C1]] : (!fir.ref>>, i32) -> !hlfir.expr<2x!fir.logical<4>> +! CHECK-DAG: hlfir.assign %[[EXPR]] to %[[OUT]] +! CHECK-NEXT: hlfir.destroy %[[EXPR]] : !hlfir.expr<2x!fir.logical<4>> +! CHECK-NEXT: return +! CHECK-NEXT: } + +! any with DIM from pointer +subroutine any4(a, s, d) + integer, pointer :: d + logical :: a(:,:), s(:) + s = ANY(a, (d)) +end subroutine +! CHECK-LABEL: func.func @_QPany4( +! CHECK: %[[ARG0:.*]]: !fir.box>> {fir.bindc_name = "a"} +! CHECK: %[[ARG1:.*]]: !fir.box>> {fir.bindc_name = "s"} +! CHECK: %[[ARG2:.*]]: !fir.ref>> {fir.bindc_name = "d"} +! CHECK-DAG: %[[ARRAY:.*]]:2 = hlfir.declare %[[ARG0]] +! CHECK-DAG: %[[OUT:.*]]:2 = hlfir.declare %[[ARG1]] +! CHECK-DAG: %[[DIM:.*]]:2 = hlfir.declare %[[ARG2]] +! CHECK-NEXT: %[[DIM_BOX:.*]] = fir.load %[[DIM]]#0 : !fir.ref>> +! CHECK-NEXT: %[[DIM_ADDR:.*]] = fir.box_addr %[[DIM_BOX]] : (!fir.box>) -> !fir.ptr +! CHECK-NEXT: %[[DIM0:.*]] = fir.load %[[DIM_ADDR]] : !fir.ptr +! CHECK-NEXT: %[[DIM1:.*]] = hlfir.no_reassoc %[[DIM0]] : i32 +! CHECK-NEXT: %[[EXPR:.*]] = hlfir.any %[[ARRAY]]#0 dim %[[DIM1]] : (!fir.box>>, i32) -> !hlfir.expr> +! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[OUT]]#0 : !hlfir.expr>, !fir.box>> +! CHECK-NEXT: hlfir.destroy %[[EXPR]] : !hlfir.expr> +! CHECK-NEXT: return +! CHECK-NEXT: } diff --git a/flang/test/Lower/HLFIR/array-ctor-as-elemental.f90 b/flang/test/Lower/HLFIR/array-ctor-as-elemental.f90 index 1cd714f38f14b..ff9ecf7ac70ff 100644 --- a/flang/test/Lower/HLFIR/array-ctor-as-elemental.f90 +++ b/flang/test/Lower/HLFIR/array-ctor-as-elemental.f90 @@ -5,65 +5,80 @@ subroutine test_as_simple_elemental(n) integer :: n call takes_int([(n+i, i=1,4)]) end subroutine -! CHECK-LABEL: func.func @_QPtest_as_simple_elemental( -! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}En -! CHECK: %[[VAL_2:.*]] = arith.constant 4 : index -! CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> -! CHECK: %[[VAL_4:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i64) -> index -! CHECK: %[[VAL_6:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i64) -> index -! CHECK: %[[VAL_8:.*]] = arith.constant 1 : index -! CHECK: %[[VAL_9:.*]] = hlfir.elemental %[[VAL_3]] : (!fir.shape<1>) -> !hlfir.expr<4xi32> { -! CHECK: ^bb0(%[[VAL_10:.*]]: index): -! CHECK: %[[VAL_11:.*]] = arith.subi %[[VAL_10]], %[[VAL_8]] : index -! CHECK: %[[VAL_12:.*]] = arith.muli %[[VAL_11]], %[[VAL_7]] : index -! CHECK: %[[VAL_13:.*]] = arith.addi %[[VAL_5]], %[[VAL_12]] : index -! CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref -! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_13]] : (index) -> i32 -! CHECK: %[[VAL_16:.*]] = arith.addi %[[VAL_14]], %[[VAL_15]] : i32 -! CHECK: hlfir.yield_element %[[VAL_16]] : i32 -! CHECK: } -! CHECK: fir.call -! CHECK: hlfir.destroy %[[VAL_9]] : !hlfir.expr<4xi32> +! CHECK-LABEL: func.func @_QPtest_as_simple_elemental( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "n"}) { +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest_as_simple_elementalEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_2:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_4:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i64) -> index +! CHECK: %[[VAL_6:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i64) -> index +! CHECK: %[[VAL_8:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_9:.*]] = hlfir.elemental %[[VAL_3]] : (!fir.shape<1>) -> !hlfir.expr<4xi32> { +! CHECK: ^bb0(%[[VAL_10:.*]]: index): +! CHECK: %[[VAL_11:.*]] = arith.subi %[[VAL_10]], %[[VAL_8]] : index +! CHECK: %[[VAL_12:.*]] = arith.muli %[[VAL_11]], %[[VAL_7]] : index +! CHECK: %[[VAL_13:.*]] = arith.addi %[[VAL_5]], %[[VAL_12]] : index +! CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref +! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_13]] : (index) -> i64 +! CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_15]] : (i64) -> i32 +! CHECK: %[[VAL_17:.*]] = arith.addi %[[VAL_14]], %[[VAL_16]] : i32 +! CHECK: hlfir.yield_element %[[VAL_17]] : i32 +! CHECK: } +! CHECK: %[[VAL_18:.*]]:3 = hlfir.associate %[[VAL_19:.*]](%[[VAL_3]]) {uniq_name = "adapt.valuebyref"} : (!hlfir.expr<4xi32>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>, i1) +! CHECK: fir.call @_QPtakes_int(%[[VAL_18]]#1) fastmath : (!fir.ref>) -> () +! CHECK: hlfir.end_associate %[[VAL_18]]#1, %[[VAL_18]]#2 : !fir.ref>, i1 +! CHECK: hlfir.destroy %[[VAL_19]] : !hlfir.expr<4xi32> +! CHECK: return +! CHECK: } subroutine test_as_strided_elemental(lb, ub, stride) integer(8) :: lb, ub, stride call takes_int([(i, i=lb,ub,stride)]) end subroutine -! CHECK-LABEL: func.func @_QPtest_as_strided_elemental( -! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare {{.*}}Elb -! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare {{.*}}Estride -! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}Eub -! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i64 -! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref -! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref -! CHECK: %[[VAL_9:.*]] = arith.subi %[[VAL_7]], %[[VAL_8]] : i64 -! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref -! CHECK: %[[VAL_11:.*]] = arith.addi %[[VAL_9]], %[[VAL_10]] : i64 -! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref -! CHECK: %[[VAL_13:.*]] = arith.divsi %[[VAL_11]], %[[VAL_12]] : i64 -! CHECK: %[[VAL_14:.*]] = arith.constant 0 : i64 -! CHECK: %[[VAL_15:.*]] = arith.cmpi sgt, %[[VAL_13]], %[[VAL_14]] : i64 -! CHECK: %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_13]], %[[VAL_14]] : i64 -! CHECK: %[[VAL_17:.*]] = arith.addi %[[VAL_6]], %[[VAL_16]] : i64 -! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (i64) -> index -! CHECK: %[[VAL_19:.*]] = fir.shape %[[VAL_18]] : (index) -> !fir.shape<1> -! CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref -! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i64) -> index -! CHECK: %[[VAL_22:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref -! CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_22]] : (i64) -> index -! CHECK: %[[VAL_24:.*]] = arith.constant 1 : index -! CHECK: %[[VAL_25:.*]] = hlfir.elemental %[[VAL_19]] : (!fir.shape<1>) -> !hlfir.expr { -! CHECK: ^bb0(%[[VAL_26:.*]]: index): -! CHECK: %[[VAL_27:.*]] = arith.subi %[[VAL_26]], %[[VAL_24]] : index -! CHECK: %[[VAL_28:.*]] = arith.muli %[[VAL_27]], %[[VAL_23]] : index -! CHECK: %[[VAL_29:.*]] = arith.addi %[[VAL_21]], %[[VAL_28]] : index -! CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (index) -> i32 -! CHECK: hlfir.yield_element %[[VAL_30]] : i32 -! CHECK: } -! CHECK: fir.call -! CHECK: hlfir.destroy %[[VAL_25]] : !hlfir.expr +! CHECK-LABEL: func.func @_QPtest_as_strided_elemental( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "lb"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "ub"}, +! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref {fir.bindc_name = "stride"}) { +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest_as_strided_elementalElb"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFtest_as_strided_elementalEstride"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest_as_strided_elementalEub"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i64 +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref +! CHECK: %[[VAL_9:.*]] = arith.subi %[[VAL_7]], %[[VAL_8]] : i64 +! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_11:.*]] = arith.addi %[[VAL_9]], %[[VAL_10]] : i64 +! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_13:.*]] = arith.divsi %[[VAL_11]], %[[VAL_12]] : i64 +! CHECK: %[[VAL_14:.*]] = arith.constant 0 : i64 +! CHECK: %[[VAL_15:.*]] = arith.cmpi sgt, %[[VAL_13]], %[[VAL_14]] : i64 +! CHECK: %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_13]], %[[VAL_14]] : i64 +! CHECK: %[[VAL_17:.*]] = arith.addi %[[VAL_6]], %[[VAL_16]] : i64 +! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (i64) -> index +! CHECK: %[[VAL_19:.*]] = fir.shape %[[VAL_18]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref +! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i64) -> index +! CHECK: %[[VAL_22:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_22]] : (i64) -> index +! CHECK: %[[VAL_24:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_25:.*]] = hlfir.elemental %[[VAL_19]] : (!fir.shape<1>) -> !hlfir.expr { +! CHECK: ^bb0(%[[VAL_26:.*]]: index): +! CHECK: %[[VAL_27:.*]] = arith.subi %[[VAL_26]], %[[VAL_24]] : index +! CHECK: %[[VAL_28:.*]] = arith.muli %[[VAL_27]], %[[VAL_23]] : index +! CHECK: %[[VAL_29:.*]] = arith.addi %[[VAL_21]], %[[VAL_28]] : index +! CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (index) -> i64 +! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (i64) -> i32 +! CHECK: hlfir.yield_element %[[VAL_31]] : i32 +! CHECK: } +! CHECK: %[[VAL_32:.*]]:3 = hlfir.associate %[[VAL_33:.*]](%[[VAL_19]]) {uniq_name = "adapt.valuebyref"} : (!hlfir.expr, !fir.shape<1>) -> (!fir.box>, !fir.ref>, i1) +! CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_32]]#1 : (!fir.ref>) -> !fir.ref> +! CHECK: fir.call @_QPtakes_int(%[[VAL_34]]) fastmath : (!fir.ref>) -> () +! CHECK: hlfir.end_associate %[[VAL_32]]#1, %[[VAL_32]]#2 : !fir.ref>, i1 +! CHECK: hlfir.destroy %[[VAL_33]] : !hlfir.expr +! CHECK: return +! CHECK: } subroutine test_as_elemental_with_pure_call(n) interface @@ -74,27 +89,32 @@ integer pure function foo(i) integer :: n call takes_int([(foo(i), i=1,4)]) end subroutine -! CHECK-LABEL: func.func @_QPtest_as_elemental_with_pure_call( -! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "n"}) { -! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest_as_elemental_with_pure_callEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) -! CHECK: %[[VAL_2:.*]] = arith.constant 4 : index -! CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> -! CHECK: %[[VAL_4:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i64) -> index -! CHECK: %[[VAL_6:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i64) -> index -! CHECK: %[[VAL_8:.*]] = arith.constant 1 : index -! CHECK: %[[VAL_9:.*]] = hlfir.elemental %[[VAL_3]] : (!fir.shape<1>) -> !hlfir.expr<4xi32> { -! CHECK: ^bb0(%[[VAL_10:.*]]: index): -! CHECK: %[[VAL_11:.*]] = arith.subi %[[VAL_10]], %[[VAL_8]] : index -! CHECK: %[[VAL_12:.*]] = arith.muli %[[VAL_11]], %[[VAL_7]] : index -! CHECK: %[[VAL_13:.*]] = arith.addi %[[VAL_5]], %[[VAL_12]] : index -! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (index) -> i32 -! CHECK: %[[VAL_15:.*]] = fir.call @_QPfoo(%[[VAL_14]]) fastmath : (i32) -> i32 -! CHECK: hlfir.yield_element %[[VAL_15]] : i32 -! CHECK: } -! CHECK: fir.call -! CHECK: hlfir.destroy %[[VAL_9]] : !hlfir.expr<4xi32> +! CHECK-LABEL: func.func @_QPtest_as_elemental_with_pure_call( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "n"}) { +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest_as_elemental_with_pure_callEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_2:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_4:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i64) -> index +! CHECK: %[[VAL_6:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i64) -> index +! CHECK: %[[VAL_8:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_9:.*]] = hlfir.elemental %[[VAL_3]] : (!fir.shape<1>) -> !hlfir.expr<4xi32> { +! CHECK: ^bb0(%[[VAL_10:.*]]: index): +! CHECK: %[[VAL_11:.*]] = arith.subi %[[VAL_10]], %[[VAL_8]] : index +! CHECK: %[[VAL_12:.*]] = arith.muli %[[VAL_11]], %[[VAL_7]] : index +! CHECK: %[[VAL_13:.*]] = arith.addi %[[VAL_5]], %[[VAL_12]] : index +! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (index) -> i64 +! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (i64) -> i32 +! CHECK: %[[VAL_16:.*]] = fir.call @_QPfoo(%[[VAL_15]]) fastmath : (i32) -> i32 +! CHECK: hlfir.yield_element %[[VAL_16]] : i32 +! CHECK: } +! CHECK: %[[VAL_17:.*]]:3 = hlfir.associate %[[VAL_18:.*]](%[[VAL_3]]) {uniq_name = "adapt.valuebyref"} : (!hlfir.expr<4xi32>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>, i1) +! CHECK: fir.call @_QPtakes_int(%[[VAL_17]]#1) fastmath : (!fir.ref>) -> () +! CHECK: hlfir.end_associate %[[VAL_17]]#1, %[[VAL_17]]#2 : !fir.ref>, i1 +! CHECK: hlfir.destroy %[[VAL_18]] : !hlfir.expr<4xi32> +! CHECK: return +! CHECK: } ! CHECK-LABEL: func.func @_QPtest_with_impure_call( subroutine test_with_impure_call(n) diff --git a/flang/test/Lower/HLFIR/array-ctor-as-inlined-temp.f90 b/flang/test/Lower/HLFIR/array-ctor-as-inlined-temp.f90 index a3e0d09cfb71a..bd9d9ffcadc41 100644 --- a/flang/test/Lower/HLFIR/array-ctor-as-inlined-temp.f90 +++ b/flang/test/Lower/HLFIR/array-ctor-as-inlined-temp.f90 @@ -109,172 +109,197 @@ subroutine test_implied_do(n) ! the implied do contains more than one scalar ac-value. call takes_int([(42, j, j=1,n)]) end subroutine -! CHECK-LABEL: func.func @_QPtest_implied_do( -! CHECK: %[[VAL_1:.*]] = fir.alloca index -! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare {{.*}}En -! CHECK: %[[VAL_3:.*]] = arith.constant 0 : i64 -! CHECK: %[[VAL_4:.*]] = arith.constant 2 : i64 -! CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref -! CHECK: %[[VAL_6:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_7:.*]] = arith.subi %[[VAL_5]], %[[VAL_6]] : i64 -! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_9:.*]] = arith.addi %[[VAL_7]], %[[VAL_8]] : i64 -! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_11:.*]] = arith.divsi %[[VAL_9]], %[[VAL_10]] : i64 -! CHECK: %[[VAL_12:.*]] = arith.constant 0 : i64 -! CHECK: %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_11]], %[[VAL_12]] : i64 -! CHECK: %[[VAL_14:.*]] = arith.select %[[VAL_13]], %[[VAL_11]], %[[VAL_12]] : i64 -! CHECK: %[[VAL_15:.*]] = arith.muli %[[VAL_4]], %[[VAL_14]] : i64 -! CHECK: %[[VAL_16:.*]] = arith.addi %[[VAL_3]], %[[VAL_15]] : i64 -! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i64) -> index -! CHECK: %[[VAL_18:.*]] = arith.constant 1 : index -! CHECK: fir.store %[[VAL_18]] to %[[VAL_1]] : !fir.ref -! CHECK: %[[VAL_19:.*]] = fir.allocmem !fir.array, %[[VAL_17]] {bindc_name = ".tmp.arrayctor", uniq_name = ""} -! CHECK: %[[VAL_20:.*]] = fir.shape %[[VAL_17]] : (index) -> !fir.shape<1> -! CHECK: %[[VAL_21:.*]]:2 = hlfir.declare %[[VAL_19]](%[[VAL_20]]) {uniq_name = ".tmp.arrayctor"} : (!fir.heap>, !fir.shape<1>) -> (!fir.box>, !fir.heap>) -! CHECK: %[[VAL_22:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_22]] : (i64) -> index -! CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref -! CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_24]] : (i64) -> index -! CHECK: %[[VAL_26:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_26]] : (i64) -> index -! CHECK: fir.do_loop %[[VAL_28:.*]] = %[[VAL_23]] to %[[VAL_25]] step %[[VAL_27]] { -! CHECK: %[[VAL_29:.*]] = arith.constant 42 : i32 -! CHECK: %[[VAL_30:.*]] = fir.load %[[VAL_1]] : !fir.ref -! CHECK: %[[VAL_31:.*]] = arith.addi %[[VAL_30]], %[[VAL_18]] : index -! CHECK: fir.store %[[VAL_31]] to %[[VAL_1]] : !fir.ref -! CHECK: %[[VAL_32:.*]] = hlfir.designate %[[VAL_21]]#0 (%[[VAL_31]]) : (!fir.box>, index) -> !fir.ref -! CHECK: hlfir.assign %[[VAL_29]] to %[[VAL_32]] : i32, !fir.ref -! CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_28]] : (index) -> i32 -! CHECK: %[[VAL_34:.*]] = fir.load %[[VAL_1]] : !fir.ref -! CHECK: %[[VAL_35:.*]] = arith.addi %[[VAL_34]], %[[VAL_18]] : index -! CHECK: fir.store %[[VAL_35]] to %[[VAL_1]] : !fir.ref -! CHECK: %[[VAL_36:.*]] = hlfir.designate %[[VAL_21]]#0 (%[[VAL_35]]) : (!fir.box>, index) -> !fir.ref -! CHECK: hlfir.assign %[[VAL_33]] to %[[VAL_36]] : i32, !fir.ref -! CHECK: } -! CHECK: %[[VAL_37:.*]] = arith.constant true -! CHECK: %[[VAL_38:.*]] = hlfir.as_expr %[[VAL_21]]#0 move %[[VAL_37]] : (!fir.box>, i1) -> !hlfir.expr -! CHECK: fir.call -! CHECK: hlfir.destroy %[[VAL_38]] : !hlfir.expr +! CHECK-LABEL: func.func @_QPtest_implied_do( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "n"}) { +! CHECK: %[[VAL_1:.*]] = fir.alloca index +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest_implied_doEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_3:.*]] = arith.constant 0 : i64 +! CHECK: %[[VAL_4:.*]] = arith.constant 2 : i64 +! CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref +! CHECK: %[[VAL_6:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_7:.*]] = arith.subi %[[VAL_5]], %[[VAL_6]] : i64 +! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_9:.*]] = arith.addi %[[VAL_7]], %[[VAL_8]] : i64 +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_11:.*]] = arith.divsi %[[VAL_9]], %[[VAL_10]] : i64 +! CHECK: %[[VAL_12:.*]] = arith.constant 0 : i64 +! CHECK: %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_11]], %[[VAL_12]] : i64 +! CHECK: %[[VAL_14:.*]] = arith.select %[[VAL_13]], %[[VAL_11]], %[[VAL_12]] : i64 +! CHECK: %[[VAL_15:.*]] = arith.muli %[[VAL_4]], %[[VAL_14]] : i64 +! CHECK: %[[VAL_16:.*]] = arith.addi %[[VAL_3]], %[[VAL_15]] : i64 +! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i64) -> index +! CHECK: %[[VAL_18:.*]] = arith.constant 1 : index +! CHECK: fir.store %[[VAL_18]] to %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_19:.*]] = fir.allocmem !fir.array, %[[VAL_17]] {bindc_name = ".tmp.arrayctor", uniq_name = ""} +! CHECK: %[[VAL_20:.*]] = fir.shape %[[VAL_17]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_21:.*]]:2 = hlfir.declare %[[VAL_19]](%[[VAL_20]]) {uniq_name = ".tmp.arrayctor"} : (!fir.heap>, !fir.shape<1>) -> (!fir.box>, !fir.heap>) +! CHECK: %[[VAL_22:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_22]] : (i64) -> index +! CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref +! CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_24]] : (i64) -> index +! CHECK: %[[VAL_26:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_26]] : (i64) -> index +! CHECK: fir.do_loop %[[VAL_28:.*]] = %[[VAL_23]] to %[[VAL_25]] step %[[VAL_27]] { +! CHECK: %[[VAL_29:.*]] = arith.constant 42 : i32 +! CHECK: %[[VAL_30:.*]] = fir.load %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_31:.*]] = arith.addi %[[VAL_30]], %[[VAL_18]] : index +! CHECK: fir.store %[[VAL_31]] to %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_32:.*]] = hlfir.designate %[[VAL_21]]#0 (%[[VAL_31]]) : (!fir.box>, index) -> !fir.ref +! CHECK: hlfir.assign %[[VAL_29]] to %[[VAL_32]] : i32, !fir.ref +! CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_28]] : (index) -> i64 +! CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_33]] : (i64) -> i32 +! CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_36:.*]] = arith.addi %[[VAL_35]], %[[VAL_18]] : index +! CHECK: fir.store %[[VAL_36]] to %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_37:.*]] = hlfir.designate %[[VAL_21]]#0 (%[[VAL_36]]) : (!fir.box>, index) -> !fir.ref +! CHECK: hlfir.assign %[[VAL_34]] to %[[VAL_37]] : i32, !fir.ref +! CHECK: } +! CHECK: %[[VAL_38:.*]] = arith.constant true +! CHECK: %[[VAL_39:.*]] = hlfir.as_expr %[[VAL_21]]#0 move %[[VAL_38]] : (!fir.box>, i1) -> !hlfir.expr +! CHECK: %[[VAL_40:.*]]:3 = hlfir.associate %[[VAL_39]](%[[VAL_20]]) {uniq_name = "adapt.valuebyref"} : (!hlfir.expr, !fir.shape<1>) -> (!fir.box>, !fir.ref>, i1) +! CHECK: %[[VAL_41:.*]] = fir.convert %[[VAL_40]]#1 : (!fir.ref>) -> !fir.ref> +! CHECK: fir.call @_QPtakes_int(%[[VAL_41]]) fastmath : (!fir.ref>) -> () +! CHECK: hlfir.end_associate %[[VAL_40]]#1, %[[VAL_40]]#2 : !fir.ref>, i1 +! CHECK: hlfir.destroy %[[VAL_39]] : !hlfir.expr +! CHECK: return +! CHECK: } subroutine test_strided_implied_do(lb, ub, stride) integer(8) :: lb, ub, stride call takes_int([(42, j, j=lb,ub,stride)]) end subroutine -! CHECK-LABEL: func.func @_QPtest_strided_implied_do( -! CHECK: %[[VAL_3:.*]] = fir.alloca index -! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare {{.*}}Elb -! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}Estride -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare {{.*}}Eub -! CHECK: %[[VAL_7:.*]] = arith.constant 0 : i64 -! CHECK: %[[VAL_8:.*]] = arith.constant 2 : i64 -! CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref -! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref -! CHECK: %[[VAL_11:.*]] = arith.subi %[[VAL_9]], %[[VAL_10]] : i64 -! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref -! CHECK: %[[VAL_13:.*]] = arith.addi %[[VAL_11]], %[[VAL_12]] : i64 -! CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref -! CHECK: %[[VAL_15:.*]] = arith.divsi %[[VAL_13]], %[[VAL_14]] : i64 -! CHECK: %[[VAL_16:.*]] = arith.constant 0 : i64 -! CHECK: %[[VAL_17:.*]] = arith.cmpi sgt, %[[VAL_15]], %[[VAL_16]] : i64 -! CHECK: %[[VAL_18:.*]] = arith.select %[[VAL_17]], %[[VAL_15]], %[[VAL_16]] : i64 -! CHECK: %[[VAL_19:.*]] = arith.muli %[[VAL_8]], %[[VAL_18]] : i64 -! CHECK: %[[VAL_20:.*]] = arith.addi %[[VAL_7]], %[[VAL_19]] : i64 -! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i64) -> index -! CHECK: %[[VAL_22:.*]] = arith.constant 1 : index -! CHECK: fir.store %[[VAL_22]] to %[[VAL_3]] : !fir.ref -! CHECK: %[[VAL_23:.*]] = fir.allocmem !fir.array, %[[VAL_21]] {bindc_name = ".tmp.arrayctor", uniq_name = ""} -! CHECK: %[[VAL_24:.*]] = fir.shape %[[VAL_21]] : (index) -> !fir.shape<1> -! CHECK: %[[VAL_25:.*]]:2 = hlfir.declare %[[VAL_23]](%[[VAL_24]]) {uniq_name = ".tmp.arrayctor"} : (!fir.heap>, !fir.shape<1>) -> (!fir.box>, !fir.heap>) -! CHECK: %[[VAL_26:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref -! CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_26]] : (i64) -> index -! CHECK: %[[VAL_28:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref -! CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_28]] : (i64) -> index -! CHECK: %[[VAL_30:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref -! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (i64) -> index -! CHECK: fir.do_loop %[[VAL_32:.*]] = %[[VAL_27]] to %[[VAL_29]] step %[[VAL_31]] { -! CHECK: %[[VAL_33:.*]] = arith.constant 42 : i32 -! CHECK: %[[VAL_34:.*]] = fir.load %[[VAL_3]] : !fir.ref -! CHECK: %[[VAL_35:.*]] = arith.addi %[[VAL_34]], %[[VAL_22]] : index -! CHECK: fir.store %[[VAL_35]] to %[[VAL_3]] : !fir.ref -! CHECK: %[[VAL_36:.*]] = hlfir.designate %[[VAL_25]]#0 (%[[VAL_35]]) : (!fir.box>, index) -> !fir.ref -! CHECK: hlfir.assign %[[VAL_33]] to %[[VAL_36]] : i32, !fir.ref -! CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_32]] : (index) -> i32 -! CHECK: %[[VAL_38:.*]] = fir.load %[[VAL_3]] : !fir.ref -! CHECK: %[[VAL_39:.*]] = arith.addi %[[VAL_38]], %[[VAL_22]] : index -! CHECK: fir.store %[[VAL_39]] to %[[VAL_3]] : !fir.ref -! CHECK: %[[VAL_40:.*]] = hlfir.designate %[[VAL_25]]#0 (%[[VAL_39]]) : (!fir.box>, index) -> !fir.ref -! CHECK: hlfir.assign %[[VAL_37]] to %[[VAL_40]] : i32, !fir.ref -! CHECK: } -! CHECK: %[[VAL_41:.*]] = arith.constant true -! CHECK: %[[VAL_42:.*]] = hlfir.as_expr %[[VAL_25]]#0 move %[[VAL_41]] : (!fir.box>, i1) -> !hlfir.expr -! CHECK: fir.call -! CHECK: hlfir.destroy %[[VAL_42]] : !hlfir.expr +! CHECK-LABEL: func.func @_QPtest_strided_implied_do( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "lb"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "ub"}, +! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref {fir.bindc_name = "stride"}) { +! CHECK: %[[VAL_3:.*]] = fir.alloca index +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest_strided_implied_doElb"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFtest_strided_implied_doEstride"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest_strided_implied_doEub"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_7:.*]] = arith.constant 0 : i64 +! CHECK: %[[VAL_8:.*]] = arith.constant 2 : i64 +! CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref +! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_11:.*]] = arith.subi %[[VAL_9]], %[[VAL_10]] : i64 +! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +! CHECK: %[[VAL_13:.*]] = arith.addi %[[VAL_11]], %[[VAL_12]] : i64 +! CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +! CHECK: %[[VAL_15:.*]] = arith.divsi %[[VAL_13]], %[[VAL_14]] : i64 +! CHECK: %[[VAL_16:.*]] = arith.constant 0 : i64 +! CHECK: %[[VAL_17:.*]] = arith.cmpi sgt, %[[VAL_15]], %[[VAL_16]] : i64 +! CHECK: %[[VAL_18:.*]] = arith.select %[[VAL_17]], %[[VAL_15]], %[[VAL_16]] : i64 +! CHECK: %[[VAL_19:.*]] = arith.muli %[[VAL_8]], %[[VAL_18]] : i64 +! CHECK: %[[VAL_20:.*]] = arith.addi %[[VAL_7]], %[[VAL_19]] : i64 +! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i64) -> index +! CHECK: %[[VAL_22:.*]] = arith.constant 1 : index +! CHECK: fir.store %[[VAL_22]] to %[[VAL_3]] : !fir.ref +! CHECK: %[[VAL_23:.*]] = fir.allocmem !fir.array, %[[VAL_21]] {bindc_name = ".tmp.arrayctor", uniq_name = ""} +! CHECK: %[[VAL_24:.*]] = fir.shape %[[VAL_21]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_25:.*]]:2 = hlfir.declare %[[VAL_23]](%[[VAL_24]]) {uniq_name = ".tmp.arrayctor"} : (!fir.heap>, !fir.shape<1>) -> (!fir.box>, !fir.heap>) +! CHECK: %[[VAL_26:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_26]] : (i64) -> index +! CHECK: %[[VAL_28:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref +! CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_28]] : (i64) -> index +! CHECK: %[[VAL_30:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (i64) -> index +! CHECK: fir.do_loop %[[VAL_32:.*]] = %[[VAL_27]] to %[[VAL_29]] step %[[VAL_31]] { +! CHECK: %[[VAL_33:.*]] = arith.constant 42 : i32 +! CHECK: %[[VAL_34:.*]] = fir.load %[[VAL_3]] : !fir.ref +! CHECK: %[[VAL_35:.*]] = arith.addi %[[VAL_34]], %[[VAL_22]] : index +! CHECK: fir.store %[[VAL_35]] to %[[VAL_3]] : !fir.ref +! CHECK: %[[VAL_36:.*]] = hlfir.designate %[[VAL_25]]#0 (%[[VAL_35]]) : (!fir.box>, index) -> !fir.ref +! CHECK: hlfir.assign %[[VAL_33]] to %[[VAL_36]] : i32, !fir.ref +! CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_32]] : (index) -> i64 +! CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_37]] : (i64) -> i32 +! CHECK: %[[VAL_39:.*]] = fir.load %[[VAL_3]] : !fir.ref +! CHECK: %[[VAL_40:.*]] = arith.addi %[[VAL_39]], %[[VAL_22]] : index +! CHECK: fir.store %[[VAL_40]] to %[[VAL_3]] : !fir.ref +! CHECK: %[[VAL_41:.*]] = hlfir.designate %[[VAL_25]]#0 (%[[VAL_40]]) : (!fir.box>, index) -> !fir.ref +! CHECK: hlfir.assign %[[VAL_38]] to %[[VAL_41]] : i32, !fir.ref +! CHECK: } +! CHECK: %[[VAL_42:.*]] = arith.constant true +! CHECK: %[[VAL_43:.*]] = hlfir.as_expr %[[VAL_25]]#0 move %[[VAL_42]] : (!fir.box>, i1) -> !hlfir.expr +! CHECK: %[[VAL_44:.*]]:3 = hlfir.associate %[[VAL_43]](%[[VAL_24]]) {uniq_name = "adapt.valuebyref"} : (!hlfir.expr, !fir.shape<1>) -> (!fir.box>, !fir.ref>, i1) +! CHECK: %[[VAL_45:.*]] = fir.convert %[[VAL_44]]#1 : (!fir.ref>) -> !fir.ref> +! CHECK: fir.call @_QPtakes_int(%[[VAL_45]]) fastmath : (!fir.ref>) -> () +! CHECK: hlfir.end_associate %[[VAL_44]]#1, %[[VAL_44]]#2 : !fir.ref>, i1 +! CHECK: hlfir.destroy %[[VAL_43]] : !hlfir.expr +! CHECK: return +! CHECK: } subroutine test_nested_implied_do(n, m) integer(8) :: n, m call takes_int([((i+j, i=1,m), j=1,n)]) end subroutine -! CHECK-LABEL: func.func @_QPtest_nested_implied_do( -! CHECK: %[[VAL_2:.*]] = fir.alloca index -! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare {{.*}}Em -! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare {{.*}}En -! CHECK: %[[VAL_5:.*]] = arith.constant 0 : i64 -! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i64 -! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref -! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_9:.*]] = arith.subi %[[VAL_7]], %[[VAL_8]] : i64 -! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_11:.*]] = arith.addi %[[VAL_9]], %[[VAL_10]] : i64 -! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_13:.*]] = arith.divsi %[[VAL_11]], %[[VAL_12]] : i64 -! CHECK: %[[VAL_14:.*]] = arith.constant 0 : i64 -! CHECK: %[[VAL_15:.*]] = arith.cmpi sgt, %[[VAL_13]], %[[VAL_14]] : i64 -! CHECK: %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_13]], %[[VAL_14]] : i64 -! CHECK: %[[VAL_17:.*]] = arith.addi %[[VAL_6]], %[[VAL_16]] : i64 -! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref -! CHECK: %[[VAL_19:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_20:.*]] = arith.subi %[[VAL_18]], %[[VAL_19]] : i64 -! CHECK: %[[VAL_21:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_22:.*]] = arith.addi %[[VAL_20]], %[[VAL_21]] : i64 -! CHECK: %[[VAL_23:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_24:.*]] = arith.divsi %[[VAL_22]], %[[VAL_23]] : i64 -! CHECK: %[[VAL_25:.*]] = arith.constant 0 : i64 -! CHECK: %[[VAL_26:.*]] = arith.cmpi sgt, %[[VAL_24]], %[[VAL_25]] : i64 -! CHECK: %[[VAL_27:.*]] = arith.select %[[VAL_26]], %[[VAL_24]], %[[VAL_25]] : i64 -! CHECK: %[[VAL_28:.*]] = arith.muli %[[VAL_17]], %[[VAL_27]] : i64 -! CHECK: %[[VAL_29:.*]] = arith.addi %[[VAL_5]], %[[VAL_28]] : i64 -! CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (i64) -> index -! CHECK: %[[VAL_31:.*]] = arith.constant 1 : index -! CHECK: fir.store %[[VAL_31]] to %[[VAL_2]] : !fir.ref -! CHECK: %[[VAL_32:.*]] = fir.allocmem !fir.array, %[[VAL_30]] {bindc_name = ".tmp.arrayctor", uniq_name = ""} -! CHECK: %[[VAL_33:.*]] = fir.shape %[[VAL_30]] : (index) -> !fir.shape<1> -! CHECK: %[[VAL_34:.*]]:2 = hlfir.declare %[[VAL_32]](%[[VAL_33]]) {uniq_name = ".tmp.arrayctor"} : (!fir.heap>, !fir.shape<1>) -> (!fir.box>, !fir.heap>) -! CHECK: %[[VAL_35:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_35]] : (i64) -> index -! CHECK: %[[VAL_37:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref -! CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_37]] : (i64) -> index -! CHECK: %[[VAL_39:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_40:.*]] = fir.convert %[[VAL_39]] : (i64) -> index -! CHECK: fir.do_loop %[[VAL_41:.*]] = %[[VAL_36]] to %[[VAL_38]] step %[[VAL_40]] { -! CHECK: %[[VAL_42:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_43:.*]] = fir.convert %[[VAL_42]] : (i64) -> index -! CHECK: %[[VAL_44:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref -! CHECK: %[[VAL_45:.*]] = fir.convert %[[VAL_44]] : (i64) -> index -! CHECK: %[[VAL_46:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_47:.*]] = fir.convert %[[VAL_46]] : (i64) -> index -! CHECK: fir.do_loop %[[VAL_48:.*]] = %[[VAL_43]] to %[[VAL_45]] step %[[VAL_47]] { -! CHECK: %[[VAL_49:.*]] = fir.convert %[[VAL_48]] : (index) -> i32 -! CHECK: %[[VAL_50:.*]] = fir.convert %[[VAL_41]] : (index) -> i32 -! CHECK: %[[VAL_51:.*]] = arith.addi %[[VAL_49]], %[[VAL_50]] : i32 -! CHECK: %[[VAL_52:.*]] = fir.load %[[VAL_2]] : !fir.ref -! CHECK: %[[VAL_53:.*]] = arith.addi %[[VAL_52]], %[[VAL_31]] : index -! CHECK: fir.store %[[VAL_53]] to %[[VAL_2]] : !fir.ref -! CHECK: %[[VAL_54:.*]] = hlfir.designate %[[VAL_34]]#0 (%[[VAL_53]]) : (!fir.box>, index) -> !fir.ref -! CHECK: hlfir.assign %[[VAL_51]] to %[[VAL_54]] : i32, !fir.ref -! CHECK: } -! CHECK: } -! CHECK: %[[VAL_55:.*]] = arith.constant true -! CHECK: %[[VAL_56:.*]] = hlfir.as_expr %[[VAL_34]]#0 move %[[VAL_55]] : (!fir.box>, i1) -> !hlfir.expr -! CHECK: fir.call -! CHECK: hlfir.destroy %[[VAL_56]] : !hlfir.expr +! CHECK-LABEL: func.func @_QPtest_nested_implied_do( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "n"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "m"}) { +! CHECK: %[[VAL_2:.*]] = fir.alloca index +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest_nested_implied_doEm"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest_nested_implied_doEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_5:.*]] = arith.constant 0 : i64 +! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i64 +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref +! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_9:.*]] = arith.subi %[[VAL_7]], %[[VAL_8]] : i64 +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_11:.*]] = arith.addi %[[VAL_9]], %[[VAL_10]] : i64 +! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_13:.*]] = arith.divsi %[[VAL_11]], %[[VAL_12]] : i64 +! CHECK: %[[VAL_14:.*]] = arith.constant 0 : i64 +! CHECK: %[[VAL_15:.*]] = arith.cmpi sgt, %[[VAL_13]], %[[VAL_14]] : i64 +! CHECK: %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_13]], %[[VAL_14]] : i64 +! CHECK: %[[VAL_17:.*]] = arith.addi %[[VAL_6]], %[[VAL_16]] : i64 +! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_19:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_20:.*]] = arith.subi %[[VAL_18]], %[[VAL_19]] : i64 +! CHECK: %[[VAL_21:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_22:.*]] = arith.addi %[[VAL_20]], %[[VAL_21]] : i64 +! CHECK: %[[VAL_23:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_24:.*]] = arith.divsi %[[VAL_22]], %[[VAL_23]] : i64 +! CHECK: %[[VAL_25:.*]] = arith.constant 0 : i64 +! CHECK: %[[VAL_26:.*]] = arith.cmpi sgt, %[[VAL_24]], %[[VAL_25]] : i64 +! CHECK: %[[VAL_27:.*]] = arith.select %[[VAL_26]], %[[VAL_24]], %[[VAL_25]] : i64 +! CHECK: %[[VAL_28:.*]] = arith.muli %[[VAL_17]], %[[VAL_27]] : i64 +! CHECK: %[[VAL_29:.*]] = arith.addi %[[VAL_5]], %[[VAL_28]] : i64 +! CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (i64) -> index +! CHECK: %[[VAL_31:.*]] = arith.constant 1 : index +! CHECK: fir.store %[[VAL_31]] to %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_32:.*]] = fir.allocmem !fir.array, %[[VAL_30]] {bindc_name = ".tmp.arrayctor", uniq_name = ""} +! CHECK: %[[VAL_33:.*]] = fir.shape %[[VAL_30]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_34:.*]]:2 = hlfir.declare %[[VAL_32]](%[[VAL_33]]) {uniq_name = ".tmp.arrayctor"} : (!fir.heap>, !fir.shape<1>) -> (!fir.box>, !fir.heap>) +! CHECK: %[[VAL_35:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_35]] : (i64) -> index +! CHECK: %[[VAL_37:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_37]] : (i64) -> index +! CHECK: %[[VAL_39:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_40:.*]] = fir.convert %[[VAL_39]] : (i64) -> index +! CHECK: fir.do_loop %[[VAL_41:.*]] = %[[VAL_36]] to %[[VAL_38]] step %[[VAL_40]] { +! CHECK: %[[VAL_42:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_43:.*]] = fir.convert %[[VAL_42]] : (i64) -> index +! CHECK: %[[VAL_44:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref +! CHECK: %[[VAL_45:.*]] = fir.convert %[[VAL_44]] : (i64) -> index +! CHECK: %[[VAL_46:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_47:.*]] = fir.convert %[[VAL_46]] : (i64) -> index +! CHECK: fir.do_loop %[[VAL_48:.*]] = %[[VAL_43]] to %[[VAL_45]] step %[[VAL_47]] { +! CHECK: %[[VAL_49:.*]] = fir.convert %[[VAL_48]] : (index) -> i64 +! CHECK: %[[VAL_50:.*]] = fir.convert %[[VAL_49]] : (i64) -> i32 +! CHECK: %[[VAL_51:.*]] = fir.convert %[[VAL_41]] : (index) -> i64 +! CHECK: %[[VAL_52:.*]] = fir.convert %[[VAL_51]] : (i64) -> i32 +! CHECK: %[[VAL_53:.*]] = arith.addi %[[VAL_50]], %[[VAL_52]] : i32 +! CHECK: %[[VAL_54:.*]] = fir.load %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_55:.*]] = arith.addi %[[VAL_54]], %[[VAL_31]] : index +! CHECK: fir.store %[[VAL_55]] to %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_56:.*]] = hlfir.designate %[[VAL_34]]#0 (%[[VAL_55]]) : (!fir.box>, index) -> !fir.ref +! CHECK: hlfir.assign %[[VAL_53]] to %[[VAL_56]] : i32, !fir.ref +! CHECK: } +! CHECK: } +! CHECK: %[[VAL_57:.*]] = arith.constant true +! CHECK: %[[VAL_58:.*]] = hlfir.as_expr %[[VAL_34]]#0 move %[[VAL_57]] : (!fir.box>, i1) -> !hlfir.expr +! CHECK: %[[VAL_59:.*]]:3 = hlfir.associate %[[VAL_58]](%[[VAL_33]]) {uniq_name = "adapt.valuebyref"} : (!hlfir.expr, !fir.shape<1>) -> (!fir.box>, !fir.ref>, i1) +! CHECK: %[[VAL_60:.*]] = fir.convert %[[VAL_59]]#1 : (!fir.ref>) -> !fir.ref> +! CHECK: fir.call @_QPtakes_int(%[[VAL_60]]) fastmath : (!fir.ref>) -> () +! CHECK: hlfir.end_associate %[[VAL_59]]#1, %[[VAL_59]]#2 : !fir.ref>, i1 +! CHECK: hlfir.destroy %[[VAL_58]] : !hlfir.expr +! CHECK: return +! CHECK: } diff --git a/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90 b/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90 index 81b29e37a08d8..26b68c3f2cb02 100644 --- a/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90 +++ b/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90 @@ -6,44 +6,58 @@ module arrayctor subroutine test_loops() call takes_int([((i, i=1,ifoo()), j=1,ibar())]) end subroutine -! CHECK-LABEL: func.func @_QMarrayctorPtest_loops() { -! CHECK: %[[VAL_0:.*]] = fir.alloca i32 -! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.array<10xi64> {bindc_name = ".rt.arrayctor.vector"} -! CHECK: %[[VAL_2:.*]] = fir.alloca !fir.box>> {bindc_name = ".tmp.arrayctor"} -! CHECK: %[[VAL_3:.*]] = arith.constant 0 : index -! CHECK: %[[VAL_4:.*]] = fir.zero_bits !fir.heap> -! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1> -! CHECK: %[[VAL_6:.*]] = fir.embox %[[VAL_4]](%[[VAL_5]]) : (!fir.heap>, !fir.shape<1>) -> !fir.box>> -! CHECK: fir.store %[[VAL_6]] to %[[VAL_2]] : !fir.ref>>> -! CHECK: %[[VAL_7:.*]] = arith.constant false -! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>) -> !fir.llvm_ptr -! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref>>>) -> !fir.ref> -! CHECK: %[[VAL_14:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_8]], %[[VAL_12]], %[[VAL_7]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr, !fir.ref>, i1, i32, !fir.ref, i32) -> none -! CHECK: %[[VAL_15:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_15]] : (i64) -> index -! CHECK: %[[VAL_17:.*]] = fir.call @_QMarrayctorPibar() {{.*}}: () -> i32 -! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (i32) -> i64 -! CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_18]] : (i64) -> index -! CHECK: %[[VAL_20:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i64) -> index -! CHECK: fir.do_loop %[[VAL_22:.*]] = %[[VAL_16]] to %[[VAL_19]] step %[[VAL_21]] { -! CHECK: %[[VAL_23:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_23]] : (i64) -> index -! CHECK: %[[VAL_25:.*]] = fir.call @_QMarrayctorPifoo() {{.*}}: () -> i32 -! CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_25]] : (i32) -> i64 -! CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_26]] : (i64) -> index -! CHECK: %[[VAL_28:.*]] = arith.constant 1 : i64 -! CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_28]] : (i64) -> index -! CHECK: fir.do_loop %[[VAL_30:.*]] = %[[VAL_24]] to %[[VAL_27]] step %[[VAL_29]] { -! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (index) -> i32 -! CHECK: fir.store %[[VAL_31]] to %[[VAL_0]] : !fir.ref -! CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr -! CHECK: %[[VAL_33:.*]] = fir.call @_FortranAPushArrayConstructorSimpleScalar(%[[VAL_8]], %[[VAL_32]]) {{.*}}: (!fir.llvm_ptr, !fir.llvm_ptr) -> none -! CHECK: } -! CHECK: } -! CHECK: %[[VAL_34:.*]] = arith.constant true -! CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_2]] : !fir.ref>>> -! CHECK: hlfir.as_expr %[[VAL_35]] move %[[VAL_34]] : (!fir.box>>, i1) -> !hlfir.expr +! CHECK-LABEL: func.func @_QMarrayctorPtest_loops() { +! CHECK: %[[VAL_0:.*]] = fir.alloca i32 +! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.array<10xi64> {bindc_name = ".rt.arrayctor.vector"} +! CHECK: %[[VAL_2:.*]] = fir.alloca !fir.box>> {bindc_name = ".tmp.arrayctor"} +! CHECK: %[[VAL_3:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_4:.*]] = fir.zero_bits !fir.heap> +! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_6:.*]] = fir.embox %[[VAL_4]](%[[VAL_5]]) : (!fir.heap>, !fir.shape<1>) -> !fir.box>> +! CHECK: fir.store %[[VAL_6]] to %[[VAL_2]] : !fir.ref>>> +! CHECK: %[[VAL_7:.*]] = arith.constant false +! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>) -> !fir.llvm_ptr +! CHECK: %[[VAL_9:.*]] = arith.constant 80 : i32 +! CHECK: %[[VAL_10:.*]] = fir.address_of(@_QQcl.{{.*}}) : !fir.ref> +! CHECK: %[[VAL_11:.*]] = arith.constant 7 : i32 +! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref>>>) -> !fir.ref> +! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_10]] : (!fir.ref>) -> !fir.ref +! CHECK: %[[VAL_14:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_8]], %[[VAL_12]], %[[VAL_7]], %[[VAL_9]], %[[VAL_13]], %[[VAL_11]]) fastmath : (!fir.llvm_ptr, !fir.ref>, i1, i32, !fir.ref, i32) -> none +! CHECK: %[[VAL_15:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_15]] : (i64) -> index +! CHECK: %[[VAL_17:.*]] = fir.call @_QMarrayctorPibar() fastmath : () -> i32 +! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (i32) -> i64 +! CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_18]] : (i64) -> index +! CHECK: %[[VAL_20:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i64) -> index +! CHECK: fir.do_loop %[[VAL_22:.*]] = %[[VAL_16]] to %[[VAL_19]] step %[[VAL_21]] { +! CHECK: %[[VAL_23:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_23]] : (i64) -> index +! CHECK: %[[VAL_25:.*]] = fir.call @_QMarrayctorPifoo() fastmath : () -> i32 +! CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_25]] : (i32) -> i64 +! CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_26]] : (i64) -> index +! CHECK: %[[VAL_28:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_28]] : (i64) -> index +! CHECK: fir.do_loop %[[VAL_30:.*]] = %[[VAL_24]] to %[[VAL_27]] step %[[VAL_29]] { +! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (index) -> i64 +! CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_31]] : (i64) -> i32 +! CHECK: fir.store %[[VAL_32]] to %[[VAL_0]] : !fir.ref +! CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_34:.*]] = fir.call @_FortranAPushArrayConstructorSimpleScalar(%[[VAL_8]], %[[VAL_33]]) fastmath : (!fir.llvm_ptr, !fir.llvm_ptr) -> none +! CHECK: } +! CHECK: } +! CHECK: %[[VAL_35:.*]] = arith.constant true +! CHECK: %[[VAL_36:.*]] = fir.load %[[VAL_2]] : !fir.ref>>> +! CHECK: %[[VAL_37:.*]] = hlfir.as_expr %[[VAL_36]] move %[[VAL_35]] : (!fir.box>>, i1) -> !hlfir.expr +! CHECK: %[[VAL_38:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_39:.*]]:3 = fir.box_dims %[[VAL_36]], %[[VAL_38]] : (!fir.box>>, index) -> (index, index, index) +! CHECK: %[[VAL_40:.*]] = fir.shape %[[VAL_39]]#1 : (index) -> !fir.shape<1> +! CHECK: %[[VAL_41:.*]]:3 = hlfir.associate %[[VAL_37]](%[[VAL_40]]) {uniq_name = "adapt.valuebyref"} : (!hlfir.expr, !fir.shape<1>) -> (!fir.box>, !fir.ref>, i1) +! CHECK: fir.call @_QMarrayctorPtakes_int(%[[VAL_41]]#0) fastmath : (!fir.box>) -> () +! CHECK: hlfir.end_associate %[[VAL_41]]#1, %[[VAL_41]]#2 : !fir.ref>, i1 +! CHECK: hlfir.destroy %[[VAL_37]] : !hlfir.expr +! CHECK: return +! CHECK: } subroutine test_arrays(a) integer :: a(:, :) diff --git a/flang/test/Lower/HLFIR/array-ctor-index.f90 b/flang/test/Lower/HLFIR/array-ctor-index.f90 new file mode 100644 index 0000000000000..b52a1afb68b2b --- /dev/null +++ b/flang/test/Lower/HLFIR/array-ctor-index.f90 @@ -0,0 +1,194 @@ +! Check that the implied-do index value is converted to proper type. +! RUN: bbc -emit-fir -hlfir -o - %s | FileCheck %s + +function test1(k) + integer*1 :: k + integer*1 :: test1(4) + test1 = ([(i*k, integer(8)::i=1,4)]) +end function test1 +! CHECK-LABEL: func.func @_QPtest1( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "k"}) -> !fir.array<4xi8> { +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest1Ek"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_2:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_3:.*]] = fir.alloca !fir.array<4xi8> {bindc_name = "test1", uniq_name = "_QFtest1Etest1"} +! CHECK: %[[VAL_4:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_3]](%[[VAL_4]]) {uniq_name = "_QFtest1Etest1"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_6]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i64) -> index +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i64) -> index +! CHECK: %[[VAL_12:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_13:.*]] = hlfir.elemental %[[VAL_7]] : (!fir.shape<1>) -> !hlfir.expr<4xi64> { +! CHECK: ^bb0(%[[VAL_14:.*]]: index): +! CHECK: %[[VAL_15:.*]] = arith.subi %[[VAL_14]], %[[VAL_12]] : index +! CHECK: %[[VAL_16:.*]] = arith.muli %[[VAL_15]], %[[VAL_11]] : index +! CHECK: %[[VAL_17:.*]] = arith.addi %[[VAL_9]], %[[VAL_16]] : index +! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (index) -> i64 +! CHECK: %[[VAL_19:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref +! CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_19]] : (i8) -> i64 +! CHECK: %[[VAL_21:.*]] = arith.muli %[[VAL_18]], %[[VAL_20]] : i64 +! CHECK: hlfir.yield_element %[[VAL_21]] : i64 +! CHECK: } +! CHECK: %[[VAL_22:.*]] = hlfir.elemental %[[VAL_7]] : (!fir.shape<1>) -> !hlfir.expr<4xi64> { +! CHECK: ^bb0(%[[VAL_23:.*]]: index): +! CHECK: %[[VAL_24:.*]] = hlfir.apply %[[VAL_25:.*]], %[[VAL_23]] : (!hlfir.expr<4xi64>, index) -> i64 +! CHECK: %[[VAL_26:.*]] = hlfir.no_reassoc %[[VAL_24]] : i64 +! CHECK: hlfir.yield_element %[[VAL_26]] : i64 +! CHECK: } +! CHECK: %[[VAL_27:.*]] = hlfir.elemental %[[VAL_7]] : (!fir.shape<1>) -> !hlfir.expr<4xi8> { +! CHECK: ^bb0(%[[VAL_28:.*]]: index): +! CHECK: %[[VAL_29:.*]] = hlfir.apply %[[VAL_30:.*]], %[[VAL_28]] : (!hlfir.expr<4xi64>, index) -> i64 +! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_29]] : (i64) -> i8 +! CHECK: hlfir.yield_element %[[VAL_31]] : i8 +! CHECK: } +! CHECK: hlfir.assign %[[VAL_32:.*]] to %[[VAL_5]]#0 : !hlfir.expr<4xi8>, !fir.ref> +! CHECK: hlfir.destroy %[[VAL_32]] : !hlfir.expr<4xi8> +! CHECK: hlfir.destroy %[[VAL_33:.*]] : !hlfir.expr<4xi64> +! CHECK: hlfir.destroy %[[VAL_34:.*]] : !hlfir.expr<4xi64> +! CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_5]]#1 : !fir.ref> +! CHECK: return %[[VAL_35]] : !fir.array<4xi8> +! CHECK: } + +function test2(k) + integer*2 :: k + integer*2 :: test2(4) + test2 = ([(i*k, integer(8)::i=1,4)]) +end function test2 +! CHECK-LABEL: func.func @_QPtest2( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "k"}) -> !fir.array<4xi16> { +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest2Ek"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_2:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_3:.*]] = fir.alloca !fir.array<4xi16> {bindc_name = "test2", uniq_name = "_QFtest2Etest2"} +! CHECK: %[[VAL_4:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_3]](%[[VAL_4]]) {uniq_name = "_QFtest2Etest2"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_6]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i64) -> index +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i64) -> index +! CHECK: %[[VAL_12:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_13:.*]] = hlfir.elemental %[[VAL_7]] : (!fir.shape<1>) -> !hlfir.expr<4xi64> { +! CHECK: ^bb0(%[[VAL_14:.*]]: index): +! CHECK: %[[VAL_15:.*]] = arith.subi %[[VAL_14]], %[[VAL_12]] : index +! CHECK: %[[VAL_16:.*]] = arith.muli %[[VAL_15]], %[[VAL_11]] : index +! CHECK: %[[VAL_17:.*]] = arith.addi %[[VAL_9]], %[[VAL_16]] : index +! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (index) -> i64 +! CHECK: %[[VAL_19:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref +! CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_19]] : (i16) -> i64 +! CHECK: %[[VAL_21:.*]] = arith.muli %[[VAL_18]], %[[VAL_20]] : i64 +! CHECK: hlfir.yield_element %[[VAL_21]] : i64 +! CHECK: } +! CHECK: %[[VAL_22:.*]] = hlfir.elemental %[[VAL_7]] : (!fir.shape<1>) -> !hlfir.expr<4xi64> { +! CHECK: ^bb0(%[[VAL_23:.*]]: index): +! CHECK: %[[VAL_24:.*]] = hlfir.apply %[[VAL_25:.*]], %[[VAL_23]] : (!hlfir.expr<4xi64>, index) -> i64 +! CHECK: %[[VAL_26:.*]] = hlfir.no_reassoc %[[VAL_24]] : i64 +! CHECK: hlfir.yield_element %[[VAL_26]] : i64 +! CHECK: } +! CHECK: %[[VAL_27:.*]] = hlfir.elemental %[[VAL_7]] : (!fir.shape<1>) -> !hlfir.expr<4xi16> { +! CHECK: ^bb0(%[[VAL_28:.*]]: index): +! CHECK: %[[VAL_29:.*]] = hlfir.apply %[[VAL_30:.*]], %[[VAL_28]] : (!hlfir.expr<4xi64>, index) -> i64 +! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_29]] : (i64) -> i16 +! CHECK: hlfir.yield_element %[[VAL_31]] : i16 +! CHECK: } +! CHECK: hlfir.assign %[[VAL_32:.*]] to %[[VAL_5]]#0 : !hlfir.expr<4xi16>, !fir.ref> +! CHECK: hlfir.destroy %[[VAL_32]] : !hlfir.expr<4xi16> +! CHECK: hlfir.destroy %[[VAL_33:.*]] : !hlfir.expr<4xi64> +! CHECK: hlfir.destroy %[[VAL_34:.*]] : !hlfir.expr<4xi64> +! CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_5]]#1 : !fir.ref> +! CHECK: return %[[VAL_35]] : !fir.array<4xi16> +! CHECK: } + +function test3(k) + integer*4 :: k + integer*4 :: test3(4) + test3 = ([(i*k, integer(8)::i=1,4)]) +end function test3 +! CHECK-LABEL: func.func @_QPtest3( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "k"}) -> !fir.array<4xi32> { +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest3Ek"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_2:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_3:.*]] = fir.alloca !fir.array<4xi32> {bindc_name = "test3", uniq_name = "_QFtest3Etest3"} +! CHECK: %[[VAL_4:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_3]](%[[VAL_4]]) {uniq_name = "_QFtest3Etest3"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_6]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i64) -> index +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i64) -> index +! CHECK: %[[VAL_12:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_13:.*]] = hlfir.elemental %[[VAL_7]] : (!fir.shape<1>) -> !hlfir.expr<4xi64> { +! CHECK: ^bb0(%[[VAL_14:.*]]: index): +! CHECK: %[[VAL_15:.*]] = arith.subi %[[VAL_14]], %[[VAL_12]] : index +! CHECK: %[[VAL_16:.*]] = arith.muli %[[VAL_15]], %[[VAL_11]] : index +! CHECK: %[[VAL_17:.*]] = arith.addi %[[VAL_9]], %[[VAL_16]] : index +! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (index) -> i64 +! CHECK: %[[VAL_19:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref +! CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_19]] : (i32) -> i64 +! CHECK: %[[VAL_21:.*]] = arith.muli %[[VAL_18]], %[[VAL_20]] : i64 +! CHECK: hlfir.yield_element %[[VAL_21]] : i64 +! CHECK: } +! CHECK: %[[VAL_22:.*]] = hlfir.elemental %[[VAL_7]] : (!fir.shape<1>) -> !hlfir.expr<4xi64> { +! CHECK: ^bb0(%[[VAL_23:.*]]: index): +! CHECK: %[[VAL_24:.*]] = hlfir.apply %[[VAL_25:.*]], %[[VAL_23]] : (!hlfir.expr<4xi64>, index) -> i64 +! CHECK: %[[VAL_26:.*]] = hlfir.no_reassoc %[[VAL_24]] : i64 +! CHECK: hlfir.yield_element %[[VAL_26]] : i64 +! CHECK: } +! CHECK: %[[VAL_27:.*]] = hlfir.elemental %[[VAL_7]] : (!fir.shape<1>) -> !hlfir.expr<4xi32> { +! CHECK: ^bb0(%[[VAL_28:.*]]: index): +! CHECK: %[[VAL_29:.*]] = hlfir.apply %[[VAL_30:.*]], %[[VAL_28]] : (!hlfir.expr<4xi64>, index) -> i64 +! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_29]] : (i64) -> i32 +! CHECK: hlfir.yield_element %[[VAL_31]] : i32 +! CHECK: } +! CHECK: hlfir.assign %[[VAL_32:.*]] to %[[VAL_5]]#0 : !hlfir.expr<4xi32>, !fir.ref> +! CHECK: hlfir.destroy %[[VAL_32]] : !hlfir.expr<4xi32> +! CHECK: hlfir.destroy %[[VAL_33:.*]] : !hlfir.expr<4xi64> +! CHECK: hlfir.destroy %[[VAL_34:.*]] : !hlfir.expr<4xi64> +! CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_5]]#1 : !fir.ref> +! CHECK: return %[[VAL_35]] : !fir.array<4xi32> +! CHECK: } + +function test4(k) + integer*8 :: k + integer*8 :: test4(4) + test4 = ([(i*k, integer(8)::i=1,4)]) +end function test4 +! CHECK-LABEL: func.func @_QPtest4( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "k"}) -> !fir.array<4xi64> { +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest4Ek"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_2:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_3:.*]] = fir.alloca !fir.array<4xi64> {bindc_name = "test4", uniq_name = "_QFtest4Etest4"} +! CHECK: %[[VAL_4:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_3]](%[[VAL_4]]) {uniq_name = "_QFtest4Etest4"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_6]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i64) -> index +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i64) -> index +! CHECK: %[[VAL_12:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_13:.*]] = hlfir.elemental %[[VAL_7]] : (!fir.shape<1>) -> !hlfir.expr<4xi64> { +! CHECK: ^bb0(%[[VAL_14:.*]]: index): +! CHECK: %[[VAL_15:.*]] = arith.subi %[[VAL_14]], %[[VAL_12]] : index +! CHECK: %[[VAL_16:.*]] = arith.muli %[[VAL_15]], %[[VAL_11]] : index +! CHECK: %[[VAL_17:.*]] = arith.addi %[[VAL_9]], %[[VAL_16]] : index +! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (index) -> i64 +! CHECK: %[[VAL_19:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref +! CHECK: %[[VAL_20:.*]] = arith.muli %[[VAL_18]], %[[VAL_19]] : i64 +! CHECK: hlfir.yield_element %[[VAL_20]] : i64 +! CHECK: } +! CHECK: %[[VAL_21:.*]] = hlfir.elemental %[[VAL_7]] : (!fir.shape<1>) -> !hlfir.expr<4xi64> { +! CHECK: ^bb0(%[[VAL_22:.*]]: index): +! CHECK: %[[VAL_23:.*]] = hlfir.apply %[[VAL_24:.*]], %[[VAL_22]] : (!hlfir.expr<4xi64>, index) -> i64 +! CHECK: %[[VAL_25:.*]] = hlfir.no_reassoc %[[VAL_23]] : i64 +! CHECK: hlfir.yield_element %[[VAL_25]] : i64 +! CHECK: } +! CHECK: hlfir.assign %[[VAL_26:.*]] to %[[VAL_5]]#0 : !hlfir.expr<4xi64>, !fir.ref> +! CHECK: hlfir.destroy %[[VAL_26]] : !hlfir.expr<4xi64> +! CHECK: hlfir.destroy %[[VAL_27:.*]] : !hlfir.expr<4xi64> +! CHECK: %[[VAL_28:.*]] = fir.load %[[VAL_5]]#1 : !fir.ref> +! CHECK: return %[[VAL_28]] : !fir.array<4xi64> +! CHECK: } diff --git a/flang/test/Lower/HLFIR/binary-ops.f90 b/flang/test/Lower/HLFIR/binary-ops.f90 index 8e5dced1396d0..4b5b1a698e8c3 100644 --- a/flang/test/Lower/HLFIR/binary-ops.f90 +++ b/flang/test/Lower/HLFIR/binary-ops.f90 @@ -131,8 +131,11 @@ subroutine complex_div(x, y, z) ! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref> ! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref> -! CHECK: %[[VAL_8:.*]] = fir.divc %[[VAL_6]], %[[VAL_7]] : !fir.complex<4> - +! CHECK: %[[VAL_8:.*]] = fir.extract_value %[[VAL_6]], [0 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[VAL_9:.*]] = fir.extract_value %[[VAL_6]], [1 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[VAL_10:.*]] = fir.extract_value %[[VAL_7]], [0 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[VAL_11:.*]] = fir.extract_value %[[VAL_7]], [1 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[VAL_12:.*]] = fir.call @__divsc3(%[[VAL_8]], %[[VAL_9]], %[[VAL_10]], %[[VAL_11]]) fastmath : (f32, f32, f32, f32) -> !fir.complex<4> subroutine int_power(x, y, z) integer :: x, y, z diff --git a/flang/test/Lower/HLFIR/forall.f90 b/flang/test/Lower/HLFIR/forall.f90 new file mode 100644 index 0000000000000..5091dde7bc79c --- /dev/null +++ b/flang/test/Lower/HLFIR/forall.f90 @@ -0,0 +1,185 @@ +! Test lowering of Forall to HLFIR. +! RUN: bbc --hlfir -o - %s | FileCheck %s + +module forall_defs + integer :: x(10, 10), y(10) + interface + pure integer(8) function ifoo2(i, j) + integer(8), value :: i, j + end function + pure integer(8) function jfoo() + end function + pure integer(8) function jbar() + end function + pure logical function predicate(i) + integer(8), intent(in) :: i + end function + end interface +end module + +subroutine test_simple_forall() + use forall_defs + forall (integer(8)::i=1:10) x(i, i) = y(i) +end subroutine +! CHECK-LABEL: func.func @_QPtest_simple_forall() { +! CHECK: %[[VAL_0:.*]] = arith.constant 10 : i32 +! CHECK: %[[VAL_1:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare {{.*}}Ey +! CHECK: hlfir.forall lb { +! CHECK: hlfir.yield %[[VAL_1]] : i32 +! CHECK: } ub { +! CHECK: hlfir.yield %[[VAL_0]] : i32 +! CHECK: } (%[[VAL_9:.*]]: i64) { +! CHECK: hlfir.region_assign { +! CHECK: %[[VAL_10:.*]] = hlfir.designate %[[VAL_8]]#0 (%[[VAL_9]]) : (!fir.ref>, i64) -> !fir.ref +! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_10]] : !fir.ref +! CHECK: hlfir.yield %[[VAL_11]] : i32 +! CHECK: } to { +! CHECK: %[[VAL_12:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_9]], %[[VAL_9]]) : (!fir.ref>, i64, i64) -> !fir.ref +! CHECK: hlfir.yield %[[VAL_12]] : !fir.ref +! CHECK: } +! CHECK: } + +subroutine test_forall_step(step) + use forall_defs + integer :: step + forall (integer(8)::i=1:10:step) x(i, i) = y(i) +end subroutine +! CHECK-LABEL: func.func @_QPtest_forall_step( +! CHECK: %[[VAL_1:.*]] = arith.constant 10 : i32 +! CHECK: %[[VAL_2:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare {{.*}}Estep +! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: %[[VAL_10:.*]]:2 = hlfir.declare {{.*}}Ey +! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_4]]#1 : !fir.ref +! CHECK: hlfir.forall lb { +! CHECK: hlfir.yield %[[VAL_2]] : i32 +! CHECK: } ub { +! CHECK: hlfir.yield %[[VAL_1]] : i32 +! CHECK: } step { +! CHECK: hlfir.yield %[[VAL_11]] : i32 +! CHECK: } (%[[VAL_12:.*]]: i64) { +! CHECK: hlfir.region_assign { +! CHECK: %[[VAL_13:.*]] = hlfir.designate %[[VAL_10]]#0 (%[[VAL_12]]) : (!fir.ref>, i64) -> !fir.ref +! CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_13]] : !fir.ref +! CHECK: hlfir.yield %[[VAL_14]] : i32 +! CHECK: } to { +! CHECK: %[[VAL_15:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_12]], %[[VAL_12]]) : (!fir.ref>, i64, i64) -> !fir.ref +! CHECK: hlfir.yield %[[VAL_15]] : !fir.ref +! CHECK: } +! CHECK: } + +subroutine test_forall_mask() + use forall_defs + forall (integer(8)::i=1:10, predicate(i)) x(i, i) = y(i) +end subroutine +! CHECK-LABEL: func.func @_QPtest_forall_mask() { +! CHECK: %[[VAL_0:.*]] = arith.constant 10 : i32 +! CHECK: %[[VAL_1:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare {{.*}}Ey +! CHECK: hlfir.forall lb { +! CHECK: hlfir.yield %[[VAL_1]] : i32 +! CHECK: } ub { +! CHECK: hlfir.yield %[[VAL_0]] : i32 +! CHECK: } (%[[VAL_9:.*]]: i64) { +! CHECK: %[[VAL_10:.*]] = hlfir.forall_index "i" %[[VAL_9]] : (i64) -> !fir.ref +! CHECK: hlfir.forall_mask { +! CHECK: %[[VAL_11:.*]] = fir.call @_QPpredicate(%[[VAL_10]]) fastmath : (!fir.ref) -> !fir.logical<4> +! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (!fir.logical<4>) -> i1 +! CHECK: hlfir.yield %[[VAL_12]] : i1 +! CHECK: } do { +! CHECK: hlfir.region_assign { +! CHECK: %[[VAL_13:.*]] = hlfir.designate %[[VAL_8]]#0 (%[[VAL_9]]) : (!fir.ref>, i64) -> !fir.ref +! CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_13]] : !fir.ref +! CHECK: hlfir.yield %[[VAL_14]] : i32 +! CHECK: } to { +! CHECK: %[[VAL_15:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_9]], %[[VAL_9]]) : (!fir.ref>, i64, i64) -> !fir.ref +! CHECK: hlfir.yield %[[VAL_15]] : !fir.ref +! CHECK: } +! CHECK: } +! CHECK: } + +subroutine test_forall_several_indices() + use forall_defs + ! Test outer forall controls are lowered outside. + forall (integer(8)::i=ibar():ifoo(), j=jfoo():jbar()) x(i, j) = y(ifoo2(i, j)) +end subroutine +! CHECK-LABEL: func.func @_QPtest_forall_several_indices() { +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare {{.*}}Ey +! CHECK: %[[VAL_7:.*]] = fir.call @_QPibar() fastmath : () -> i32 +! CHECK: %[[VAL_8:.*]] = fir.call @_QPifoo() fastmath : () -> i32 +! CHECK: %[[VAL_9:.*]] = fir.call @_QPjfoo() fastmath : () -> i64 +! CHECK: %[[VAL_10:.*]] = fir.call @_QPjbar() fastmath : () -> i64 +! CHECK: hlfir.forall lb { +! CHECK: hlfir.yield %[[VAL_7]] : i32 +! CHECK: } ub { +! CHECK: hlfir.yield %[[VAL_8]] : i32 +! CHECK: } (%[[VAL_11:.*]]: i64) { +! CHECK: hlfir.forall lb { +! CHECK: hlfir.yield %[[VAL_9]] : i64 +! CHECK: } ub { +! CHECK: hlfir.yield %[[VAL_10]] : i64 +! CHECK: } (%[[VAL_12:.*]]: i64) { +! CHECK: hlfir.region_assign { +! CHECK: %[[VAL_13:.*]] = fir.call @_QPifoo2(%[[VAL_11]], %[[VAL_12]]) fastmath : (i64, i64) -> i64 +! CHECK: %[[VAL_14:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_13]]) : (!fir.ref>, i64) -> !fir.ref +! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_14]] : !fir.ref +! CHECK: hlfir.yield %[[VAL_15]] : i32 +! CHECK: } to { +! CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_11]], %[[VAL_12]]) : (!fir.ref>, i64, i64) -> !fir.ref +! CHECK: hlfir.yield %[[VAL_16]] : !fir.ref +! CHECK: } +! CHECK: } +! CHECK: } + +subroutine test_nested_foralls() + use forall_defs + forall (integer(8)::i=1:10) + x(i, i) = y(i) + ! ifoo and ibar could depend on x since it is a module + ! variable use associated. The calls in the control value + ! computation cannot be hoisted from the outer forall + ! even when they do not depend on outer forall indicies. + forall (integer(8)::j=jfoo():jbar()) + x(i, j) = x(j, i) + end forall + end forall +end subroutine +! CHECK-LABEL: func.func @_QPtest_nested_foralls() { +! CHECK: %[[VAL_0:.*]] = arith.constant 10 : i32 +! CHECK: %[[VAL_1:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare {{.*}}Ey +! CHECK: hlfir.forall lb { +! CHECK: hlfir.yield %[[VAL_1]] : i32 +! CHECK: } ub { +! CHECK: hlfir.yield %[[VAL_0]] : i32 +! CHECK: } (%[[VAL_9:.*]]: i64) { +! CHECK: hlfir.region_assign { +! CHECK: %[[VAL_10:.*]] = hlfir.designate %[[VAL_8]]#0 (%[[VAL_9]]) : (!fir.ref>, i64) -> !fir.ref +! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_10]] : !fir.ref +! CHECK: hlfir.yield %[[VAL_11]] : i32 +! CHECK: } to { +! CHECK: %[[VAL_12:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_9]], %[[VAL_9]]) : (!fir.ref>, i64, i64) -> !fir.ref +! CHECK: hlfir.yield %[[VAL_12]] : !fir.ref +! CHECK: } +! CHECK: hlfir.forall lb { +! CHECK: %[[VAL_13:.*]] = fir.call @_QPjfoo() fastmath : () -> i64 +! CHECK: hlfir.yield %[[VAL_13]] : i64 +! CHECK: } ub { +! CHECK: %[[VAL_14:.*]] = fir.call @_QPjbar() fastmath : () -> i64 +! CHECK: hlfir.yield %[[VAL_14]] : i64 +! CHECK: } (%[[VAL_15:.*]]: i64) { +! CHECK: hlfir.region_assign { +! CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_15]], %[[VAL_9]]) : (!fir.ref>, i64, i64) -> !fir.ref +! CHECK: %[[VAL_17:.*]] = fir.load %[[VAL_16]] : !fir.ref +! CHECK: hlfir.yield %[[VAL_17]] : i32 +! CHECK: } to { +! CHECK: %[[VAL_18:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_9]], %[[VAL_15]]) : (!fir.ref>, i64, i64) -> !fir.ref +! CHECK: hlfir.yield %[[VAL_18]] : !fir.ref +! CHECK: } +! CHECK: } +! CHECK: } diff --git a/flang/test/Lower/HLFIR/intrinsic-module-procedures.f90 b/flang/test/Lower/HLFIR/intrinsic-module-procedures.f90 index 40bb39e967265..7a124e2886510 100644 --- a/flang/test/Lower/HLFIR/intrinsic-module-procedures.f90 +++ b/flang/test/Lower/HLFIR/intrinsic-module-procedures.f90 @@ -8,7 +8,7 @@ subroutine foo(cptr, x) use iso_c_binding, only : c_ptr, c_loc type(c_ptr) :: cptr - integer :: x + integer, target :: x cptr = c_loc(x) end subroutine ! CHECK-LABEL: func.func @_QPfoo( diff --git a/flang/test/Lower/HLFIR/null.f90 b/flang/test/Lower/HLFIR/null.f90 index 6ae44082f3164..985b8146fa11c 100644 --- a/flang/test/Lower/HLFIR/null.f90 +++ b/flang/test/Lower/HLFIR/null.f90 @@ -1,6 +1,6 @@ ! Test lowering of NULL(MOLD) to HLFIR. ! RUN: bbc -emit-fir -hlfir -o - %s | FileCheck %s -subroutine test(mold) +subroutine test1(mold) integer, pointer :: mold(:) interface subroutine takes_ptr(p) @@ -9,7 +9,7 @@ subroutine takes_ptr(p) end interface call takes_ptr(null(mold)) end subroutine -! CHECK-LABEL: func.func @_QPtest( +! CHECK-LABEL: func.func @_QPtest1( ! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.box>> ! CHECK: %[[VAL_3:.*]] = fir.zero_bits !fir.ptr> ! CHECK: %[[VAL_4:.*]] = arith.constant 0 : index @@ -18,3 +18,31 @@ subroutine takes_ptr(p) ! CHECK: fir.store %[[VAL_6]] to %[[VAL_1]] : !fir.ref>>> ! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) ! CHECK: fir.call @_QPtakes_ptr(%[[VAL_7]]#0) fastmath : (!fir.ref>>>) -> () + +subroutine test2 + integer, pointer :: i + logical :: l + l = associated(null(),i) +end subroutine test2 +! CHECK-LABEL: func.func @_QPtest2() { +! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.box> +! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.box> {bindc_name = "i", uniq_name = "_QFtest2Ei"} +! CHECK: %[[VAL_2:.*]] = fir.zero_bits !fir.ptr +! CHECK: %[[VAL_3:.*]] = fir.embox %[[VAL_2]] : (!fir.ptr) -> !fir.box> +! CHECK: fir.store %[[VAL_3]] to %[[VAL_1]] : !fir.ref>> +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_1]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest2Ei"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) +! CHECK: %[[VAL_5:.*]] = fir.alloca !fir.logical<4> {bindc_name = "l", uniq_name = "_QFtest2El"} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFtest2El"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_7:.*]] = fir.zero_bits !fir.ptr +! CHECK: %[[VAL_8:.*]] = fir.embox %[[VAL_7]] : (!fir.ptr) -> !fir.box> +! CHECK: fir.store %[[VAL_8]] to %[[VAL_0]] : !fir.ref>> +! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = ".tmp.null_box"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) +! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_4]]#1 : !fir.ref>> +! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_9]]#1 : !fir.ref>> +! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (!fir.box>) -> !fir.box +! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_10]] : (!fir.box>) -> !fir.box +! CHECK: %[[VAL_14:.*]] = fir.call @_FortranAPointerIsAssociatedWith(%[[VAL_12]], %[[VAL_13]]) fastmath : (!fir.box, !fir.box) -> i1 +! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (i1) -> !fir.logical<4> +! CHECK: hlfir.assign %[[VAL_15]] to %[[VAL_6]]#0 : !fir.logical<4>, !fir.ref> +! CHECK: return +! CHECK: } diff --git a/flang/test/Lower/HLFIR/vector-subscript-lhs.f90 b/flang/test/Lower/HLFIR/vector-subscript-lhs.f90 new file mode 100644 index 0000000000000..62c3481b7995b --- /dev/null +++ b/flang/test/Lower/HLFIR/vector-subscript-lhs.f90 @@ -0,0 +1,193 @@ +! Test lowering of vector subscripted designators in assignment +! left-hand sides. +! RUN: bbc -emit-fir -hlfir -o - -I nw %s 2>&1 | FileCheck %s + +subroutine test_simple(x, vector) + integer(8) :: vector(10) + real :: x(:) + x(vector) = 42. +end subroutine +! CHECK-LABEL: func.func @_QPtest_simple( +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare {{.*}}Evector +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: hlfir.region_assign { +! CHECK: %[[VAL_6:.*]] = arith.constant 4.200000e+01 : f32 +! CHECK: hlfir.yield %[[VAL_6]] : f32 +! CHECK: } to { +! CHECK: %[[VAL_7:.*]] = arith.constant 10 : index +! CHECK: %[[VAL_8:.*]] = fir.shape %[[VAL_7]] : (index) -> !fir.shape<1> +! CHECK: hlfir.elemental_addr %[[VAL_8]] : !fir.shape<1> { +! CHECK: ^bb0(%[[VAL_9:.*]]: index): +! CHECK: %[[VAL_10:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_9]]) : (!fir.ref>, index) -> !fir.ref +! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_10]] : !fir.ref +! CHECK: %[[VAL_12:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_11]]) : (!fir.box>, i64) -> !fir.ref +! CHECK: hlfir.yield %[[VAL_12]] : !fir.ref +! CHECK: } +! CHECK: } + +subroutine test_cleanup(x, vector, matrix) + integer(8) :: vector(10), matrix(10, 5) + real :: x(:) + x(matmul(vector, matrix)) = 42. +end subroutine +! CHECK-LABEL: func.func @_QPtest_cleanup( +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare {{.*}}Ematrix +! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare {{.*}}Evector +! CHECK: %[[VAL_10:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: hlfir.region_assign { +! CHECK: %[[VAL_11:.*]] = arith.constant 4.200000e+01 : f32 +! CHECK: hlfir.yield %[[VAL_11]] : f32 +! CHECK: } to { +! CHECK: %[[VAL_12:.*]] = hlfir.matmul %[[VAL_9]]#0 %[[VAL_6]]#0 {fastmath = #arith.fastmath} : (!fir.ref>, !fir.ref>) -> !hlfir.expr<5xi64> +! CHECK: %[[VAL_13:.*]] = arith.constant 5 : index +! CHECK: %[[VAL_14:.*]] = fir.shape %[[VAL_13]] : (index) -> !fir.shape<1> +! CHECK: hlfir.elemental_addr %[[VAL_14]] : !fir.shape<1> { +! CHECK: ^bb0(%[[VAL_15:.*]]: index): +! CHECK: %[[VAL_16:.*]] = hlfir.apply %[[VAL_12]], %[[VAL_15]] : (!hlfir.expr<5xi64>, index) -> i64 +! CHECK: %[[VAL_17:.*]] = hlfir.designate %[[VAL_10]]#0 (%[[VAL_16]]) : (!fir.box>, i64) -> !fir.ref +! CHECK: hlfir.yield %[[VAL_17]] : !fir.ref +! CHECK: } cleanup { +! CHECK: hlfir.destroy %[[VAL_12]] : !hlfir.expr<5xi64> +! CHECK: } +! CHECK: } + +subroutine test_nested_vectors(x, vector1, vector2, vector3) + integer(8) :: vector1(10), vector2(8), vector3(6) + real :: x(:) + x(vector1(vector2(vector3))) = 42. +end subroutine +! CHECK-LABEL: func.func @_QPtest_nested_vectors( +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare {{.*}}Evector1 +! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare {{.*}}Evector2 +! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare {{.*}}Evector3 +! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: hlfir.region_assign { +! CHECK: %[[VAL_14:.*]] = arith.constant 4.200000e+01 : f32 +! CHECK: hlfir.yield %[[VAL_14]] : f32 +! CHECK: } to { +! CHECK: %[[VAL_15:.*]] = arith.constant 6 : index +! CHECK: %[[VAL_16:.*]] = fir.shape %[[VAL_15]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_17:.*]] = hlfir.elemental %[[VAL_16]] : (!fir.shape<1>) -> !hlfir.expr<6xi64> { +! CHECK: ^bb0(%[[VAL_18:.*]]: index): +! CHECK: %[[VAL_19:.*]] = hlfir.designate %[[VAL_12]]#0 (%[[VAL_18]]) : (!fir.ref>, index) -> !fir.ref +! CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_19]] : !fir.ref +! CHECK: %[[VAL_21:.*]] = hlfir.designate %[[VAL_9]]#0 (%[[VAL_20]]) : (!fir.ref>, i64) -> !fir.ref +! CHECK: %[[VAL_22:.*]] = fir.load %[[VAL_21]] : !fir.ref +! CHECK: hlfir.yield_element %[[VAL_22]] : i64 +! CHECK: } +! CHECK: %[[VAL_23:.*]] = arith.constant 6 : index +! CHECK: %[[VAL_24:.*]] = fir.shape %[[VAL_23]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_25:.*]] = hlfir.elemental %[[VAL_24]] : (!fir.shape<1>) -> !hlfir.expr<6xi64> { +! CHECK: ^bb0(%[[VAL_26:.*]]: index): +! CHECK: %[[VAL_27:.*]] = hlfir.apply %[[VAL_28:.*]], %[[VAL_26]] : (!hlfir.expr<6xi64>, index) -> i64 +! CHECK: %[[VAL_29:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_27]]) : (!fir.ref>, i64) -> !fir.ref +! CHECK: %[[VAL_30:.*]] = fir.load %[[VAL_29]] : !fir.ref +! CHECK: hlfir.yield_element %[[VAL_30]] : i64 +! CHECK: } +! CHECK: %[[VAL_31:.*]] = arith.constant 6 : index +! CHECK: %[[VAL_32:.*]] = fir.shape %[[VAL_31]] : (index) -> !fir.shape<1> +! CHECK: hlfir.elemental_addr %[[VAL_32]] : !fir.shape<1> { +! CHECK: ^bb0(%[[VAL_33:.*]]: index): +! CHECK: %[[VAL_34:.*]] = hlfir.apply %[[VAL_35:.*]], %[[VAL_33]] : (!hlfir.expr<6xi64>, index) -> i64 +! CHECK: %[[VAL_36:.*]] = hlfir.designate %[[VAL_13]]#0 (%[[VAL_34]]) : (!fir.box>, i64) -> !fir.ref +! CHECK: hlfir.yield %[[VAL_36]] : !fir.ref +! CHECK: } cleanup { +! CHECK: hlfir.destroy %[[VAL_37:.*]] : !hlfir.expr<6xi64> +! CHECK: hlfir.destroy %[[VAL_38:.*]] : !hlfir.expr<6xi64> +! CHECK: } +! CHECK: } + +subroutine test_substring(x, vector) + integer(8) :: vector(10), ifoo, ibar + external :: ifoo, ibar + character(*) :: x(:) + x(vector)(ifoo(): ibar()) = "hello" +end subroutine +! CHECK-LABEL: func.func @_QPtest_substring( +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare {{.*}}Evector +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: hlfir.region_assign { +! CHECK: %[[VAL_6:.*]] = fir.address_of(@{{.*}}) : !fir.ref> +! CHECK: %[[VAL_7:.*]] = arith.constant 5 : index +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_6]] typeparams %[[VAL_7]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QQcl.68656C6C6F"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +! CHECK: hlfir.yield %[[VAL_8]]#0 : !fir.ref> +! CHECK: } to { +! CHECK: %[[VAL_9:.*]] = arith.constant 10 : index +! CHECK: %[[VAL_10:.*]] = fir.shape %[[VAL_9]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_11:.*]] = fir.call @_QPifoo() {{.*}}: () -> i64 +! CHECK: %[[VAL_12:.*]] = fir.call @_QPibar() {{.*}}: () -> i64 +! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_11]] : (i64) -> index +! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_12]] : (i64) -> index +! CHECK: %[[VAL_15:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_16:.*]] = arith.subi %[[VAL_14]], %[[VAL_13]] : index +! CHECK: %[[VAL_17:.*]] = arith.addi %[[VAL_16]], %[[VAL_15]] : index +! CHECK: %[[VAL_18:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_19:.*]] = arith.cmpi sgt, %[[VAL_17]], %[[VAL_18]] : index +! CHECK: %[[VAL_20:.*]] = arith.select %[[VAL_19]], %[[VAL_17]], %[[VAL_18]] : index +! CHECK: hlfir.elemental_addr %[[VAL_10]] typeparams %[[VAL_20]] : !fir.shape<1>, index { +! CHECK: ^bb0(%[[VAL_21:.*]]: index): +! CHECK: %[[VAL_22:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_21]]) : (!fir.ref>, index) -> !fir.ref +! CHECK: %[[VAL_23:.*]] = fir.load %[[VAL_22]] : !fir.ref +! CHECK: %[[VAL_24:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_23]]) substr %[[VAL_13]], %[[VAL_14]] typeparams %[[VAL_20]] : (!fir.box>>, i64, index, index, index) -> !fir.boxchar<1> +! CHECK: hlfir.yield %[[VAL_24]] : !fir.boxchar<1> +! CHECK: } +! CHECK: } + +subroutine test_hard_array_ref(x, vector1, vector2) + integer(8) :: vector1(10), vector2(20), ifoo, ibar, ibaz + external :: ifoo, ibar, ibaz + real :: x(:, :, :, :, :) + x(vector1, :, ifoo():ibar(), ibaz(), vector2) = 42. +end subroutine +! CHECK-LABEL: func.func @_QPtest_hard_array_ref( +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}Evector1 +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare {{.*}}Evector2 +! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: hlfir.region_assign { +! CHECK: %[[VAL_10:.*]] = arith.constant 4.200000e+01 : f32 +! CHECK: hlfir.yield %[[VAL_10]] : f32 +! CHECK: } to { +! CHECK: %[[VAL_11:.*]] = arith.constant 10 : index +! CHECK: %[[VAL_12:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_13:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_14:.*]]:3 = fir.box_dims %[[VAL_9]]#1, %[[VAL_13]] : (!fir.box>, index) -> (index, index, index) +! CHECK: %[[VAL_15:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_16:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_17:.*]] = arith.subi %[[VAL_14]]#1, %[[VAL_12]] : index +! CHECK: %[[VAL_18:.*]] = arith.addi %[[VAL_17]], %[[VAL_15]] : index +! CHECK: %[[VAL_19:.*]] = arith.divsi %[[VAL_18]], %[[VAL_15]] : index +! CHECK: %[[VAL_20:.*]] = arith.cmpi sgt, %[[VAL_19]], %[[VAL_16]] : index +! CHECK: %[[VAL_21:.*]] = arith.select %[[VAL_20]], %[[VAL_19]], %[[VAL_16]] : index +! CHECK: %[[VAL_22:.*]] = fir.call @_QPifoo() {{.*}}: () -> i64 +! CHECK: %[[VAL_23:.*]] = fir.call @_QPibar() {{.*}}: () -> i64 +! CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_22]] : (i64) -> index +! CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_23]] : (i64) -> index +! CHECK: %[[VAL_26:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_27:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_28:.*]] = arith.subi %[[VAL_25]], %[[VAL_24]] : index +! CHECK: %[[VAL_29:.*]] = arith.addi %[[VAL_28]], %[[VAL_26]] : index +! CHECK: %[[VAL_30:.*]] = arith.divsi %[[VAL_29]], %[[VAL_26]] : index +! CHECK: %[[VAL_31:.*]] = arith.cmpi sgt, %[[VAL_30]], %[[VAL_27]] : index +! CHECK: %[[VAL_32:.*]] = arith.select %[[VAL_31]], %[[VAL_30]], %[[VAL_27]] : index +! CHECK: %[[VAL_33:.*]] = fir.call @_QPibaz() {{.*}}: () -> i64 +! CHECK: %[[VAL_34:.*]] = arith.constant 20 : index +! CHECK: %[[VAL_35:.*]] = fir.shape %[[VAL_11]], %[[VAL_21]], %[[VAL_32]], %[[VAL_34]] : (index, index, index, index) -> !fir.shape<4> +! CHECK: hlfir.elemental_addr %[[VAL_35]] : !fir.shape<4> { +! CHECK: ^bb0(%[[VAL_36:.*]]: index, %[[VAL_37:.*]]: index, %[[VAL_38:.*]]: index, %[[VAL_39:.*]]: index): +! CHECK: %[[VAL_40:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_36]]) : (!fir.ref>, index) -> !fir.ref +! CHECK: %[[VAL_41:.*]] = fir.load %[[VAL_40]] : !fir.ref +! CHECK: %[[VAL_42:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_43:.*]] = arith.subi %[[VAL_37]], %[[VAL_42]] : index +! CHECK: %[[VAL_44:.*]] = arith.muli %[[VAL_43]], %[[VAL_15]] : index +! CHECK: %[[VAL_45:.*]] = arith.addi %[[VAL_12]], %[[VAL_44]] : index +! CHECK: %[[VAL_46:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_47:.*]] = arith.subi %[[VAL_38]], %[[VAL_46]] : index +! CHECK: %[[VAL_48:.*]] = arith.muli %[[VAL_47]], %[[VAL_26]] : index +! CHECK: %[[VAL_49:.*]] = arith.addi %[[VAL_24]], %[[VAL_48]] : index +! CHECK: %[[VAL_50:.*]] = hlfir.designate %[[VAL_8]]#0 (%[[VAL_39]]) : (!fir.ref>, index) -> !fir.ref +! CHECK: %[[VAL_51:.*]] = fir.load %[[VAL_50]] : !fir.ref +! CHECK: %[[VAL_52:.*]] = hlfir.designate %[[VAL_9]]#0 (%[[VAL_41]], %[[VAL_45]], %[[VAL_49]], %[[VAL_33]], %[[VAL_51]]) : (!fir.box>, i64, index, index, i64, i64) -> !fir.ref +! CHECK: hlfir.yield %[[VAL_52]] : !fir.ref +! CHECK: } +! CHECK: } +! CHECK: return diff --git a/flang/test/Lower/HLFIR/where.f90 b/flang/test/Lower/HLFIR/where.f90 new file mode 100644 index 0000000000000..88e49c9d740a3 --- /dev/null +++ b/flang/test/Lower/HLFIR/where.f90 @@ -0,0 +1,170 @@ +! Test lowering of WHERE construct and statements to HLFIR. +! RUN: bbc --hlfir -emit-fir -o - %s | FileCheck %s + +module where_defs + logical :: mask(10) + real :: x(10), y(10) + real, allocatable :: a(:), b(:) + interface + function return_temporary_mask() + logical, allocatable :: return_temporary_mask(:) + end function + function return_temporary_array() + real, allocatable :: return_temporary_array(:) + end function + end interface +end module + +subroutine simple_where() + use where_defs, only: mask, x, y + where (mask) x = y +end subroutine +! CHECK-LABEL: func.func @_QPsimple_where() { +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare {{.*}}Emask +! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare {{.*}}Ey +! CHECK: hlfir.where { +! CHECK: hlfir.yield %[[VAL_3]]#0 : !fir.ref>> +! CHECK: } do { +! CHECK: hlfir.region_assign { +! CHECK: hlfir.yield %[[VAL_11]]#0 : !fir.ref> +! CHECK: } to { +! CHECK: hlfir.yield %[[VAL_7]]#0 : !fir.ref> +! CHECK: } +! CHECK: } +! CHECK: return +! CHECK:} + +subroutine where_construct() + use where_defs + where (mask) + x = y + a = b + end where +end subroutine +! CHECK-LABEL: func.func @_QPwhere_construct() { +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QMwhere_defsEa"} +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QMwhere_defsEb"} +! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare {{.*}}Emask +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare {{.*}}Ey +! CHECK: hlfir.where { +! CHECK: hlfir.yield %[[VAL_7]]#0 : !fir.ref>> +! CHECK: } do { +! CHECK: hlfir.region_assign { +! CHECK: hlfir.yield %[[VAL_15]]#0 : !fir.ref> +! CHECK: } to { +! CHECK: hlfir.yield %[[VAL_11]]#0 : !fir.ref> +! CHECK: } +! CHECK: hlfir.region_assign { +! CHECK: %[[VAL_16:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref>>> +! CHECK: hlfir.yield %[[VAL_16]] : !fir.box>> +! CHECK: } to { +! CHECK: %[[VAL_17:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref>>> +! CHECK: hlfir.yield %[[VAL_17]] : !fir.box>> +! CHECK: } +! CHECK: } +! CHECK: return +! CHECK:} + +subroutine where_cleanup() + use where_defs, only: x, return_temporary_mask, return_temporary_array + where (return_temporary_mask()) x = return_temporary_array() +end subroutine +! CHECK-LABEL: func.func @_QPwhere_cleanup() { +! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.box>> {bindc_name = ".result"} +! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.box>>> {bindc_name = ".result"} +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: hlfir.where { +! CHECK: %[[VAL_6:.*]] = fir.call @_QPreturn_temporary_mask() fastmath : () -> !fir.box>>> +! CHECK: fir.save_result %[[VAL_6]] to %[[VAL_1]] : !fir.box>>>, !fir.ref>>>> +! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = ".tmp.func_result"} : (!fir.ref>>>>) -> (!fir.ref>>>>, !fir.ref>>>>) +! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_7]]#0 : !fir.ref>>>> +! CHECK: hlfir.yield %[[VAL_8]] : !fir.box>>> cleanup { +! CHECK: fir.freemem +! CHECK: } +! CHECK: } do { +! CHECK: hlfir.region_assign { +! CHECK: %[[VAL_14:.*]] = fir.call @_QPreturn_temporary_array() fastmath : () -> !fir.box>> +! CHECK: fir.save_result %[[VAL_14]] to %[[VAL_0]] : !fir.box>>, !fir.ref>>> +! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = ".tmp.func_result"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) +! CHECK: %[[VAL_16:.*]] = fir.load %[[VAL_15]]#0 : !fir.ref>>> +! CHECK: hlfir.yield %[[VAL_16]] : !fir.box>> cleanup { +! CHECK: fir.freemem +! CHECK: } +! CHECK: } to { +! CHECK: hlfir.yield %[[VAL_5]]#0 : !fir.ref> +! CHECK: } +! CHECK: } + +subroutine simple_elsewhere() + use where_defs + where (mask) + x = y + elsewhere + y = x + end where +end subroutine +! CHECK-LABEL: func.func @_QPsimple_elsewhere() { +! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare {{.*}}Emask +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare {{.*}}Ey +! CHECK: hlfir.where { +! CHECK: hlfir.yield %[[VAL_7]]#0 : !fir.ref>> +! CHECK: } do { +! CHECK: hlfir.region_assign { +! CHECK: hlfir.yield %[[VAL_15]]#0 : !fir.ref> +! CHECK: } to { +! CHECK: hlfir.yield %[[VAL_11]]#0 : !fir.ref> +! CHECK: } +! CHECK: hlfir.elsewhere do { +! CHECK: hlfir.region_assign { +! CHECK: hlfir.yield %[[VAL_11]]#0 : !fir.ref> +! CHECK: } to { +! CHECK: hlfir.yield %[[VAL_15]]#0 : !fir.ref> +! CHECK: } +! CHECK: } +! CHECK: } + +subroutine elsewhere_2(mask2) + use where_defs, only : mask, x, y + logical :: mask2(:) + where (mask) + x = y + elsewhere(mask2) + y = x + elsewhere + x = foo() + end where +end subroutine +! CHECK-LABEL: func.func @_QPelsewhere_2( +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}Emask +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare {{.*}}Emask2 +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare {{.*}}Ex +! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare {{.*}}Ey +! CHECK: hlfir.where { +! CHECK: hlfir.yield %[[VAL_5]]#0 : !fir.ref>> +! CHECK: } do { +! CHECK: hlfir.region_assign { +! CHECK: hlfir.yield %[[VAL_15]]#0 : !fir.ref> +! CHECK: } to { +! CHECK: hlfir.yield %[[VAL_11]]#0 : !fir.ref> +! CHECK: } +! CHECK: hlfir.elsewhere mask { +! CHECK: hlfir.yield %[[VAL_6]]#0 : !fir.box>> +! CHECK: } do { +! CHECK: hlfir.region_assign { +! CHECK: hlfir.yield %[[VAL_11]]#0 : !fir.ref> +! CHECK: } to { +! CHECK: hlfir.yield %[[VAL_15]]#0 : !fir.ref> +! CHECK: } +! CHECK: hlfir.elsewhere do { +! CHECK: hlfir.region_assign { +! CHECK: %[[VAL_16:.*]] = fir.call @_QPfoo() fastmath : () -> f32 +! CHECK: hlfir.yield %[[VAL_16]] : f32 +! CHECK: } to { +! CHECK: hlfir.yield %[[VAL_11]]#0 : !fir.ref> +! CHECK: } +! CHECK: } +! CHECK: } +! CHECK: } diff --git a/flang/test/Lower/Intrinsics/ubound.f90 b/flang/test/Lower/Intrinsics/ubound.f90 index 1883d5bf75231..8210ff38994b5 100644 --- a/flang/test/Lower/Intrinsics/ubound.f90 +++ b/flang/test/Lower/Intrinsics/ubound.f90 @@ -69,3 +69,15 @@ subroutine ubound_test_3(a, dim, res) ! CHECK: fir.store %[[VAL_16]] to %{{.*}} : !fir.ref res = ubound(a, dim, 8) end subroutine + + +! CHECK-LABEL: func @_QPubound_test_const_dim( +subroutine ubound_test_const_dim(array) + real :: array(11:) + integer :: res +! Should not call _FortranASizeDim when dim is compile time constant. But instead load from descriptor directly. +! CHECK: %[[C0:.*]] = arith.constant 0 : index +! CHECK: %[[DIMS:.*]]:3 = fir.box_dims %arg0, %[[C0]] : (!fir.box>, index) -> (index, index, index) +! CHECK: %{{.*}} = fir.convert %[[DIMS]]#1 : (index) -> i32 + res = ubound(array, 1) +end subroutine diff --git a/flang/test/Lower/OpenACC/acc-data-operands.f90 b/flang/test/Lower/OpenACC/acc-data-operands.f90 index 2f6838e94aa81..2a61bc285c945 100644 --- a/flang/test/Lower/OpenACC/acc-data-operands.f90 +++ b/flang/test/Lower/OpenACC/acc-data-operands.f90 @@ -73,8 +73,7 @@ subroutine acc_operand_derived_type_component() ! CHECK: %[[EXT:.*]] = arith.constant 100 : index ! CHECK: %[[ONE:.*]] = arith.constant 1 : index ! CHECK: %[[LB:.*]] = arith.constant 0 : index -! CHECK: %[[LBEXT:.*]] = arith.addi %[[EXT]], %[[ONE]] : index -! CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[ONE]] : index +! CHECK: %[[UB:.*]] = arith.subi %[[EXT]], %[[ONE]] : index ! CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[ONE]] : index) ! CHECK: %[[COPY_COPYIN:.*]] = acc.copyin varPtr(%[[COORD_DATA]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {dataClause = 3 : i64, name = "w%data"} ! CHECK: acc.data dataOperands(%[[COPY_COPYIN]] : !fir.ref>) { @@ -102,8 +101,7 @@ subroutine acc_operand_array_derived_type_component() ! CHECK: %[[EXT:.*]] = arith.constant 100 : index ! CHECK: %[[ONE:.*]] = arith.constant 1 : index ! CHECK: %[[LB:.*]] = arith.constant 0 : index -! CHECK: %[[LBEXT:.*]] = arith.addi %[[EXT]], %[[ONE]] : index -! CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[ONE]] : index +! CHECK: %[[UB:.*]] = arith.subi %[[EXT]], %[[ONE]] : index ! CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[ONE]] : index) ! CHECK: %[[COPY_COPYIN:.*]] = acc.copyin varPtr(%[[COORD_W1_DATA]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {dataClause = 3 : i64, name = "w(1_8)%data"} ! CHECK: acc.data dataOperands(%[[COPY_COPYIN]] : !fir.ref>) { diff --git a/flang/test/Lower/OpenACC/acc-data.f90 b/flang/test/Lower/OpenACC/acc-data.f90 index c8f44affea37a..32af8039af7c4 100644 --- a/flang/test/Lower/OpenACC/acc-data.f90 +++ b/flang/test/Lower/OpenACC/acc-data.f90 @@ -96,6 +96,12 @@ subroutine acc_data ! CHECK: acc.delete accPtr(%[[CREATE_B]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {dataClause = 7 : i64, name = "b"} ! CHECK: acc.delete accPtr(%[[CREATE_C]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {dataClause = 8 : i64, name = "c"} + !$acc data create(c) copy(b) create(a) + !$acc end data +!CHECK: %[[CREATE_C:.*]] = acc.create varPtr(%[[C]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {name = "c"} +!CHECK: %[[COPY_B:.*]] = acc.copyin varPtr(%[[B]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 3 : i64, name = "b"} +!CHECK: %[[CREATE_A:.*]] = acc.create varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {name = "a"} +!CHECK: acc.data dataOperands(%[[CREATE_C]], %[[COPY_B]], %[[CREATE_A]] : !fir.ref>, !fir.ref>, !fir.ref>) { !$acc data no_create(a, b) create(zero: c) !$acc end data diff --git a/flang/test/Lower/OpenACC/acc-enter-data.f90 b/flang/test/Lower/OpenACC/acc-enter-data.f90 index 1aa7f579945a2..a6ee866e5ebb8 100644 --- a/flang/test/Lower/OpenACC/acc-enter-data.f90 +++ b/flang/test/Lower/OpenACC/acc-enter-data.f90 @@ -18,12 +18,10 @@ subroutine acc_enter_data !$acc enter data create(a) !CHECK: %[[ONE:.*]] = arith.constant 1 : index !CHECK: %[[LB:.*]] = arith.constant 0 : index -!CHECK: %[[LBEXT:.*]] = arith.addi %[[C10]], %[[ONE]] : index -!CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[ONE]] : index +!CHECK: %[[UB:.*]] = arith.subi %[[C10]], %[[ONE]] : index !CHECK: %[[BOUND0:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[ONE]] : index) !CHECK: %[[LB:.*]] = arith.constant 0 : index -!CHECK: %[[LBEXT:.*]] = arith.addi %[[EXTENT_C10]], %[[ONE]] : index -!CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[ONE]] : index +!CHECK: %[[UB:.*]] = arith.subi %[[EXTENT_C10]], %[[ONE]] : index !CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[ONE]] : index) !CHECK: %[[CREATE_A:.*]] = acc.create varPtr(%[[A]] : !fir.ref>) bounds(%[[BOUND0]], %[[BOUND1]]) -> !fir.ref> {name = "a", structured = false} !CHECK: acc.enter_data dataOperands(%[[CREATE_A]] : !fir.ref>){{$}} @@ -31,12 +29,10 @@ subroutine acc_enter_data !$acc enter data create(a) if(.true.) !CHECK: %[[ONE:.*]] = arith.constant 1 : index !CHECK: %[[LB:.*]] = arith.constant 0 : index -!CHECK: %[[LBEXT:.*]] = arith.addi %[[C10]], %[[ONE]] : index -!CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[ONE]] : index +!CHECK: %[[UB:.*]] = arith.subi %[[C10]], %[[ONE]] : index !CHECK: %[[BOUND0:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[ONE]] : index) !CHECK: %[[LB:.*]] = arith.constant 0 : index -!CHECK: %[[LBEXT:.*]] = arith.addi %[[EXTENT_C10]], %[[ONE]] : index -!CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[ONE]] : index +!CHECK: %[[UB:.*]] = arith.subi %[[EXTENT_C10]], %[[ONE]] : index !CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[ONE]] : index) !CHECK: %[[CREATE_A:.*]] = acc.create varPtr(%[[A]] : !fir.ref>) bounds(%[[BOUND0]], %[[BOUND1]]) -> !fir.ref> {name = "a", structured = false} !CHECK: [[IF1:%.*]] = arith.constant true @@ -45,12 +41,10 @@ subroutine acc_enter_data !$acc enter data create(a) if(ifCondition) !CHECK: %[[ONE:.*]] = arith.constant 1 : index !CHECK: %[[LB:.*]] = arith.constant 0 : index -!CHECK: %[[LBEXT:.*]] = arith.addi %[[C10]], %[[ONE]] : index -!CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[ONE]] : index +!CHECK: %[[UB:.*]] = arith.subi %[[C10]], %[[ONE]] : index !CHECK: %[[BOUND0:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[ONE]] : index) !CHECK: %[[LB:.*]] = arith.constant 0 : index -!CHECK: %[[LBEXT:.*]] = arith.addi %[[EXTENT_C10]], %[[ONE]] : index -!CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[ONE]] : index +!CHECK: %[[UB:.*]] = arith.subi %[[EXTENT_C10]], %[[ONE]] : index !CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[ONE]] : index) !CHECK: %[[CREATE_A:.*]] = acc.create varPtr(%[[A]] : !fir.ref>) bounds(%[[BOUND0]], %[[BOUND1]]) -> !fir.ref> {name = "a", structured = false} !CHECK: [[IFCOND:%.*]] = fir.load %{{.*}} : !fir.ref> @@ -266,6 +260,7 @@ subroutine acc_enter_data_dummy(a, b, n, m) ! Test lowering of array section for non default lower bound. subroutine acc_enter_data_non_default_lb() integer :: a(0:9) + integer :: b(11:20) !CHECK-LABEL: func.func @_QPacc_enter_data_non_default_lb() { !CHECK: %[[BASELB:.*]] = arith.constant 0 : index @@ -306,6 +301,14 @@ subroutine acc_enter_data_non_default_lb() !CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[ONE]] : index !CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[BASELB]] : index) !CHECK: %[[CREATE:.*]] = acc.create varPtr(%[[A]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "a(4:)", structured = false} +!CHECK: acc.enter_data dataOperands(%[[CREATE]] : !fir.ref>) + + !$acc enter data create(b) +!CHECK: %[[ONE:.*]] = arith.constant 1 : index +!CHECK: %[[LB:.*]] = arith.constant 0 : index +!CHECK: %[[UB:.*]] = arith.subi %c10{{.*}}, %[[ONE]] : index +!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%c11{{.*}} : index) +!CHECK: %[[CREATE:.*]] = acc.create varPtr(%1 : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "b", structured = false} !CHECK: acc.enter_data dataOperands(%[[CREATE]] : !fir.ref>) end subroutine @@ -598,8 +601,7 @@ subroutine acc_enter_data_derived_type() !CHECK: %[[C10:.*]] = arith.constant 10 : index !CHECK: %[[C1:.*]] = arith.constant 1 : index !CHECK: %[[LB:.*]] = arith.constant 0 : index -!CHECK: %[[LBEXT:.*]] = arith.addi %[[C10]], %[[C1]] : index -!CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[C1]] : index +!CHECK: %[[UB:.*]] = arith.subi %[[C10]], %[[C1]] : index !CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[C1]] : index) startIdx(%[[C1]] : index) !CHECK: %[[CREATE:.*]] = acc.create varPtr(%[[ARRAY_COORD]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "a%array", structured = false} !CHECK: acc.enter_data dataOperands(%[[CREATE]] : !fir.ref>) @@ -655,8 +657,7 @@ subroutine acc_enter_data_derived_type() !CHECK: %[[C10:.*]] = arith.constant 10 : index !CHECK: %[[C1:.*]] = arith.constant 1 : index !CHECK: %[[LB:.*]] = arith.constant 0 : index -!CHECK: %[[LBEXT:.*]] = arith.addi %[[C10]], %[[C1]] : index -!CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[C1]] : index +!CHECK: %[[UB:.*]] = arith.subi %[[C10]], %[[C1]] : index !CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[C1]] : index) startIdx(%[[C1]] : index) !CHECK: %[[CREATE:.*]] = acc.create varPtr(%[[ARRAY_COORD]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "b%d%array", structured = false} @@ -687,8 +688,7 @@ subroutine acc_enter_data_derived_type() !CHECK: %[[C10:.*]] = arith.constant 10 : index !CHECK: %[[C1:.*]] = arith.constant 1 : index !CHECK: %[[LB:.*]] = arith.constant 0 : index -!CHECK: %[[LBEXT:.*]] = arith.addi %[[C10]], %[[C1]] : index -!CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[C1]] : index +!CHECK: %[[UB:.*]] = arith.subi %[[C10]], %[[C1]] : index !CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[C1]] : index) startIdx(%[[C1]] : index) !CHECK: %[[CREATE:.*]] = acc.create varPtr(%[[ARRAY_COORD]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "d%d(1_8)%array", structured = false} !CHECK: acc.enter_data dataOperands(%[[CREATE]] : !fir.ref>) diff --git a/flang/test/Lower/OpenACC/acc-parallel.f90 b/flang/test/Lower/OpenACC/acc-parallel.f90 index 8229890f9a875..a880f151d7eb9 100644 --- a/flang/test/Lower/OpenACC/acc-parallel.f90 +++ b/flang/test/Lower/OpenACC/acc-parallel.f90 @@ -235,6 +235,13 @@ subroutine acc_parallel !CHECK: acc.delete accPtr(%[[CREATE_B]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {dataClause = 7 : i64, name = "b"} !CHECK: acc.delete accPtr(%[[CREATE_C]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {dataClause = 8 : i64, name = "c"} + !$acc parallel create(c) copy(b) create(a) + !$acc end parallel +!CHECK: %[[CREATE_C:.*]] = acc.create varPtr(%[[C]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {name = "c"} +!CHECK: %[[COPY_B:.*]] = acc.copyin varPtr(%[[B]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 3 : i64, name = "b"} +!CHECK: %[[CREATE_A:.*]] = acc.create varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {name = "a"} +!CHECK: acc.parallel dataOperands(%[[CREATE_C]], %[[COPY_B]], %[[CREATE_A]] : !fir.ref>, !fir.ref>, !fir.ref>) { + !$acc parallel no_create(a, b) create(zero: c) !$acc end parallel diff --git a/flang/test/Lower/OpenACC/acc-update.f90 b/flang/test/Lower/OpenACC/acc-update.f90 index ee02371e2d4f6..afe02bf9a0bcb 100644 --- a/flang/test/Lower/OpenACC/acc-update.f90 +++ b/flang/test/Lower/OpenACC/acc-update.f90 @@ -16,6 +16,16 @@ subroutine acc_update ! CHECK: acc.update dataOperands(%[[DEVPTR_A]] : !fir.ref>){{$}} ! CHECK: acc.update_host accPtr(%[[DEVPTR_A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) to varPtr(%[[A]] : !fir.ref>) {name = "a", structured = false} + !$acc update host(a) if_present +! CHECK: %[[DEVPTR_A:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 17 : i64, name = "a", structured = false} +! CHECK: acc.update dataOperands(%[[DEVPTR_A]] : !fir.ref>) attributes {ifPresent}{{$}} +! CHECK: acc.update_host accPtr(%[[DEVPTR_A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) to varPtr(%[[A]] : !fir.ref>) {name = "a", structured = false} + + !$acc update self(a) +! CHECK: %[[DEVPTR_A:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 18 : i64, name = "a", structured = false} +! CHECK: acc.update dataOperands(%[[DEVPTR_A]] : !fir.ref>){{$}} +! CHECK: acc.update_host accPtr(%[[DEVPTR_A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) to varPtr(%[[A]] : !fir.ref>) {dataClause = 18 : i64, name = "a", structured = false} + !$acc update host(a) if(.true.) ! CHECK: %[[DEVPTR_A:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 17 : i64, name = "a", structured = false} ! CHECK: %[[IF1:.*]] = arith.constant true diff --git a/flang/test/Lower/allocatable-assignment.f90 b/flang/test/Lower/allocatable-assignment.f90 index 5d2f28177bcbf..60f6fac107bf4 100644 --- a/flang/test/Lower/allocatable-assignment.f90 +++ b/flang/test/Lower/allocatable-assignment.f90 @@ -1242,7 +1242,7 @@ end function elt ! CHECK: } end subroutine -! CHECK: fir.global linkonce @[[error_message]] constant : !fir.char<1,76> { +! CHECK: fir.global internal @[[error_message]] constant : !fir.char<1,76> { ! CHECK: %[[msg:.*]] = fir.string_lit "array left hand side must be allocated when the right hand side is a scalar\00"(76) : !fir.char<1,76> ! CHECK: fir.has_value %[[msg:.*]] : !fir.char<1,76> ! CHECK: } diff --git a/flang/test/Lower/array-character.f90 b/flang/test/Lower/array-character.f90 index d4fd3401082bb..032077226be36 100644 --- a/flang/test/Lower/array-character.f90 +++ b/flang/test/Lower/array-character.f90 @@ -100,7 +100,7 @@ subroutine charlit ! CHECK: %[[VAL_8:.*]] = fir.address_of(@_QQcl.{{.*}}) : !fir.ref>) -> !fir.ref ! CHECK: %[[VAL_10:.*]] = fir.call @_FortranAioBeginExternalListOutput(%[[VAL_0]], %[[VAL_9]], %{{.*}}) {{.*}}: (i32, !fir.ref, i32) -> !fir.ref - ! CHECK: %[[VAL_11:.*]] = fir.address_of(@_QQro.4x3xc1.1636b396a657de68ffb870a885ac44b4) : !fir.ref>> + ! CHECK: %[[VAL_11:.*]] = fir.address_of(@_QQro.4x3xc1.0) : !fir.ref>> ! CHECK: %[[VAL_12:.*]] = fir.shape %[[VAL_5]] : (index) -> !fir.shape<1> ! CHECK: %[[VAL_13:.*]] = fir.allocmem !fir.array<4x!fir.char<1,3>> ! CHECK: cf.br ^bb1(%[[VAL_6]], %[[VAL_5]] : index, index) @@ -174,7 +174,7 @@ subroutine charlit ! CHECK: } end -! CHECK: fir.global internal @_QQro.4x3xc1.1636b396a657de68ffb870a885ac44b4 constant : !fir.array<4x!fir.char<1,3>> +! CHECK: fir.global internal @_QQro.4x3xc1.0 constant : !fir.array<4x!fir.char<1,3>> ! CHECK: AA ! CHECK: MM ! CHECK: ZZ diff --git a/flang/test/Lower/array-constructor-1.f90 b/flang/test/Lower/array-constructor-1.f90 index b166395f9a93c..4c11e94aae587 100644 --- a/flang/test/Lower/array-constructor-1.f90 +++ b/flang/test/Lower/array-constructor-1.f90 @@ -29,7 +29,7 @@ subroutine check_units subroutine zero complex, parameter :: a(0) = [(((k,k=1,10),j=-2,2,-1),i=2,-2,-2)] complex, parameter :: b(0) = [(7,i=3,-3)] - ! CHECK: fir.address_of(@_QQro.0xz4.null) : !fir.ref>> + ! CHECK: fir.address_of(@_QQro.0xz4.null.0) : !fir.ref>> ! CHECK-NOT: _QQro print*, '>', a, '<' print*, '>', b, '<' diff --git a/flang/test/Lower/array-constructor-2.f90 b/flang/test/Lower/array-constructor-2.f90 index 4d5fb336f0b27..10f4590205216 100644 --- a/flang/test/Lower/array-constructor-2.f90 +++ b/flang/test/Lower/array-constructor-2.f90 @@ -10,11 +10,11 @@ subroutine test1(a, b) ! Array ctors for constant arrays should be outlined as constant globals. ! Look at inline constructor case - ! CHECK: %{{.*}} = fir.address_of(@_QQro.3xr4.6e55f044605a4991f15fd4505d83faf4) : !fir.ref> + ! CHECK: %{{.*}} = fir.address_of(@_QQro.3xr4.0) : !fir.ref> a = (/ 1.0, 2.0, 3.0 /) ! Look at PARAMETER case - ! CHECK: %{{.*}} = fir.address_of(@_QQro.4xi4.6a6af0eea868c84da59807d34f7e1a86) : !fir.ref> + ! CHECK: %{{.*}} = fir.address_of(@_QQro.4xi4.1) : !fir.ref> b = constant_array end subroutine test1 @@ -128,7 +128,7 @@ subroutine test5(a, array2) ! Array ctor with runtime element values and constant extents. ! Concatenation of array values of constant extent. ! CHECK: %[[res:.*]] = fir.allocmem !fir.array<4xf32> - ! CHECK: fir.address_of(@_QQro.2xr4.057a7f5ab69cb695657046b18832c330) : !fir.ref> + ! CHECK: fir.address_of(@_QQro.2xr4.2) : !fir.ref> ! CHECK: %[[tmp1:.*]] = fir.allocmem !fir.array<2xf32> ! CHECK: fir.call @llvm.memcpy.p0.p0.i64(%{{.*}}, %{{.*}}, %{{.*}}, %false{{.*}}) {{.*}}: (!fir.ref, !fir.ref, i64, i1) -> () ! CHECK: %[[tmp2:.*]] = fir.allocmem !fir.array<2xf32> @@ -172,6 +172,6 @@ subroutine test7(a, n) a = (/ (CHAR(i), i=1,n) /) end subroutine test7 -! CHECK: fir.global internal @_QQro.3xr4.{{.*}}(dense<[1.000000e+00, 2.000000e+00, 3.000000e+00]> : tensor<3xf32>) constant : !fir.array<3xf32> +! CHECK: fir.global internal @_QQro.3xr4.0(dense<[1.000000e+00, 2.000000e+00, 3.000000e+00]> : tensor<3xf32>) constant : !fir.array<3xf32> -! CHECK: fir.global internal @_QQro.4xi4.{{.*}}(dense<[6, 7, 42, 9]> : tensor<4xi32>) constant : !fir.array<4xi32> +! CHECK: fir.global internal @_QQro.4xi4.1(dense<[6, 7, 42, 9]> : tensor<4xi32>) constant : !fir.array<4xi32> diff --git a/flang/test/Lower/array-constructor-index.f90 b/flang/test/Lower/array-constructor-index.f90 new file mode 100644 index 0000000000000..8332fc5f72091 --- /dev/null +++ b/flang/test/Lower/array-constructor-index.f90 @@ -0,0 +1,300 @@ +! Check that the implied-do index value is converted to proper type. +! RUN: bbc -emit-fir -o - %s | FileCheck %s + +function test1(k) + integer*1 :: k + integer*1 :: test1(4) + test1 = ([(i*k, integer(8)::i=1,4)]) +end function test1 +! CHECK-LABEL: func.func @_QPtest1( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "k"}) -> !fir.array<4xi8> { +! CHECK: %[[VAL_1:.*]] = fir.alloca index {bindc_name = ".buff.pos"} +! CHECK: %[[VAL_2:.*]] = fir.alloca index {bindc_name = ".buff.size"} +! CHECK: %[[VAL_3:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_4:.*]] = fir.alloca !fir.array<4xi8> {bindc_name = "test1", uniq_name = "_QFtest1Etest1"} +! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_6:.*]] = fir.array_load %[[VAL_4]](%[[VAL_5]]) : (!fir.ref>, !fir.shape<1>) -> !fir.array<4xi8> +! CHECK: %[[VAL_7:.*]] = arith.constant 0 : index +! CHECK: fir.store %[[VAL_7]] to %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_8:.*]] = fir.allocmem !fir.array<4xi64> +! CHECK: %[[VAL_9:.*]] = arith.constant 4 : index +! CHECK: fir.store %[[VAL_9]] to %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i64) -> index +! CHECK: %[[VAL_12:.*]] = arith.constant 4 : i64 +! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_12]] : (i64) -> index +! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (i64) -> index +! CHECK: %[[VAL_16:.*]] = fir.do_loop %[[VAL_17:.*]] = %[[VAL_11]] to %[[VAL_13]] step %[[VAL_15]] iter_args(%[[VAL_18:.*]] = %[[VAL_8]]) -> (!fir.heap>) { +! CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_17]] : (index) -> i64 +! CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_0]] : !fir.ref +! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i8) -> i64 +! CHECK: %[[VAL_22:.*]] = arith.muli %[[VAL_19]], %[[VAL_21]] : i64 +! CHECK: %[[VAL_23:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_24:.*]] = fir.zero_bits !fir.ref> +! CHECK: %[[VAL_25:.*]] = fir.coordinate_of %[[VAL_24]], %[[VAL_23]] : (!fir.ref>, index) -> !fir.ref +! CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_25]] : (!fir.ref) -> index +! CHECK: %[[VAL_27:.*]] = fir.load %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_28:.*]] = fir.load %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_29:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_30:.*]] = arith.addi %[[VAL_27]], %[[VAL_29]] : index +! CHECK: %[[VAL_31:.*]] = arith.cmpi sle, %[[VAL_28]], %[[VAL_30]] : index +! CHECK: %[[VAL_32:.*]] = fir.if %[[VAL_31]] -> (!fir.heap>) { +! CHECK: %[[VAL_33:.*]] = arith.constant 2 : index +! CHECK: %[[VAL_34:.*]] = arith.muli %[[VAL_30]], %[[VAL_33]] : index +! CHECK: fir.store %[[VAL_34]] to %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_35:.*]] = arith.muli %[[VAL_34]], %[[VAL_26]] : index +! CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_18]] : (!fir.heap>) -> !fir.ref +! CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_35]] : (index) -> i64 +! CHECK: %[[VAL_38:.*]] = fir.call @realloc(%[[VAL_36]], %[[VAL_37]]) fastmath : (!fir.ref, i64) -> !fir.ref +! CHECK: %[[VAL_39:.*]] = fir.convert %[[VAL_38]] : (!fir.ref) -> !fir.heap> +! CHECK: fir.result %[[VAL_39]] : !fir.heap> +! CHECK: } else { +! CHECK: fir.result %[[VAL_18]] : !fir.heap> +! CHECK: } +! CHECK: %[[VAL_40:.*]] = fir.coordinate_of %[[VAL_41:.*]], %[[VAL_27]] : (!fir.heap>, index) -> !fir.ref +! CHECK: fir.store %[[VAL_22]] to %[[VAL_40]] : !fir.ref +! CHECK: fir.store %[[VAL_30]] to %[[VAL_1]] : !fir.ref +! CHECK: fir.result %[[VAL_41]] : !fir.heap> +! CHECK: } +! CHECK: %[[VAL_42:.*]] = fir.load %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_43:.*]] = fir.shape %[[VAL_42]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_44:.*]] = fir.array_load %[[VAL_45:.*]](%[[VAL_43]]) : (!fir.heap>, !fir.shape<1>) -> !fir.array<4xi64> +! CHECK: %[[VAL_46:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_47:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_48:.*]] = arith.subi %[[VAL_3]], %[[VAL_46]] : index +! CHECK: %[[VAL_49:.*]] = fir.do_loop %[[VAL_50:.*]] = %[[VAL_47]] to %[[VAL_48]] step %[[VAL_46]] unordered iter_args(%[[VAL_51:.*]] = %[[VAL_6]]) -> (!fir.array<4xi8>) { +! CHECK: %[[VAL_52:.*]] = fir.array_fetch %[[VAL_44]], %[[VAL_50]] : (!fir.array<4xi64>, index) -> i64 +! CHECK: %[[VAL_53:.*]] = fir.no_reassoc %[[VAL_52]] : i64 +! CHECK: %[[VAL_54:.*]] = fir.convert %[[VAL_53]] : (i64) -> i8 +! CHECK: %[[VAL_55:.*]] = fir.array_update %[[VAL_51]], %[[VAL_54]], %[[VAL_50]] : (!fir.array<4xi8>, i8, index) -> !fir.array<4xi8> +! CHECK: fir.result %[[VAL_55]] : !fir.array<4xi8> +! CHECK: } +! CHECK: fir.array_merge_store %[[VAL_6]], %[[VAL_56:.*]] to %[[VAL_4]] : !fir.array<4xi8>, !fir.array<4xi8>, !fir.ref> +! CHECK: fir.freemem %[[VAL_45]] : !fir.heap> +! CHECK: %[[VAL_57:.*]] = fir.load %[[VAL_4]] : !fir.ref> +! CHECK: return %[[VAL_57]] : !fir.array<4xi8> +! CHECK: } + +function test2(k) + integer*2 :: k + integer*2 :: test2(4) + test2 = ([(i*k, integer(8)::i=1,4)]) +end function test2 +! CHECK-LABEL: func.func @_QPtest2( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "k"}) -> !fir.array<4xi16> { +! CHECK: %[[VAL_1:.*]] = fir.alloca index {bindc_name = ".buff.pos"} +! CHECK: %[[VAL_2:.*]] = fir.alloca index {bindc_name = ".buff.size"} +! CHECK: %[[VAL_3:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_4:.*]] = fir.alloca !fir.array<4xi16> {bindc_name = "test2", uniq_name = "_QFtest2Etest2"} +! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_6:.*]] = fir.array_load %[[VAL_4]](%[[VAL_5]]) : (!fir.ref>, !fir.shape<1>) -> !fir.array<4xi16> +! CHECK: %[[VAL_7:.*]] = arith.constant 0 : index +! CHECK: fir.store %[[VAL_7]] to %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_8:.*]] = fir.allocmem !fir.array<4xi64> +! CHECK: %[[VAL_9:.*]] = arith.constant 4 : index +! CHECK: fir.store %[[VAL_9]] to %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i64) -> index +! CHECK: %[[VAL_12:.*]] = arith.constant 4 : i64 +! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_12]] : (i64) -> index +! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (i64) -> index +! CHECK: %[[VAL_16:.*]] = fir.do_loop %[[VAL_17:.*]] = %[[VAL_11]] to %[[VAL_13]] step %[[VAL_15]] iter_args(%[[VAL_18:.*]] = %[[VAL_8]]) -> (!fir.heap>) { +! CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_17]] : (index) -> i64 +! CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_0]] : !fir.ref +! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i16) -> i64 +! CHECK: %[[VAL_22:.*]] = arith.muli %[[VAL_19]], %[[VAL_21]] : i64 +! CHECK: %[[VAL_23:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_24:.*]] = fir.zero_bits !fir.ref> +! CHECK: %[[VAL_25:.*]] = fir.coordinate_of %[[VAL_24]], %[[VAL_23]] : (!fir.ref>, index) -> !fir.ref +! CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_25]] : (!fir.ref) -> index +! CHECK: %[[VAL_27:.*]] = fir.load %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_28:.*]] = fir.load %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_29:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_30:.*]] = arith.addi %[[VAL_27]], %[[VAL_29]] : index +! CHECK: %[[VAL_31:.*]] = arith.cmpi sle, %[[VAL_28]], %[[VAL_30]] : index +! CHECK: %[[VAL_32:.*]] = fir.if %[[VAL_31]] -> (!fir.heap>) { +! CHECK: %[[VAL_33:.*]] = arith.constant 2 : index +! CHECK: %[[VAL_34:.*]] = arith.muli %[[VAL_30]], %[[VAL_33]] : index +! CHECK: fir.store %[[VAL_34]] to %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_35:.*]] = arith.muli %[[VAL_34]], %[[VAL_26]] : index +! CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_18]] : (!fir.heap>) -> !fir.ref +! CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_35]] : (index) -> i64 +! CHECK: %[[VAL_38:.*]] = fir.call @realloc(%[[VAL_36]], %[[VAL_37]]) fastmath : (!fir.ref, i64) -> !fir.ref +! CHECK: %[[VAL_39:.*]] = fir.convert %[[VAL_38]] : (!fir.ref) -> !fir.heap> +! CHECK: fir.result %[[VAL_39]] : !fir.heap> +! CHECK: } else { +! CHECK: fir.result %[[VAL_18]] : !fir.heap> +! CHECK: } +! CHECK: %[[VAL_40:.*]] = fir.coordinate_of %[[VAL_41:.*]], %[[VAL_27]] : (!fir.heap>, index) -> !fir.ref +! CHECK: fir.store %[[VAL_22]] to %[[VAL_40]] : !fir.ref +! CHECK: fir.store %[[VAL_30]] to %[[VAL_1]] : !fir.ref +! CHECK: fir.result %[[VAL_41]] : !fir.heap> +! CHECK: } +! CHECK: %[[VAL_42:.*]] = fir.load %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_43:.*]] = fir.shape %[[VAL_42]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_44:.*]] = fir.array_load %[[VAL_45:.*]](%[[VAL_43]]) : (!fir.heap>, !fir.shape<1>) -> !fir.array<4xi64> +! CHECK: %[[VAL_46:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_47:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_48:.*]] = arith.subi %[[VAL_3]], %[[VAL_46]] : index +! CHECK: %[[VAL_49:.*]] = fir.do_loop %[[VAL_50:.*]] = %[[VAL_47]] to %[[VAL_48]] step %[[VAL_46]] unordered iter_args(%[[VAL_51:.*]] = %[[VAL_6]]) -> (!fir.array<4xi16>) { +! CHECK: %[[VAL_52:.*]] = fir.array_fetch %[[VAL_44]], %[[VAL_50]] : (!fir.array<4xi64>, index) -> i64 +! CHECK: %[[VAL_53:.*]] = fir.no_reassoc %[[VAL_52]] : i64 +! CHECK: %[[VAL_54:.*]] = fir.convert %[[VAL_53]] : (i64) -> i16 +! CHECK: %[[VAL_55:.*]] = fir.array_update %[[VAL_51]], %[[VAL_54]], %[[VAL_50]] : (!fir.array<4xi16>, i16, index) -> !fir.array<4xi16> +! CHECK: fir.result %[[VAL_55]] : !fir.array<4xi16> +! CHECK: } +! CHECK: fir.array_merge_store %[[VAL_6]], %[[VAL_56:.*]] to %[[VAL_4]] : !fir.array<4xi16>, !fir.array<4xi16>, !fir.ref> +! CHECK: fir.freemem %[[VAL_45]] : !fir.heap> +! CHECK: %[[VAL_57:.*]] = fir.load %[[VAL_4]] : !fir.ref> +! CHECK: return %[[VAL_57]] : !fir.array<4xi16> +! CHECK: } + +function test3(k) + integer*4 :: k + integer*4 :: test3(4) + test3 = ([(i*k, integer(8)::i=1,4)]) +end function test3 +! CHECK-LABEL: func.func @_QPtest3( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "k"}) -> !fir.array<4xi32> { +! CHECK: %[[VAL_1:.*]] = fir.alloca index {bindc_name = ".buff.pos"} +! CHECK: %[[VAL_2:.*]] = fir.alloca index {bindc_name = ".buff.size"} +! CHECK: %[[VAL_3:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_4:.*]] = fir.alloca !fir.array<4xi32> {bindc_name = "test3", uniq_name = "_QFtest3Etest3"} +! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_6:.*]] = fir.array_load %[[VAL_4]](%[[VAL_5]]) : (!fir.ref>, !fir.shape<1>) -> !fir.array<4xi32> +! CHECK: %[[VAL_7:.*]] = arith.constant 0 : index +! CHECK: fir.store %[[VAL_7]] to %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_8:.*]] = fir.allocmem !fir.array<4xi64> +! CHECK: %[[VAL_9:.*]] = arith.constant 4 : index +! CHECK: fir.store %[[VAL_9]] to %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i64) -> index +! CHECK: %[[VAL_12:.*]] = arith.constant 4 : i64 +! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_12]] : (i64) -> index +! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (i64) -> index +! CHECK: %[[VAL_16:.*]] = fir.do_loop %[[VAL_17:.*]] = %[[VAL_11]] to %[[VAL_13]] step %[[VAL_15]] iter_args(%[[VAL_18:.*]] = %[[VAL_8]]) -> (!fir.heap>) { +! CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_17]] : (index) -> i64 +! CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_0]] : !fir.ref +! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i32) -> i64 +! CHECK: %[[VAL_22:.*]] = arith.muli %[[VAL_19]], %[[VAL_21]] : i64 +! CHECK: %[[VAL_23:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_24:.*]] = fir.zero_bits !fir.ref> +! CHECK: %[[VAL_25:.*]] = fir.coordinate_of %[[VAL_24]], %[[VAL_23]] : (!fir.ref>, index) -> !fir.ref +! CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_25]] : (!fir.ref) -> index +! CHECK: %[[VAL_27:.*]] = fir.load %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_28:.*]] = fir.load %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_29:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_30:.*]] = arith.addi %[[VAL_27]], %[[VAL_29]] : index +! CHECK: %[[VAL_31:.*]] = arith.cmpi sle, %[[VAL_28]], %[[VAL_30]] : index +! CHECK: %[[VAL_32:.*]] = fir.if %[[VAL_31]] -> (!fir.heap>) { +! CHECK: %[[VAL_33:.*]] = arith.constant 2 : index +! CHECK: %[[VAL_34:.*]] = arith.muli %[[VAL_30]], %[[VAL_33]] : index +! CHECK: fir.store %[[VAL_34]] to %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_35:.*]] = arith.muli %[[VAL_34]], %[[VAL_26]] : index +! CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_18]] : (!fir.heap>) -> !fir.ref +! CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_35]] : (index) -> i64 +! CHECK: %[[VAL_38:.*]] = fir.call @realloc(%[[VAL_36]], %[[VAL_37]]) fastmath : (!fir.ref, i64) -> !fir.ref +! CHECK: %[[VAL_39:.*]] = fir.convert %[[VAL_38]] : (!fir.ref) -> !fir.heap> +! CHECK: fir.result %[[VAL_39]] : !fir.heap> +! CHECK: } else { +! CHECK: fir.result %[[VAL_18]] : !fir.heap> +! CHECK: } +! CHECK: %[[VAL_40:.*]] = fir.coordinate_of %[[VAL_41:.*]], %[[VAL_27]] : (!fir.heap>, index) -> !fir.ref +! CHECK: fir.store %[[VAL_22]] to %[[VAL_40]] : !fir.ref +! CHECK: fir.store %[[VAL_30]] to %[[VAL_1]] : !fir.ref +! CHECK: fir.result %[[VAL_41]] : !fir.heap> +! CHECK: } +! CHECK: %[[VAL_42:.*]] = fir.load %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_43:.*]] = fir.shape %[[VAL_42]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_44:.*]] = fir.array_load %[[VAL_45:.*]](%[[VAL_43]]) : (!fir.heap>, !fir.shape<1>) -> !fir.array<4xi64> +! CHECK: %[[VAL_46:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_47:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_48:.*]] = arith.subi %[[VAL_3]], %[[VAL_46]] : index +! CHECK: %[[VAL_49:.*]] = fir.do_loop %[[VAL_50:.*]] = %[[VAL_47]] to %[[VAL_48]] step %[[VAL_46]] unordered iter_args(%[[VAL_51:.*]] = %[[VAL_6]]) -> (!fir.array<4xi32>) { +! CHECK: %[[VAL_52:.*]] = fir.array_fetch %[[VAL_44]], %[[VAL_50]] : (!fir.array<4xi64>, index) -> i64 +! CHECK: %[[VAL_53:.*]] = fir.no_reassoc %[[VAL_52]] : i64 +! CHECK: %[[VAL_54:.*]] = fir.convert %[[VAL_53]] : (i64) -> i32 +! CHECK: %[[VAL_55:.*]] = fir.array_update %[[VAL_51]], %[[VAL_54]], %[[VAL_50]] : (!fir.array<4xi32>, i32, index) -> !fir.array<4xi32> +! CHECK: fir.result %[[VAL_55]] : !fir.array<4xi32> +! CHECK: } +! CHECK: fir.array_merge_store %[[VAL_6]], %[[VAL_56:.*]] to %[[VAL_4]] : !fir.array<4xi32>, !fir.array<4xi32>, !fir.ref> +! CHECK: fir.freemem %[[VAL_45]] : !fir.heap> +! CHECK: %[[VAL_57:.*]] = fir.load %[[VAL_4]] : !fir.ref> +! CHECK: return %[[VAL_57]] : !fir.array<4xi32> +! CHECK: } + +function test4(k) + integer*8 :: k + integer*8 :: test4(4) + test4 = ([(i*k, integer(8)::i=1,4)]) +end function test4 +! CHECK-LABEL: func.func @_QPtest4( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "k"}) -> !fir.array<4xi64> { +! CHECK: %[[VAL_1:.*]] = fir.alloca index {bindc_name = ".buff.pos"} +! CHECK: %[[VAL_2:.*]] = fir.alloca index {bindc_name = ".buff.size"} +! CHECK: %[[VAL_3:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_4:.*]] = fir.alloca !fir.array<4xi64> {bindc_name = "test4", uniq_name = "_QFtest4Etest4"} +! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_6:.*]] = fir.array_load %[[VAL_4]](%[[VAL_5]]) : (!fir.ref>, !fir.shape<1>) -> !fir.array<4xi64> +! CHECK: %[[VAL_7:.*]] = arith.constant 0 : index +! CHECK: fir.store %[[VAL_7]] to %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_8:.*]] = fir.allocmem !fir.array<4xi64> +! CHECK: %[[VAL_9:.*]] = arith.constant 4 : index +! CHECK: fir.store %[[VAL_9]] to %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i64) -> index +! CHECK: %[[VAL_12:.*]] = arith.constant 4 : i64 +! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_12]] : (i64) -> index +! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i64 +! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (i64) -> index +! CHECK: %[[VAL_16:.*]] = fir.do_loop %[[VAL_17:.*]] = %[[VAL_11]] to %[[VAL_13]] step %[[VAL_15]] iter_args(%[[VAL_18:.*]] = %[[VAL_8]]) -> (!fir.heap>) { +! CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_17]] : (index) -> i64 +! CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_0]] : !fir.ref +! CHECK: %[[VAL_21:.*]] = arith.muli %[[VAL_19]], %[[VAL_20]] : i64 +! CHECK: %[[VAL_22:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_23:.*]] = fir.zero_bits !fir.ref> +! CHECK: %[[VAL_24:.*]] = fir.coordinate_of %[[VAL_23]], %[[VAL_22]] : (!fir.ref>, index) -> !fir.ref +! CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_24]] : (!fir.ref) -> index +! CHECK: %[[VAL_26:.*]] = fir.load %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_27:.*]] = fir.load %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_28:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_29:.*]] = arith.addi %[[VAL_26]], %[[VAL_28]] : index +! CHECK: %[[VAL_30:.*]] = arith.cmpi sle, %[[VAL_27]], %[[VAL_29]] : index +! CHECK: %[[VAL_31:.*]] = fir.if %[[VAL_30]] -> (!fir.heap>) { +! CHECK: %[[VAL_32:.*]] = arith.constant 2 : index +! CHECK: %[[VAL_33:.*]] = arith.muli %[[VAL_29]], %[[VAL_32]] : index +! CHECK: fir.store %[[VAL_33]] to %[[VAL_2]] : !fir.ref +! CHECK: %[[VAL_34:.*]] = arith.muli %[[VAL_33]], %[[VAL_25]] : index +! CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_18]] : (!fir.heap>) -> !fir.ref +! CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_34]] : (index) -> i64 +! CHECK: %[[VAL_37:.*]] = fir.call @realloc(%[[VAL_35]], %[[VAL_36]]) fastmath : (!fir.ref, i64) -> !fir.ref +! CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_37]] : (!fir.ref) -> !fir.heap> +! CHECK: fir.result %[[VAL_38]] : !fir.heap> +! CHECK: } else { +! CHECK: fir.result %[[VAL_18]] : !fir.heap> +! CHECK: } +! CHECK: %[[VAL_39:.*]] = fir.coordinate_of %[[VAL_40:.*]], %[[VAL_26]] : (!fir.heap>, index) -> !fir.ref +! CHECK: fir.store %[[VAL_21]] to %[[VAL_39]] : !fir.ref +! CHECK: fir.store %[[VAL_29]] to %[[VAL_1]] : !fir.ref +! CHECK: fir.result %[[VAL_40]] : !fir.heap> +! CHECK: } +! CHECK: %[[VAL_41:.*]] = fir.load %[[VAL_1]] : !fir.ref +! CHECK: %[[VAL_42:.*]] = fir.shape %[[VAL_41]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_43:.*]] = fir.array_load %[[VAL_44:.*]](%[[VAL_42]]) : (!fir.heap>, !fir.shape<1>) -> !fir.array<4xi64> +! CHECK: %[[VAL_45:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_46:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_47:.*]] = arith.subi %[[VAL_3]], %[[VAL_45]] : index +! CHECK: %[[VAL_48:.*]] = fir.do_loop %[[VAL_49:.*]] = %[[VAL_46]] to %[[VAL_47]] step %[[VAL_45]] unordered iter_args(%[[VAL_50:.*]] = %[[VAL_6]]) -> (!fir.array<4xi64>) { +! CHECK: %[[VAL_51:.*]] = fir.array_fetch %[[VAL_43]], %[[VAL_49]] : (!fir.array<4xi64>, index) -> i64 +! CHECK: %[[VAL_52:.*]] = fir.no_reassoc %[[VAL_51]] : i64 +! CHECK: %[[VAL_53:.*]] = fir.array_update %[[VAL_50]], %[[VAL_52]], %[[VAL_49]] : (!fir.array<4xi64>, i64, index) -> !fir.array<4xi64> +! CHECK: fir.result %[[VAL_53]] : !fir.array<4xi64> +! CHECK: } +! CHECK: fir.array_merge_store %[[VAL_6]], %[[VAL_54:.*]] to %[[VAL_4]] : !fir.array<4xi64>, !fir.array<4xi64>, !fir.ref> +! CHECK: fir.freemem %[[VAL_44]] : !fir.heap> +! CHECK: %[[VAL_55:.*]] = fir.load %[[VAL_4]] : !fir.ref> +! CHECK: return %[[VAL_55]] : !fir.array<4xi64> +! CHECK: } diff --git a/flang/test/Lower/array-expression-slice-1.f90 b/flang/test/Lower/array-expression-slice-1.f90 index ba1b92324527b..0f8b3c12041be 100644 --- a/flang/test/Lower/array-expression-slice-1.f90 +++ b/flang/test/Lower/array-expression-slice-1.f90 @@ -227,7 +227,7 @@ ! CHECK: %[[VAL_185:.*]] = fir.call @_FortranAioEndIoStatement(%[[VAL_176]]) {{.*}}: (!fir.ref) -> i32 ! CHECK: br ^bb24 ! CHECK: ^bb24: -! CHECK: %[[VAL_186:.*]] = fir.address_of(@_QQro.3xi4.b7f1b733471804c07debf489e49d9c2f) : !fir.ref> +! CHECK: %[[VAL_186:.*]] = fir.address_of(@_QQro.3xi4.0) : !fir.ref> ! CHECK: br ^bb25(%[[VAL_6]], %[[VAL_11]] : index, index) ! CHECK: ^bb25(%[[VAL_187:.*]]: index, %[[VAL_188:.*]]: index): ! CHECK: %[[VAL_189:.*]] = arith.cmpi sgt, %[[VAL_188]], %[[VAL_6]] : index diff --git a/flang/test/Lower/assignment.f90 b/flang/test/Lower/assignment.f90 index 8e836ce30cdb3..9b5039e3ea88e 100644 --- a/flang/test/Lower/assignment.f90 +++ b/flang/test/Lower/assignment.f90 @@ -251,7 +251,11 @@ real function divf(a, b) ! CHECK: %[[FCTRES:.*]] = fir.alloca !fir.complex<4> ! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref> ! CHECK: %[[B_VAL:.*]] = fir.load %[[B]] : !fir.ref> -! CHECK: %[[DIV:.*]] = fir.divc %[[A_VAL]], %[[B_VAL]] : !fir.complex<4> +! CHECK: %[[A_REAL:.*]] = fir.extract_value %[[A_VAL]], [0 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[A_IMAG:.*]] = fir.extract_value %[[A_VAL]], [1 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[B_REAL:.*]] = fir.extract_value %[[B_VAL]], [0 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[B_IMAG:.*]] = fir.extract_value %[[B_VAL]], [1 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[DIV:.*]] = fir.call @__divsc3(%[[A_REAL]], %[[A_IMAG]], %[[B_REAL]], %[[B_IMAG]]) fastmath : (f32, f32, f32, f32) -> !fir.complex<4> ! CHECK: fir.store %[[DIV]] to %[[FCTRES]] : !fir.ref> ! CHECK: %[[RET:.*]] = fir.load %[[FCTRES]] : !fir.ref> ! CHECK: return %[[RET]] : !fir.complex<4> diff --git a/flang/test/Lower/call-copy-in-out.f90 b/flang/test/Lower/call-copy-in-out.f90 index fcf0abc41183c..d6e21c73e3b7c 100644 --- a/flang/test/Lower/call-copy-in-out.f90 +++ b/flang/test/Lower/call-copy-in-out.f90 @@ -323,7 +323,7 @@ subroutine whole_component_contiguous_char_pointer() ! CHECK: %[[a:.*]] = fir.alloca !fir.type<_QFwhole_component_contiguous_char_pointerTt{i:!fir.box>>>}> type(t) :: a ! CHECK: %[[field:.*]] = fir.field_index i, !fir.type<_QFwhole_component_contiguous_char_pointerTt{i:!fir.box>>>}> - ! CHECK: %[[coor:.*]] = fir.coordinate_of %0, %1 : (!fir.ref>>>}>>, !fir.field) -> !fir.ref>>>> + ! CHECK: %[[coor:.*]] = fir.coordinate_of %[[a]], %[[field]] : (!fir.ref>>>}>>, !fir.field) -> !fir.ref>>>> ! CHECK: %[[box_load:.*]] = fir.load %[[coor]] : !fir.ref>>>> ! CHECK: %[[addr:.*]] = fir.box_addr %[[box_load]] : (!fir.box>>>) -> !fir.ptr>> ! CHECK: %[[len:.*]] = fir.box_elesize %[[box_load]] : (!fir.box>>>) -> index diff --git a/flang/test/Lower/character-assignment.f90 b/flang/test/Lower/character-assignment.f90 index 7f1874d3f083f..fad419ea9fc3b 100644 --- a/flang/test/Lower/character-assignment.f90 +++ b/flang/test/Lower/character-assignment.f90 @@ -102,7 +102,7 @@ subroutine assign_zero_size_array(n) ! CHECK: return end subroutine -! CHECK-LABEL: fir.global linkonce @_QQcl.48656C6C6F20576F726C64 +! CHECK-LABEL: fir.global internal @_QQcl.48656C6C6F20576F726C64 ! CHECK: %[[lit:.*]] = fir.string_lit "Hello World"(11) : !fir.char<1,11> ! CHECK: fir.has_value %[[lit]] : !fir.char<1,11> ! CHECK: } diff --git a/flang/test/Lower/complex-operations.f90 b/flang/test/Lower/complex-operations.f90 index b11ce6ee7f215..c686671c7a112 100644 --- a/flang/test/Lower/complex-operations.f90 +++ b/flang/test/Lower/complex-operations.f90 @@ -27,11 +27,90 @@ subroutine mul_test(a,b,c) a = b * c end subroutine mul_test -! CHECK-LABEL: @_QPdiv_test -subroutine div_test(a,b,c) - complex :: a, b, c - ! CHECK-NOT: fir.extract_value - ! CHECK-NOT: fir.insert_value - ! CHECK: fir.divc {{.*}}: !fir.complex +! CHECK-LABEL: @_QPdiv_test_half +! CHECK-SAME: %[[AREF:.*]]: !fir.ref> {{.*}}, %[[BREF:.*]]: !fir.ref> {{.*}}, %[[CREF:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref> +! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref> +! CHECK: %[[BVAL_CVT:.*]] = fir.convert %[[BVAL]] : (!fir.complex<2>) -> complex +! CHECK: %[[CVAL_CVT:.*]] = fir.convert %[[CVAL]] : (!fir.complex<2>) -> complex +! CHECK: %[[AVAL_CVT:.*]] = complex.div %[[BVAL_CVT]], %[[CVAL_CVT]] : complex +! CHECK: %[[AVAL:.*]] = fir.convert %[[AVAL_CVT]] : (complex) -> !fir.complex<2> +! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref> +subroutine div_test_half(a,b,c) + complex(kind=2) :: a, b, c + a = b / c +end subroutine div_test_half + +! CHECK-LABEL: @_QPdiv_test_bfloat +! CHECK-SAME: %[[AREF:.*]]: !fir.ref> {{.*}}, %[[BREF:.*]]: !fir.ref> {{.*}}, %[[CREF:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref> +! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref> +! CHECK: %[[BVAL_CVT:.*]] = fir.convert %[[BVAL]] : (!fir.complex<3>) -> complex +! CHECK: %[[CVAL_CVT:.*]] = fir.convert %[[CVAL]] : (!fir.complex<3>) -> complex +! CHECK: %[[AVAL_CVT:.*]] = complex.div %[[BVAL_CVT]], %[[CVAL_CVT]] : complex +! CHECK: %[[AVAL:.*]] = fir.convert %[[AVAL_CVT]] : (complex) -> !fir.complex<3> +! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref> +subroutine div_test_bfloat(a,b,c) + complex(kind=3) :: a, b, c + a = b / c +end subroutine div_test_bfloat + +! CHECK-LABEL: @_QPdiv_test_single +! CHECK-SAME: %[[AREF:.*]]: !fir.ref> {{.*}}, %[[BREF:.*]]: !fir.ref> {{.*}}, %[[CREF:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref> +! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref> +! CHECK: %[[BREAL:.*]] = fir.extract_value %[[BVAL]], [0 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[BIMAG:.*]] = fir.extract_value %[[BVAL]], [1 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[CREAL:.*]] = fir.extract_value %[[CVAL]], [0 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[CIMAG:.*]] = fir.extract_value %[[CVAL]], [1 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[AVAL:.*]] = fir.call @__divsc3(%[[BREAL]], %[[BIMAG]], %[[CREAL]], %[[CIMAG]]) fastmath : (f32, f32, f32, f32) -> !fir.complex<4> +! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref> +subroutine div_test_single(a,b,c) + complex(kind=4) :: a, b, c + a = b / c +end subroutine div_test_single + +! CHECK-LABEL: @_QPdiv_test_double +! CHECK-SAME: %[[AREF:.*]]: !fir.ref> {{.*}}, %[[BREF:.*]]: !fir.ref> {{.*}}, %[[CREF:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref> +! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref> +! CHECK: %[[BREAL:.*]] = fir.extract_value %[[BVAL]], [0 : index] : (!fir.complex<8>) -> f64 +! CHECK: %[[BIMAG:.*]] = fir.extract_value %[[BVAL]], [1 : index] : (!fir.complex<8>) -> f64 +! CHECK: %[[CREAL:.*]] = fir.extract_value %[[CVAL]], [0 : index] : (!fir.complex<8>) -> f64 +! CHECK: %[[CIMAG:.*]] = fir.extract_value %[[CVAL]], [1 : index] : (!fir.complex<8>) -> f64 +! CHECK: %[[AVAL:.*]] = fir.call @__divdc3(%[[BREAL]], %[[BIMAG]], %[[CREAL]], %[[CIMAG]]) fastmath : (f64, f64, f64, f64) -> !fir.complex<8> +! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref> +subroutine div_test_double(a,b,c) + complex(kind=8) :: a, b, c + a = b / c +end subroutine div_test_double + +! CHECK-LABEL: @_QPdiv_test_extended +! CHECK-SAME: %[[AREF:.*]]: !fir.ref> {{.*}}, %[[BREF:.*]]: !fir.ref> {{.*}}, %[[CREF:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref> +! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref> +! CHECK: %[[BREAL:.*]] = fir.extract_value %[[BVAL]], [0 : index] : (!fir.complex<10>) -> f80 +! CHECK: %[[BIMAG:.*]] = fir.extract_value %[[BVAL]], [1 : index] : (!fir.complex<10>) -> f80 +! CHECK: %[[CREAL:.*]] = fir.extract_value %[[CVAL]], [0 : index] : (!fir.complex<10>) -> f80 +! CHECK: %[[CIMAG:.*]] = fir.extract_value %[[CVAL]], [1 : index] : (!fir.complex<10>) -> f80 +! CHECK: %[[AVAL:.*]] = fir.call @__divxc3(%[[BREAL]], %[[BIMAG]], %[[CREAL]], %[[CIMAG]]) fastmath : (f80, f80, f80, f80) -> !fir.complex<10> +! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref> +subroutine div_test_extended(a,b,c) + complex(kind=10) :: a, b, c + a = b / c +end subroutine div_test_extended + +! CHECK-LABEL: @_QPdiv_test_quad +! CHECK-SAME: %[[AREF:.*]]: !fir.ref> {{.*}}, %[[BREF:.*]]: !fir.ref> {{.*}}, %[[CREF:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref> +! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref> +! CHECK: %[[BREAL:.*]] = fir.extract_value %[[BVAL]], [0 : index] : (!fir.complex<16>) -> f128 +! CHECK: %[[BIMAG:.*]] = fir.extract_value %[[BVAL]], [1 : index] : (!fir.complex<16>) -> f128 +! CHECK: %[[CREAL:.*]] = fir.extract_value %[[CVAL]], [0 : index] : (!fir.complex<16>) -> f128 +! CHECK: %[[CIMAG:.*]] = fir.extract_value %[[CVAL]], [1 : index] : (!fir.complex<16>) -> f128 +! CHECK: %[[AVAL:.*]] = fir.call @__divtc3(%[[BREAL]], %[[BIMAG]], %[[CREAL]], %[[CIMAG]]) fastmath : (f128, f128, f128, f128) -> !fir.complex<16> +! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref> +subroutine div_test_quad(a,b,c) + complex(kind=16) :: a, b, c a = b / c -end subroutine div_test +end subroutine div_test_quad diff --git a/flang/test/Lower/constant-literal-mangling.f90 b/flang/test/Lower/constant-literal-mangling.f90 index abb2754bc2f95..ef33ffe450b0f 100644 --- a/flang/test/Lower/constant-literal-mangling.f90 +++ b/flang/test/Lower/constant-literal-mangling.f90 @@ -5,36 +5,89 @@ integer :: i end type +type otherType + integer :: i +end type + print *, [42, 42] -! CHECK: fir.address_of(@_QQro.2xi4.53fa91e04725d4ee6f22cf1e2d38428a) +! CHECK: fir.address_of(@_QQro.2xi4.0) print *, reshape([42, 42, 42, 42, 42, 42], [2,3]) -! CHECK: fir.address_of(@_QQro.2x3xi4.9af8c8182bab45c4e7888ec3623db3b6) +! CHECK: fir.address_of(@_QQro.2x3xi4.1) print *, [42_8, 42_8] -! CHECK: fir.address_of(@_QQro.2xi8.3b1356831516d19b976038974b2673ac) +! CHECK: fir.address_of(@_QQro.2xi8.2) print *, [0.42, 0.42] -! CHECK: fir.address_of(@_QQro.2xr4.3c5becae2e4426ad1615e253139ceff8) +! CHECK: fir.address_of(@_QQro.2xr4.3) print *, [0.42_8, 0.42_8] -! CHECK: fir.address_of(@_QQro.2xr8.ebefec8f7537fbf54acc4530e75084e6) +! CHECK: fir.address_of(@_QQro.2xr8.4) print *, [.true.] -! CHECK: fir.address_of(@_QQro.1xl4.4352d88a78aa39750bf70cd6f27bcaa5) +! CHECK: fir.address_of(@_QQro.1xl4.5) print *, [.true._8] -! CHECK: fir.address_of(@_QQro.1xl8.33cdeccccebe80329f1fdbee7f5874cb) +! CHECK: fir.address_of(@_QQro.1xl8.6) print *, [(1., -1.), (-1., 1)] -! CHECK: fir.address_of(@_QQro.2xz4.ac09ecb1abceb4f9cad4b1a50000074e) +! CHECK: fir.address_of(@_QQro.2xz4.7) print *, [(1._8, -1._8), (-1._8, 1._8)] -! CHECK: fir.address_of(@_QQro.2xz8.a3652db37055e37d2cae8198ae4cd959) +! CHECK: fir.address_of(@_QQro.2xz8.8) print *, [someType(42), someType(43)] -! CHECK: fir.address_of(@_QQro.2x_QFTsometype. -! Note: the hash for derived types cannot clash with other constant in the same -! compilation unit, but is unstable because it hashes some noise contained in -! unused std::vector storage. +! CHECK: fir.address_of(@_QQro.2x_QFTsometype.9 + + ! Verify that literals of the same type/shape + ! are mapped to different global objects: + print *, [someType(11)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.10) + print *, [someType(42)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.11) + print *, [someType(11)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.10) + print *, [someType(42)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.11) + print *, [someType(11)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.10) + print *, [someType(42)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.11) + print *, [someType(11)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.10) + print *, [someType(42)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.11) + + print *, [Character(4)::] +! CHECK: fir.address_of(@_QQro.0x4xc1.null.12) + print *, [Character(2)::] +! CHECK: fir.address_of(@_QQro.0x2xc1.null.13) + print *, [Character(2)::] +! CHECK: fir.address_of(@_QQro.0x2xc1.null.13) + + print *, [otherType(42)] +! CHECK: fir.address_of(@_QQro.1x_QFTothertype.14) + end + +! CHECK: fir.global internal @_QQro.1x_QFTsometype.10 constant : !fir.array<1x!fir.type<_QFTsometype{i:i32}>> { +! CHECK: %{{.*}} = arith.constant 11 : i32 +! CHECK: } + +! CHECK: fir.global internal @_QQro.1x_QFTsometype.11 constant : !fir.array<1x!fir.type<_QFTsometype{i:i32}>> { +! CHECK: %{{.*}} = arith.constant 42 : i32 +! CHECK: } + +! CHECK: fir.global internal @_QQro.0x4xc1.null.12 constant : !fir.array<0x!fir.char<1,4>> { +! CHECK: %[[T1:.*]] = fir.undefined !fir.array<0x!fir.char<1,4>> +! CHECK: fir.has_value %[[T1]] : !fir.array<0x!fir.char<1,4>> +! CHECK: } + +! CHECK: fir.global internal @_QQro.0x2xc1.null.13 constant : !fir.array<0x!fir.char<1,2>> { +! CHECK: %[[T2:.*]] = fir.undefined !fir.array<0x!fir.char<1,2>> +! CHECK: fir.has_value %[[T2]] : !fir.array<0x!fir.char<1,2>> +! CHECK: } + +! CHECK: fir.global internal @_QQro.1x_QFTothertype.14 constant : !fir.array<1x!fir.type<_QFTothertype{i:i32}>> { +! CHECK: %{{.*}} = arith.constant 42 : i32 +! CHECK: } diff --git a/flang/test/Lower/convert.f90 b/flang/test/Lower/convert.f90 index 1ab93dcc17320..50050190803e2 100755 --- a/flang/test/Lower/convert.f90 +++ b/flang/test/Lower/convert.f90 @@ -21,11 +21,11 @@ program test ! ALL: %[[VAL_8:.*]] = fir.insert_value %[[VAL_4]], %[[VAL_7]], [0 : index, 1 : index] : (!fir.array<1xtuple, !fir.ref>>, !fir.ref) -> !fir.array<1xtuple, !fir.ref>> ! ALL: fir.has_value %[[VAL_8]] : !fir.array<1xtuple, !fir.ref>> -! ALL: fir.global linkonce @[[FC_STR]] constant : !fir.char<1,13> { +! ALL: fir.global internal @[[FC_STR]] constant : !fir.char<1,13> { ! ALL: %[[VAL_0:.*]] = fir.string_lit "FORT_CONVERT\00"(13) : !fir.char<1,13> ! ALL: fir.has_value %[[VAL_0]] : !fir.char<1,13> -! ALL: fir.global linkonce @[[OPT_STR]] constant : !fir.char<1,[[OPT_STR_LEN]]> { +! ALL: fir.global internal @[[OPT_STR]] constant : !fir.char<1,[[OPT_STR_LEN]]> { ! UNKNOWN: %[[VAL_0:.*]] = fir.string_lit "UNKNOWN\00"([[OPT_STR_LEN]]) : !fir.char<1,[[OPT_STR_LEN]]> ! NATIVE: %[[VAL_0:.*]] = fir.string_lit "NATIVE\00"([[OPT_STR_LEN]]) : !fir.char<1,[[OPT_STR_LEN]]> ! LITTLE_ENDIAN: %[[VAL_0:.*]] = fir.string_lit "LITTLE_ENDIAN\00"([[OPT_STR_LEN]]) : !fir.char<1,[[OPT_STR_LEN]]> diff --git a/flang/test/Lower/global-format-strings.f90 b/flang/test/Lower/global-format-strings.f90 index 3112da33dc0fe..d9307abd74731 100644 --- a/flang/test/Lower/global-format-strings.f90 +++ b/flang/test/Lower/global-format-strings.f90 @@ -8,7 +8,7 @@ program other ! CHECK: fir.address_of(@{{.*}}) : 1008 format('ok') end -! CHECK-LABEL: fir.global linkonce @_QQcl.28276F6B2729 constant +! CHECK-LABEL: fir.global internal @_QQcl.28276F6B2729 constant ! CHECK: %[[lit:.*]] = fir.string_lit "('ok')"(6) : !fir.char<1,6> ! CHECK: fir.has_value %[[lit]] : !fir.char<1,6> ! CHECK: } diff --git a/flang/test/Lower/io-statement-open-options.f90 b/flang/test/Lower/io-statement-open-options.f90 index 4348767ec2033..4d414e069f599 100755 --- a/flang/test/Lower/io-statement-open-options.f90 +++ b/flang/test/Lower/io-statement-open-options.f90 @@ -15,6 +15,6 @@ subroutine test_convert_specifier(unit) close(unit) end subroutine -! CHECK: fir.global linkonce @[[be_str_name]] constant : !fir.char<1,10> { +! CHECK: fir.global internal @[[be_str_name]] constant : !fir.char<1,10> { ! CHECK: %[[be_str_lit:.*]] = fir.string_lit "BIG_ENDIAN"(10) : !fir.char<1,10> ! CHECK: fir.has_value %[[be_str_lit]] : !fir.char<1,10> diff --git a/flang/test/Lower/namelist.f90 b/flang/test/Lower/namelist.f90 index 0a9a5b34b9387..7789effc0d313 100644 --- a/flang/test/Lower/namelist.f90 +++ b/flang/test/Lower/namelist.f90 @@ -83,6 +83,6 @@ subroutine global_pointer write(10, nml=mygroup) end - ! CHECK-DAG: fir.global linkonce @_QQcl.6A6A6A00 constant : !fir.char<1,4> - ! CHECK-DAG: fir.global linkonce @_QQcl.63636300 constant : !fir.char<1,4> - ! CHECK-DAG: fir.global linkonce @_QQcl.6E6E6E00 constant : !fir.char<1,4> + ! CHECK-DAG: fir.global internal @_QQcl.6A6A6A00 constant : !fir.char<1,4> + ! CHECK-DAG: fir.global internal @_QQcl.63636300 constant : !fir.char<1,4> + ! CHECK-DAG: fir.global internal @_QQcl.6E6E6E00 constant : !fir.char<1,4> diff --git a/flang/test/Lower/pass-null-for-class-arg.f90 b/flang/test/Lower/pass-null-for-class-arg.f90 new file mode 100644 index 0000000000000..d3d657f29a36c --- /dev/null +++ b/flang/test/Lower/pass-null-for-class-arg.f90 @@ -0,0 +1,31 @@ +! RUN: bbc -emit-fir -polymorphic-type %s -o - | FileCheck %s --check-prefix=FIR +! RUN: bbc -emit-fir -polymorphic-type -hlfir %s -o - | FileCheck %s --check-prefix=HLFIR + +subroutine test + interface + subroutine s1p(n) + type t + integer :: n + end type t + class(t), pointer :: n + end subroutine s1p + end interface + call s1p(null()) +end subroutine test +! FIR-LABEL: func.func @_QPtest() { +! FIR: %[[VAL_0:.*]] = fir.alloca !fir.class>> +! FIR: %[[VAL_1:.*]] = fir.zero_bits !fir.ptr> +! FIR: %[[VAL_2:.*]] = fir.embox %[[VAL_1]] : (!fir.ptr>) -> !fir.class>> +! FIR: fir.store %[[VAL_2]] to %[[VAL_0]] : !fir.ref>>> +! FIR: fir.call @_QPs1p(%[[VAL_0]]) fastmath : (!fir.ref>>>) -> () +! FIR: return +! FIR: } + +! HLFIR-LABEL: func.func @_QPtest() { +! HLFIR: %[[VAL_0:.*]] = fir.alloca !fir.class>> +! HLFIR: %[[VAL_1:.*]] = fir.zero_bits !fir.ptr> +! HLFIR: %[[VAL_2:.*]] = fir.embox %[[VAL_1]] : (!fir.ptr>) -> !fir.class>> +! HLFIR: fir.store %[[VAL_2]] to %[[VAL_0]] : !fir.ref>>> +! HLFIR: fir.call @_QPs1p(%[[VAL_0]]) fastmath : (!fir.ref>>>) -> () +! HLFIR: return +! HLFIR: } diff --git a/flang/test/Lower/pointer-default-init.f90 b/flang/test/Lower/pointer-default-init.f90 new file mode 100644 index 0000000000000..4697d601347e7 --- /dev/null +++ b/flang/test/Lower/pointer-default-init.f90 @@ -0,0 +1,116 @@ +! Test that pointer and pointer components are always initialized to a +! clean NULL() status. This is required by f18 runtime to do pointer +! association with a RHS with an undefined association status from a +! Fortran point of view. +! RUN: bbc -emit-fir -I nw %s -o - | FileCheck %s + +module test + type t + integer :: i + real, pointer :: x(:) + end type + + real, pointer :: test_module_pointer(:) +! CHECK-LABEL: fir.global @_QMtestEtest_module_pointer : !fir.box>> { +! CHECK: %[[VAL_0:.*]] = fir.zero_bits !fir.ptr> +! CHECK: %[[VAL_1:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_2:.*]] = fir.shape %[[VAL_1]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_3:.*]] = fir.embox %[[VAL_0]](%[[VAL_2]]) : (!fir.ptr>, !fir.shape<1>) -> !fir.box>> +! CHECK: fir.has_value %[[VAL_3]] : !fir.box>> + + type(t) :: test_module_var +! CHECK-LABEL: fir.global @_QMtestEtest_module_var : !fir.type<_QMtestTt{i:i32,x:!fir.box>>}> { +! CHECK: %[[VAL_0:.*]] = fir.undefined !fir.type<_QMtestTt{i:i32,x:!fir.box>>}> +! CHECK: %[[VAL_1:.*]] = fir.undefined i32 +! CHECK: %[[VAL_2:.*]] = fir.field_index i +! CHECK: %[[VAL_3:.*]] = fir.insert_value %[[VAL_0]], %[[VAL_1]] +! CHECK: %[[VAL_4:.*]] = fir.zero_bits !fir.ptr> +! CHECK: %[[VAL_5:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_5]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_7:.*]] = fir.embox %[[VAL_4]](%[[VAL_6]]) : (!fir.ptr>, !fir.shape<1>) -> !fir.box>> +! CHECK: %[[VAL_8:.*]] = fir.field_index x +! CHECK: %[[VAL_9:.*]] = fir.insert_value %[[VAL_3]], %[[VAL_7]] +! CHECK: fir.has_value %[[VAL_9]] +end module + +subroutine test_local() + use test, only : t + type(t) :: x +end subroutine +! CHECK-LABEL: func.func @_QPtest_local() { +! CHECK: fir.call @_FortranAInitialize( + +subroutine test_saved() + use test, only : t + type(t), save :: x +end subroutine +! See check for fir.global internal @_QFtest_savedEx below. + +subroutine test_alloc(x) + use test, only : t + type(t), allocatable :: x + allocate(x) +end subroutine +! CHECK-LABEL: func.func @_QPtest_alloc( +! CHECK: fir.call @_FortranAAllocatableAllocate + +subroutine test_intentout(x) + use test, only : t + type(t), intent(out):: x +end subroutine +! CHECK-LABEL: func.func @_QPtest_intentout( +! CHECK-NOT: fir.call @_FortranAInitialize( +! CHECK: return + +subroutine test_struct_ctor_cst(x) + use test, only : t + type(t):: x + x = t(42) +end subroutine +! CHECK-LABEL: func.func @_QPtest_struct_ctor_cst( +! CHECK: fir.call @_FortranAInitialize( + +subroutine test_struct_ctor_dyn(x, i) + use test, only : t + type(t):: x + integer :: i + x = t(i) +end subroutine +! CHECK-LABEL: func.func @_QPtest_struct_ctor_dyn( +! CHECK: fir.call @_FortranAInitialize( + +subroutine test_local_pointer() + real, pointer :: x(:) +end subroutine +! CHECK-LABEL: func.func @_QPtest_local_pointer() { +! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.box>> {bindc_name = "x", uniq_name = "_QFtest_local_pointerEx"} +! CHECK: %[[VAL_1:.*]] = fir.zero_bits !fir.ptr> +! CHECK: %[[VAL_2:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_4:.*]] = fir.embox %[[VAL_1]](%[[VAL_3]]) : (!fir.ptr>, !fir.shape<1>) -> !fir.box>> +! CHECK: fir.store %[[VAL_4]] to %[[VAL_0]] : !fir.ref>>> + +subroutine test_saved_pointer() + real, pointer, save :: x(:) +end subroutine +! See check for fir.global internal @_QFtest_saved_pointerEx below. + +! CHECK-LABEL: fir.global internal @_QFtest_savedEx : !fir.type<_QMtestTt{i:i32,x:!fir.box>>}> { +! CHECK: %[[VAL_0:.*]] = fir.undefined !fir.type<_QMtestTt{i:i32,x:!fir.box>>}> +! CHECK: %[[VAL_1:.*]] = fir.undefined i32 +! CHECK: %[[VAL_2:.*]] = fir.field_index i +! CHECK: %[[VAL_3:.*]] = fir.insert_value %[[VAL_0]], %[[VAL_1]] +! CHECK: %[[VAL_4:.*]] = fir.zero_bits !fir.ptr> +! CHECK: %[[VAL_5:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_5]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_7:.*]] = fir.embox %[[VAL_4]](%[[VAL_6]]) : (!fir.ptr>, !fir.shape<1>) -> !fir.box>> +! CHECK: %[[VAL_8:.*]] = fir.field_index x +! CHECK: %[[VAL_9:.*]] = fir.insert_value %[[VAL_3]], %[[VAL_7]] +! CHECK: fir.has_value %[[VAL_9]] + +! CHECK-LABEL: fir.global internal @_QFtest_saved_pointerEx : !fir.box>> { +! CHECK: %[[VAL_0:.*]] = fir.zero_bits !fir.ptr> +! CHECK: %[[VAL_1:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_2:.*]] = fir.shape %[[VAL_1]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_3:.*]] = fir.embox %[[VAL_0]](%[[VAL_2]]) : (!fir.ptr>, !fir.shape<1>) -> !fir.box>> +! CHECK: fir.has_value %[[VAL_3]] : !fir.box>> diff --git a/flang/test/Lower/read-write-buffer.f90 b/flang/test/Lower/read-write-buffer.f90 index 889209242cb4a..188cdb088973f 100644 --- a/flang/test/Lower/read-write-buffer.f90 +++ b/flang/test/Lower/read-write-buffer.f90 @@ -29,7 +29,7 @@ subroutine some() write (buffer, 10) "compiler" read (buffer, 10) greeting end -! CHECK-LABEL: fir.global linkonce @_QQcl.636F6D70696C6572 +! CHECK-LABEL: fir.global internal @_QQcl.636F6D70696C6572 ! CHECK: %[[lit:.*]] = fir.string_lit "compiler"(8) : !fir.char<1,8> ! CHECK: fir.has_value %[[lit]] : !fir.char<1,8> ! CHECK: } diff --git a/flang/test/Parser/OpenMP/allocators-unparse.f90 b/flang/test/Parser/OpenMP/allocators-unparse.f90 new file mode 100644 index 0000000000000..062a48b02635f --- /dev/null +++ b/flang/test/Parser/OpenMP/allocators-unparse.f90 @@ -0,0 +1,63 @@ +! RUN: %flang_fc1 -fdebug-unparse-no-sema -fopenmp %s | FileCheck --ignore-case %s +! RUN: %flang_fc1 -fdebug-dump-parse-tree-no-sema -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s +! Check unparsing of OpenMP 5.2 Allocators construct + +subroutine allocate() + use omp_lib + integer, allocatable :: arr1(:), arr2(:, :) + + !$omp allocators allocate(omp_default_mem_alloc: arr1) + allocate(arr1(5)) + + !$omp allocators allocate(allocator(omp_default_mem_alloc), align(32): arr1) & + !$omp allocate(omp_default_mem_alloc: arr2) + allocate(arr1(10), arr2(3, 2)) + + !$omp allocators allocate(align(32): arr2) + allocate(arr2(5, 3)) +end subroutine allocate + +!CHECK: INTEGER, ALLOCATABLE :: arr1(:), arr2(:,:) +!CHECK-NEXT:!$OMP ALLOCATE ALLOCATE(omp_default_mem_alloc:arr1) +!CHECK-NEXT: ALLOCATE(arr1(5)) +!CHECK-NEXT:!$OMP ALLOCATE ALLOCATE(ALLOCATOR(omp_default_mem_alloc),ALIGN(32):arr1) ALLOC& +!CHECK-NEXT:!$OMP&ATE(omp_default_mem_alloc:arr2) +!CHECK-NEXT: ALLOCATE(arr1(10), arr2(3,2)) +!CHECK-NEXT:!$OMP ALLOCATE ALLOCATE(ALIGN(32):arr2) +!CHECK-NEXT: ALLOCATE(arr2(5,3)) + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPAllocatorsConstruct +!PARSE-TREE-NEXT: Verbatim +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Allocate -> OmpAllocateClause +!PARSE-TREE-NEXT: AllocateModifier -> Allocator -> Scalar -> Integer -> Expr -> Designator -> DataRef -> Name = +!PARSE-TREE-NEXT: OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr1' +!PARSE-TREE-NEXT: AllocateStmt +!PARSE-TREE-NEXT: Allocation +!PARSE-TREE-NEXT: AllocateObject -> Name = 'arr1' + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPAllocatorsConstruct +!PARSE-TREE-NEXT: Verbatim +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Allocate -> OmpAllocateClause +!PARSE-TREE-NEXT: AllocateModifier -> ComplexModifier +!PARSE-TREE-NEXT: Allocator -> Scalar -> Integer -> Expr -> Designator -> DataRef -> Name = +!PARSE-TREE-NEXT: Align -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '32' +!PARSE-TREE-NEXT: OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr1' +!PARSE-TREE-NEXT: OmpClause -> Allocate -> OmpAllocateClause +!PARSE-TREE-NEXT: AllocateModifier -> Allocator -> Scalar -> Integer -> Expr -> Designator -> DataRef -> Name = +!PARSE-TREE-NEXT: OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr2' +!PARSE-TREE-NEXT: AllocateStmt +!PARSE-TREE-NEXT: Allocation +!PARSE-TREE-NEXT: AllocateObject -> Name = 'arr1' +!PARSE-TREE-NEXT: AllocateShapeSpec +!PARSE-TREE-NEXT: Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '10' +!PARSE-TREE-NEXT: Allocation +!PARSE-TREE-NEXT: AllocateObject -> Name = 'arr2' + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPAllocatorsConstruct +!PARSE-TREE-NEXT: Verbatim +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Allocate -> OmpAllocateClause +!PARSE-TREE-NEXT: AllocateModifier -> Align -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '32' +!PARSE-TREE-NEXT: OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr2' +!PARSE-TREE-NEXT: AllocateStmt +!PARSE-TREE-NEXT: Allocation +!PARSE-TREE-NEXT: AllocateObject -> Name = 'arr2' diff --git a/flang/test/Semantics/OpenMP/use_device_addr.f90 b/flang/test/Semantics/OpenMP/use_device_addr.f90 new file mode 100644 index 0000000000000..67b274929647c --- /dev/null +++ b/flang/test/Semantics/OpenMP/use_device_addr.f90 @@ -0,0 +1,17 @@ +! RUN: %flang -fc1 -fopenmp -fdebug-dump-symbols %s | FileCheck %s +! OpenMP Version 5.1 +! 2.14.2 use_device_addr clause +! List item that appears in a use_device_addr clause has corresponding storage +! in the device data environment, references to the list item in the associated +! structured block are converted into references to the corresponding list item. + +subroutine omp_target_data + integer :: a(1024) + !CHECK: b, TARGET size=4096 offset=4096: ObjectEntity type: INTEGER(4) shape: 1_8:1024_8 + integer, target :: b(1024) + a = 1 + !$omp target data map(tofrom: a) use_device_addr(b) + !CHECK: b (OmpUseDeviceAddr): HostAssoc + b = a + !$omp end target data +end subroutine omp_target_data diff --git a/flang/test/Semantics/c_loc01.f90 b/flang/test/Semantics/c_loc01.f90 new file mode 100644 index 0000000000000..02f32e3801d91 --- /dev/null +++ b/flang/test/Semantics/c_loc01.f90 @@ -0,0 +1,37 @@ +! RUN: %python %S/test_errors.py %s %flang_fc1 +module m + use iso_c_binding + type haslen(L) + integer, len :: L + end type + contains + subroutine test(assumedType, poly, nclen) + type(*), target :: assumedType + class(*), target :: poly + type(c_ptr) cp + real notATarget + procedure(sin), pointer :: pptr + real, target :: arr(3) + type(hasLen(1)), target :: clen + type(hasLen(*)), target :: nclen + character(2), target :: ch + !ERROR: C_LOC() argument must be a data pointer or target + cp = c_loc(notATarget) + !ERROR: C_LOC() argument must be a data pointer or target + cp = c_loc(pptr) + !ERROR: C_LOC() argument must be contiguous + cp = c_loc(arr(1:3:2)) + !ERROR: C_LOC() argument may not be a zero-sized array + cp = c_loc(arr(3:1)) + !ERROR: C_LOC() argument must have an intrinsic type, assumed type, or non-polymorphic derived type with no non-constant length parameter + cp = c_loc(poly) + cp = c_loc(clen) ! ok + !ERROR: C_LOC() argument must have an intrinsic type, assumed type, or non-polymorphic derived type with no non-constant length parameter + cp = c_loc(nclen) + !ERROR: C_LOC() argument may not be zero-length character + cp = c_loc(ch(2:1)) + !WARNING: C_LOC() argument has non-interoperable intrinsic type, kind, or length + cp = c_loc(ch) + cp = c_loc(ch(1:1)) ! ok) + end +end module diff --git a/flang/test/Semantics/canondo01.f90 b/flang/test/Semantics/canondo01.f90 index 50ffa489019e2..7a48db346e9a7 100644 --- a/flang/test/Semantics/canondo01.f90 +++ b/flang/test/Semantics/canondo01.f90 @@ -1,4 +1,3 @@ - ! RUN: %flang_fc1 -fdebug-unparse-with-symbols %s 2>&1 | FileCheck %s ! CHECK: end do diff --git a/flang/test/Semantics/data05.f90 b/flang/test/Semantics/data05.f90 index 7d7693ba3d21f..35b9ed1548d60 100644 --- a/flang/test/Semantics/data05.f90 +++ b/flang/test/Semantics/data05.f90 @@ -25,7 +25,7 @@ real function rfunc(x) end type contains subroutine s1 - procedure(ifunc), pointer :: ifptr ! CHECK: ifptr, EXTERNAL, POINTER (Function, InDataStmt) size=24 offset=0: ProcEntity ifunc => ifunc + procedure(ifunc), pointer :: ifptr ! CHECK: ifptr, EXTERNAL, POINTER (Function, InDataStmt) size=8 offset=0: ProcEntity ifunc => ifunc data ifptr/ifunc/ end subroutine subroutine s2 @@ -59,7 +59,7 @@ real function rfunc2(x) rfunc2 = x + 1. end function subroutine s8 - procedure(rfunc), pointer :: rfptr ! CHECK: rfptr, EXTERNAL, POINTER (Function, InDataStmt) size=24 offset=0: ProcEntity rfunc => rfunc2 + procedure(rfunc), pointer :: rfptr ! CHECK: rfptr, EXTERNAL, POINTER (Function, InDataStmt) size=8 offset=0: ProcEntity rfunc => rfunc2 data rfptr/rfunc2/ end subroutine subroutine s10 @@ -73,20 +73,20 @@ integer function ifunc2(n) end function subroutine s11 real, target, save :: arr(3,4) ! CHECK: arr, SAVE, TARGET size=48 offset=0: ObjectEntity type: REAL(4) shape: 1_8:3_8,1_8:4_8 - type(t1) :: d1 = t1(1,reshape([1,2,3,4],[2,2]),(6.,7.),.false.,'ab',arr,ifunc2,rfunc,extrfunc) ! CHECK: d1 size=168 offset=48: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","a"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc) + type(t1) :: d1 = t1(1,reshape([1,2,3,4],[2,2]),(6.,7.),.false.,'ab',arr,ifunc2,rfunc,extrfunc) ! CHECK: d1 size=136 offset=48: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","a"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc) type(t1(4,len=1)) :: d2 = t1(4)(xrp=extrfunc,rp=rfunc,ifptr=ifunc2,xp=arr,c='a& - &b',t=.false.,z=(6.,7.),x=reshape([1,2,3,4],[2,2]),j=1) ! CHECK: d2 size=168 offset=216: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","a"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc) - type(t1(2+2)) :: d3 ! CHECK: d3 (InDataStmt) size=168 offset=384: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","a"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc) + &b',t=.false.,z=(6.,7.),x=reshape([1,2,3,4],[2,2]),j=1) ! CHECK: d2 size=136 offset=184: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","a"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc) + type(t1(2+2)) :: d3 ! CHECK: d3 (InDataStmt) size=136 offset=320: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","a"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc) data d3/t1(1,reshape([1,2,3,4],[2,2]),(6.,7.),.false.,'ab',arr,ifunc2,rfunc,extrfunc)/ - type(t1) :: d4 ! CHECK: d4 (InDataStmt) size=168 offset=552: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","a"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc) + type(t1) :: d4 ! CHECK: d4 (InDataStmt) size=136 offset=456: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","a"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc) data d4/t1(4)(xrp=extrfunc,rp=rfunc,ifptr=ifunc2,xp=arr,c='ab',t=.false.,z=(6& &.,7.),x=reshape([1,2,3,4],[2,2]),j=1)/ - type(t1) :: d5 ! CHECK: d5 (InDataStmt) size=168 offset=720: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","b"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc) + type(t1) :: d5 ! CHECK: d5 (InDataStmt) size=136 offset=592: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","b"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc) data d5%j/1/,d5%x/1,2,3,4/,d5%z%re/6./,d5%z%im/7./,d5%t/.false./,d5%c(1:1)/'a'/,d5%c(2:& &2)/'b'/,d5%xp/arr/,d5%ifptr/ifunc2/,d5%rp/rfunc/,d5%xrp/extrfunc/ end subroutine subroutine s12 - procedure(rfunc), pointer :: pp ! CHECK: pp, EXTERNAL, POINTER (Function, InDataStmt) size=24 offset=0: ProcEntity rfunc => rfunc2 + procedure(rfunc), pointer :: pp ! CHECK: pp, EXTERNAL, POINTER (Function, InDataStmt) size=8 offset=0: ProcEntity rfunc => rfunc2 data pp/rfunc2/ end subroutine end module diff --git a/flang/test/Semantics/structconst07.f90 b/flang/test/Semantics/structconst07.f90 new file mode 100644 index 0000000000000..a34289a817af4 --- /dev/null +++ b/flang/test/Semantics/structconst07.f90 @@ -0,0 +1,9 @@ +! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s +type :: hasPointer + class(*), pointer :: sp +end type +type(hasPointer) hp +!CHECK: hp=haspointer(sp=NULL()) +hp = hasPointer() +end + diff --git a/flang/test/Semantics/structconst07.f90# b/flang/test/Semantics/structconst07.f90# deleted file mode 100644 index af75b43658d32..0000000000000 --- a/flang/test/Semantics/structconst07.f90# +++ /dev/null @@ -1,5 +0,0 @@ -! RUN: %python %S/test_errors.py %s %flang_fc1 -! C1594(4) -module m - type t1 - diff --git a/flang/test/Semantics/typeinfo01.f90 b/flang/test/Semantics/typeinfo01.f90 index e0e742148cb97..336a5cb623692 100644 --- a/flang/test/Semantics/typeinfo01.f90 +++ b/flang/test/Semantics/typeinfo01.f90 @@ -62,7 +62,7 @@ module m05 subroutine s1(x) class(t), intent(in) :: x end subroutine -!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=24_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=.p.t,special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=8_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=.p.t,special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) !CHECK: .p.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(procptrcomponent) shape: 0_8:0_8 init:[procptrcomponent::procptrcomponent(name=.n.p1,offset=0_8,initialization=s1)] end module diff --git a/flang/test/Semantics/typeinfo03.f90 b/flang/test/Semantics/typeinfo03.f90 new file mode 100644 index 0000000000000..f0c0a817da4a4 --- /dev/null +++ b/flang/test/Semantics/typeinfo03.f90 @@ -0,0 +1,9 @@ +!RUN: bbc --dump-symbols %s | FileCheck %s +!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s +!Ensure that type with pointer component(s) has "noinitializationneeded=0" +module m + type hasPointer + class(*), pointer :: sp, ap(:) + end type +end module +!CHECK: .dt.haspointer, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.haspointer,sizeinbytes=104_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.haspointer,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) diff --git a/flang/test/Transforms/OpenACC/convert-data-operands-to-llvmir.fir b/flang/test/Transforms/OpenACC/convert-data-operands-to-llvmir.fir deleted file mode 100644 index bfe5c378bb364..0000000000000 --- a/flang/test/Transforms/OpenACC/convert-data-operands-to-llvmir.fir +++ /dev/null @@ -1,79 +0,0 @@ -// RUN: fir-opt -fir-openacc-data-operand-conversion='use-opaque-pointers=1' -split-input-file %s | FileCheck %s -// RUN: fir-opt -fir-openacc-data-operand-conversion='use-opaque-pointers=1' -split-input-file %s | fir-opt -split-input-file --fir-to-llvm-ir | FileCheck %s --check-prefix=LLVMIR - -fir.global internal @_QFEa : !fir.array<10xf32> { - %0 = fir.undefined !fir.array<10xf32> - fir.has_value %0 : !fir.array<10xf32> -} - -func.func @_QQsub1() attributes {fir.bindc_name = "arr"} { - %0 = fir.address_of(@_QFEa) : !fir.ref> - acc.data copy(%0 : !fir.ref>) { - acc.terminator - } - return -} - -// CHECK-LABEL: func.func @_QQsub1() attributes {fir.bindc_name = "arr"} { -// CHECK: %[[ADDR:.*]] = fir.address_of(@_QFEa) : !fir.ref> -// CHECK: %[[CAST:.*]] = builtin.unrealized_conversion_cast %[[ADDR]] : !fir.ref> to !llvm.ptr> -// CHECK: acc.data copy(%[[CAST]] : !llvm.ptr>) - -// LLVMIR-LABEL: llvm.func @_QQsub1() attributes {fir.bindc_name = "arr"} { -// LLVMIR: %[[ADDR:.*]] = llvm.mlir.addressof @_QFEa : !llvm.ptr> -// LLVMIR: acc.data copy(%[[ADDR]] : !llvm.ptr>) { - -// ----- - -fir.global internal @_QFEa : !fir.array<10xf32> { - %0 = fir.undefined !fir.array<10xf32> - fir.has_value %0 : !fir.array<10xf32> -} - -func.func @_QQsub_enter_exit() attributes {fir.bindc_name = "a"} { - %0 = fir.address_of(@_QFEa) : !fir.ref> - acc.enter_data copyin(%0 : !fir.ref>) - acc.exit_data copyout(%0 : !fir.ref>) - return -} - -// CHECK-LABEL: func.func @_QQsub_enter_exit() attributes {fir.bindc_name = "a"} { -// CHECK: %[[ADDR:.*]] = fir.address_of(@_QFEa) : !fir.ref> -// CHECK: %[[CAST0:.*]] = builtin.unrealized_conversion_cast %[[ADDR]] : !fir.ref> to !llvm.ptr> -// CHECK: acc.enter_data copyin(%[[CAST0]] : !llvm.ptr>) -// CHECK: %[[CAST1:.*]] = builtin.unrealized_conversion_cast %[[ADDR]] : !fir.ref> to !llvm.ptr> -// CHECK: acc.exit_data copyout(%[[CAST1]] : !llvm.ptr>) - -// LLVMIR-LABEL: llvm.func @_QQsub_enter_exit() attributes {fir.bindc_name = "a"} { -// LLVMIR: %[[ADDR:.*]] = llvm.mlir.addressof @_QFEa : !llvm.ptr> -// LLVMIR: acc.enter_data copyin(%[[ADDR]] : !llvm.ptr>) -// LLVMIR: acc.exit_data copyout(%[[ADDR]] : !llvm.ptr>) - -// ----- - -fir.global internal @_QFEa : !fir.array<10xf32> { - %0 = fir.undefined !fir.array<10xf32> - fir.has_value %0 : !fir.array<10xf32> -} - -func.func @_QQsub_parallel() attributes {fir.bindc_name = "test"} { - %0 = fir.address_of(@_QFEa) : !fir.ref> - %1 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"} - acc.parallel copyin(%0: !fir.ref>) { - acc.loop { - acc.yield - } - acc.yield - } - return -} - -// CHECK-LABEL: func.func @_QQsub_parallel() attributes {fir.bindc_name = "test"} { -// CHECK: %[[ADDR:.*]] = fir.address_of(@_QFEa) : !fir.ref> -// CHECK: %[[CAST:.*]] = builtin.unrealized_conversion_cast %[[ADDR]] : !fir.ref> to !llvm.ptr> -// CHECK: acc.parallel copyin(%[[CAST]] : !llvm.ptr>) { -// CHECK: acc.loop - -// LLVMIR-LABEL: llvm.func @_QQsub_parallel() attributes {fir.bindc_name = "test"} { -// LLVMIR: %[[ADDR:.*]] = llvm.mlir.addressof @_QFEa : !llvm.ptr> -// LLVMIR: acc.parallel copyin(%[[ADDR]] : !llvm.ptr>) { diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp index e9cf208ea03ed..dcb37043e6eb7 100644 --- a/flang/tools/bbc/bbc.cpp +++ b/flang/tools/bbc/bbc.cpp @@ -375,7 +375,7 @@ int main(int argc, char **argv) { // enable parsing of OpenACC if (enableOpenACC) { options.features.Enable(Fortran::common::LanguageFeature::OpenACC); - options.predefinitions.emplace_back("_OPENACC", "201911"); + options.predefinitions.emplace_back("_OPENACC", "202011"); } Fortran::common::IntrinsicTypeDefaultKinds defaultKinds; diff --git a/flang/unittests/Optimizer/Builder/FIRBuilderTest.cpp b/flang/unittests/Optimizer/Builder/FIRBuilderTest.cpp index c3436ccd1c779..650a4d13b2b52 100644 --- a/flang/unittests/Optimizer/Builder/FIRBuilderTest.cpp +++ b/flang/unittests/Optimizer/Builder/FIRBuilderTest.cpp @@ -311,7 +311,7 @@ TEST_F(FIRBuilderTest, createStringLiteral) { auto symbol = addrOp.getSymbol().getRootReference().getValue(); auto global = builder.getNamedGlobal(symbol); EXPECT_EQ( - builder.createLinkOnceLinkage().getValue(), global.getLinkName().value()); + builder.createInternalLinkage().getValue(), global.getLinkName().value()); EXPECT_EQ(fir::CharacterType::get(builder.getContext(), 1, strValue.size()), global.getType()); diff --git a/hot-alloctype.patch b/hot-alloctype.patch deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index e0e5b69b47cf8..622851695084a 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.13.4) +cmake_minimum_required(VERSION 3.20.0) # Include LLVM's cmake policies. if(NOT DEFINED LLVM_COMMON_CMAKE_UTILS) diff --git a/libc/benchmarks/CMakeLists.txt b/libc/benchmarks/CMakeLists.txt index f4e1ff6ec7fa1..3d665ce1c6e71 100644 --- a/libc/benchmarks/CMakeLists.txt +++ b/libc/benchmarks/CMakeLists.txt @@ -59,10 +59,18 @@ ExternalProject_Add(google-benchmark-libc -DBENCHMARK_ENABLE_WERROR:BOOL=${LLVM_ENABLE_WERROR} -DBENCHMARK_FORCE_WERROR:BOOL=OFF -DBENCHMARK_USE_LIBCXX:BOOL=OFF - -DCMAKE_BUILD_TYPE:STRING=RELEASE + -DCMAKE_BUILD_TYPE:STRING=Release + + -DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME} + -DCMAKE_SYSTEM_PROCESSOR:STRING=${CMAKE_SYSTEM_PROCESSOR} -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER} - -DCMAKE_CXX_FLAGS:STRING=${BENCHMARK_LIBC_COMPILE_FLAGS} + -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} + -DCMAKE_FIND_ROOT_PATH:STRING=${CMAKE_FIND_ROOT_PATH} + + -DBUILD_SHARED_LIBS:BOOL=OFF + -DCMAKE_EXE_LINKER_FLAGS:STRING=-static + -DCMAKE_CXX_STANDARD:STRING=14 -DCMAKE_INSTALL_PREFIX:PATH= ) @@ -181,12 +189,12 @@ add_executable(libc.benchmarks.memory_functions.opt_host target_link_libraries(libc.benchmarks.memory_functions.opt_host PRIVATE libc-memory-benchmark - libc.src.string.memcmp_opt_host - libc.src.string.bcmp_opt_host - libc.src.string.memcpy_opt_host - libc.src.string.memset_opt_host - libc.src.string.bzero_opt_host - libc.src.string.memmove_opt_host + libc.src.string.memcmp_opt_host.__internal__ + libc.src.string.bcmp_opt_host.__internal__ + libc.src.string.memcpy_opt_host.__internal__ + libc.src.string.memset_opt_host.__internal__ + libc.src.string.bzero_opt_host.__internal__ + libc.src.string.memmove_opt_host.__internal__ benchmark_main ) llvm_update_compile_flags(libc.benchmarks.memory_functions.opt_host) diff --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake index 4c1b143b66186..4458c006899e7 100644 --- a/libc/cmake/modules/LLVMLibCTestRules.cmake +++ b/libc/cmake/modules/LLVMLibCTestRules.cmake @@ -186,7 +186,7 @@ function(create_libc_unittest fq_target_name) if(NOT LIBC_UNITTEST_NO_RUN_POSTBUILD) add_custom_target( ${fq_target_name} - COMMAND $ + COMMAND ${fq_build_target_name} COMMENT "Running unit test ${fq_target_name}" ) endif() diff --git a/libc/examples/hello_world/CMakeLists.txt b/libc/examples/hello_world/CMakeLists.txt index 89bf35c0340d0..1561cdc1c3bf5 100644 --- a/libc/examples/hello_world/CMakeLists.txt +++ b/libc/examples/hello_world/CMakeLists.txt @@ -1,5 +1,5 @@ project(hello_world) -cmake_minimum_required(VERSION 3.13.4) +cmake_minimum_required(VERSION 3.20.0) include(../examples.cmake) add_example( diff --git a/libc/src/__support/RPC/rpc.h b/libc/src/__support/RPC/rpc.h index 55ce6700380f5..540adcebd76b7 100644 --- a/libc/src/__support/RPC/rpc.h +++ b/libc/src/__support/RPC/rpc.h @@ -36,6 +36,8 @@ enum Opcode : uint16_t { PRINT_TO_STDERR = 1, EXIT = 2, TEST_INCREMENT = 3, + TEST_INTERFACE = 4, + TEST_STREAM = 5, }; /// A fixed size channel used to communicate between the RPC client and server. @@ -73,7 +75,7 @@ struct alignas(64) Packet { // of thumb is that you should have at least as many ports as possible // concurrent work items on the GPU to mitigate the lack offorward // progress guarantees on the GPU. -constexpr uint64_t default_port_count = 64; +constexpr uint64_t DEFAULT_PORT_COUNT = 64; /// A common process used to synchronize communication between a client and a /// server. The process contains an inbox and an outbox used for signaling @@ -106,29 +108,44 @@ template struct Process { uint64_t port_count; uint32_t lane_size; - cpp::Atomic *lock; cpp::Atomic *inbox; cpp::Atomic *outbox; Packet *packet; + cpp::Atomic lock[DEFAULT_PORT_COUNT] = {0}; + /// Initialize the communication channels. - LIBC_INLINE void reset(uint64_t port_count, uint32_t lane_size, void *lock, - void *inbox, void *outbox, void *packet) { - *this = {port_count, - lane_size, - reinterpret_cast *>(lock), - reinterpret_cast *>(inbox), - reinterpret_cast *>(outbox), - reinterpret_cast(packet)}; + LIBC_INLINE void reset(uint64_t port_count, uint32_t lane_size, + void *buffer) { + this->port_count = port_count; + this->lane_size = lane_size; + this->inbox = reinterpret_cast *>( + advance(buffer, inbox_offset(port_count))); + this->outbox = reinterpret_cast *>( + advance(buffer, outbox_offset(port_count))); + this->packet = + reinterpret_cast(advance(buffer, buffer_offset(port_count))); + } + + /// Allocate a memory buffer sufficient to store the following equivalent + /// representation in memory. + /// + /// struct Equivalent { + /// Atomic primary[port_count]; + /// Atomic secondary[port_count]; + /// Packet buffer[port_count]; + /// }; + LIBC_INLINE static uint64_t allocation_size(uint64_t port_count, + uint32_t lane_size) { + return buffer_offset(port_count) + buffer_bytes(port_count, lane_size); } /// The length of the packet is flexible because the server needs to look up /// the lane size at runtime. This helper indexes at the proper offset. LIBC_INLINE Packet &get_packet(uint64_t index) { - return *reinterpret_cast( - reinterpret_cast(packet) + - index * align_up(sizeof(Header) + lane_size * sizeof(Buffer), - alignof(Packet))); + return *reinterpret_cast(advance( + packet, index * align_up(sizeof(Header) + lane_size * sizeof(Buffer), + alignof(Packet)))); } /// Inverting the bits loaded from the inbox in exactly one of the pair of @@ -244,41 +261,88 @@ template struct Process { fn(&packet.payload.slot[i], i); } } + + /// Number of bytes to allocate for an inbox or outbox. + LIBC_INLINE static uint64_t mailbox_bytes(uint64_t port_count) { + return port_count * sizeof(cpp::Atomic); + } + + /// Number of bytes to allocate for the buffer containing the packets. + LIBC_INLINE static uint64_t buffer_bytes(uint64_t port_count, + uint32_t lane_size) { + return is_process_gpu() + ? port_count * sizeof(Packet) + : port_count * + align_up(sizeof(Header) + (lane_size * sizeof(Buffer)), + alignof(Packet)); + } + + /// Offset of the inbox in memory. This is the same as the outbox if inverted. + LIBC_INLINE static uint64_t inbox_offset(uint64_t port_count) { + return InvertInbox ? mailbox_bytes(port_count) : 0; + } + + /// Offset of the outbox in memory. This is the same as the inbox if inverted. + LIBC_INLINE static uint64_t outbox_offset(uint64_t port_count) { + return InvertInbox ? 0 : mailbox_bytes(port_count); + } + + /// Offset of the buffer containing the packets after the inbox and outbox. + LIBC_INLINE static uint64_t buffer_offset(uint64_t port_count) { + return align_up(2 * mailbox_bytes(port_count), alignof(Packet)); + } }; /// The port provides the interface to communicate between the multiple /// processes. A port is conceptually an index into the memory provided by the /// underlying process that is guarded by a lock bit. template struct Port { - // TODO: This should be move-only. LIBC_INLINE Port(Process &process, uint64_t lane_mask, uint64_t index, uint32_t out) - : process(process), lane_mask(lane_mask), index(index), out(out) {} + : process(process), lane_mask(lane_mask), index(index), out(out), + receive(false), owns_buffer(true) {} + LIBC_INLINE ~Port() = default; + +private: LIBC_INLINE Port(const Port &) = delete; LIBC_INLINE Port &operator=(const Port &) = delete; LIBC_INLINE Port(Port &&) = default; LIBC_INLINE Port &operator=(Port &&) = default; - LIBC_INLINE ~Port() = default; + friend struct Client; + friend struct Server; + friend class cpp::optional>; + +public: template LIBC_INLINE void recv(U use); template LIBC_INLINE void send(F fill); template LIBC_INLINE void send_and_recv(F fill, U use); template LIBC_INLINE void recv_and_send(W work); + LIBC_INLINE void send_n(const void *const *src, uint64_t *size); LIBC_INLINE void send_n(const void *src, uint64_t size); - template LIBC_INLINE void recv_n(A alloc); + template + LIBC_INLINE void recv_n(void **dst, uint64_t *size, A &&alloc); LIBC_INLINE uint16_t get_opcode() const { return process.get_packet(index).header.opcode; } - LIBC_INLINE void close() { process.unlock(lane_mask, index); } + LIBC_INLINE void close() { + // The server is passive, if it own the buffer when it closes we need to + // give ownership back to the client. + if (owns_buffer && T) + out = process.invert_outbox(index, out); + process.unlock(lane_mask, index); + } private: Process &process; uint64_t lane_mask; uint64_t index; uint32_t out; + bool receive; + bool owns_buffer; }; /// The RPC client used to make requests to the server. @@ -307,7 +371,7 @@ struct Server : public Process { /// Applies \p fill to the shared buffer and initiates a send operation. template template LIBC_INLINE void Port::send(F fill) { - uint32_t in = process.load_inbox(index); + uint32_t in = owns_buffer ? out ^ T : process.load_inbox(index); // We need to wait until we own the buffer before sending. while (Process::buffer_unavailable(in, out)) { @@ -319,11 +383,20 @@ template template LIBC_INLINE void Port::send(F fill) { process.invoke_rpc(fill, process.get_packet(index)); atomic_thread_fence(cpp::MemoryOrder::RELEASE); out = process.invert_outbox(index, out); + owns_buffer = false; + receive = false; } /// Applies \p use to the shared buffer and acknowledges the send. template template LIBC_INLINE void Port::recv(U use) { - uint32_t in = process.load_inbox(index); + // We only exchange ownership of the buffer during a receive if we are waiting + // for a previous receive to finish. + if (receive) { + out = process.invert_outbox(index, out); + owns_buffer = false; + } + + uint32_t in = owns_buffer ? out ^ T : process.load_inbox(index); // We need to wait until we own the buffer before receiving. while (Process::buffer_unavailable(in, out)) { @@ -334,7 +407,8 @@ template template LIBC_INLINE void Port::recv(U use) { // Apply the \p use function to read the memory out of the buffer. process.invoke_rpc(use, process.get_packet(index)); - out = process.invert_outbox(index, out); + receive = true; + owns_buffer = true; } /// Combines a send and receive into a single function. @@ -358,67 +432,65 @@ LIBC_INLINE void Port::recv_and_send(W work) { /// Sends an arbitrarily sized data buffer \p src across the shared channel in /// multiples of the packet length. template -LIBC_INLINE void Port::send_n(const void *src, uint64_t size) { +LIBC_INLINE void Port::send_n(const void *const *src, uint64_t *size) { // TODO: We could send the first bytes in this call and potentially save an // extra send operation. // TODO: We may need a way for the CPU to send different strings per thread. - send([=](Buffer *buffer) { - reinterpret_cast(buffer->data)[0] = size; + uint64_t num_sends = 0; + send([&](Buffer *buffer, uint32_t id) { + reinterpret_cast(buffer->data)[0] = lane_value(size, id); + num_sends = is_process_gpu() ? lane_value(size, id) + : max(lane_value(size, id), num_sends); }); - const uint8_t *ptr = reinterpret_cast(src); - for (uint64_t idx = 0; idx < size; idx += sizeof(Buffer::data)) { - send([=](Buffer *buffer) { - const uint64_t len = - size - idx > sizeof(Buffer::data) ? sizeof(Buffer::data) : size - idx; - inline_memcpy(buffer->data, ptr + idx, len); + for (uint64_t idx = 0; idx < num_sends; idx += sizeof(Buffer::data)) { + send([=](Buffer *buffer, uint32_t id) { + const uint64_t len = lane_value(size, id) - idx > sizeof(Buffer::data) + ? sizeof(Buffer::data) + : lane_value(size, id) - idx; + if (idx < lane_value(size, id)) + inline_memcpy( + buffer->data, + reinterpret_cast(lane_value(src, id)) + idx, len); }); } gpu::sync_lane(process.get_packet(index).header.mask); } +/// Helper routine to simplify the interface when sending from the GPU using +/// thread private pointers to the underlying value. +template +LIBC_INLINE void Port::send_n(const void *src, uint64_t size) { + static_assert(is_process_gpu(), "Only valid when running on the GPU"); + const void **src_ptr = &src; + uint64_t *size_ptr = &size; + send_n(src_ptr, size_ptr); +} + /// Receives an arbitrarily sized data buffer across the shared channel in /// multiples of the packet length. The \p alloc function is called with the /// size of the data so that we can initialize the size of the \p dst buffer. template template -LIBC_INLINE void Port::recv_n(A alloc) { - // The GPU handles thread private variables and masking implicitly through its - // execution model. If this is the CPU we need to manually handle the - // possibility that the sent data is of different length. - if constexpr (is_process_gpu()) { - uint64_t size = 0; - recv([&](Buffer *buffer) { - size = reinterpret_cast(buffer->data)[0]; - }); - uint8_t *dst = reinterpret_cast(alloc(size), gpu::get_lane_id()); - for (uint64_t idx = 0; idx < size; idx += sizeof(Buffer::data)) { - recv([=](Buffer *buffer) { - uint64_t len = size - idx > sizeof(Buffer::data) ? sizeof(Buffer::data) - : size - idx; - inline_memcpy(dst + idx, buffer->data, len); - }); - } - return; - } else { - uint64_t size[MAX_LANE_SIZE]; - uint8_t *dst[MAX_LANE_SIZE]; - uint64_t max = 0; - recv([&](Buffer *buffer, uint32_t id) { - size[id] = reinterpret_cast(buffer->data)[0]; - dst[id] = reinterpret_cast(alloc(size[id], id)); - max = size[id] > max ? size[id] : max; +LIBC_INLINE void Port::recv_n(void **dst, uint64_t *size, A &&alloc) { + uint64_t num_recvs = 0; + recv([&](Buffer *buffer, uint32_t id) { + lane_value(size, id) = reinterpret_cast(buffer->data)[0]; + lane_value(dst, id) = + reinterpret_cast(alloc(lane_value(size, id))); + num_recvs = is_process_gpu() ? lane_value(size, id) + : max(lane_value(size, id), num_recvs); + }); + for (uint64_t idx = 0; idx < num_recvs; idx += sizeof(Buffer::data)) { + recv([=](Buffer *buffer, uint32_t id) { + uint64_t len = lane_value(size, id) - idx > sizeof(Buffer::data) + ? sizeof(Buffer::data) + : lane_value(size, id) - idx; + if (idx < lane_value(size, id)) + inline_memcpy(reinterpret_cast(lane_value(dst, id)) + idx, + buffer->data, len); }); - for (uint64_t idx = 0; idx < max; idx += sizeof(Buffer::data)) { - recv([=](Buffer *buffer, uint32_t id) { - uint64_t len = size[id] - idx > sizeof(Buffer::data) - ? sizeof(Buffer::data) - : size[id] - idx; - if (idx < size[id]) - inline_memcpy(dst[id] + idx, buffer->data, len); - }); - } - return; } + return; } /// Attempts to open a port to use as the client. The client can only open a diff --git a/libc/src/__support/RPC/rpc_util.h b/libc/src/__support/RPC/rpc_util.h index c6282e40c903e..b9ffdaa089693 100644 --- a/libc/src/__support/RPC/rpc_util.h +++ b/libc/src/__support/RPC/rpc_util.h @@ -54,6 +54,26 @@ template LIBC_INLINE V align_up(V val, A align) { return ((val + V(align) - 1) / V(align)) * V(align); } +/// Utility to provide a unified interface between the CPU and GPU's memory +/// model. On the GPU stack variables are always private to a lane so we can +/// simply use the variable passed in. On the CPU we need to allocate enough +/// space for the whole lane and index into it. +template LIBC_INLINE V &lane_value(V *val, uint32_t id) { + if constexpr (is_process_gpu()) + return *val; + return val[id]; +} + +/// Helper to get the maximum value. +template LIBC_INLINE const T &max(const T &x, const T &y) { + return x < y ? y : x; +} + +/// Advance the \p ptr by \p bytes. +template LIBC_INLINE T *advance(T ptr, U bytes) { + return reinterpret_cast(reinterpret_cast(ptr) + bytes); +} + } // namespace rpc } // namespace __llvm_libc diff --git a/libc/src/__support/UInt.h b/libc/src/__support/UInt.h index 8b273e3689643..a702aaad827b2 100644 --- a/libc/src/__support/UInt.h +++ b/libc/src/__support/UInt.h @@ -342,6 +342,126 @@ template struct UInt { return remainder; } + // Efficiently perform UInt / (x * 2^e), where x is a 32-bit unsigned integer, + // and return the remainder. + // The main idea is as follow: + // Let q = y / (x * 2^e) be the quotient, and + // r = y % (x * 2^e) be the remainder. + // First, notice that: + // r % (2^e) = y % (2^e), + // so we just need to focus on all the bits of y that is >= 2^e. + // To speed up the shift-and-add steps, we only use x as the divisor, and + // performing 32-bit shiftings instead of bit-by-bit shiftings. + // Since the remainder of each division step < x < 2^32, the computation of + // each step is now properly contained within uint64_t. + // And finally we perform some extra alignment steps for the remaining bits. + constexpr optional> div_uint32_times_pow_2(uint32_t x, size_t e) { + UInt remainder(0); + + if (x == 0) { + return nullopt; + } + if (e >= Bits) { + remainder = *this; + *this = UInt(0); + return remainder; + } + + UInt quotient(0); + uint64_t x64 = static_cast(x); + // lower64 = smallest multiple of 64 that is >= e. + size_t lower64 = ((e >> 6) + ((e & 63) != 0)) << 6; + // lower_pos is the index of the closest 64-bit chunk >= 2^e. + size_t lower_pos = lower64 / 64; + // Keep track of current remainder mod x * 2^(32*i) + uint64_t rem = 0; + // pos is the index of the current 64-bit chunk that we are processing. + size_t pos = WORDCOUNT; + + for (size_t q_pos = WORDCOUNT - lower_pos; q_pos > 0; --q_pos) { + // q_pos is 1 + the index of the current 64-bit chunk of the quotient + // being processed. + // Performing the division / modulus with divisor: + // x * 2^(64*q_pos - 32), + // i.e. using the upper 32-bit of the current 64-bit chunk. + rem <<= 32; + rem += val[--pos] >> 32; + uint64_t q_tmp = rem / x64; + rem %= x64; + + // Performing the division / modulus with divisor: + // x * 2^(64*(q_pos - 1)), + // i.e. using the lower 32-bit of the current 64-bit chunk. + rem <<= 32; + rem += val[pos] & MASK32; + quotient.val[q_pos - 1] = (q_tmp << 32) + rem / x64; + rem %= x64; + } + + // So far, what we have is: + // quotient = y / (x * 2^lower64), and + // rem = (y % (x * 2^lower64)) / 2^lower64. + // If (lower64 > e), we will need to perform an extra adjustment of the + // quotient and remainder, namely: + // y / (x * 2^e) = [ y / (x * 2^lower64) ] * 2^(lower64 - e) + + // + (rem * 2^(lower64 - e)) / x + // (y % (x * 2^e)) / 2^e = (rem * 2^(lower64 - e)) % x + size_t last_shift = lower64 - e; + + if (last_shift > 0) { + // quotient * 2^(lower64 - e) + quotient <<= last_shift; + uint64_t q_tmp = 0; + uint64_t d = val[--pos]; + if (last_shift >= 32) { + // The shifting (rem * 2^(lower64 - e)) might overflow uint64_t, so we + // perform a 32-bit shift first. + rem <<= 32; + rem += d >> 32; + d &= MASK32; + q_tmp = rem / x64; + rem %= x64; + last_shift -= 32; + } else { + // Only use the upper 32-bit of the current 64-bit chunk. + d >>= 32; + } + + if (last_shift > 0) { + rem <<= 32; + rem += d; + q_tmp <<= last_shift; + x64 <<= 32 - last_shift; + q_tmp += rem / x64; + rem %= x64; + } + + quotient.val[0] += q_tmp; + + if (lower64 - e <= 32) { + // The remainder rem * 2^(lower64 - e) might overflow to the higher + // 64-bit chunk. + if (pos < WORDCOUNT - 1) { + remainder[pos + 1] = rem >> 32; + } + remainder[pos] = (rem << 32) + (val[pos] & MASK32); + } else { + remainder[pos] = rem; + } + + } else { + remainder[pos] = rem; + } + + // Set the remaining lower bits of the remainder. + for (; pos > 0; --pos) { + remainder[pos - 1] = val[pos - 1]; + } + + *this = quotient; + return remainder; + } + constexpr UInt operator/(const UInt &other) const { UInt result(*this); result.div(other); diff --git a/libc/src/__support/macros/properties/architectures.h b/libc/src/__support/macros/properties/architectures.h index 1247fd6ef5cbc..66bb6fb68a642 100644 --- a/libc/src/__support/macros/properties/architectures.h +++ b/libc/src/__support/macros/properties/architectures.h @@ -49,6 +49,10 @@ #define LIBC_TARGET_ARCH_IS_RISCV64 #endif +#if defined(__riscv) && (__riscv_xlen == 32) +#define LIBC_TARGET_ARCH_IS_RISCV32 +#endif + #if (defined(LIBC_TARGET_ARCH_IS_AARCH64) || defined(LIBC_TARGET_ARCH_IS_ARM)) #define LIBC_TARGET_ARCH_IS_ANY_ARM #endif diff --git a/libc/src/string/memory_utils/CMakeLists.txt b/libc/src/string/memory_utils/CMakeLists.txt index 31335227f4ab3..7bb0e960ee13d 100644 --- a/libc/src/string/memory_utils/CMakeLists.txt +++ b/libc/src/string/memory_utils/CMakeLists.txt @@ -18,6 +18,7 @@ add_header_library( x86_64/memcmp_implementations.h x86_64/memcpy_implementations.h DEPS + libc.src.__support.common libc.src.__support.CPP.bit libc.src.__support.CPP.cstddef libc.src.__support.CPP.type_traits diff --git a/libc/src/string/memory_utils/memcpy_implementations.h b/libc/src/string/memory_utils/memcpy_implementations.h index b1b60ff590d50..b22606781703f 100644 --- a/libc/src/string/memory_utils/memcpy_implementations.h +++ b/libc/src/string/memory_utils/memcpy_implementations.h @@ -26,24 +26,79 @@ namespace __llvm_libc { [[maybe_unused]] LIBC_INLINE void -inline_memcpy_embedded_tiny(Ptr __restrict dst, CPtr __restrict src, - size_t count) { +inline_memcpy_byte_per_byte(Ptr dst, CPtr src, size_t offset, size_t count) { LIBC_LOOP_NOUNROLL - for (size_t offset = 0; offset < count; ++offset) - builtin::Memcpy<1>::block(dst + offset, src + offset); + for (; offset < count; ++offset) + dst[offset] = src[offset]; +} + +[[maybe_unused]] LIBC_INLINE void +inline_memcpy_aligned_access_32bit(Ptr __restrict dst, CPtr __restrict src, + size_t count) { + constexpr size_t kAlign = sizeof(uint32_t); + if (count <= 2 * kAlign) + return inline_memcpy_byte_per_byte(dst, src, 0, count); + size_t bytes_to_dst_align = distance_to_align_up(dst); + inline_memcpy_byte_per_byte(dst, src, 0, bytes_to_dst_align); + size_t offset = bytes_to_dst_align; + size_t src_alignment = distance_to_align_down(src + offset); + for (; offset < count - kAlign; offset += kAlign) { + uint32_t value; + if (src_alignment == 0) + value = load32_aligned(src, offset); + else if (src_alignment == 2) + value = load32_aligned(src, offset); + else + value = load32_aligned(src, offset); + store32_aligned(value, dst, offset); + } + // remainder + inline_memcpy_byte_per_byte(dst, src, offset, count); +} + +[[maybe_unused]] LIBC_INLINE void +inline_memcpy_aligned_access_64bit(Ptr __restrict dst, CPtr __restrict src, + size_t count) { + constexpr size_t kAlign = sizeof(uint64_t); + if (count <= 2 * kAlign) + return inline_memcpy_byte_per_byte(dst, src, 0, count); + size_t bytes_to_dst_align = distance_to_align_up(dst); + inline_memcpy_byte_per_byte(dst, src, 0, bytes_to_dst_align); + size_t offset = bytes_to_dst_align; + size_t src_alignment = distance_to_align_down(src + offset); + for (; offset < count - kAlign; offset += kAlign) { + uint64_t value; + if (src_alignment == 0) + value = load64_aligned(src, offset); + else if (src_alignment == 4) + value = load64_aligned(src, offset); + else if (src_alignment == 2) + value = + load64_aligned(src, offset); + else + value = load64_aligned( + src, offset); + store64_aligned(value, dst, offset); + } + // remainder + inline_memcpy_byte_per_byte(dst, src, offset, count); } LIBC_INLINE void inline_memcpy(Ptr __restrict dst, CPtr __restrict src, size_t count) { using namespace __llvm_libc::builtin; #if defined(LIBC_COPT_MEMCPY_USE_EMBEDDED_TINY) - return inline_memcpy_embedded_tiny(dst, src, count); + return inline_memcpy_byte_per_byte(dst, src, 0, count); #elif defined(LIBC_TARGET_ARCH_IS_X86) return inline_memcpy_x86_maybe_interpose_repmovsb(dst, src, count); #elif defined(LIBC_TARGET_ARCH_IS_AARCH64) return inline_memcpy_aarch64(dst, src, count); +#elif defined(LIBC_TARGET_ARCH_IS_RISCV64) + return inline_memcpy_aligned_access_64bit(dst, src, count); +#elif defined(LIBC_TARGET_ARCH_IS_RISCV32) + return inline_memcpy_aligned_access_32bit(dst, src, count); #else - return inline_memcpy_embedded_tiny(dst, src, count); + return inline_memcpy_byte_per_byte(dst, src, 0, count); #endif } diff --git a/libc/src/string/memory_utils/memset_implementations.h b/libc/src/string/memory_utils/memset_implementations.h index e78a4470f4985..28ecc3b540b38 100644 --- a/libc/src/string/memory_utils/memset_implementations.h +++ b/libc/src/string/memory_utils/memset_implementations.h @@ -23,12 +23,39 @@ namespace __llvm_libc { [[maybe_unused]] LIBC_INLINE static void -inline_memset_embedded_tiny(Ptr dst, uint8_t value, size_t count) { +inline_memset_byte_per_byte(Ptr dst, size_t offset, uint8_t value, + size_t count) { LIBC_LOOP_NOUNROLL - for (size_t offset = 0; offset < count; ++offset) + for (; offset < count; ++offset) generic::Memset::block(dst + offset, value); } +[[maybe_unused]] LIBC_INLINE static void +inline_memset_aligned_access_32bit(Ptr dst, uint8_t value, size_t count) { + constexpr size_t kAlign = sizeof(uint32_t); + if (count <= 2 * kAlign) + return inline_memset_byte_per_byte(dst, 0, value, count); + size_t bytes_to_dst_align = distance_to_align_up(dst); + inline_memset_byte_per_byte(dst, 0, value, bytes_to_dst_align); + size_t offset = bytes_to_dst_align; + for (; offset < count - kAlign; offset += kAlign) + store32_aligned(generic::splat(value), dst, offset); + inline_memset_byte_per_byte(dst, offset, value, count); +} + +[[maybe_unused]] LIBC_INLINE static void +inline_memset_aligned_access_64bit(Ptr dst, uint8_t value, size_t count) { + constexpr size_t kAlign = sizeof(uint64_t); + if (count <= 2 * kAlign) + return inline_memset_byte_per_byte(dst, 0, value, count); + size_t bytes_to_dst_align = distance_to_align_up(dst); + inline_memset_byte_per_byte(dst, 0, value, bytes_to_dst_align); + size_t offset = bytes_to_dst_align; + for (; offset < count - kAlign; offset += kAlign) + store64_aligned(generic::splat(value), dst, offset); + inline_memset_byte_per_byte(dst, offset, value, count); +} + #if defined(LIBC_TARGET_ARCH_IS_X86) [[maybe_unused]] LIBC_INLINE static void inline_memset_x86(Ptr dst, uint8_t value, size_t count) { @@ -121,8 +148,12 @@ LIBC_INLINE static void inline_memset(Ptr dst, uint8_t value, size_t count) { return inline_memset_x86(dst, value, count); #elif defined(LIBC_TARGET_ARCH_IS_AARCH64) return inline_memset_aarch64(dst, value, count); +#elif defined(LIBC_TARGET_ARCH_IS_RISCV64) + return inline_memset_aligned_access_64bit(dst, value, count); +#elif defined(LIBC_TARGET_ARCH_IS_RISCV32) + return inline_memset_aligned_access_32bit(dst, value, count); #else - return inline_memset_embedded_tiny(dst, value, count); + return inline_memset_byte_per_byte(dst, 0, value, count); #endif } diff --git a/libc/src/string/memory_utils/utils.h b/libc/src/string/memory_utils/utils.h index 5c7b360ad108f..ab33331847afe 100644 --- a/libc/src/string/memory_utils/utils.h +++ b/libc/src/string/memory_utils/utils.h @@ -12,8 +12,9 @@ #include "src/__support/CPP/bit.h" #include "src/__support/CPP/cstddef.h" #include "src/__support/CPP/type_traits.h" -#include "src/__support/macros/attributes.h" //LIBC_INLINE -#include "src/__support/macros/config.h" // LIBC_HAS_BUILTIN +#include "src/__support/endian.h" +#include "src/__support/macros/attributes.h" // LIBC_INLINE +#include "src/__support/macros/config.h" // LIBC_HAS_BUILTIN #include // size_t #include // intptr_t / uintptr_t @@ -97,8 +98,15 @@ LIBC_INLINE void memcpy_inline(void *__restrict dst, #ifdef LLVM_LIBC_HAS_BUILTIN_MEMCPY_INLINE __builtin_memcpy_inline(dst, src, Size); #else +// In memory functions `memcpy_inline` is instantiated several times with +// different value of the Size parameter. This doesn't play well with GCC's +// Value Range Analysis that wrongly detects out of bounds accesses. We disable +// the 'array-bounds' warning for the purpose of this function. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" for (size_t i = 0; i < Size; ++i) static_cast(dst)[i] = static_cast(src)[i]; +#pragma GCC diagnostic pop #endif } @@ -153,6 +161,81 @@ template LIBC_INLINE void store(Ptr ptr, T value) { memcpy_inline(ptr, &value); } +// On architectures that do not allow for unaligned access we perform several +// aligned accesses and recombine them through shifts and logicals operations. +// For instance, if we know that the pointer is 2-byte aligned we can decompose +// a 64-bit operation into four 16-bit operations. + +// Loads a 'ValueType' by decomposing it into several loads that are assumed to +// be aligned. +// e.g. load_aligned(ptr); +template +ValueType load_aligned(CPtr src) { + static_assert(sizeof(ValueType) >= (sizeof(T) + ... + sizeof(TS))); + const ValueType value = load(assume_aligned(src)); + if constexpr (sizeof...(TS) > 0) { + constexpr size_t shift = sizeof(T) * 8; + const ValueType next = load_aligned(src + sizeof(T)); + if constexpr (Endian::IS_LITTLE) + return value | (next << shift); + else if constexpr (Endian::IS_BIG) + return (value << shift) | next; + else + deferred_static_assert("Invalid endianness"); + } else { + return value; + } +} + +// Alias for loading a 'uint32_t'. +template +auto load32_aligned(CPtr src, size_t offset) { + static_assert((sizeof(T) + ... + sizeof(TS)) == sizeof(uint32_t)); + return load_aligned(src + offset); +} + +// Alias for loading a 'uint64_t'. +template +auto load64_aligned(CPtr src, size_t offset) { + static_assert((sizeof(T) + ... + sizeof(TS)) == sizeof(uint64_t)); + return load_aligned(src + offset); +} + +// Stores a 'ValueType' by decomposing it into several stores that are assumed +// to be aligned. +// e.g. store_aligned(value, ptr); +template +void store_aligned(ValueType value, Ptr dst) { + static_assert(sizeof(ValueType) >= (sizeof(T) + ... + sizeof(TS))); + constexpr size_t shift = sizeof(T) * 8; + if constexpr (Endian::IS_LITTLE) { + store(assume_aligned(dst), value & ~T(0)); + if constexpr (sizeof...(TS) > 0) + store_aligned(value >> shift, dst + sizeof(T)); + } else if constexpr (Endian::IS_BIG) { + constexpr size_t OFFSET = (0 + ... + sizeof(TS)); + store(assume_aligned(dst + OFFSET), value & ~T(0)); + if constexpr (sizeof...(TS) > 0) + store_aligned(value >> shift, dst); + } else { + deferred_static_assert("Invalid endianness"); + } +} + +// Alias for storing a 'uint32_t'. +template +void store32_aligned(uint32_t value, Ptr dst, size_t offset) { + static_assert((sizeof(T) + ... + sizeof(TS)) == sizeof(uint32_t)); + store_aligned(value, dst + offset); +} + +// Alias for storing a 'uint64_t'. +template +void store64_aligned(uint64_t value, Ptr dst, size_t offset) { + static_assert((sizeof(T) + ... + sizeof(TS)) == sizeof(uint64_t)); + store_aligned(value, dst + offset); +} + // Advances the pointers p1 and p2 by offset bytes and decrease count by the // same amount. template diff --git a/libc/startup/gpu/amdgpu/start.cpp b/libc/startup/gpu/amdgpu/start.cpp index 84adb3b97527b..8d85fe1a4b03d 100644 --- a/libc/startup/gpu/amdgpu/start.cpp +++ b/libc/startup/gpu/amdgpu/start.cpp @@ -15,8 +15,6 @@ extern "C" int main(int argc, char **argv, char **envp); namespace __llvm_libc { -static cpp::Atomic lock[rpc::default_port_count] = {0}; - extern "C" uintptr_t __init_array_start[]; extern "C" uintptr_t __init_array_end[]; extern "C" uintptr_t __fini_array_start[]; @@ -40,12 +38,12 @@ static void call_fini_array_callbacks() { } // namespace __llvm_libc extern "C" [[gnu::visibility("protected"), clang::amdgpu_kernel]] void -_begin(int argc, char **argv, char **env, void *in, void *out, void *buffer) { +_begin(int argc, char **argv, char **env, void *rpc_shared_buffer) { // We need to set up the RPC client first in case any of the constructors // require it. - __llvm_libc::rpc::client.reset(__llvm_libc::rpc::default_port_count, + __llvm_libc::rpc::client.reset(__llvm_libc::rpc::DEFAULT_PORT_COUNT, __llvm_libc::gpu::get_lane_size(), - &__llvm_libc::lock, in, out, buffer); + rpc_shared_buffer); // We want the fini array callbacks to be run after other atexit // callbacks are run. So, we register them before running the init diff --git a/libc/startup/gpu/nvptx/start.cpp b/libc/startup/gpu/nvptx/start.cpp index 1d366dc829dfb..fdd3c439530e1 100644 --- a/libc/startup/gpu/nvptx/start.cpp +++ b/libc/startup/gpu/nvptx/start.cpp @@ -15,8 +15,6 @@ extern "C" int main(int argc, char **argv, char **envp); namespace __llvm_libc { -static cpp::Atomic lock[rpc::default_port_count] = {0}; - extern "C" { // Nvidia's 'nvlink' linker does not provide these symbols. We instead need // to manually create them and update the globals in the loader implememtation. @@ -44,12 +42,12 @@ static void call_fini_array_callbacks() { } // namespace __llvm_libc extern "C" [[gnu::visibility("protected"), clang::nvptx_kernel]] void -_begin(int argc, char **argv, char **env, void *in, void *out, void *buffer) { +_begin(int argc, char **argv, char **env, void *rpc_shared_buffer) { // We need to set up the RPC client first in case any of the constructors // require it. - __llvm_libc::rpc::client.reset(__llvm_libc::rpc::default_port_count, + __llvm_libc::rpc::client.reset(__llvm_libc::rpc::DEFAULT_PORT_COUNT, __llvm_libc::gpu::get_lane_size(), - &__llvm_libc::lock, in, out, buffer); + rpc_shared_buffer); // We want the fini array callbacks to be run after other atexit // callbacks are run. So, we register them before running the init diff --git a/libc/test/IntegrationTest/test.cpp b/libc/test/IntegrationTest/test.cpp index e86e0a8d22c82..8e2feccd0dac7 100644 --- a/libc/test/IntegrationTest/test.cpp +++ b/libc/test/IntegrationTest/test.cpp @@ -57,7 +57,8 @@ int atexit(void (*func)(void)) { return __llvm_libc::atexit(func); } // which just hands out continuous blocks from a statically allocated chunk of // memory. -static uint8_t memory[16384]; +static constexpr uint64_t MEMORY_SIZE = 16384; +static uint8_t memory[MEMORY_SIZE]; static uint8_t *ptr = memory; extern "C" { @@ -65,7 +66,7 @@ extern "C" { void *malloc(size_t s) { void *mem = ptr; ptr += s; - return mem; + return static_cast(ptr - memory) >= MEMORY_SIZE ? nullptr : mem; } void free(void *) {} diff --git a/libc/test/UnitTest/HermeticTestUtils.cpp b/libc/test/UnitTest/HermeticTestUtils.cpp index c8279e54e15dd..04ec22f165b86 100644 --- a/libc/test/UnitTest/HermeticTestUtils.cpp +++ b/libc/test/UnitTest/HermeticTestUtils.cpp @@ -29,7 +29,8 @@ namespace { // requires. Hence, as a work around for this problem, we use a simple allocator // which just hands out continuous blocks from a statically allocated chunk of // memory. -static uint8_t memory[16384]; +static constexpr uint64_t MEMORY_SIZE = 16384; +static uint8_t memory[MEMORY_SIZE]; static uint8_t *ptr = memory; } // anonymous namespace @@ -68,7 +69,7 @@ void *malloc(size_t s) { s = ((s + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; void *mem = ptr; ptr += s; - return mem; + return static_cast(ptr - memory) >= MEMORY_SIZE ? nullptr : mem; } void free(void *) {} diff --git a/libc/test/integration/startup/gpu/CMakeLists.txt b/libc/test/integration/startup/gpu/CMakeLists.txt index d2028cc941f05..02018f9c58930 100644 --- a/libc/test/integration/startup/gpu/CMakeLists.txt +++ b/libc/test/integration/startup/gpu/CMakeLists.txt @@ -36,3 +36,19 @@ add_integration_test( SRCS init_fini_array_test.cpp ) + +add_integration_test( + startup_rpc_interface_test + SUITE libc-startup-tests + SRCS + rpc_interface_test.cpp +) + +add_integration_test( + startup_rpc_stream_test + SUITE libc-startup-tests + SRCS + rpc_stream_test.cpp + LOADER_ARGS + --threads-x 32 +) diff --git a/libc/test/integration/startup/gpu/rpc_interface_test.cpp b/libc/test/integration/startup/gpu/rpc_interface_test.cpp new file mode 100644 index 0000000000000..b4b03ead31c10 --- /dev/null +++ b/libc/test/integration/startup/gpu/rpc_interface_test.cpp @@ -0,0 +1,43 @@ +//===-- Loader test to check the RPC interface with the loader ------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/__support/GPU/utils.h" +#include "src/__support/RPC/rpc_client.h" +#include "test/IntegrationTest/test.h" + +using namespace __llvm_libc; + +// Test to ensure that we can use aribtrary combinations of sends and recieves +// as long as they are mirrored. +static void test_interface(bool end_with_send) { + uint64_t cnt = 0; + rpc::Client::Port port = rpc::client.open(); + port.send([&](rpc::Buffer *buffer) { buffer->data[0] = end_with_send; }); + port.send([&](rpc::Buffer *buffer) { buffer->data[0] = cnt = cnt + 1; }); + port.recv([&](rpc::Buffer *buffer) { cnt = buffer->data[0]; }); + port.send([&](rpc::Buffer *buffer) { buffer->data[0] = cnt = cnt + 1; }); + port.recv([&](rpc::Buffer *buffer) { cnt = buffer->data[0]; }); + port.send([&](rpc::Buffer *buffer) { buffer->data[0] = cnt = cnt + 1; }); + port.send([&](rpc::Buffer *buffer) { buffer->data[0] = cnt = cnt + 1; }); + port.recv([&](rpc::Buffer *buffer) { cnt = buffer->data[0]; }); + port.recv([&](rpc::Buffer *buffer) { cnt = buffer->data[0]; }); + if (end_with_send) + port.send([&](rpc::Buffer *buffer) { buffer->data[0] = cnt = cnt + 1; }); + else + port.recv([&](rpc::Buffer *buffer) { cnt = buffer->data[0]; }); + port.close(); + + ASSERT_TRUE(cnt == 9 && "Invalid number of increments"); +} + +TEST_MAIN(int argc, char **argv, char **envp) { + test_interface(true); + test_interface(false); + + return 0; +} diff --git a/libc/test/integration/startup/gpu/rpc_stream_test.cpp b/libc/test/integration/startup/gpu/rpc_stream_test.cpp new file mode 100644 index 0000000000000..3d495b4df9940 --- /dev/null +++ b/libc/test/integration/startup/gpu/rpc_stream_test.cpp @@ -0,0 +1,51 @@ +//===-- Loader test to check the RPC streaming interface with the loader --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/__support/GPU/utils.h" +#include "src/__support/RPC/rpc_client.h" +#include "src/__support/integer_to_string.h" +#include "src/string/memory_utils/memcmp_implementations.h" +#include "src/string/memory_utils/memcpy_implementations.h" +#include "src/string/string_utils.h" +#include "test/IntegrationTest/test.h" + +extern "C" void *malloc(uint64_t); +extern "C" void free(void *); + +using namespace __llvm_libc; + +static void test_stream() { + const char str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy" + "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy"; + uint64_t send_size = sizeof(str); + void *send_ptr = malloc(send_size); + void *recv_ptr; + uint64_t recv_size; + + inline_memcpy(send_ptr, str, send_size); + ASSERT_TRUE(inline_memcmp(send_ptr, str, send_size) == 0 && "Data mismatch"); + rpc::Client::Port port = rpc::client.open(); + port.send_n(send_ptr, send_size); + port.recv_n(&recv_ptr, &recv_size, + [](uint64_t size) { return malloc(size); }); + port.close(); + ASSERT_TRUE(inline_memcmp(recv_ptr, str, recv_size) == 0 && "Data mismatch"); + ASSERT_TRUE(recv_size == send_size && "Data size mismatch"); + + free(send_ptr); + free(recv_ptr); +} + +TEST_MAIN(int argc, char **argv, char **envp) { + test_stream(); + + return 0; +} diff --git a/libc/test/src/__support/uint_test.cpp b/libc/test/src/__support/uint_test.cpp index fb266c25da261..77a6e6b2b39bf 100644 --- a/libc/test/src/__support/uint_test.cpp +++ b/libc/test/src/__support/uint_test.cpp @@ -533,3 +533,30 @@ TEST(LlvmLibcUIntClassTest, ConstexprInitTests) { constexpr LL_UInt128 sub = LL_UInt128(5) - LL_UInt128(4); ASSERT_EQ(sub, LL_UInt128(1)); } + +#define TEST_QUICK_DIV_UINT32_POW2(x, e) \ + do { \ + LL_UInt320 y({0x8899aabbccddeeffULL, 0x0011223344556677ULL, \ + 0x583715f4d3b29171ULL, 0xffeeddccbbaa9988ULL, \ + 0x1f2f3f4f5f6f7f8fULL}); \ + LL_UInt320 d = LL_UInt320(x); \ + d <<= e; \ + LL_UInt320 q1 = y / d; \ + LL_UInt320 r1 = y % d; \ + LL_UInt320 r2 = *y.div_uint32_times_pow_2(x, e); \ + EXPECT_EQ(q1, y); \ + EXPECT_EQ(r1, r2); \ + } while (0) + +TEST(LlvmLibcUIntClassTest, DivUInt32TimesPow2Tests) { + for (size_t i = 0; i < 320; i += 32) { + TEST_QUICK_DIV_UINT32_POW2(1, i); + TEST_QUICK_DIV_UINT32_POW2(13151719, i); + } + + TEST_QUICK_DIV_UINT32_POW2(1, 75); + TEST_QUICK_DIV_UINT32_POW2(1, 101); + + TEST_QUICK_DIV_UINT32_POW2(1000000000, 75); + TEST_QUICK_DIV_UINT32_POW2(1000000000, 101); +} diff --git a/libc/test/src/string/memory_utils/utils_test.cpp b/libc/test/src/string/memory_utils/utils_test.cpp index 3f8ce5da72aaa..37d61d84c53b6 100644 --- a/libc/test/src/string/memory_utils/utils_test.cpp +++ b/libc/test/src/string/memory_utils/utils_test.cpp @@ -144,4 +144,44 @@ TEST(LlvmLibcUtilsTest, Align2) { } } +TEST(LlvmLibcUtilsTest, LoadStoreAligned) { + const uint64_t init = 0xDEAD'C0DE'BEEF'F00D; + CPtr const src = reinterpret_cast(&init); + uint64_t store; + Ptr const dst = reinterpret_cast(&store); + + using LoadFun = uint64_t (*)(CPtr); + using StoreFun = void (*)(uint64_t, Ptr); + + { + LoadFun ld = load_aligned; + StoreFun st = store_aligned; + const uint64_t loaded = ld(src); + EXPECT_EQ(init, loaded); + store = 0; + st(init, dst); + EXPECT_EQ(init, store); + } + + { + LoadFun ld = load_aligned; + StoreFun st = store_aligned; + const uint64_t loaded = ld(src); + EXPECT_EQ(init, loaded); + store = 0; + st(init, dst); + EXPECT_EQ(init, store); + } + + { + LoadFun ld = load_aligned; + StoreFun st = store_aligned; + const uint64_t loaded = ld(src); + EXPECT_EQ(init, loaded); + store = 0; + st(init, dst); + EXPECT_EQ(init, store); + } +} + } // namespace __llvm_libc diff --git a/libc/utils/gpu/loader/Loader.h b/libc/utils/gpu/loader/Loader.h index 2f55b3ac8fc47..fcff0ec1516e2 100644 --- a/libc/utils/gpu/loader/Loader.h +++ b/libc/utils/gpu/loader/Loader.h @@ -28,9 +28,7 @@ struct begin_args_t { int argc; void *argv; void *envp; - void *inbox; - void *outbox; - void *buffer; + void *rpc_shared_buffer; }; /// The arguments to the '_start' kernel. diff --git a/libc/utils/gpu/loader/Server.h b/libc/utils/gpu/loader/Server.h index f77bf256618a4..2e9fdfd6e69b1 100644 --- a/libc/utils/gpu/loader/Server.h +++ b/libc/utils/gpu/loader/Server.h @@ -19,12 +19,11 @@ static __llvm_libc::rpc::Server server; -static __llvm_libc::cpp::Atomic - lock[__llvm_libc::rpc::default_port_count] = {0}; - /// Queries the RPC client at least once and performs server-side work if there /// are any active requests. void handle_server() { + using namespace __llvm_libc; + // Continue servicing the client until there is no work left and we return. for (;;) { auto port = server.try_open(); @@ -32,38 +31,65 @@ void handle_server() { return; switch (port->get_opcode()) { - case __llvm_libc::rpc::Opcode::PRINT_TO_STDERR: { - uint64_t str_size[__llvm_libc::rpc::MAX_LANE_SIZE] = {0}; - char *strs[__llvm_libc::rpc::MAX_LANE_SIZE] = {nullptr}; - port->recv_n([&](uint64_t size, uint32_t id) { - str_size[id] = size; - strs[id] = new char[size]; - return strs[id]; - }); - for (uint64_t i = 0; i < __llvm_libc::rpc::MAX_LANE_SIZE; ++i) { + case rpc::Opcode::PRINT_TO_STDERR: { + uint64_t sizes[rpc::MAX_LANE_SIZE] = {0}; + void *strs[rpc::MAX_LANE_SIZE] = {nullptr}; + port->recv_n(strs, sizes, [&](uint64_t size) { return new char[size]; }); + for (uint64_t i = 0; i < rpc::MAX_LANE_SIZE; ++i) { if (strs[i]) { - fwrite(strs[i], str_size[i], 1, stderr); - delete[] strs[i]; + fwrite(strs[i], sizes[i], 1, stderr); + delete[] reinterpret_cast(strs[i]); } } break; } - case __llvm_libc::rpc::Opcode::EXIT: { - port->recv([](__llvm_libc::rpc::Buffer *buffer) { + case rpc::Opcode::EXIT: { + port->recv([](rpc::Buffer *buffer) { exit(reinterpret_cast(buffer->data)[0]); }); break; } - case __llvm_libc::rpc::Opcode::TEST_INCREMENT: { - port->recv_and_send([](__llvm_libc::rpc::Buffer *buffer) { + case rpc::Opcode::TEST_INCREMENT: { + port->recv_and_send([](rpc::Buffer *buffer) { reinterpret_cast(buffer->data)[0] += 1; }); break; } + case rpc::Opcode::TEST_INTERFACE: { + uint64_t cnt = 0; + bool end_with_recv; + port->recv([&](rpc::Buffer *buffer) { end_with_recv = buffer->data[0]; }); + port->recv([&](rpc::Buffer *buffer) { cnt = buffer->data[0]; }); + port->send([&](rpc::Buffer *buffer) { buffer->data[0] = cnt = cnt + 1; }); + port->recv([&](rpc::Buffer *buffer) { cnt = buffer->data[0]; }); + port->send([&](rpc::Buffer *buffer) { buffer->data[0] = cnt = cnt + 1; }); + port->recv([&](rpc::Buffer *buffer) { cnt = buffer->data[0]; }); + port->recv([&](rpc::Buffer *buffer) { cnt = buffer->data[0]; }); + port->send([&](rpc::Buffer *buffer) { buffer->data[0] = cnt = cnt + 1; }); + port->send([&](rpc::Buffer *buffer) { buffer->data[0] = cnt = cnt + 1; }); + if (end_with_recv) + port->recv([&](rpc::Buffer *buffer) { cnt = buffer->data[0]; }); + else + port->send( + [&](rpc::Buffer *buffer) { buffer->data[0] = cnt = cnt + 1; }); + break; + } + case rpc::Opcode::TEST_STREAM: { + uint64_t sizes[rpc::MAX_LANE_SIZE] = {0}; + void *dst[rpc::MAX_LANE_SIZE] = {nullptr}; + port->recv_n(dst, sizes, [](uint64_t size) { return new char[size]; }); + port->send_n(dst, sizes); + for (uint64_t i = 0; i < rpc::MAX_LANE_SIZE; ++i) { + if (dst[i]) + delete[] reinterpret_cast(dst[i]); + } + break; + } default: - port->recv([](__llvm_libc::rpc::Buffer *buffer) {}); + port->recv([](rpc::Buffer *buffer) {}); } port->close(); } } + #endif diff --git a/libc/utils/gpu/loader/amdgpu/Loader.cpp b/libc/utils/gpu/loader/amdgpu/Loader.cpp index 07fa1ae7fe161..a98b557b877c4 100644 --- a/libc/utils/gpu/loader/amdgpu/Loader.cpp +++ b/libc/utils/gpu/loader/amdgpu/Loader.cpp @@ -221,6 +221,10 @@ hsa_status_t launch_kernel(hsa_agent_t dev_agent, hsa_executable_t executable, /*timeout_hint=*/1024, HSA_WAIT_STATE_ACTIVE) != 0) handle_server(); + // Handle the server one more time in case the kernel exited with a pending + // send still in flight. + handle_server(); + // Destroy the resources acquired to launch the kernel and return. if (hsa_status_t err = hsa_amd_memory_pool_free(args)) handle_error(err); @@ -330,37 +334,23 @@ int load(int argc, char **argv, char **envp, void *image, size_t size, hsa_amd_memory_fill(dev_ret, 0, sizeof(int)); // Allocate finegrained memory for the RPC server and client to share. - uint64_t port_size = __llvm_libc::rpc::default_port_count; + uint64_t port_size = __llvm_libc::rpc::DEFAULT_PORT_COUNT; uint32_t wavefront_size = 0; if (hsa_status_t err = hsa_agent_get_info( dev_agent, HSA_AGENT_INFO_WAVEFRONT_SIZE, &wavefront_size)) handle_error(err); - void *server_inbox; - void *server_outbox; - void *buffer; - if (hsa_status_t err = hsa_amd_memory_pool_allocate( - finegrained_pool, port_size * sizeof(__llvm_libc::cpp::Atomic), - /*flags=*/0, &server_inbox)) - handle_error(err); - if (hsa_status_t err = hsa_amd_memory_pool_allocate( - finegrained_pool, port_size * sizeof(__llvm_libc::cpp::Atomic), - /*flags=*/0, &server_outbox)) - handle_error(err); - if (hsa_status_t err = hsa_amd_memory_pool_allocate( - finegrained_pool, - port_size * - align_up(sizeof(__llvm_libc::rpc::Header) + - (wavefront_size * sizeof(__llvm_libc::rpc::Buffer)), - alignof(__llvm_libc::rpc::Packet)), - /*flags=*/0, &buffer)) - handle_error(err); - hsa_amd_agents_allow_access(1, &dev_agent, nullptr, server_inbox); - hsa_amd_agents_allow_access(1, &dev_agent, nullptr, server_outbox); - hsa_amd_agents_allow_access(1, &dev_agent, nullptr, buffer); + + uint64_t rpc_shared_buffer_size = + __llvm_libc::rpc::Server::allocation_size(port_size, wavefront_size); + void *rpc_shared_buffer; + if (hsa_status_t err = + hsa_amd_memory_pool_allocate(finegrained_pool, rpc_shared_buffer_size, + /*flags=*/0, &rpc_shared_buffer)) + handle_error(err); + hsa_amd_agents_allow_access(1, &dev_agent, nullptr, rpc_shared_buffer); // Initialize the RPC server's buffer for host-device communication. - server.reset(port_size, wavefront_size, &lock, server_inbox, server_outbox, - buffer); + server.reset(port_size, wavefront_size, rpc_shared_buffer); // Obtain a queue with the minimum (power of two) size, used to send commands // to the HSA runtime and launch execution on the device. @@ -375,8 +365,7 @@ int load(int argc, char **argv, char **envp, void *image, size_t size, handle_error(err); LaunchParameters single_threaded_params = {1, 1, 1, 1, 1, 1}; - begin_args_t init_args = {argc, dev_argv, dev_envp, - server_outbox, server_inbox, buffer}; + begin_args_t init_args = {argc, dev_argv, dev_envp, rpc_shared_buffer}; if (hsa_status_t err = launch_kernel(dev_agent, executable, kernargs_pool, queue, single_threaded_params, "_begin.kd", init_args)) @@ -423,11 +412,7 @@ int load(int argc, char **argv, char **envp, void *image, size_t size, handle_error(err); if (hsa_status_t err = hsa_amd_memory_pool_free(dev_ret)) handle_error(err); - if (hsa_status_t err = hsa_amd_memory_pool_free(server_inbox)) - handle_error(err); - if (hsa_status_t err = hsa_amd_memory_pool_free(server_outbox)) - handle_error(err); - if (hsa_status_t err = hsa_amd_memory_pool_free(buffer)) + if (hsa_status_t err = hsa_amd_memory_pool_free(rpc_shared_buffer)) handle_error(err); if (hsa_status_t err = hsa_amd_memory_pool_free(host_ret)) handle_error(err); diff --git a/libc/utils/gpu/loader/nvptx/Loader.cpp b/libc/utils/gpu/loader/nvptx/Loader.cpp index 314f5a8055fb9..7879deea65a0a 100644 --- a/libc/utils/gpu/loader/nvptx/Loader.cpp +++ b/libc/utils/gpu/loader/nvptx/Loader.cpp @@ -186,6 +186,10 @@ CUresult launch_kernel(CUmodule binary, CUstream stream, while (cuStreamQuery(stream) == CUDA_ERROR_NOT_READY) handle_server(); + // Handle the server one more time in case the kernel exited with a pending + // send still in flight. + handle_server(); + return CUDA_SUCCESS; } @@ -246,27 +250,22 @@ int load(int argc, char **argv, char **envp, void *image, size_t size, if (CUresult err = cuMemsetD32(dev_ret, 0, 1)) handle_error(err); - uint64_t port_size = __llvm_libc::rpc::default_port_count; + uint64_t port_size = __llvm_libc::rpc::DEFAULT_PORT_COUNT; uint32_t warp_size = 32; - void *server_inbox = - allocator(port_size * sizeof(__llvm_libc::cpp::Atomic)); - void *server_outbox = - allocator(port_size * sizeof(__llvm_libc::cpp::Atomic)); - void *buffer = allocator( - port_size * align_up(sizeof(__llvm_libc::rpc::Header) + - (warp_size * sizeof(__llvm_libc::rpc::Buffer)), - alignof(__llvm_libc::rpc::Packet))); - if (!server_inbox || !server_outbox || !buffer) + + uint64_t rpc_shared_buffer_size = + __llvm_libc::rpc::Server::allocation_size(port_size, warp_size); + void *rpc_shared_buffer = allocator(rpc_shared_buffer_size); + + if (!rpc_shared_buffer) handle_error("Failed to allocate memory the RPC client / server."); // Initialize the RPC server's buffer for host-device communication. - server.reset(port_size, warp_size, &lock, server_inbox, server_outbox, - buffer); + server.reset(port_size, warp_size, rpc_shared_buffer); LaunchParameters single_threaded_params = {1, 1, 1, 1, 1, 1}; // Call the kernel to - begin_args_t init_args = {argc, dev_argv, dev_envp, - server_outbox, server_inbox, buffer}; + begin_args_t init_args = {argc, dev_argv, dev_envp, rpc_shared_buffer}; if (CUresult err = launch_kernel(binary, stream, single_threaded_params, "_begin", init_args)) handle_error(err); @@ -296,11 +295,7 @@ int load(int argc, char **argv, char **envp, void *image, size_t size, handle_error(err); if (CUresult err = cuMemFreeHost(dev_argv)) handle_error(err); - if (CUresult err = cuMemFreeHost(server_inbox)) - handle_error(err); - if (CUresult err = cuMemFreeHost(server_outbox)) - handle_error(err); - if (CUresult err = cuMemFreeHost(buffer)) + if (CUresult err = cuMemFreeHost(rpc_shared_buffer)) handle_error(err); // Destroy the context and the loaded binary. diff --git a/libclc/CMakeLists.txt b/libclc/CMakeLists.txt index 63c5a566feb7b..6edd22bc719df 100644 --- a/libclc/CMakeLists.txt +++ b/libclc/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.13.4) +cmake_minimum_required(VERSION 3.20.0) add_custom_target(libspirv-builtins COMMENT "Build libspirv builtins") add_custom_target(libclc-builtins COMMENT "Build libclc builtins") @@ -363,14 +363,14 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} ) set( spvflags --spirv-max-version=1.1 ) elseif( ${ARCH} STREQUAL "clspv" ) set( t "spir--" ) - set( build_flags ) + set( build_flags "-Wno-unknown-assumption") set( opt_flags -O3 ) elseif( ${ARCH} STREQUAL "nvptx" OR ${ARCH} STREQUAL "nvptx64" ) set( build_flags ) set( opt_flags -O3 "--nvvm-reflect-enable=false" ) elseif( ${ARCH} STREQUAL "clspv64" ) set( t "spir64--" ) - set( build_flags ) + set( build_flags "-Wno-unknown-assumption") set( opt_flags -O3 ) else() set( build_flags ) diff --git a/libclc/clspv/lib/SOURCES b/libclc/clspv/lib/SOURCES index 98bc71a869b2a..7c369aa379e98 100644 --- a/libclc/clspv/lib/SOURCES +++ b/libclc/clspv/lib/SOURCES @@ -1,5 +1,6 @@ math/fma.cl math/nextafter.cl +shared/vstore_half.cl subnormal_config.cl ../../generic/lib/geometric/distance.cl ../../generic/lib/geometric/length.cl @@ -45,6 +46,12 @@ subnormal_config.cl ../../generic/lib/math/frexp.cl ../../generic/lib/math/half_cos.cl ../../generic/lib/math/half_divide.cl +../../generic/lib/math/half_exp.cl +../../generic/lib/math/half_exp10.cl +../../generic/lib/math/half_exp2.cl +../../generic/lib/math/half_log.cl +../../generic/lib/math/half_log10.cl +../../generic/lib/math/half_log2.cl ../../generic/lib/math/half_powr.cl ../../generic/lib/math/half_recip.cl ../../generic/lib/math/half_sin.cl diff --git a/libclc/clspv/lib/math/fma.cl b/libclc/clspv/lib/math/fma.cl index fdc8b8b296876..4f2806933eda9 100644 --- a/libclc/clspv/lib/math/fma.cl +++ b/libclc/clspv/lib/math/fma.cl @@ -34,6 +34,92 @@ struct fp { uint sign; }; +static uint2 u2_set(uint hi, uint lo) { + uint2 res; + res.lo = lo; + res.hi = hi; + return res; +} + +static uint2 u2_set_u(uint val) { return u2_set(0, val); } + +static uint2 u2_mul(uint a, uint b) { + uint2 res; + res.hi = mul_hi(a, b); + res.lo = a * b; + return res; +} + +static uint2 u2_sll(uint2 val, uint shift) { + if (shift == 0) + return val; + if (shift < 32) { + val.hi <<= shift; + val.hi |= val.lo >> (32 - shift); + val.lo <<= shift; + } else { + val.hi = val.lo << (shift - 32); + val.lo = 0; + } + return val; +} + +static uint2 u2_srl(uint2 val, uint shift) { + if (shift == 0) + return val; + if (shift < 32) { + val.lo >>= shift; + val.lo |= val.hi << (32 - shift); + val.hi >>= shift; + } else { + val.lo = val.hi >> (shift - 32); + val.hi = 0; + } + return val; +} + +static uint2 u2_or(uint2 a, uint b) { + a.lo |= b; + return a; +} + +static uint2 u2_and(uint2 a, uint2 b) { + a.lo &= b.lo; + a.hi &= b.hi; + return a; +} + +static uint2 u2_add(uint2 a, uint2 b) { + uint carry = (hadd(a.lo, b.lo) >> 31) & 0x1; + a.lo += b.lo; + a.hi += b.hi + carry; + return a; +} + +static uint2 u2_add_u(uint2 a, uint b) { return u2_add(a, u2_set_u(b)); } + +static uint2 u2_inv(uint2 a) { + a.lo = ~a.lo; + a.hi = ~a.hi; + return u2_add_u(a, 1); +} + +static uint u2_clz(uint2 a) { + uint leading_zeroes = clz(a.hi); + if (leading_zeroes == 32) { + leading_zeroes += clz(a.lo); + } + return leading_zeroes; +} + +static bool u2_eq(uint2 a, uint2 b) { return a.lo == b.lo && a.hi == b.hi; } + +static bool u2_zero(uint2 a) { return u2_eq(a, u2_set_u(0)); } + +static bool u2_gt(uint2 a, uint2 b) { + return a.hi > b.hi || (a.hi == b.hi && a.lo > b.lo); +} + _CLC_DEF _CLC_OVERLOAD float fma(float a, float b, float c) { /* special cases */ if (isnan(a) || isnan(b) || isnan(c) || isinf(a) || isinf(b)) { @@ -63,12 +149,9 @@ _CLC_DEF _CLC_OVERLOAD float fma(float a, float b, float c) { st_b.exponent = b == .0f ? 0 : ((as_uint(b) & 0x7f800000) >> 23) - 127; st_c.exponent = c == .0f ? 0 : ((as_uint(c) & 0x7f800000) >> 23) - 127; - st_a.mantissa.lo = a == .0f ? 0 : (as_uint(a) & 0x7fffff) | 0x800000; - st_b.mantissa.lo = b == .0f ? 0 : (as_uint(b) & 0x7fffff) | 0x800000; - st_c.mantissa.lo = c == .0f ? 0 : (as_uint(c) & 0x7fffff) | 0x800000; - st_a.mantissa.hi = 0; - st_b.mantissa.hi = 0; - st_c.mantissa.hi = 0; + st_a.mantissa = u2_set_u(a == .0f ? 0 : (as_uint(a) & 0x7fffff) | 0x800000); + st_b.mantissa = u2_set_u(b == .0f ? 0 : (as_uint(b) & 0x7fffff) | 0x800000); + st_c.mantissa = u2_set_u(c == .0f ? 0 : (as_uint(c) & 0x7fffff) | 0x800000); st_a.sign = as_uint(a) & 0x80000000; st_b.sign = as_uint(b) & 0x80000000; @@ -81,15 +164,13 @@ _CLC_DEF _CLC_OVERLOAD float fma(float a, float b, float c) { // add another bit to detect subtraction underflow struct fp st_mul; st_mul.sign = st_a.sign ^ st_b.sign; - st_mul.mantissa.hi = mul_hi(st_a.mantissa.lo, st_b.mantissa.lo); - st_mul.mantissa.lo = st_a.mantissa.lo * st_b.mantissa.lo; - uint upper_14bits = (st_mul.mantissa.lo >> 18) & 0x3fff; - st_mul.mantissa.lo <<= 14; - st_mul.mantissa.hi <<= 14; - st_mul.mantissa.hi |= upper_14bits; - st_mul.exponent = (st_mul.mantissa.lo != 0 || st_mul.mantissa.hi != 0) - ? st_a.exponent + st_b.exponent - : 0; + st_mul.mantissa = u2_sll(u2_mul(st_a.mantissa.lo, st_b.mantissa.lo), 14); + st_mul.exponent = + !u2_zero(st_mul.mantissa) ? st_a.exponent + st_b.exponent : 0; + + // FIXME: Detecting a == 0 || b == 0 above crashed GCN isel + if (st_mul.exponent == 0 && u2_zero(st_mul.mantissa)) + return c; // Mantissa is 23 fractional bits, shift it the same way as product mantissa #define C_ADJUST 37ul @@ -97,146 +178,80 @@ _CLC_DEF _CLC_OVERLOAD float fma(float a, float b, float c) { // both exponents are bias adjusted int exp_diff = st_mul.exponent - st_c.exponent; - uint abs_exp_diff = abs(exp_diff); - st_c.mantissa.hi = (st_c.mantissa.lo << 5); - st_c.mantissa.lo = 0; - uint2 cutoff_bits = (uint2)(0, 0); - uint2 cutoff_mask = (uint2)(0, 0); - if (abs_exp_diff < 32) { - cutoff_mask.lo = (1u << abs(exp_diff)) - 1u; - } else if (abs_exp_diff < 64) { - cutoff_mask.lo = 0xffffffff; - uint remaining = abs_exp_diff - 32; - cutoff_mask.hi = (1u << remaining) - 1u; + st_c.mantissa = u2_sll(st_c.mantissa, C_ADJUST); + uint2 cutoff_bits = u2_set_u(0); + uint2 cutoff_mask = u2_add(u2_sll(u2_set_u(1), abs(exp_diff)), + u2_set(0xffffffff, 0xffffffff)); + if (exp_diff > 0) { + cutoff_bits = + exp_diff >= 64 ? st_c.mantissa : u2_and(st_c.mantissa, cutoff_mask); + st_c.mantissa = + exp_diff >= 64 ? u2_set_u(0) : u2_srl(st_c.mantissa, exp_diff); } else { - cutoff_mask = (uint2)(0, 0); - } - uint2 tmp = (exp_diff > 0) ? st_c.mantissa : st_mul.mantissa; - if (abs_exp_diff > 0) { - cutoff_bits = abs_exp_diff >= 64 ? tmp : (tmp & cutoff_mask); - if (abs_exp_diff < 32) { - // shift some of the hi bits into the shifted lo bits. - uint shift_mask = (1u << abs_exp_diff) - 1; - uint upper_saved_bits = tmp.hi & shift_mask; - upper_saved_bits = upper_saved_bits << (32 - abs_exp_diff); - tmp.hi >>= abs_exp_diff; - tmp.lo >>= abs_exp_diff; - tmp.lo |= upper_saved_bits; - } else if (abs_exp_diff < 64) { - tmp.lo = (tmp.hi >> (abs_exp_diff - 32)); - tmp.hi = 0; - } else { - tmp = (uint2)(0, 0); - } + cutoff_bits = -exp_diff >= 64 ? st_mul.mantissa + : u2_and(st_mul.mantissa, cutoff_mask); + st_mul.mantissa = + -exp_diff >= 64 ? u2_set_u(0) : u2_srl(st_mul.mantissa, -exp_diff); } - if (exp_diff > 0) - st_c.mantissa = tmp; - else - st_mul.mantissa = tmp; struct fp st_fma; st_fma.sign = st_mul.sign; st_fma.exponent = max(st_mul.exponent, st_c.exponent); - st_fma.mantissa = (uint2)(0, 0); if (st_c.sign == st_mul.sign) { - uint carry = (hadd(st_mul.mantissa.lo, st_c.mantissa.lo) >> 31) & 0x1; - st_fma.mantissa = st_mul.mantissa + st_c.mantissa; - st_fma.mantissa.hi += carry; + st_fma.mantissa = u2_add(st_mul.mantissa, st_c.mantissa); } else { // cutoff bits borrow one - uint cutoff_borrow = ((cutoff_bits.lo != 0 || cutoff_bits.hi != 0) && - (st_mul.exponent > st_c.exponent)) - ? 1 - : 0; - uint borrow = 0; - if (st_c.mantissa.lo > st_mul.mantissa.lo) { - borrow = 1; - } else if (st_c.mantissa.lo == UINT_MAX && cutoff_borrow == 1) { - borrow = 1; - } else if ((st_c.mantissa.lo + cutoff_borrow) > st_mul.mantissa.lo) { - borrow = 1; - } - - st_fma.mantissa.lo = st_mul.mantissa.lo - st_c.mantissa.lo - cutoff_borrow; - st_fma.mantissa.hi = st_mul.mantissa.hi - st_c.mantissa.hi - borrow; + st_fma.mantissa = + u2_add(u2_add(st_mul.mantissa, u2_inv(st_c.mantissa)), + (!u2_zero(cutoff_bits) && (st_mul.exponent > st_c.exponent) + ? u2_set(0xffffffff, 0xffffffff) + : u2_set_u(0))); } // underflow: st_c.sign != st_mul.sign, and magnitude switches the sign - if (st_fma.mantissa.hi > INT_MAX) { - st_fma.mantissa = ~st_fma.mantissa; - uint carry = (hadd(st_fma.mantissa.lo, 1u) >> 31) & 0x1; - st_fma.mantissa.lo += 1; - st_fma.mantissa.hi += carry; - + if (u2_gt(st_fma.mantissa, u2_set(0x7fffffff, 0xffffffff))) { + st_fma.mantissa = u2_inv(st_fma.mantissa); st_fma.sign = st_mul.sign ^ 0x80000000; } // detect overflow/underflow - uint leading_zeroes = clz(st_fma.mantissa.hi); - if (leading_zeroes == 32) { - leading_zeroes += clz(st_fma.mantissa.lo); - } - int overflow_bits = 3 - leading_zeroes; + int overflow_bits = 3 - u2_clz(st_fma.mantissa); // adjust exponent st_fma.exponent += overflow_bits; // handle underflow if (overflow_bits < 0) { - uint shift = -overflow_bits; - if (shift < 32) { - uint shift_mask = (1u << shift) - 1; - uint saved_lo_bits = (st_fma.mantissa.lo >> (32 - shift)) & shift_mask; - st_fma.mantissa.lo <<= shift; - st_fma.mantissa.hi <<= shift; - st_fma.mantissa.hi |= saved_lo_bits; - } else if (shift < 64) { - st_fma.mantissa.hi = (st_fma.mantissa.lo << (64 - shift)); - st_fma.mantissa.lo = 0; - } else { - st_fma.mantissa = (uint2)(0, 0); - } - + st_fma.mantissa = u2_sll(st_fma.mantissa, -overflow_bits); overflow_bits = 0; } // rounding - // overflow_bits is now in the range of [0, 3] making the shift greater than - // 32 bits. - uint2 trunc_mask; - uint trunc_shift = C_ADJUST + overflow_bits - 32; - trunc_mask.hi = (1u << trunc_shift) - 1; - trunc_mask.lo = UINT_MAX; - uint2 trunc_bits = st_fma.mantissa & trunc_mask; - trunc_bits.lo |= (cutoff_bits.hi != 0 || cutoff_bits.lo != 0) ? 1 : 0; - uint2 last_bit; - last_bit.lo = 0; - last_bit.hi = st_fma.mantissa.hi & (1u << trunc_shift); - uint grs_shift = C_ADJUST - 3 + overflow_bits - 32; - uint2 grs_bits; - grs_bits.lo = 0; - grs_bits.hi = 0x4u << grs_shift; + uint2 trunc_mask = u2_add(u2_sll(u2_set_u(1), C_ADJUST + overflow_bits), + u2_set(0xffffffff, 0xffffffff)); + uint2 trunc_bits = + u2_or(u2_and(st_fma.mantissa, trunc_mask), !u2_zero(cutoff_bits)); + uint2 last_bit = + u2_and(st_fma.mantissa, u2_sll(u2_set_u(1), C_ADJUST + overflow_bits)); + uint2 grs_bits = u2_sll(u2_set_u(4), C_ADJUST - 3 + overflow_bits); // round to nearest even - if ((trunc_bits.hi > grs_bits.hi || - (trunc_bits.hi == grs_bits.hi && trunc_bits.lo > grs_bits.lo)) || - (trunc_bits.hi == grs_bits.hi && trunc_bits.lo == grs_bits.lo && - last_bit.hi != 0)) { - uint shift = C_ADJUST + overflow_bits - 32; - st_fma.mantissa.hi += 1u << shift; + if (u2_gt(trunc_bits, grs_bits) || + (u2_eq(trunc_bits, grs_bits) && !u2_zero(last_bit))) { + st_fma.mantissa = + u2_add(st_fma.mantissa, u2_sll(u2_set_u(1), C_ADJUST + overflow_bits)); } - // Shift mantissa back to bit 23 - st_fma.mantissa.lo = (st_fma.mantissa.hi >> (C_ADJUST + overflow_bits - 32)); - st_fma.mantissa.hi = 0; + // Shift mantissa back to bit 23 + st_fma.mantissa = u2_srl(st_fma.mantissa, C_ADJUST + overflow_bits); // Detect rounding overflow - if (st_fma.mantissa.lo > 0xffffff) { + if (u2_gt(st_fma.mantissa, u2_set_u(0xffffff))) { ++st_fma.exponent; - st_fma.mantissa.lo >>= 1; + st_fma.mantissa = u2_srl(st_fma.mantissa, 1); } - if (st_fma.mantissa.lo == 0) { + if (u2_zero(st_fma.mantissa)) { return 0.0f; } diff --git a/libclc/clspv/lib/shared/vstore_half.cl b/libclc/clspv/lib/shared/vstore_half.cl new file mode 100644 index 0000000000000..b05fcfe75fb7a --- /dev/null +++ b/libclc/clspv/lib/shared/vstore_half.cl @@ -0,0 +1,135 @@ +#include + +#pragma OPENCL EXTENSION cl_khr_byte_addressable_store : enable + +#define ROUND_VEC1(out, in, ROUNDF) out = ROUNDF(in); +#define ROUND_VEC2(out, in, ROUNDF) \ + ROUND_VEC1(out.lo, in.lo, ROUNDF); \ + ROUND_VEC1(out.hi, in.hi, ROUNDF); +#define ROUND_VEC3(out, in, ROUNDF) \ + ROUND_VEC1(out.s0, in.s0, ROUNDF); \ + ROUND_VEC1(out.s1, in.s1, ROUNDF); \ + ROUND_VEC1(out.s2, in.s2, ROUNDF); +#define ROUND_VEC4(out, in, ROUNDF) \ + ROUND_VEC2(out.lo, in.lo, ROUNDF); \ + ROUND_VEC2(out.hi, in.hi, ROUNDF); +#define ROUND_VEC8(out, in, ROUNDF) \ + ROUND_VEC4(out.lo, in.lo, ROUNDF); \ + ROUND_VEC4(out.hi, in.hi, ROUNDF); +#define ROUND_VEC16(out, in, ROUNDF) \ + ROUND_VEC8(out.lo, in.lo, ROUNDF); \ + ROUND_VEC8(out.hi, in.hi, ROUNDF); + +#define __FUNC(SUFFIX, VEC_SIZE, TYPE, AS, ROUNDF) \ + void _CLC_OVERLOAD vstore_half_##VEC_SIZE(TYPE, size_t, AS half *); \ + _CLC_OVERLOAD _CLC_DEF void vstore_half##SUFFIX(TYPE vec, size_t offset, \ + AS half *mem) { \ + TYPE rounded_vec; \ + ROUND_VEC##VEC_SIZE(rounded_vec, vec, ROUNDF); \ + vstore_half_##VEC_SIZE(rounded_vec, offset, mem); \ + } \ + void _CLC_OVERLOAD vstorea_half_##VEC_SIZE(TYPE, size_t, AS half *); \ + _CLC_OVERLOAD _CLC_DEF void vstorea_half##SUFFIX(TYPE vec, size_t offset, \ + AS half *mem) { \ + TYPE rounded_vec; \ + ROUND_VEC##VEC_SIZE(rounded_vec, vec, ROUNDF); \ + vstorea_half_##VEC_SIZE(rounded_vec, offset, mem); \ + } + +_CLC_DEF _CLC_OVERLOAD float __clc_rtz(float x) { + /* Handle nan corner case */ + if (isnan(x)) + return x; + /* RTZ does not produce Inf for large numbers */ + if (fabs(x) > 65504.0f && !isinf(x)) + return copysign(65504.0f, x); + + const int exp = (as_uint(x) >> 23 & 0xff) - 127; + /* Manage range rounded to +- zero explicitely */ + if (exp < -24) + return copysign(0.0f, x); + + /* Remove lower 13 bits to make sure the number is rounded down */ + int mask = 0xffffe000; + /* Denormals cannot be flushed, and they use different bit for rounding */ + if (exp < -14) + mask <<= min(-(exp + 14), 10); + + return as_float(as_uint(x) & mask); +} + +_CLC_DEF _CLC_OVERLOAD float __clc_rti(float x) { + /* Handle nan corner case */ + if (isnan(x)) + return x; + + const float inf = copysign(INFINITY, x); + uint ux = as_uint(x); + + /* Manage +- infinity explicitely */ + if (as_float(ux & 0x7fffffff) > 0x1.ffcp+15f) { + return inf; + } + /* Manage +- zero explicitely */ + if ((ux & 0x7fffffff) == 0) { + return copysign(0.0f, x); + } + + const int exp = (as_uint(x) >> 23 & 0xff) - 127; + /* Manage range rounded to smallest half denormal explicitely */ + if (exp < -24) { + return copysign(0x1.0p-24f, x); + } + + /* Set lower 13 bits */ + int mask = (1 << 13) - 1; + /* Denormals cannot be flushed, and they use different bit for rounding */ + if (exp < -14) { + mask = (1 << (13 + min(-(exp + 14), 10))) - 1; + } + + const float next = nextafter(as_float(ux | mask), inf); + return ((ux & mask) == 0) ? as_float(ux) : next; +} +_CLC_DEF _CLC_OVERLOAD float __clc_rtn(float x) { + return ((as_uint(x) & 0x80000000) == 0) ? __clc_rtz(x) : __clc_rti(x); +} +_CLC_DEF _CLC_OVERLOAD float __clc_rtp(float x) { + return ((as_uint(x) & 0x80000000) == 0) ? __clc_rti(x) : __clc_rtz(x); +} +_CLC_DEF _CLC_OVERLOAD float __clc_rte(float x) { + /* Mantisa + implicit bit */ + const uint mantissa = (as_uint(x) & 0x7fffff) | (1u << 23); + const int exp = (as_uint(x) >> 23 & 0xff) - 127; + int shift = 13; + if (exp < -14) { + /* The default assumes lower 13 bits are rounded, + * but it might be more for denormals. + * Shifting beyond last == 0b, and qr == 00b is not necessary */ + shift += min(-(exp + 14), 15); + } + int mask = (1 << shift) - 1; + const uint grs = mantissa & mask; + const uint last = mantissa & (1 << shift); + /* IEEE round up rule is: grs > 101b or grs == 100b and last == 1. + * exp > 15 should round to inf. */ + bool roundup = (grs > (1 << (shift - 1))) || + (grs == (1 << (shift - 1)) && last != 0) || (exp > 15); + return roundup ? __clc_rti(x) : __clc_rtz(x); +} + +#define __XFUNC(SUFFIX, VEC_SIZE, TYPE, AS) \ + __FUNC(SUFFIX, VEC_SIZE, TYPE, AS, __clc_rte) \ + __FUNC(SUFFIX##_rtz, VEC_SIZE, TYPE, AS, __clc_rtz) \ + __FUNC(SUFFIX##_rtn, VEC_SIZE, TYPE, AS, __clc_rtn) \ + __FUNC(SUFFIX##_rtp, VEC_SIZE, TYPE, AS, __clc_rtp) \ + __FUNC(SUFFIX##_rte, VEC_SIZE, TYPE, AS, __clc_rte) + +#define FUNC(SUFFIX, VEC_SIZE, TYPE, AS) __XFUNC(SUFFIX, VEC_SIZE, TYPE, AS) + +#define __CLC_BODY "vstore_half.inc" +#include +#undef __CLC_BODY +#undef FUNC +#undef __XFUNC +#undef __FUNC diff --git a/libclc/clspv/lib/shared/vstore_half.inc b/libclc/clspv/lib/shared/vstore_half.inc new file mode 100644 index 0000000000000..83704cca3a010 --- /dev/null +++ b/libclc/clspv/lib/shared/vstore_half.inc @@ -0,0 +1,15 @@ +// This does exist only for fp32 +#if __CLC_FPSIZE == 32 +#ifdef __CLC_VECSIZE + +FUNC(__CLC_VECSIZE, __CLC_VECSIZE, __CLC_GENTYPE, __private); +FUNC(__CLC_VECSIZE, __CLC_VECSIZE, __CLC_GENTYPE, __local); +FUNC(__CLC_VECSIZE, __CLC_VECSIZE, __CLC_GENTYPE, __global); + +#undef __CLC_OFFSET +#else +FUNC(, 1, __CLC_GENTYPE, __private); +FUNC(, 1, __CLC_GENTYPE, __local); +FUNC(, 1, __CLC_GENTYPE, __global); +#endif +#endif diff --git a/libclc/generic/include/func.h b/libclc/generic/include/func.h index 27532c35f1e8f..91a196c8d6334 100644 --- a/libclc/generic/include/func.h +++ b/libclc/generic/include/func.h @@ -5,9 +5,11 @@ #define _CLC_DECL // avoid inlines for SPIR-V related targets since we'll optimise later in the // chain -#if defined(CLC_SPIRV) || defined(CLC_SPIRV64) || defined(CLC_CLSPV) || \ - defined(CLC_CLSPV64) +#if defined(CLC_SPIRV) || defined(CLC_SPIRV64) #define _CLC_DEF +#elif defined(CLC_CLSPV) || defined(CLC_CLSPV64) +#define _CLC_DEF \ + __attribute__((noinline)) __attribute__((assume("clspv_libclc_builtin"))) #else #define _CLC_DEF __attribute__((always_inline)) #endif diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt index 40c5a9c0a0a68..a003d1e98048c 100644 --- a/libcxx/CMakeLists.txt +++ b/libcxx/CMakeLists.txt @@ -4,7 +4,7 @@ #=============================================================================== # Setup Project #=============================================================================== -cmake_minimum_required(VERSION 3.13.4) +cmake_minimum_required(VERSION 3.20.0) set(LLVM_COMMON_CMAKE_UTILS "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") diff --git a/libcxx/docs/Contributing.rst b/libcxx/docs/Contributing.rst index 90b5c8b09b815..66585cd5daec2 100644 --- a/libcxx/docs/Contributing.rst +++ b/libcxx/docs/Contributing.rst @@ -61,18 +61,6 @@ rule -- for very simple patches, use your judgement. The `"libc++" review group consists of frequent libc++ contributors with a good understanding of the project's guidelines -- if you would like to be added to it, please reach out on Discord. -Post-release check list -======================= - -After branching for an LLVM release: - -1. Update ``_LIBCPP_VERSION`` in ``libcxx/include/__config`` -2. Update the version number in ``libcxx/docs/conf.py`` -3. Update ``_LIBCPPABI_VERSION`` in ``libcxxabi/include/cxxabi.h`` -4. Update ``_LIBUNWIND_VERSION`` in ``libunwind/include/__libunwind_config.h`` -5. Update the list of supported clang versions in ``libcxx/docs/index.rst`` -6. Remove the in-progress warning from ``libcxx/docs/ReleaseNotes.rst`` - Exporting new symbols from the library ====================================== @@ -218,3 +206,16 @@ Contains the jobs executed in the CI. This file contains the version information of the jobs being executed. Since this script differs between the ``main`` and ``release`` branch, both branches can use different compiler versions. + +Post-release check list +======================= + +Here's a list of tasks to do after branching for an LLVM release. This +is only meant for the review manager, not for individual contributors. + +1. Update ``_LIBCPP_VERSION`` in ``libcxx/include/__config`` +2. Update the version number in ``libcxx/docs/conf.py`` +3. Update ``_LIBCPPABI_VERSION`` in ``libcxxabi/include/cxxabi.h`` +4. Update ``_LIBUNWIND_VERSION`` in ``libunwind/include/__libunwind_config.h`` +5. Update the list of supported clang versions in ``libcxx/docs/index.rst`` +6. Remove the in-progress warning from ``libcxx/docs/ReleaseNotes.rst`` diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst index 952aa3bee4f51..16143c1c2edf7 100644 --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -53,6 +53,9 @@ Improvements and New Features - The performance of ``dynamic_cast`` on its hot paths is greatly improved and is as efficient as the ``libsupc++`` implementation. Note that the performance improvements are shipped in ``libcxxabi``. +- `D122780 `_ Improved the performance of ``std::sort`` and ``std::ranges::sort`` + by up to 50% for arithmetic types and by approximately 10% for other types. + Deprecations and Removals ------------------------- diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv index c5b99c113d886..a310cfc5ff161 100644 --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -41,7 +41,7 @@ "`P0323R12 `__","LWG","``std::expected``","February 2022","|Complete|","16.0" "`P0533R9 `__","LWG","``constexpr`` for ```` and ````","February 2022","|In progress| [#note-P0533R9]_","" "`P0627R6 `__","LWG","Function to mark unreachable code","February 2022","|Complete|","15.0" -"`P1206R7 `__","LWG","``ranges::to``: A function to convert any range to a container","February 2022","","","|ranges|" +"`P1206R7 `__","LWG","``ranges::to``: A function to convert any range to a container","February 2022","|In Progress|","","|ranges|" "`P1413R3 `__","LWG","Deprecate ``std::aligned_storage`` and ``std::aligned_union``","February 2022","|Complete| [#note-P1413R3]_","" "`P2255R2 `__","LWG","A type trait to detect reference binding to temporary","February 2022","","" "`P2273R3 `__","LWG","Making ``std::unique_ptr`` constexpr","February 2022","|Complete|","16.0" diff --git a/libcxx/docs/TestingLibcxx.rst b/libcxx/docs/TestingLibcxx.rst index 259672c261c2c..3d37c990ac1ad 100644 --- a/libcxx/docs/TestingLibcxx.rst +++ b/libcxx/docs/TestingLibcxx.rst @@ -39,7 +39,7 @@ whether the required libraries have been built, you can use the $ /bin/llvm-lit -sv libcxx/test/std/depr/depr.c.headers/stdlib_h.pass.cpp # Run a single test $ /bin/llvm-lit -sv libcxx/test/std/atomics libcxx/test/std/threads # Test std::thread and std::atomic -If you used **ninja** as your build system then running ``ninja check-cxx`` will run +If you used **ninja** as your build system, running ``ninja -C check-cxx`` will run all the tests in the libc++ testsuite. .. note:: diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index f42c82c3ab146..3e210323e51d3 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -70,9 +70,20 @@ set(files __algorithm/pop_heap.h __algorithm/prev_permutation.h __algorithm/pstl_any_all_none_of.h + __algorithm/pstl_backend.h + __algorithm/pstl_backends/cpu_backend.h + __algorithm/pstl_backends/cpu_backends/any_of.h + __algorithm/pstl_backends/cpu_backends/backend.h + __algorithm/pstl_backends/cpu_backends/fill.h + __algorithm/pstl_backends/cpu_backends/find_if.h + __algorithm/pstl_backends/cpu_backends/for_each.h + __algorithm/pstl_backends/cpu_backends/serial.h + __algorithm/pstl_backends/cpu_backends/transform.h __algorithm/pstl_fill.h __algorithm/pstl_find.h __algorithm/pstl_for_each.h + __algorithm/pstl_frontend_dispatch.h + __algorithm/pstl_transform.h __algorithm/push_heap.h __algorithm/ranges_adjacent_find.h __algorithm/ranges_all_of.h @@ -155,6 +166,7 @@ set(files __algorithm/ranges_sort_heap.h __algorithm/ranges_stable_partition.h __algorithm/ranges_stable_sort.h + __algorithm/ranges_starts_with.h __algorithm/ranges_swap_ranges.h __algorithm/ranges_transform.h __algorithm/ranges_unique.h @@ -386,7 +398,6 @@ set(files __functional/reference_wrapper.h __functional/unary_function.h __functional/unary_negate.h - __functional/unwrap_ref.h __functional/weak_result_type.h __fwd/array.h __fwd/fstream.h @@ -532,8 +543,6 @@ set(files __pstl/internal/parallel_backend_serial.h __pstl/internal/parallel_backend_tbb.h __pstl/internal/parallel_backend_utils.h - __pstl/internal/parallel_impl.h - __pstl/internal/pstl_config.h __pstl/internal/unseq_backend_simd.h __pstl/internal/utils.h __pstl_algorithm @@ -581,6 +590,7 @@ set(files __ranges/as_rvalue_view.h __ranges/common_view.h __ranges/concepts.h + __ranges/container_compatible_range.h __ranges/copyable_box.h __ranges/counted.h __ranges/dangling.h @@ -593,6 +603,7 @@ set(files __ranges/enable_borrowed_range.h __ranges/enable_view.h __ranges/filter_view.h + __ranges/from_range.h __ranges/iota_view.h __ranges/istream_view.h __ranges/join_view.h @@ -783,6 +794,7 @@ set(files __type_traits/type_identity.h __type_traits/type_list.h __type_traits/underlying_type.h + __type_traits/unwrap_ref.h __type_traits/void_t.h __undef_macros __utility/as_const.h diff --git a/libcxx/include/__algorithm/pstl_any_all_none_of.h b/libcxx/include/__algorithm/pstl_any_all_none_of.h index 49bae753a4bf4..374d9af17cc0b 100644 --- a/libcxx/include/__algorithm/pstl_any_all_none_of.h +++ b/libcxx/include/__algorithm/pstl_any_all_none_of.h @@ -9,11 +9,10 @@ #ifndef _LIBCPP___ALGORITHM_PSTL_ANY_ALL_NONE_OF_H #define _LIBCPP___ALGORITHM_PSTL_ANY_ALL_NONE_OF_H -#include <__algorithm/any_of.h> +#include <__algorithm/pstl_find.h> +#include <__algorithm/pstl_frontend_dispatch.h> #include <__config> #include <__iterator/iterator_traits.h> -#include <__pstl/internal/parallel_impl.h> -#include <__pstl/internal/unseq_backend_simd.h> #include <__type_traits/enable_if.h> #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> @@ -27,50 +26,66 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +void __pstl_any_of(); // declaration needed for the frontend dispatch below + template >, int> = 0> + class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, + enable_if_t, int> = 0> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool any_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { - if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && - __is_cpp17_random_access_iterator<_ForwardIterator>::value) { - return std::__terminate_on_exception([&] { - return __pstl::__internal::__parallel_or( - __pstl::__internal::__par_backend_tag{}, - __policy, - __first, - __last, - [&__policy, &__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - return std::any_of(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __pred); - }); - }); - } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && - __is_cpp17_random_access_iterator<_ForwardIterator>::value) { - return __pstl::__unseq_backend::__simd_or(__first, __last - __first, __pred); - } else { - return std::any_of(__first, __last, __pred); - } + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_any_of), + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) { + return std::find_if(__policy, __g_first, __g_last, __g_pred) != __g_last; + }, + std::move(__first), + std::move(__last), + std::move(__pred)); } +template +void __pstl_all_of(); // declaration needed for the frontend dispatch below + template >, int> = 0> + class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, + enable_if_t, int> = 0> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool all_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) { - return !std::any_of(__policy, __first, __last, [&](__iter_reference<_ForwardIterator> __value) { - return !__pred(__value); - }); + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_all_of), + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) { + return !std::any_of(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __value) { + return !__g_pred(__value); + }); + }, + std::move(__first), + std::move(__last), + std::move(__pred)); } +template +void __pstl_none_of(); // declaration needed for the frontend dispatch below + template >, int> = 0> + class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, + enable_if_t, int> = 0> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool none_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) { - return !std::any_of(__policy, __first, __last, __pred); + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_none_of), + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) { + return !std::any_of(__policy, __g_first, __g_last, __g_pred); + }, + std::move(__first), + std::move(__last), + std::move(__pred)); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/pstl_backend.h b/libcxx/include/__algorithm/pstl_backend.h new file mode 100644 index 0000000000000..9ac8002a3d271 --- /dev/null +++ b/libcxx/include/__algorithm/pstl_backend.h @@ -0,0 +1,110 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PSTL_BACKEND_H +#define _LIBCPP___ALGORITHM_PSTL_BACKEND_H + +#include <__algorithm/pstl_backends/cpu_backend.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +/* +TODO: Documentation of how backends work + +A PSTL parallel backend is a tag type to which the following functions are associated, at minimum: + + template + void __pstl_for_each(_Backend, _ExecutionPolicy&&, _Iterator __first, _Iterator __last, _Func __f); + + template + _Iterator __pstl_find_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); + + template + _OutIterator __pstl_transform(_InIterator __first, _InIterator __last, _OutIterator __result, _UnaryOperation __op); + + template + _OutIterator __pstl_transform(_InIterator1 __first1, + _InIterator1 __last1, + _InIterator2 __first2, + _OutIterator __result, + _BinaryOperation __op); + +// TODO: Complete this list + +The following functions are optional but can be provided. If provided, they are used by the corresponding +algorithms, otherwise they are implemented in terms of other algorithms. If none of the optional algorithms are +implemented, all the algorithms will eventually forward to the basis algorithms listed above: + + template + void __pstl_for_each_n(_Backend, _ExecutionPolicy&&, _Iterator __first, _Size __n, _Func __f); + + template + bool __pstl_any_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); + + template + bool __pstl_all_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); + + template + bool __pstl_none_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); + + template + void __pstl_fill(_Iterator __first, _Iterator __last, const _Tp& __value); + + template + void __pstl_fill_n(_Iterator __first, _SizeT __n, const _Tp& __value); + +// TODO: Complete this list + +*/ + +template +struct __select_backend; + +template <> +struct __select_backend { + using type = __cpu_backend_tag; +}; + +# if _LIBCPP_STD_VER >= 20 +template <> +struct __select_backend { + using type = __cpu_backend_tag; +}; +# endif + +# if defined(_PSTL_CPU_BACKEND_SERIAL) +template <> +struct __select_backend { + using type = __cpu_backend_tag; +}; + +template <> +struct __select_backend { + using type = __cpu_backend_tag; +}; + +# else + +// ...New vendors can add parallel backends here... + +# error "Invalid choice of a PSTL parallel backend" +# endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___ALGORITHM_PSTL_BACKEND_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backend.h b/libcxx/include/__algorithm/pstl_backends/cpu_backend.h new file mode 100644 index 0000000000000..a15e7f8f1acd2 --- /dev/null +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backend.h @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_H +#define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_H + +#include <__config> + +/* + + // _Functor takes a subrange for [__first, __last) that should be executed in serial + template + void __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func); + + // Cancel the execution of other jobs - they aren't needed anymore + void __cancel_execution(); + + TODO: Document the parallel backend +*/ + +#include <__algorithm/pstl_backends/cpu_backends/any_of.h> +#include <__algorithm/pstl_backends/cpu_backends/fill.h> +#include <__algorithm/pstl_backends/cpu_backends/find_if.h> +#include <__algorithm/pstl_backends/cpu_backends/for_each.h> +#include <__algorithm/pstl_backends/cpu_backends/transform.h> + +#endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h new file mode 100644 index 0000000000000..661ea2df6ad72 --- /dev/null +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h @@ -0,0 +1,90 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_ANY_OF_H +#define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_ANY_OF_H + +#include <__algorithm/any_of.h> +#include <__algorithm/find_if.h> +#include <__algorithm/pstl_backends/cpu_backends/backend.h> +#include <__atomic/atomic.h> +#include <__atomic/memory_order.h> +#include <__config> +#include <__functional/operations.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_execution_policy.h> +#include <__utility/pair.h> +#include <__utility/terminate_on_exception.h> +#include + +#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI bool __parallel_or(_Index __first, _Index __last, _Brick __f) { + std::atomic __found(false); + __par_backend::__parallel_for(__first, __last, [__f, &__found](_Index __i, _Index __j) { + if (!__found.load(std::memory_order_relaxed) && __f(__i, __j)) { + __found.store(true, std::memory_order_relaxed); + __par_backend::__cancel_execution(); + } + }); + return __found; +} + +// TODO: check whether __simd_first() can be used here +template +_LIBCPP_HIDE_FROM_ABI bool __simd_or(_Index __first, _DifferenceType __n, _Pred __pred) noexcept { + _DifferenceType __block_size = 4 < __n ? 4 : __n; + const _Index __last = __first + __n; + while (__last != __first) { + int32_t __flag = 1; + _PSTL_PRAGMA_SIMD_REDUCTION(& : __flag) + for (_DifferenceType __i = 0; __i < __block_size; ++__i) + if (__pred(*(__first + __i))) + __flag = 0; + if (!__flag) + return true; + + __first += __block_size; + if (__last - __first >= __block_size << 1) { + // Double the block _Size. Any unnecessary iterations can be amortized against work done so far. + __block_size <<= 1; + } else { + __block_size = __last - __first; + } + } + return false; +} + +template +_LIBCPP_HIDE_FROM_ABI bool +__pstl_any_of(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && + __is_cpp17_random_access_iterator<_ForwardIterator>::value) { + return std::__terminate_on_exception([&] { + return std::__parallel_or( + __first, __last, [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + return std::__pstl_any_of<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __pred); + }); + }); + } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && + __is_cpp17_random_access_iterator<_ForwardIterator>::value) { + return std::__simd_or(__first, __last - __first, __pred); + } else { + return std::any_of(__first, __last, __pred); + } +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_ANY_OF_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/backend.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/backend.h new file mode 100644 index 0000000000000..d6b03d282bd3e --- /dev/null +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/backend.h @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_BACKEND_H +#define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_BACKEND_H + +#include <__config> + +#if defined(_LIBCPP_HAS_NO_THREADS) || defined(_PSTL_CPU_BACKEND_SERIAL) +# include <__algorithm/pstl_backends/cpu_backends/serial.h> +#else +# error "Invalid CPU backend choice" +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +struct __cpu_backend_tag {}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_BACKEND_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h new file mode 100644 index 0000000000000..7163c33d64359 --- /dev/null +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_FILL_H +#define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_FILL_H + +#include <__algorithm/fill.h> +#include <__algorithm/pstl_backends/cpu_backends/backend.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_execution_policy.h> +#include <__utility/terminate_on_exception.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _Index __simd_fill_n(_Index __first, _DifferenceType __n, const _Tp& __value) noexcept { + _PSTL_USE_NONTEMPORAL_STORES_IF_ALLOWED + _PSTL_PRAGMA_SIMD + for (_DifferenceType __i = 0; __i < __n; ++__i) + __first[__i] = __value; + return __first + __n; +} + +template +_LIBCPP_HIDE_FROM_ABI void +__pstl_fill(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && + __is_cpp17_random_access_iterator<_ForwardIterator>::value) { + std::__terminate_on_exception([&] { + __par_backend::__parallel_for( + __first, __last, [&__value](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + std::__pstl_fill<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __value); + }); + }); + } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && + __is_cpp17_random_access_iterator<_ForwardIterator>::value) { + std::__simd_fill_n(__first, __last - __first, __value); + } else { + std::fill(__first, __last, __value); + } +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_FILL_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h new file mode 100644 index 0000000000000..bfab9b54a8a46 --- /dev/null +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h @@ -0,0 +1,125 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_FIND_IF_H +#define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_FIND_IF_H + +#include <__algorithm/find_if.h> +#include <__algorithm/pstl_backends/cpu_backends/backend.h> +#include <__atomic/atomic.h> +#include <__config> +#include <__functional/operations.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_execution_policy.h> +#include <__utility/pair.h> +#include <__utility/terminate_on_exception.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _Index +__parallel_find(_Index __first, _Index __last, _Brick __f, _Compare __comp, bool __b_first) { + typedef typename std::iterator_traits<_Index>::difference_type _DifferenceType; + const _DifferenceType __n = __last - __first; + _DifferenceType __initial_dist = __b_first ? __n : -1; + std::atomic<_DifferenceType> __extremum(__initial_dist); + // TODO: find out what is better here: parallel_for or parallel_reduce + __par_backend::__parallel_for(__first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) { + // See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of + // why using a shared variable scales fairly well in this situation. + if (__comp(__i - __first, __extremum)) { + _Index __res = __f(__i, __j); + // If not '__last' returned then we found what we want so put this to extremum + if (__res != __j) { + const _DifferenceType __k = __res - __first; + for (_DifferenceType __old = __extremum; __comp(__k, __old); __old = __extremum) { + __extremum.compare_exchange_weak(__old, __k); + } + } + } + }); + return __extremum != __initial_dist ? __first + __extremum : __last; +} + +const std::size_t __lane_size = 64; + +template +_LIBCPP_HIDE_FROM_ABI _Index +__simd_first(_Index __first, _DifferenceType __begin, _DifferenceType __end, _Compare __comp) noexcept { + // Experiments show good block sizes like this + const _DifferenceType __block_size = 8; + alignas(__lane_size) _DifferenceType __lane[__block_size] = {0}; + while (__end - __begin >= __block_size) { + _DifferenceType __found = 0; + _PSTL_PRAGMA_SIMD_REDUCTION(| : __found) for (_DifferenceType __i = __begin; __i < __begin + __block_size; ++__i) { + const _DifferenceType __t = __comp(__first, __i); + __lane[__i - __begin] = __t; + __found |= __t; + } + if (__found) { + _DifferenceType __i; + // This will vectorize + for (__i = 0; __i < __block_size; ++__i) { + if (__lane[__i]) { + break; + } + } + return __first + __begin + __i; + } + __begin += __block_size; + } + + // Keep remainder scalar + while (__begin != __end) { + if (__comp(__first, __begin)) { + return __first + __begin; + } + ++__begin; + } + return __first + __end; +} + +template +_LIBCPP_HIDE_FROM_ABI _ForwardIterator +__pstl_find_if(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && + __is_cpp17_random_access_iterator<_ForwardIterator>::value) { + return std::__terminate_on_exception([&] { + return std::__parallel_find( + __first, + __last, + [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + return std::__pstl_find_if<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __pred); + }, + less<>{}, + true); + }); + } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && + __is_cpp17_random_access_iterator<_ForwardIterator>::value) { + using __diff_t = __iter_diff_t<_ForwardIterator>; + return std::__simd_first(__first, __diff_t(0), __last - __first, [&__pred](_ForwardIterator __iter, __diff_t __i) { + return __pred(__iter[__i]); + }); + } else { + return std::find_if(__first, __last, __pred); + } +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_FIND_IF_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h new file mode 100644 index 0000000000000..1d3ca817f4e0e --- /dev/null +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKNEDS_FOR_EACH_H +#define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKNEDS_FOR_EACH_H + +#include <__algorithm/for_each.h> +#include <__algorithm/pstl_backends/cpu_backends/backend.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_execution_policy.h> +#include <__utility/terminate_on_exception.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _Iterator __simd_walk_1(_Iterator __first, _DifferenceType __n, _Function __f) noexcept { + _PSTL_PRAGMA_SIMD + for (_DifferenceType __i = 0; __i < __n; ++__i) + __f(__first[__i]); + + return __first + __n; +} + +template +_LIBCPP_HIDE_FROM_ABI void +__pstl_for_each(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Functor __func) { + if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && + __is_cpp17_random_access_iterator<_ForwardIterator>::value) { + std::__terminate_on_exception([&] { + std::__par_backend::__parallel_for( + __first, __last, [__func](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + std::__pstl_for_each<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __func); + }); + }); + } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && + __is_cpp17_random_access_iterator<_ForwardIterator>::value) { + std::__simd_walk_1(__first, __last - __first, __func); + } else { + std::for_each(__first, __last, __func); + } +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKNEDS_FOR_EACH_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h new file mode 100644 index 0000000000000..ccd24cb15ba89 --- /dev/null +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h @@ -0,0 +1,42 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_SERIAL_H +#define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_SERIAL_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __par_backend { +inline namespace __serial_cpu_backend { + +template +_LIBCPP_HIDE_FROM_ABI void __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) { + __f(__first, __last); +} + +_LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() {} + +// TODO: Complete this list + +} // namespace __serial_cpu_backend +} // namespace __par_backend + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && && _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_SERIAL_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h new file mode 100644 index 0000000000000..f1aac24607c23 --- /dev/null +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h @@ -0,0 +1,132 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_TRANSFORM_H +#define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_TRANSFORM_H + +#include <__algorithm/pstl_backends/cpu_backends/backend.h> +#include <__algorithm/transform.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_execution_policy.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/terminate_on_exception.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _Iterator2 +__simd_walk_2(_Iterator1 __first1, _DifferenceType __n, _Iterator2 __first2, _Function __f) noexcept { + _PSTL_PRAGMA_SIMD + for (_DifferenceType __i = 0; __i < __n; ++__i) + __f(__first1[__i], __first2[__i]); + return __first2 + __n; +} + +template +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform( + __cpu_backend_tag, + _ForwardIterator __first, + _ForwardIterator __last, + _ForwardOutIterator __result, + _UnaryOperation __op) { + if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && + __is_cpp17_random_access_iterator<_ForwardIterator>::value && + __is_cpp17_random_access_iterator<_ForwardOutIterator>::value) { + std::__terminate_on_exception([&] { + std::__par_backend::__parallel_for( + __first, __last, [__op, __first, __result](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + return std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __result + (__brick_first - __first), __op); + }); + }); + return __result + (__last - __first); + } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && + __is_cpp17_random_access_iterator<_ForwardIterator>::value && + __is_cpp17_random_access_iterator<_ForwardOutIterator>::value) { + return std::__simd_walk_2( + __first, + __last - __first, + __result, + [&](__iter_reference<_ForwardIterator> __in_value, __iter_reference<_ForwardOutIterator> __out_value) { + __out_value = __op(__in_value); + }); + } else { + return std::transform(__first, __last, __result, __op); + } +} + +template +_LIBCPP_HIDE_FROM_ABI _Iterator3 __simd_walk_3( + _Iterator1 __first1, _DifferenceType __n, _Iterator2 __first2, _Iterator3 __first3, _Function __f) noexcept { + _PSTL_PRAGMA_SIMD + for (_DifferenceType __i = 0; __i < __n; ++__i) + __f(__first1[__i], __first2[__i], __first3[__i]); + return __first3 + __n; +} +template >, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform( + __cpu_backend_tag, + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardOutIterator __result, + _BinaryOperation __op) { + if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && + __is_cpp17_random_access_iterator<_ForwardIterator1>::value && + __is_cpp17_random_access_iterator<_ForwardIterator2>::value && + __is_cpp17_random_access_iterator<_ForwardOutIterator>::value) { + std::__terminate_on_exception([&] { + std::__par_backend::__parallel_for( + __first1, + __last1, + [__op, __first1, __first2, __result](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) { + return std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, + __brick_first, + __brick_last, + __first2 + (__brick_first - __first1), + __result + (__brick_first - __first1), + __op); + }); + }); + return __result + (__last1 - __first1); + } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && + __is_cpp17_random_access_iterator<_ForwardIterator1>::value && + __is_cpp17_random_access_iterator<_ForwardIterator2>::value && + __is_cpp17_random_access_iterator<_ForwardOutIterator>::value) { + return std::__simd_walk_3( + __first1, + __last1 - __first1, + __first2, + __result, + [&](__iter_reference<_ForwardIterator1> __in1, + __iter_reference<_ForwardIterator2> __in2, + __iter_reference<_ForwardOutIterator> __out_value) { __out_value = __op(__in1, __in2); }); + } else { + return std::transform(__first1, __last1, __first2, __result, __op); + } +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_TRANSFORM_H diff --git a/libcxx/include/__algorithm/pstl_fill.h b/libcxx/include/__algorithm/pstl_fill.h index c2771b29e1c2e..f7850d031efb0 100644 --- a/libcxx/include/__algorithm/pstl_fill.h +++ b/libcxx/include/__algorithm/pstl_fill.h @@ -9,11 +9,11 @@ #ifndef _LIBCPP___ALGORITHM_PSTL_FILL_H #define _LIBCPP___ALGORITHM_PSTL_FILL_H -#include <__algorithm/fill.h> +#include <__algorithm/fill_n.h> +#include <__algorithm/pstl_for_each.h> +#include <__algorithm/pstl_frontend_dispatch.h> #include <__config> #include <__iterator/iterator_traits.h> -#include <__pstl/internal/parallel_impl.h> -#include <__pstl/internal/unseq_backend_simd.h> #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/terminate_on_exception.h> @@ -26,43 +26,50 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +void __pstl_fill(); // declaration needed for the frontend dispatch below + template >, int> = 0> + class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, + enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI void fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { - if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && - __is_cpp17_random_access_iterator<_ForwardIterator>::value) { - std::__terminate_on_exception([&] { - __pstl::__par_backend::__parallel_for( - __pstl::__internal::__par_backend_tag{}, - __policy, - __first, - __last, - [&__policy, &__value](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - std::fill(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __value); - }); - }); - } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && - __is_cpp17_random_access_iterator<_ForwardIterator>::value) { - __pstl::__unseq_backend::__simd_fill_n(__first, __last - __first, __value); - } else { - std::fill(__first, __last, __value); - } + std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_fill), + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) { + std::for_each(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __element) { + __element = __g_value; + }); + }, + std::move(__first), + std::move(__last), + __value); } +template +void __pstl_fill_n(); // declaration needed for the frontend dispatch below + template >, int> = 0> + class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, + enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI void fill_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _SizeT __n, const _Tp& __value) { - if constexpr (__is_cpp17_random_access_iterator<_ForwardIterator>::value) - std::fill(__policy, __first, __first + __n, __value); - else - std::fill_n(__first, __n, __value); + std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_fill_n), + [&](_ForwardIterator __g_first, _SizeT __g_n, const _Tp& __g_value) { + if constexpr (__is_cpp17_random_access_iterator<_ForwardIterator>::value) + std::fill(__policy, __g_first, __g_first + __g_n, __g_value); + else + std::fill_n(__g_first, __g_n, __g_value); + }, + std::move(__first), + __n, + __value); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/pstl_find.h b/libcxx/include/__algorithm/pstl_find.h index be53ee29d5f20..6d69560dc42f8 100644 --- a/libcxx/include/__algorithm/pstl_find.h +++ b/libcxx/include/__algorithm/pstl_find.h @@ -11,9 +11,10 @@ #include <__algorithm/comp.h> #include <__algorithm/find.h> +#include <__algorithm/pstl_backend.h> +#include <__algorithm/pstl_frontend_dispatch.h> #include <__config> -#include <__pstl/internal/parallel_impl.h> -#include <__pstl/internal/unseq_backend_simd.h> +#include <__iterator/iterator_traits.h> #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/terminate_on_exception.h> @@ -28,77 +29,57 @@ _LIBCPP_BEGIN_NAMESPACE_STD template >, int> = 0> + class _Predicate, + class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, + enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI _ForwardIterator -find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { - if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && - __is_cpp17_random_access_iterator<_ForwardIterator>::value) { - return std::__terminate_on_exception([&] { - return __pstl::__internal::__parallel_find( - __pstl::__internal::__par_backend_tag{}, - __policy, - __first, - __last, - [&__policy, &__value](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - return std::find(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __value); - }, - less<>{}, - true); - }); - } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && - __is_cpp17_random_access_iterator<_ForwardIterator>::value) { - using __diff_t = __iter_diff_t<_ForwardIterator>; - return __pstl::__unseq_backend::__simd_first( - __first, __diff_t(0), __last - __first, [&__value](_ForwardIterator __iter, __diff_t __i) { - return __iter[__i] == __value; - }); - } else { - return std::find(__first, __last, __value); - } +find_if(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + using _Backend = typename __select_backend<_RawPolicy>::type; + return std::__pstl_find_if<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__pred)); } +template +void __pstl_find_if_not(); + template >, int> = 0> + class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, + enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI _ForwardIterator -find_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { - if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && - __is_cpp17_random_access_iterator<_ForwardIterator>::value) { - return std::__terminate_on_exception([&] { - return __pstl::__internal::__parallel_find( - __pstl::__internal::__par_backend_tag{}, - __policy, - __first, - __last, - [&__policy, &__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - return std::find_if(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __pred); - }, - less<>{}, - true); - }); - } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && - __is_cpp17_random_access_iterator<_ForwardIterator>::value) { - using __diff_t = __iter_diff_t<_ForwardIterator>; - return __pstl::__unseq_backend::__simd_first( - __first, __diff_t(0), __last - __first, [&__pred](_ForwardIterator __iter, __diff_t __i) { - return __pred(__iter[__i]); +find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_find_if_not), + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) { + return std::find_if(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __value) { + return !__g_pred(__value); }); - } else { - return std::find_if(__first, __last, __pred); - } + }, + std::move(__first), + std::move(__last), + std::move(__pred)); } +template +void __pstl_find(); + template >, int> = 0> + class _Tp, + class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, + enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI _ForwardIterator -find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { - return std::find_if(__policy, __first, __last, [&](__iter_reference<_ForwardIterator> __value) { - return !__pred(__value); - }); +find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_find), + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) { + return std::find_if(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __element) { + return __element == __g_value; + }); + }, + std::move(__first), + std::move(__last), + __value); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/pstl_for_each.h b/libcxx/include/__algorithm/pstl_for_each.h index 08fd4b887460b..78cb01c7b5ab3 100644 --- a/libcxx/include/__algorithm/pstl_for_each.h +++ b/libcxx/include/__algorithm/pstl_for_each.h @@ -11,12 +11,13 @@ #include <__algorithm/for_each.h> #include <__algorithm/for_each_n.h> +#include <__algorithm/pstl_backend.h> +#include <__algorithm/pstl_frontend_dispatch.h> #include <__config> #include <__iterator/iterator_traits.h> -#include <__pstl/internal/parallel_backend.h> -#include <__pstl/internal/unseq_backend_simd.h> #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> +#include <__type_traits/void_t.h> #include <__utility/terminate_on_exception.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -30,41 +31,37 @@ _LIBCPP_BEGIN_NAMESPACE_STD template >, int> = 0> + class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, + enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI void -for_each(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Function __func) { - if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && - __is_cpp17_random_access_iterator<_ForwardIterator>::value) { - std::__terminate_on_exception([&] { - __pstl::__par_backend::__parallel_for( - {}, - __policy, - __first, - __last, - [&__policy, __func](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - std::for_each(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __func); - }); - }); - } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && - __is_cpp17_random_access_iterator<_ForwardIterator>::value) { - __pstl::__unseq_backend::__simd_walk_1(__first, __last - __first, __func); - } else { - std::for_each(__first, __last, __func); - } +for_each(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Function __func) { + using _Backend = typename __select_backend<_RawPolicy>::type; + std::__pstl_for_each<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__func)); } +template +void __pstl_for_each_n(); // declaration needed for the frontend dispatch below + template >, int> = 0> + class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, + enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI void for_each_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __size, _Function __func) { - if constexpr (__is_cpp17_random_access_iterator<_ForwardIterator>::value) { - std::for_each(__policy, __first, __first + __size, __func); - } else { - std::for_each_n(__first, __size, __func); - } + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_for_each_n), + [&](_ForwardIterator __g_first, _Size __g_size, _Function __g_func) { + if constexpr (__is_cpp17_random_access_iterator<_ForwardIterator>::value) { + std::for_each(__policy, std::move(__g_first), __g_first + __g_size, std::move(__g_func)); + } else { + std::for_each_n(std::move(__g_first), __g_size, std::move(__g_func)); + } + }, + __first, + __size, + std::move(__func)); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/pstl_frontend_dispatch.h b/libcxx/include/__algorithm/pstl_frontend_dispatch.h new file mode 100644 index 0000000000000..dc49f3e5163a3 --- /dev/null +++ b/libcxx/include/__algorithm/pstl_frontend_dispatch.h @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PSTL_FRONTEND_DISPATCH +#define _LIBCPP___ALGORITHM_PSTL_FRONTEND_DISPATCH + +#include <__config> +#include <__type_traits/is_callable.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +# define _LIBCPP_PSTL_CUSTOMIZATION_POINT(name) \ + [](auto&&... __args) -> decltype(std::name<_RawPolicy>(typename __select_backend<_RawPolicy>::type{}, \ + std::forward(__args)...)) { \ + return std::name<_RawPolicy>( \ + typename __select_backend<_RawPolicy>::type{}, std::forward(__args)...); \ + } + +template +_LIBCPP_HIDE_FROM_ABI decltype(auto) +__pstl_frontend_dispatch(_SpecializedImpl __specialized_impl, _GenericImpl __generic_impl, _Args&&... __args) { + if constexpr (__is_callable<_SpecializedImpl, _Args...>::value) { + return __specialized_impl(std::forward<_Args>(__args)...); + } else { + return __generic_impl(std::forward<_Args>(__args)...); + } +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___ALGORITHM_PSTL_FRONTEND_DISPATCH diff --git a/libcxx/include/__algorithm/pstl_transform.h b/libcxx/include/__algorithm/pstl_transform.h new file mode 100644 index 0000000000000..9d2d731eeb150 --- /dev/null +++ b/libcxx/include/__algorithm/pstl_transform.h @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PSTL_TRANSFORM_H +#define _LIBCPP___ALGORITHM_PSTL_TRANSFORM_H + +#include <__algorithm/pstl_backend.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_execution_policy.h> +#include <__utility/terminate_on_exception.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform( + _ExecutionPolicy&&, + _ForwardIterator __first, + _ForwardIterator __last, + _ForwardOutIterator __result, + _UnaryOperation __op) { + using _Backend = typename __select_backend<_RawPolicy>::type; + return std::__pstl_transform<_RawPolicy>( + _Backend{}, std::move(__first), std::move(__last), std::move(__result), std::move(__op)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform( + _ExecutionPolicy&&, + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardOutIterator __result, + _BinaryOperation __op) { + using _Backend = typename __select_backend<_RawPolicy>::type; + return std::__pstl_transform<_RawPolicy>( + _Backend{}, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__result), std::move(__op)); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___ALGORITHM_PSTL_TRANSFORM_H diff --git a/libcxx/include/__algorithm/ranges_starts_with.h b/libcxx/include/__algorithm/ranges_starts_with.h new file mode 100644 index 0000000000000..4c37756f67204 --- /dev/null +++ b/libcxx/include/__algorithm/ranges_starts_with.h @@ -0,0 +1,90 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_STARTS_WITH_H +#define _LIBCPP___ALGORITHM_RANGES_STARTS_WITH_H + +#include "ranges_mismatch.h" +#include <__algorithm/in_in_result.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/indirectly_comparable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __starts_with { +struct __fn { + template _Sent1, + input_iterator _Iter2, + sentinel_for<_Iter2> _Sent2, + class _Pred = ranges::equal_to, + class _Proj1 = identity, + class _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr bool operator()( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred __pred = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + return __mismatch::__fn::__go( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + __pred, + __proj1, + __proj2) + .in2 == __last2; + } + + template + requires indirectly_comparable, iterator_t<_Range2>, _Pred, _Proj1, _Proj2> + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr bool operator()( + _Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { + return __mismatch::__fn::__go( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + __pred, + __proj1, + __proj2) + .in2 == ranges::end(__range2); + } +}; +} // namespace __starts_with +inline namespace __cpo { +inline constexpr auto starts_with = __starts_with::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +#endif // _LIBCPP___ALGORITHM_RANGES_STARTS_WITH_H diff --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h index f8706129082a8..3583c4499cc2f 100644 --- a/libcxx/include/__algorithm/sort.h +++ b/libcxx/include/__algorithm/sort.h @@ -279,12 +279,13 @@ void __insertion_sort(_BidirectionalIterator __first, _BidirectionalIterator __l // element in the input range is greater or equal to the element at __first - 1. template _LIBCPP_HIDE_FROM_ABI void -__insertion_sort_unguarded(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { +__insertion_sort_unguarded(_RandomAccessIterator const __first, _RandomAccessIterator __last, _Compare __comp) { using _Ops = _IterOps<_AlgPolicy>; typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; if (__first == __last) return; + const _RandomAccessIterator __leftmost = __first - difference_type(1); (void)__leftmost; // can be unused when assertions are disabled for (_RandomAccessIterator __i = __first + difference_type(1); __i != __last; ++__i) { _RandomAccessIterator __j = __i - difference_type(1); if (__comp(*__i, *__j)) { @@ -294,6 +295,7 @@ __insertion_sort_unguarded(_RandomAccessIterator __first, _RandomAccessIterator do { *__j = _Ops::__iter_move(__k); __j = __k; + _LIBCPP_ASSERT(__k != __leftmost, "Would read out of bounds, is your comparator a valid strict-weak ordering?"); } while (__comp(__t, *--__k)); // No need for bounds check due to the assumption stated above. *__j = std::move(__t); } @@ -496,14 +498,17 @@ __bitset_partition(_RandomAccessIterator __first, _RandomAccessIterator __last, typedef typename std::iterator_traits<_RandomAccessIterator>::value_type value_type; typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type difference_type; _LIBCPP_ASSERT(__last - __first >= difference_type(3), ""); + const _RandomAccessIterator __begin = __first; // used for bounds checking, those are not moved around + const _RandomAccessIterator __end = __last; (void)__end; // - _RandomAccessIterator __begin = __first; value_type __pivot(_Ops::__iter_move(__first)); // Find the first element greater than the pivot. if (__comp(__pivot, *(__last - difference_type(1)))) { // Not guarded since we know the last element is greater than the pivot. - while (!__comp(__pivot, *++__first)) { - } + do { + ++__first; + _LIBCPP_ASSERT(__first != __end, "Would read out of bounds, is your comparator a valid strict-weak ordering?"); + } while (!__comp(__pivot, *__first)); } else { while (++__first < __last && !__comp(__pivot, *__first)) { } @@ -512,8 +517,10 @@ __bitset_partition(_RandomAccessIterator __first, _RandomAccessIterator __last, if (__first < __last) { // It will be always guarded because __introsort will do the median-of-three // before calling this. - while (__comp(__pivot, *--__last)) { - } + do { + _LIBCPP_ASSERT(__last != __begin, "Would read out of bounds, is your comparator a valid strict-weak ordering?"); + --__last; + } while (__comp(__pivot, *__last)); } // If the first element greater than the pivot is at or after the // last element less than or equal to the pivot, then we have covered the @@ -578,13 +585,16 @@ __partition_with_equals_on_right(_RandomAccessIterator __first, _RandomAccessIte typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; typedef typename std::iterator_traits<_RandomAccessIterator>::value_type value_type; _LIBCPP_ASSERT(__last - __first >= difference_type(3), ""); - _RandomAccessIterator __begin = __first; + const _RandomAccessIterator __begin = __first; // used for bounds checking, those are not moved around + const _RandomAccessIterator __end = __last; (void)__end; // value_type __pivot(_Ops::__iter_move(__first)); // Find the first element greater or equal to the pivot. It will be always // guarded because __introsort will do the median-of-three before calling // this. - while (__comp(*++__first, __pivot)) - ; + do { + ++__first; + _LIBCPP_ASSERT(__first != __end, "Would read out of bounds, is your comparator a valid strict-weak ordering?"); + } while (__comp(*__first, __pivot)); // Find the last element less than the pivot. if (__begin == __first - difference_type(1)) { @@ -592,8 +602,10 @@ __partition_with_equals_on_right(_RandomAccessIterator __first, _RandomAccessIte ; } else { // Guarded. - while (!__comp(*--__last, __pivot)) - ; + do { + _LIBCPP_ASSERT(__last != __begin, "Would read out of bounds, is your comparator a valid strict-weak ordering?"); + --__last; + } while (!__comp(*__last, __pivot)); } // If the first element greater than or equal to the pivot is at or after the @@ -605,10 +617,14 @@ __partition_with_equals_on_right(_RandomAccessIterator __first, _RandomAccessIte // correct side of the pivot. while (__first < __last) { _Ops::iter_swap(__first, __last); - while (__comp(*++__first, __pivot)) - ; - while (!__comp(*--__last, __pivot)) - ; + do { + ++__first; + _LIBCPP_ASSERT(__first != __end, "Would read out of bounds, is your comparator a valid strict-weak ordering?"); + } while (__comp(*__first, __pivot)); + do { + _LIBCPP_ASSERT(__last != __begin, "Would read out of bounds, is your comparator a valid strict-weak ordering?"); + --__last; + } while (!__comp(*__last, __pivot)); } // Move the pivot to its correct position. _RandomAccessIterator __pivot_pos = __first - difference_type(1); @@ -627,12 +643,15 @@ __partition_with_equals_on_left(_RandomAccessIterator __first, _RandomAccessIter using _Ops = _IterOps<_AlgPolicy>; typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; typedef typename std::iterator_traits<_RandomAccessIterator>::value_type value_type; - _RandomAccessIterator __begin = __first; + const _RandomAccessIterator __begin = __first; // used for bounds checking, those are not moved around + const _RandomAccessIterator __end = __last; (void)__end; // value_type __pivot(_Ops::__iter_move(__first)); if (__comp(__pivot, *(__last - difference_type(1)))) { // Guarded. - while (!__comp(__pivot, *++__first)) { - } + do { + ++__first; + _LIBCPP_ASSERT(__first != __end, "Would read out of bounds, is your comparator a valid strict-weak ordering?"); + } while (!__comp(__pivot, *__first)); } else { while (++__first < __last && !__comp(__pivot, *__first)) { } @@ -641,15 +660,21 @@ __partition_with_equals_on_left(_RandomAccessIterator __first, _RandomAccessIter if (__first < __last) { // It will be always guarded because __introsort will do the // median-of-three before calling this. - while (__comp(__pivot, *--__last)) { - } + do { + _LIBCPP_ASSERT(__last != __begin, "Would read out of bounds, is your comparator a valid strict-weak ordering?"); + --__last; + } while (__comp(__pivot, *__last)); } while (__first < __last) { _Ops::iter_swap(__first, __last); - while (!__comp(__pivot, *++__first)) - ; - while (__comp(__pivot, *--__last)) - ; + do { + ++__first; + _LIBCPP_ASSERT(__first != __end, "Would read out of bounds, is your comparator a valid strict-weak ordering?"); + } while (!__comp(__pivot, *__first)); + do { + _LIBCPP_ASSERT(__last != __begin, "Would read out of bounds, is your comparator a valid strict-weak ordering?"); + --__last; + } while (__comp(__pivot, *__last)); } _RandomAccessIterator __pivot_pos = __first - difference_type(1); if (__begin != __pivot_pos) { diff --git a/libcxx/include/__atomic/aliases.h b/libcxx/include/__atomic/aliases.h index 806589b630ee2..e2f9fae4094ef 100644 --- a/libcxx/include/__atomic/aliases.h +++ b/libcxx/include/__atomic/aliases.h @@ -82,7 +82,7 @@ using atomic_uintmax_t = atomic; // atomic_*_lock_free : prefer the contention type most highly, then the largest lock-free type -#ifdef __cpp_lib_atomic_is_always_lock_free +#if _LIBCPP_STD_VER >= 17 # define _LIBCPP_CONTENTION_LOCK_FREE ::std::__libcpp_is_always_lock_free<__cxx_contention_t>::__value #else # define _LIBCPP_CONTENTION_LOCK_FREE false diff --git a/libcxx/include/__atomic/atomic_base.h b/libcxx/include/__atomic/atomic_base.h index 7a9ba78433194..87100ba5d8a50 100644 --- a/libcxx/include/__atomic/atomic_base.h +++ b/libcxx/include/__atomic/atomic_base.h @@ -33,7 +33,7 @@ struct __atomic_base // false { mutable __cxx_atomic_impl<_Tp> __a_; -#if defined(__cpp_lib_atomic_is_always_lock_free) +#if _LIBCPP_STD_VER >= 17 static _LIBCPP_CONSTEXPR bool is_always_lock_free = __libcpp_is_always_lock_free<__cxx_atomic_impl<_Tp> >::__value; #endif @@ -139,7 +139,7 @@ struct __atomic_base // false __atomic_base(const __atomic_base&) = delete; }; -#if defined(__cpp_lib_atomic_is_always_lock_free) +#if _LIBCPP_STD_VER >= 17 template _LIBCPP_CONSTEXPR bool __atomic_base<_Tp, __b>::is_always_lock_free; #endif diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h index a91a592a88e21..7e8af44f35d31 100644 --- a/libcxx/include/__chrono/formatter.h +++ b/libcxx/include/__chrono/formatter.h @@ -485,12 +485,12 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __month_name_ok(const _Tp& __value) { static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); } -template +template _LIBCPP_HIDE_FROM_ABI auto __format_chrono(const _Tp& __value, - auto& __ctx, + _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs, - basic_string_view<_CharT> __chrono_specs) -> decltype(__ctx.out()) { + basic_string_view<_CharT> __chrono_specs) { basic_stringstream<_CharT> __sstr; // [time.format]/2 // 2.1 - the "C" locale if the L option is not present in chrono-format-spec, otherwise @@ -566,14 +566,14 @@ __format_chrono(const _Tp& __value, template <__fmt_char_type _CharT> struct _LIBCPP_TEMPLATE_VIS __formatter_chrono { public: - _LIBCPP_HIDE_FROM_ABI constexpr auto __parse( - basic_format_parse_context<_CharT>& __parse_ctx, __format_spec::__fields __fields, __format_spec::__flags __flags) - -> decltype(__parse_ctx.begin()) { - return __parser_.__parse(__parse_ctx, __fields, __flags); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator + __parse(_ParseContext& __ctx, __format_spec::__fields __fields, __format_spec::__flags __flags) { + return __parser_.__parse(__ctx, __fields, __flags); } - template - _LIBCPP_HIDE_FROM_ABI auto format(const _Tp& __value, auto& __ctx) const -> decltype(__ctx.out()) const { + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const _Tp& __value, _FormatContext& __ctx) const { return __formatter::__format_chrono( __value, __ctx, __parser_.__parser_.__get_parsed_chrono_specifications(__ctx), __parser_.__chrono_specs_); } @@ -586,9 +586,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : pub public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); } }; @@ -597,9 +597,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : pu public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); } }; @@ -608,10 +608,10 @@ struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : p public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { // The flags are not __clock since there is no associated time-zone. - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date_time); + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date_time); } }; @@ -620,8 +620,8 @@ struct formatter, _CharT> : public __formatter_c public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { // [time.format]/1 // Giving a precision specification in the chrono-format-spec is valid only // for std::chrono::duration types where the representation type Rep is a @@ -631,9 +631,9 @@ struct formatter, _CharT> : public __formatter_c // // Note this doesn't refer to chrono::treat_as_floating_point_v<_Rep>. if constexpr (std::floating_point<_Rep>) - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono_fractional, __format_spec::__flags::__duration); + return _Base::__parse(__ctx, __format_spec::__fields_chrono_fractional, __format_spec::__flags::__duration); else - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__duration); + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__duration); } }; @@ -643,9 +643,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__day); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__day); } }; @@ -655,9 +655,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month); } }; @@ -667,9 +667,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year); } }; @@ -679,9 +679,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); } }; @@ -691,9 +691,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); } }; @@ -703,9 +703,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); } }; @@ -715,9 +715,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_day); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_day); } }; @@ -727,9 +727,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month); } }; @@ -739,9 +739,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_weekday); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_weekday); } }; @@ -751,9 +751,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_weekday); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_weekday); } }; @@ -763,9 +763,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year_month); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year_month); } }; @@ -775,9 +775,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); } }; @@ -787,9 +787,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); } }; @@ -799,9 +799,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); } }; @@ -811,9 +811,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); } }; @@ -822,9 +822,9 @@ struct formatter, _CharT> : public __formatter_chron public: using _Base = __formatter_chrono<_CharT>; - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__time); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__time); } }; #endif // if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT) diff --git a/libcxx/include/__chrono/parser_std_format_spec.h b/libcxx/include/__chrono/parser_std_format_spec.h index 27b8aa738a66d..44c19abee1932 100644 --- a/libcxx/include/__chrono/parser_std_format_spec.h +++ b/libcxx/include/__chrono/parser_std_format_spec.h @@ -140,11 +140,11 @@ class _LIBCPP_TEMPLATE_VIS __parser_chrono { using _ConstIterator = typename basic_format_parse_context<_CharT>::const_iterator; public: - _LIBCPP_HIDE_FROM_ABI constexpr auto - __parse(basic_format_parse_context<_CharT>& __parse_ctx, __fields __fields, __flags __flags) - -> decltype(__parse_ctx.begin()) { - _ConstIterator __begin = __parser_.__parse(__parse_ctx, __fields); - _ConstIterator __end = __parse_ctx.end(); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator + __parse(_ParseContext& __ctx, __fields __fields, __flags __flags) { + _ConstIterator __begin = __parser_.__parse(__ctx, __fields); + _ConstIterator __end = __ctx.end(); if (__begin == __end) return __begin; diff --git a/libcxx/include/__config b/libcxx/include/__config index 43af83220e855..86156c8521fd6 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1271,6 +1271,47 @@ _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_END_NAMESPACE_STD # define _LIBCPP_WORKAROUND_OBJCXX_COMPILER_INTRINSICS # endif +// TODO: Make this a proper configuration option +#define _PSTL_PAR_BACKEND_SERIAL +#define _PSTL_CPU_BACKEND_SERIAL + +#define _PSTL_PRAGMA(x) _Pragma(# x) + +// Enable SIMD for compilers that support OpenMP 4.0 +#if (defined(_OPENMP) && _OPENMP >= 201307) + +# define _PSTL_UDR_PRESENT +# define _PSTL_PRAGMA_SIMD _PSTL_PRAGMA(omp simd) +# define _PSTL_PRAGMA_DECLARE_SIMD _PSTL_PRAGMA(omp declare simd) +# define _PSTL_PRAGMA_SIMD_REDUCTION(PRM) _PSTL_PRAGMA(omp simd reduction(PRM)) +# define _PSTL_PRAGMA_SIMD_SCAN(PRM) _PSTL_PRAGMA(omp simd reduction(inscan, PRM)) +# define _PSTL_PRAGMA_SIMD_INCLUSIVE_SCAN(PRM) _PSTL_PRAGMA(omp scan inclusive(PRM)) +# define _PSTL_PRAGMA_SIMD_EXCLUSIVE_SCAN(PRM) _PSTL_PRAGMA(omp scan exclusive(PRM)) + +// Declaration of reduction functor, where +// NAME - the name of the functor +// OP - type of the callable object with the reduction operation +// omp_in - refers to the local partial result +// omp_out - refers to the final value of the combiner operator +// omp_priv - refers to the private copy of the initial value +// omp_orig - refers to the original variable to be reduced +# define _PSTL_PRAGMA_DECLARE_REDUCTION(NAME, OP) \ + _PSTL_PRAGMA(omp declare reduction(NAME:OP : omp_out(omp_in)) initializer(omp_priv = omp_orig)) + +#else // (defined(_OPENMP) && _OPENMP >= 201307) + +# define _PSTL_PRAGMA_SIMD +# define _PSTL_PRAGMA_DECLARE_SIMD +# define _PSTL_PRAGMA_SIMD_REDUCTION(PRM) +# define _PSTL_PRAGMA_SIMD_SCAN(PRM) +# define _PSTL_PRAGMA_SIMD_INCLUSIVE_SCAN(PRM) +# define _PSTL_PRAGMA_SIMD_EXCLUSIVE_SCAN(PRM) +# define _PSTL_PRAGMA_DECLARE_REDUCTION(NAME, OP) + +#endif // (defined(_OPENMP) && _OPENMP >= 201307) + +#define _PSTL_USE_NONTEMPORAL_STORES_IF_ALLOWED + #endif // __cplusplus #endif // _LIBCPP___CONFIG diff --git a/libcxx/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h index 60b40cb4f8aae..f47a9f8cf1d21 100644 --- a/libcxx/include/__format/format_functions.h +++ b/libcxx/include/__format/format_functions.h @@ -89,14 +89,16 @@ namespace __format { template class _LIBCPP_TEMPLATE_VIS __compile_time_handle { public: - _LIBCPP_HIDE_FROM_ABI - constexpr void __parse(basic_format_parse_context<_CharT>& __parse_ctx) const { __parse_(__parse_ctx); } + template + _LIBCPP_HIDE_FROM_ABI constexpr void __parse(_ParseContext& __ctx) const { + __parse_(__ctx); + } template _LIBCPP_HIDE_FROM_ABI constexpr void __enable() { - __parse_ = [](basic_format_parse_context<_CharT>& __parse_ctx) { + __parse_ = [](basic_format_parse_context<_CharT>& __ctx) { formatter<_Tp, _CharT> __f; - __parse_ctx.advance_to(__f.parse(__parse_ctx)); + __ctx.advance_to(__f.parse(__ctx)); }; } diff --git a/libcxx/include/__format/formatter_bool.h b/libcxx/include/__format/formatter_bool.h index 1fb75755fc572..e95a216bb3e7e 100644 --- a/libcxx/include/__format/formatter_bool.h +++ b/libcxx/include/__format/formatter_bool.h @@ -38,14 +38,15 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <__fmt_char_type _CharT> struct _LIBCPP_TEMPLATE_VIS formatter { public: - _LIBCPP_HIDE_FROM_ABI constexpr auto - parse(basic_format_parse_context<_CharT>& __parse_ctx) -> decltype(__parse_ctx.begin()) { - auto __result = __parser_.__parse(__parse_ctx, __format_spec::__fields_integral); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_integral); __format_spec::__process_parsed_bool(__parser_); return __result; } - _LIBCPP_HIDE_FROM_ABI auto format(bool __value, auto& __ctx) const -> decltype(__ctx.out()) { + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(bool __value, _FormatContext& __ctx) const { switch (__parser_.__type_) { case __format_spec::__type::__default: case __format_spec::__type::__string: diff --git a/libcxx/include/__format/formatter_char.h b/libcxx/include/__format/formatter_char.h index 7d63c042c554f..15a649807b73f 100644 --- a/libcxx/include/__format/formatter_char.h +++ b/libcxx/include/__format/formatter_char.h @@ -33,14 +33,15 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <__fmt_char_type _CharT> struct _LIBCPP_TEMPLATE_VIS __formatter_char { public: - _LIBCPP_HIDE_FROM_ABI constexpr auto - parse(basic_format_parse_context<_CharT>& __parse_ctx) -> decltype(__parse_ctx.begin()) { - auto __result = __parser_.__parse(__parse_ctx, __format_spec::__fields_integral); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_integral); __format_spec::__process_parsed_char(__parser_); return __result; } - _LIBCPP_HIDE_FROM_ABI auto format(_CharT __value, auto& __ctx) const -> decltype(__ctx.out()) { + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_CharT __value, _FormatContext& __ctx) const { if (__parser_.__type_ == __format_spec::__type::__default || __parser_.__type_ == __format_spec::__type::__char) return __formatter::__format_char(__value, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx)); @@ -60,7 +61,8 @@ struct _LIBCPP_TEMPLATE_VIS __formatter_char { return __formatter::__format_integer(__value, __ctx, __parser_.__get_parsed_std_specifications(__ctx)); } - _LIBCPP_HIDE_FROM_ABI auto format(char __value, auto& __ctx) const -> decltype(__ctx.out()) + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(char __value, _FormatContext& __ctx) const requires(same_as<_CharT, wchar_t>) { return format(static_cast(__value), __ctx); diff --git a/libcxx/include/__format/formatter_floating_point.h b/libcxx/include/__format/formatter_floating_point.h index 12c7e589ff5d1..9a38c056b63c2 100644 --- a/libcxx/include/__format/formatter_floating_point.h +++ b/libcxx/include/__format/formatter_floating_point.h @@ -608,10 +608,9 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __format_floating_point_non_finite( return __formatter::__write(__buffer, __last, _VSTD::move(__out_it), __specs); } -template -_LIBCPP_HIDE_FROM_ABI auto -__format_floating_point(_Tp __value, auto& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) - -> decltype(__ctx.out()) { +template +_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator +__format_floating_point(_Tp __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) { bool __negative = _VSTD::signbit(__value); if (!_VSTD::isfinite(__value)) [[unlikely]] @@ -728,15 +727,15 @@ __format_floating_point(_Tp __value, auto& __ctx, __format_spec::__parsed_specif template <__fmt_char_type _CharT> struct _LIBCPP_TEMPLATE_VIS __formatter_floating_point { public: - _LIBCPP_HIDE_FROM_ABI constexpr auto - parse(basic_format_parse_context<_CharT>& __parse_ctx) -> decltype(__parse_ctx.begin()) { - auto __result = __parser_.__parse(__parse_ctx, __format_spec::__fields_floating_point); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_floating_point); __format_spec::__process_parsed_floating_point(__parser_); return __result; } - template - _LIBCPP_HIDE_FROM_ABI auto format(_Tp __value, auto& __ctx) const -> decltype(__ctx.out()) { + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_Tp __value, _FormatContext& __ctx) const { return __formatter::__format_floating_point(__value, __ctx, __parser_.__get_parsed_std_specifications(__ctx)); } diff --git a/libcxx/include/__format/formatter_integer.h b/libcxx/include/__format/formatter_integer.h index 0e144100da9ab..f7dac28850b4e 100644 --- a/libcxx/include/__format/formatter_integer.h +++ b/libcxx/include/__format/formatter_integer.h @@ -34,15 +34,15 @@ struct _LIBCPP_TEMPLATE_VIS __formatter_integer { public: - _LIBCPP_HIDE_FROM_ABI constexpr auto - parse(basic_format_parse_context<_CharT>& __parse_ctx) -> decltype(__parse_ctx.begin()) { - auto __result = __parser_.__parse(__parse_ctx, __format_spec::__fields_integral); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_integral); __format_spec::__process_parsed_integer(__parser_); return __result; } - template - _LIBCPP_HIDE_FROM_ABI auto format(_Tp __value, auto& __ctx) const -> decltype(__ctx.out()) { + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_Tp __value, _FormatContext& __ctx) const { __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx); if (__specs.__std_.__type_ == __format_spec::__type::__char) diff --git a/libcxx/include/__format/formatter_integral.h b/libcxx/include/__format/formatter_integral.h index 80d2457aff283..463070ec5361e 100644 --- a/libcxx/include/__format/formatter_integral.h +++ b/libcxx/include/__format/formatter_integral.h @@ -203,16 +203,16 @@ consteval size_t __buffer_size() noexcept + 1; // Reserve space for the sign. } -template -_LIBCPP_HIDE_FROM_ABI auto __format_integer( +template +_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator __format_integer( _Tp __value, - auto& __ctx, + _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs, bool __negative, char* __begin, char* __end, const char* __prefix, - int __base) -> decltype(__ctx.out()) { + int __base) { char* __first = __formatter::__insert_sign(__begin, __negative, __specs.__std_.__sign_); if (__specs.__std_.__alternate_form_ && __prefix) while (*__prefix) @@ -263,10 +263,12 @@ _LIBCPP_HIDE_FROM_ABI auto __format_integer( return __formatter::__write_transformed(__first, __last, __ctx.out(), __specs, __formatter::__hex_to_upper); } -template -_LIBCPP_HIDE_FROM_ABI auto __format_integer( - _Tp __value, auto& __ctx, __format_spec::__parsed_specifications<_CharT> __specs, bool __negative = false) - -> decltype(__ctx.out()) { +template +_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator +__format_integer(_Tp __value, + _FormatContext& __ctx, + __format_spec::__parsed_specifications<_CharT> __specs, + bool __negative = false) { switch (__specs.__std_.__type_) { case __format_spec::__type::__binary_lower_case: { array()> __array; @@ -302,10 +304,9 @@ _LIBCPP_HIDE_FROM_ABI auto __format_integer( } } -template -_LIBCPP_HIDE_FROM_ABI auto -__format_integer(_Tp __value, auto& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) - -> decltype(__ctx.out()) { +template +_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator +__format_integer(_Tp __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) { // Depending on the std-format-spec string the sign and the value // might not be outputted together: // - alternate form may insert a prefix string. @@ -341,10 +342,9 @@ struct _LIBCPP_TEMPLATE_VIS __bool_strings { }; # endif -template -_LIBCPP_HIDE_FROM_ABI auto -__format_bool(bool __value, auto& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) - -> decltype(__ctx.out()) { +template +_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator +__format_bool(bool __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) { # ifndef _LIBCPP_HAS_NO_LOCALIZATION if (__specs.__std_.__locale_specific_form_) { const auto& __np = std::use_facet>(__ctx.locale()); diff --git a/libcxx/include/__format/formatter_pointer.h b/libcxx/include/__format/formatter_pointer.h index 48d8372a2341f..ab699ba65ccd8 100644 --- a/libcxx/include/__format/formatter_pointer.h +++ b/libcxx/include/__format/formatter_pointer.h @@ -32,14 +32,15 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <__fmt_char_type _CharT> struct _LIBCPP_TEMPLATE_VIS __formatter_pointer { public: - _LIBCPP_HIDE_FROM_ABI constexpr auto - parse(basic_format_parse_context<_CharT>& __parse_ctx) -> decltype(__parse_ctx.begin()) { - auto __result = __parser_.__parse(__parse_ctx, __format_spec::__fields_pointer); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_pointer); __format_spec::__process_display_type_pointer(__parser_.__type_); return __result; } - _LIBCPP_HIDE_FROM_ABI auto format(const void* __ptr, auto& __ctx) const -> decltype(__ctx.out()) { + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const void* __ptr, _FormatContext& __ctx) const { __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx); __specs.__std_.__alternate_form_ = true; __specs.__std_.__type_ = __format_spec::__type::__hexadecimal_lower_case; diff --git a/libcxx/include/__format/formatter_string.h b/libcxx/include/__format/formatter_string.h index c14518be495bc..25a9e8ee4920c 100644 --- a/libcxx/include/__format/formatter_string.h +++ b/libcxx/include/__format/formatter_string.h @@ -32,14 +32,16 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <__fmt_char_type _CharT> struct _LIBCPP_TEMPLATE_VIS __formatter_string { public: - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - auto __result = __parser_.__parse(__parse_ctx, __format_spec::__fields_string); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_string); __format_spec::__process_display_type_string(__parser_.__type_); return __result; } - _LIBCPP_HIDE_FROM_ABI auto format(basic_string_view<_CharT> __str, auto& __ctx) const -> decltype(__ctx.out()) { + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator + format(basic_string_view<_CharT> __str, _FormatContext& __ctx) const { # if _LIBCPP_STD_VER >= 23 if (__parser_.__type_ == __format_spec::__type::__debug) return __formatter::__format_escaped_string(__str, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx)); @@ -61,7 +63,8 @@ struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_string<_CharT> { using _Base = __formatter_string<_CharT>; - _LIBCPP_HIDE_FROM_ABI auto format(const _CharT* __str, auto& __ctx) const -> decltype(__ctx.out()) { + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const _CharT* __str, _FormatContext& __ctx) const { _LIBCPP_ASSERT(__str, "The basic_format_arg constructor should have " "prevented an invalid pointer."); @@ -99,7 +102,8 @@ struct _LIBCPP_TEMPLATE_VIS formatter<_CharT*, _CharT> : public formatter { using _Base = formatter; - _LIBCPP_HIDE_FROM_ABI auto format(_CharT* __str, auto& __ctx) const -> decltype(__ctx.out()) { + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_CharT* __str, _FormatContext& __ctx) const { return _Base::format(__str, __ctx); } }; @@ -110,7 +114,8 @@ struct _LIBCPP_TEMPLATE_VIS formatter<_CharT[_Size], _CharT> : public __formatter_string<_CharT> { using _Base = __formatter_string<_CharT>; - _LIBCPP_HIDE_FROM_ABI auto format(_CharT __str[_Size], auto& __ctx) const -> decltype(__ctx.out()) { + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_CharT __str[_Size], _FormatContext& __ctx) const { return _Base::format(basic_string_view<_CharT>(__str, _Size), __ctx); } }; @@ -121,8 +126,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter, : public __formatter_string<_CharT> { using _Base = __formatter_string<_CharT>; - _LIBCPP_HIDE_FROM_ABI auto format(const basic_string<_CharT, _Traits, _Allocator>& __str, auto& __ctx) const - -> decltype(__ctx.out()) { + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator + format(const basic_string<_CharT, _Traits, _Allocator>& __str, _FormatContext& __ctx) const { // Drop _Traits and _Allocator to have one std::basic_string formatter. return _Base::format(basic_string_view<_CharT>(__str.data(), __str.size()), __ctx); } @@ -134,8 +140,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter, _CharT : public __formatter_string<_CharT> { using _Base = __formatter_string<_CharT>; - _LIBCPP_HIDE_FROM_ABI auto format(basic_string_view<_CharT, _Traits> __str, auto& __ctx) const - -> decltype(__ctx.out()) { + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator + format(basic_string_view<_CharT, _Traits> __str, _FormatContext& __ctx) const { // Drop _Traits to have one std::basic_string_view formatter. return _Base::format(basic_string_view<_CharT>(__str.data(), __str.size()), __ctx); } diff --git a/libcxx/include/__format/formatter_tuple.h b/libcxx/include/__format/formatter_tuple.h index 9d6367be8f432..92380f858fee6 100644 --- a/libcxx/include/__format/formatter_tuple.h +++ b/libcxx/include/__format/formatter_tuple.h @@ -50,10 +50,10 @@ struct _LIBCPP_TEMPLATE_VIS __formatter_tuple { } template - _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __parse_ctx) { - auto __begin = __parser_.__parse(__parse_ctx, __format_spec::__fields_tuple); + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + auto __begin = __parser_.__parse(__ctx, __format_spec::__fields_tuple); - auto __end = __parse_ctx.end(); + auto __end = __ctx.end(); if (__begin != __end) { if (*__begin == _CharT('m')) { if constexpr (sizeof...(_Args) == 2) { @@ -71,14 +71,14 @@ struct _LIBCPP_TEMPLATE_VIS __formatter_tuple { if (__begin != __end && *__begin != _CharT('}')) std::__throw_format_error("The format-spec should consume the input or end with a '}'"); - __parse_ctx.advance_to(__begin); + __ctx.advance_to(__begin); // [format.tuple]/7 // ... For each element e in underlying_, if e.set_debug_format() // is a valid expression, calls e.set_debug_format(). std::__for_each_index_sequence(make_index_sequence(), [&] { auto& __formatter = std::get<_Index>(__underlying_); - __formatter.parse(__parse_ctx); + __formatter.parse(__ctx); // Unlike the range_formatter we don't guard against evil parsers. Since // this format-spec never has a format-spec for the underlying type // adding the test would give additional overhead. diff --git a/libcxx/include/__format/parser_std_format_spec.h b/libcxx/include/__format/parser_std_format_spec.h index eb7ca37d2e615..9c3eb35c02854 100644 --- a/libcxx/include/__format/parser_std_format_spec.h +++ b/libcxx/include/__format/parser_std_format_spec.h @@ -50,16 +50,16 @@ _LIBCPP_BEGIN_NAMESPACE_STD namespace __format_spec { -template +template _LIBCPP_HIDE_FROM_ABI constexpr __format::__parse_number_result<_Iterator> -__parse_arg_id(_Iterator __begin, _Iterator __end, auto& __parse_ctx) { +__parse_arg_id(_Iterator __begin, _Iterator __end, _ParseContext& __ctx) { using _CharT = iter_value_t<_Iterator>; // This function is a wrapper to call the real parser. But it does the // validation for the pre-conditions and post-conditions. if (__begin == __end) std::__throw_format_error("End of input while parsing format-spec arg-id"); - __format::__parse_number_result __r = __format::__parse_arg_id(__begin, __end, __parse_ctx); + __format::__parse_number_result __r = __format::__parse_arg_id(__begin, __end, __ctx); if (__r.__last == __end || *__r.__last != _CharT('}')) std::__throw_format_error("Invalid arg-id"); @@ -282,11 +282,10 @@ static_assert(is_trivially_copyable_v<__parsed_specifications>); template class _LIBCPP_TEMPLATE_VIS __parser { public: - _LIBCPP_HIDE_FROM_ABI constexpr auto __parse(basic_format_parse_context<_CharT>& __parse_ctx, __fields __fields) - -> decltype(__parse_ctx.begin()) { - - auto __begin = __parse_ctx.begin(); - auto __end = __parse_ctx.end(); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator __parse(_ParseContext& __ctx, __fields __fields) { + auto __begin = __ctx.begin(); + auto __end = __ctx.end(); if (__begin == __end) return __begin; @@ -302,10 +301,10 @@ class _LIBCPP_TEMPLATE_VIS __parser { if (__fields.__zero_padding_ && __parse_zero_padding(__begin) && __begin == __end) return __begin; - if (__parse_width(__begin, __end, __parse_ctx) && __begin == __end) + if (__parse_width(__begin, __end, __ctx) && __begin == __end) return __begin; - if (__fields.__precision_ && __parse_precision(__begin, __end, __parse_ctx) && __begin == __end) + if (__fields.__precision_ && __parse_precision(__begin, __end, __ctx) && __begin == __end) return __begin; if (__fields.__locale_specific_form_ && __parse_locale_specific_form(__begin) && __begin == __end) @@ -476,12 +475,12 @@ class _LIBCPP_TEMPLATE_VIS __parser { } template - _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_width(_Iterator& __begin, _Iterator __end, auto& __parse_ctx) { + _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_width(_Iterator& __begin, _Iterator __end, auto& __ctx) { if (*__begin == _CharT('0')) std::__throw_format_error("A format-spec width field shouldn't have a leading zero"); if (*__begin == _CharT('{')) { - __format::__parse_number_result __r = __format_spec::__parse_arg_id(++__begin, __end, __parse_ctx); + __format::__parse_number_result __r = __format_spec::__parse_arg_id(++__begin, __end, __ctx); __width_as_arg_ = true; __width_ = __r.__value; __begin = __r.__last; @@ -500,7 +499,7 @@ class _LIBCPP_TEMPLATE_VIS __parser { } template - _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_precision(_Iterator& __begin, _Iterator __end, auto& __parse_ctx) { + _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_precision(_Iterator& __begin, _Iterator __end, auto& __ctx) { if (*__begin != _CharT('.')) return false; @@ -509,7 +508,7 @@ class _LIBCPP_TEMPLATE_VIS __parser { std::__throw_format_error("End of input while parsing format-spec precision"); if (*__begin == _CharT('{')) { - __format::__parse_number_result __arg_id = __format_spec::__parse_arg_id(++__begin, __end, __parse_ctx); + __format::__parse_number_result __arg_id = __format_spec::__parse_arg_id(++__begin, __end, __ctx); __precision_as_arg_ = true; __precision_ = __arg_id.__value; __begin = __arg_id.__last; diff --git a/libcxx/include/__format/range_formatter.h b/libcxx/include/__format/range_formatter.h index 0af233e81580b..8c3fbd7b43b39 100644 --- a/libcxx/include/__format/range_formatter.h +++ b/libcxx/include/__format/range_formatter.h @@ -54,15 +54,15 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter { _LIBCPP_HIDE_FROM_ABI constexpr const formatter<_Tp, _CharT>& underlying() const noexcept { return __underlying_; } template - _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __parse_ctx) { - auto __begin = __parser_.__parse(__parse_ctx, __format_spec::__fields_range); - auto __end = __parse_ctx.end(); + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + auto __begin = __parser_.__parse(__ctx, __format_spec::__fields_range); + auto __end = __ctx.end(); // Note the cases where __begin == __end in this code only happens when the // replacement-field has no terminating }, or when the parse is manually // called with a format-spec. The former is an error and the latter means // using a formatter without the format functions or print. if (__begin == __end) [[unlikely]] - return __parse_empty_range_underlying_spec(__parse_ctx, __begin); + return __parse_empty_range_underlying_spec(__ctx, __begin); // The n field overrides a possible m type, therefore delay applying the // effect of n until the type has been procesed. @@ -72,7 +72,7 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter { if (__begin == __end) [[unlikely]] { // Since there is no more data, clear the brackets before returning. set_brackets({}, {}); - return __parse_empty_range_underlying_spec(__parse_ctx, __begin); + return __parse_empty_range_underlying_spec(__ctx, __begin); } } @@ -80,7 +80,7 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter { if (__clear_brackets) set_brackets({}, {}); if (__begin == __end) [[unlikely]] - return __parse_empty_range_underlying_spec(__parse_ctx, __begin); + return __parse_empty_range_underlying_spec(__ctx, __begin); bool __has_range_underlying_spec = *__begin == _CharT(':'); if (__has_range_underlying_spec) { @@ -95,8 +95,8 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter { // get -} as input which my be valid. std::__throw_format_error("The format-spec should consume the input or end with a '}'"); - __parse_ctx.advance_to(__begin); - __begin = __underlying_.parse(__parse_ctx); + __ctx.advance_to(__begin); + __begin = __underlying_.parse(__ctx); // This test should not be required if __has_range_underlying_spec is false. // However this test makes sure the underlying formatter left the parser in @@ -260,9 +260,9 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter { template _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator - __parse_empty_range_underlying_spec(_ParseContext& __parse_ctx, typename _ParseContext::iterator __begin) { - __parse_ctx.advance_to(__begin); - [[maybe_unused]] typename _ParseContext::iterator __result = __underlying_.parse(__parse_ctx); + __parse_empty_range_underlying_spec(_ParseContext& __ctx, typename _ParseContext::iterator __begin) { + __ctx.advance_to(__begin); + [[maybe_unused]] typename _ParseContext::iterator __result = __underlying_.parse(__ctx); _LIBCPP_ASSERT(__result == __begin, "the underlying's parse function should not advance the input beyond the end of the input"); return __begin; diff --git a/libcxx/include/__iterator/iterator_traits.h b/libcxx/include/__iterator/iterator_traits.h index f066b962e7a54..c0b8dd037544f 100644 --- a/libcxx/include/__iterator/iterator_traits.h +++ b/libcxx/include/__iterator/iterator_traits.h @@ -531,9 +531,6 @@ using __iterator_pointer_type = typename iterator_traits<_Iter>::pointer; template using __iter_diff_t = typename iterator_traits<_Iter>::difference_type; -template -using __iter_value_type = typename iterator_traits<_InputIterator>::value_type; - template using __iter_reference = typename iterator_traits<_Iter>::reference; diff --git a/libcxx/include/__mbstate_t.h b/libcxx/include/__mbstate_t.h index d793787fa0cd6..000af71119f49 100644 --- a/libcxx/include/__mbstate_t.h +++ b/libcxx/include/__mbstate_t.h @@ -27,6 +27,14 @@ // This does not define std::mbstate_t -- this only brings in the declaration // in the global namespace. +// We define this here to support older versions of glibc that do +// not define this for clang. This is also set in libc++'s header, +// and we need to do so here too to avoid a different function signature given +// a different include order. +#ifdef __cplusplus +# define __CORRECT_ISO_CPP_WCHAR_H_PROTO +#endif + #if __has_include() # include // works on most Unixes #elif __has_include() diff --git a/libcxx/include/__pstl/internal/algorithm_fwd.h b/libcxx/include/__pstl/internal/algorithm_fwd.h index 4f6d73103ec81..ba350392c2ac6 100644 --- a/libcxx/include/__pstl/internal/algorithm_fwd.h +++ b/libcxx/include/__pstl/internal/algorithm_fwd.h @@ -10,12 +10,11 @@ #ifndef _PSTL_ALGORITHM_FWD_H #define _PSTL_ALGORITHM_FWD_H +#include <__config> #include #include #include -#include "pstl_config.h" - namespace __pstl { namespace __internal { diff --git a/libcxx/include/__pstl/internal/algorithm_impl.h b/libcxx/include/__pstl/internal/algorithm_impl.h index 1f51651065f2a..c01e5f5c87263 100644 --- a/libcxx/include/__pstl/internal/algorithm_impl.h +++ b/libcxx/include/__pstl/internal/algorithm_impl.h @@ -11,6 +11,7 @@ #define _PSTL_ALGORITHM_IMPL_H #include <__assert> +#include <__config> #include #include #include @@ -22,7 +23,6 @@ #include "parallel_backend.h" #include "parallel_backend_utils.h" #include "parallel_impl.h" -#include "pstl_config.h" #include "unseq_backend_simd.h" namespace __pstl { diff --git a/libcxx/include/__pstl/internal/execution_defs.h b/libcxx/include/__pstl/internal/execution_defs.h index 6abd1ff32938c..5992f0e4a3751 100644 --- a/libcxx/include/__pstl/internal/execution_defs.h +++ b/libcxx/include/__pstl/internal/execution_defs.h @@ -10,12 +10,11 @@ #ifndef _PSTL_EXECUTION_POLICY_DEFS_H #define _PSTL_EXECUTION_POLICY_DEFS_H +#include <__config> #include <__type_traits/decay.h> #include <__type_traits/enable_if.h> #include <__type_traits/integral_constant.h> -#include "pstl_config.h" - #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 namespace __pstl { diff --git a/libcxx/include/__pstl/internal/execution_impl.h b/libcxx/include/__pstl/internal/execution_impl.h index 51ec104db282b..c3a7405d393f1 100644 --- a/libcxx/include/__pstl/internal/execution_impl.h +++ b/libcxx/include/__pstl/internal/execution_impl.h @@ -10,13 +10,15 @@ #ifndef _PSTL_EXECUTION_IMPL_H #define _PSTL_EXECUTION_IMPL_H +#include <__config> #include <__iterator/iterator_traits.h> #include <__type_traits/conditional.h> #include <__type_traits/conjunction.h> +#include <__type_traits/decay.h> +#include <__type_traits/integral_constant.h> #include <__type_traits/is_base_of.h> -#include "execution_defs.h" -#include "pstl_config.h" +#include <__pstl/internal/execution_defs.h> #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__pstl/internal/glue_algorithm_defs.h b/libcxx/include/__pstl/internal/glue_algorithm_defs.h index f751802b47a13..de4501e56b2cf 100644 --- a/libcxx/include/__pstl/internal/glue_algorithm_defs.h +++ b/libcxx/include/__pstl/internal/glue_algorithm_defs.h @@ -10,11 +10,11 @@ #ifndef _PSTL_GLUE_ALGORITHM_DEFS_H #define _PSTL_GLUE_ALGORITHM_DEFS_H +#include <__config> #include #include #include "execution_defs.h" -#include "pstl_config.h" namespace std { @@ -134,29 +134,6 @@ template swap_ranges( _ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2); -// [alg.transform] - -template -__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2> -transform(_ExecutionPolicy&& __exec, - _ForwardIterator1 __first, - _ForwardIterator1 __last, - _ForwardIterator2 __result, - _UnaryOperation __op); - -template -__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator> -transform(_ExecutionPolicy&& __exec, - _ForwardIterator1 __first1, - _ForwardIterator1 __last1, - _ForwardIterator2 __first2, - _ForwardIterator __result, - _BinaryOperation __op); - // [alg.replace] template diff --git a/libcxx/include/__pstl/internal/glue_algorithm_impl.h b/libcxx/include/__pstl/internal/glue_algorithm_impl.h index 3d207185401bd..bae5efa7d0575 100644 --- a/libcxx/include/__pstl/internal/glue_algorithm_impl.h +++ b/libcxx/include/__pstl/internal/glue_algorithm_impl.h @@ -10,10 +10,9 @@ #ifndef _PSTL_GLUE_ALGORITHM_IMPL_H #define _PSTL_GLUE_ALGORITHM_IMPL_H +#include <__config> #include -#include "pstl_config.h" - #include "algorithm_fwd.h" #include "execution_defs.h" #include "numeric_fwd.h" /* count and count_if use __pattern_transform_reduce */ @@ -252,27 +251,6 @@ __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardItera // [alg.transform] -template -__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2> -transform(_ExecutionPolicy&& __exec, - _ForwardIterator1 __first, - _ForwardIterator1 __last, - _ForwardIterator2 __result, - _UnaryOperation __op) { - typedef typename iterator_traits<_ForwardIterator1>::reference _InputType; - typedef typename iterator_traits<_ForwardIterator2>::reference _OutputType; - - auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first, __result); - - return __pstl::__internal::__pattern_walk2( - __dispatch_tag, - std::forward<_ExecutionPolicy>(__exec), - __first, - __last, - __result, - [__op](_InputType __x, _OutputType __y) mutable { __y = __op(__x); }); -} - template + #include "execution_defs.h" -#include "pstl_config.h" namespace std { diff --git a/libcxx/include/__pstl/internal/glue_memory_impl.h b/libcxx/include/__pstl/internal/glue_memory_impl.h index e65d6947dabed..b645ba3fca109 100644 --- a/libcxx/include/__pstl/internal/glue_memory_impl.h +++ b/libcxx/include/__pstl/internal/glue_memory_impl.h @@ -10,7 +10,7 @@ #ifndef _PSTL_GLUE_MEMORY_IMPL_H #define _PSTL_GLUE_MEMORY_IMPL_H -#include "pstl_config.h" +#include <__config> #include "algorithm_fwd.h" #include "execution_defs.h" diff --git a/libcxx/include/__pstl/internal/glue_numeric_defs.h b/libcxx/include/__pstl/internal/glue_numeric_defs.h index 40e0202624735..9ce35e362c5bd 100644 --- a/libcxx/include/__pstl/internal/glue_numeric_defs.h +++ b/libcxx/include/__pstl/internal/glue_numeric_defs.h @@ -10,10 +10,10 @@ #ifndef _PSTL_GLUE_NUMERIC_DEFS_H #define _PSTL_GLUE_NUMERIC_DEFS_H +#include <__config> #include #include "execution_defs.h" -#include "pstl_config.h" namespace std { // [reduce] diff --git a/libcxx/include/__pstl/internal/glue_numeric_impl.h b/libcxx/include/__pstl/internal/glue_numeric_impl.h index 4923191319431..d8666716e8188 100644 --- a/libcxx/include/__pstl/internal/glue_numeric_impl.h +++ b/libcxx/include/__pstl/internal/glue_numeric_impl.h @@ -10,10 +10,9 @@ #ifndef _PSTL_GLUE_NUMERIC_IMPL_H #define _PSTL_GLUE_NUMERIC_IMPL_H +#include <__config> #include -#include "pstl_config.h" - #include "execution_impl.h" #include "numeric_fwd.h" #include "utils.h" diff --git a/libcxx/include/__pstl/internal/memory_impl.h b/libcxx/include/__pstl/internal/memory_impl.h index 1967d5d7b735d..5315ccd9a344a 100644 --- a/libcxx/include/__pstl/internal/memory_impl.h +++ b/libcxx/include/__pstl/internal/memory_impl.h @@ -10,9 +10,9 @@ #ifndef _PSTL_MEMORY_IMPL_H #define _PSTL_MEMORY_IMPL_H +#include <__config> #include -#include "pstl_config.h" #include "unseq_backend_simd.h" namespace __pstl { diff --git a/libcxx/include/__pstl/internal/numeric_fwd.h b/libcxx/include/__pstl/internal/numeric_fwd.h index ccf7b634b2f0f..258a925f663e6 100644 --- a/libcxx/include/__pstl/internal/numeric_fwd.h +++ b/libcxx/include/__pstl/internal/numeric_fwd.h @@ -10,11 +10,10 @@ #ifndef _PSTL_NUMERIC_FWD_H #define _PSTL_NUMERIC_FWD_H +#include <__config> #include #include -#include "pstl_config.h" - namespace __pstl { namespace __internal { diff --git a/libcxx/include/__pstl/internal/numeric_impl.h b/libcxx/include/__pstl/internal/numeric_impl.h index 7c852d7b0825d..f26be1d985e42 100644 --- a/libcxx/include/__pstl/internal/numeric_impl.h +++ b/libcxx/include/__pstl/internal/numeric_impl.h @@ -11,12 +11,12 @@ #define _PSTL_NUMERIC_IMPL_H #include <__assert> +#include <__config> #include #include #include #include "parallel_backend.h" -#include "pstl_config.h" #include "execution_impl.h" #include "unseq_backend_simd.h" #include "algorithm_fwd.h" diff --git a/libcxx/include/__pstl/internal/parallel_backend.h b/libcxx/include/__pstl/internal/parallel_backend.h index a584df17c39ff..9c30ee142746c 100644 --- a/libcxx/include/__pstl/internal/parallel_backend.h +++ b/libcxx/include/__pstl/internal/parallel_backend.h @@ -10,7 +10,7 @@ #ifndef _PSTL_PARALLEL_BACKEND_H #define _PSTL_PARALLEL_BACKEND_H -#include "pstl_config.h" +#include <__config> #if defined(_PSTL_PAR_BACKEND_SERIAL) # include "parallel_backend_serial.h" diff --git a/libcxx/include/__pstl/internal/parallel_backend_serial.h b/libcxx/include/__pstl/internal/parallel_backend_serial.h index 10c0630fbd5d6..b3ecb82175a64 100644 --- a/libcxx/include/__pstl/internal/parallel_backend_serial.h +++ b/libcxx/include/__pstl/internal/parallel_backend_serial.h @@ -10,11 +10,11 @@ #ifndef _PSTL_PARALLEL_BACKEND_SERIAL_H #define _PSTL_PARALLEL_BACKEND_SERIAL_H +#include <__config> #include <__memory/allocator.h> #include <__pstl/internal/execution_impl.h> #include <__utility/forward.h> - -#include "pstl_config.h" +#include #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 @@ -46,18 +46,6 @@ class __buffer _LIBCPP_HIDE_FROM_ABI ~__buffer() { __allocator_.deallocate(__ptr_, __buf_size_); } }; -_LIBCPP_HIDE_FROM_ABI inline void -__cancel_execution() -{ -} - -template -_LIBCPP_HIDE_FROM_ABI void -__parallel_for(__pstl::__internal::__serial_backend_tag, _ExecutionPolicy&&, _Index __first, _Index __last, _Fp __f) -{ - __f(__first, __last); -} - template _LIBCPP_HIDE_FROM_ABI _Value __parallel_reduce(__pstl::__internal::__serial_backend_tag, _ExecutionPolicy&&, _Index __first, _Index __last, diff --git a/libcxx/include/__pstl/internal/parallel_backend_tbb.h b/libcxx/include/__pstl/internal/parallel_backend_tbb.h index 3bee7e2764e1b..41fe9d846017d 100644 --- a/libcxx/include/__pstl/internal/parallel_backend_tbb.h +++ b/libcxx/include/__pstl/internal/parallel_backend_tbb.h @@ -11,10 +11,10 @@ #define _PSTL_PARALLEL_BACKEND_TBB_H #include <__assert> +#include <__config> #include #include -#include "pstl_config.h" #include "parallel_backend_utils.h" // Bring in minimal required subset of Intel TBB diff --git a/libcxx/include/__pstl/internal/parallel_backend_utils.h b/libcxx/include/__pstl/internal/parallel_backend_utils.h index b27d1ef2b1ce4..032a0479ec7e9 100644 --- a/libcxx/include/__pstl/internal/parallel_backend_utils.h +++ b/libcxx/include/__pstl/internal/parallel_backend_utils.h @@ -11,13 +11,12 @@ #define _PSTL_PARALLEL_BACKEND_UTILS_H #include <__assert> +#include <__config> #include <__iterator/iterator_traits.h> #include <__memory/addressof.h> #include "utils.h" -#include "pstl_config.h" - namespace __pstl { diff --git a/libcxx/include/__pstl/internal/parallel_impl.h b/libcxx/include/__pstl/internal/parallel_impl.h deleted file mode 100644 index 19ec508cfa299..0000000000000 --- a/libcxx/include/__pstl/internal/parallel_impl.h +++ /dev/null @@ -1,89 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef _PSTL_PARALLEL_IMPL_H -#define _PSTL_PARALLEL_IMPL_H - -#include "pstl_config.h" - -#include <__atomic/atomic.h> -#include <__atomic/memory_order.h> -#include <__pstl/internal/parallel_backend.h> - -#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 - -namespace __pstl -{ -namespace __internal -{ - -//------------------------------------------------------------------------ -// parallel_find -//----------------------------------------------------------------------- -/** Return extremum value returned by brick f[i,j) for subranges [i,j) of [first,last) -Each f[i,j) must return a value in [i,j). */ -template -_LIBCPP_HIDE_FROM_ABI _Index -__parallel_find(_BackendTag __tag, _ExecutionPolicy&& __exec, _Index __first, _Index __last, _Brick __f, - _Compare __comp, bool __b_first) -{ - typedef typename std::iterator_traits<_Index>::difference_type _DifferenceType; - const _DifferenceType __n = __last - __first; - _DifferenceType __initial_dist = __b_first ? __n : -1; - std::atomic<_DifferenceType> __extremum(__initial_dist); - // TODO: find out what is better here: parallel_for or parallel_reduce - __par_backend::__parallel_for(__tag, std::forward<_ExecutionPolicy>(__exec), __first, __last, - [__comp, __f, __first, &__extremum](_Index __i, _Index __j) - { - // See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of - // why using a shared variable scales fairly well in this situation. - if (__comp(__i - __first, __extremum)) - { - _Index __res = __f(__i, __j); - // If not '__last' returned then we found what we want so put this to extremum - if (__res != __j) - { - const _DifferenceType __k = __res - __first; - for (_DifferenceType __old = __extremum; __comp(__k, __old); - __old = __extremum) - { - __extremum.compare_exchange_weak(__old, __k); - } - } - } - }); - return __extremum != __initial_dist ? __first + __extremum : __last; -} - -//------------------------------------------------------------------------ -// parallel_or -//------------------------------------------------------------------------ -//! Return true if brick f[i,j) returns true for some subrange [i,j) of [first,last) -template -_LIBCPP_HIDE_FROM_ABI -bool __parallel_or(_BackendTag __tag, _ExecutionPolicy&& __exec, _Index __first, _Index __last, _Brick __f) { - std::atomic __found(false); - __par_backend::__parallel_for(__tag, std::forward<_ExecutionPolicy>(__exec), __first, __last, - [__f, &__found](_Index __i, _Index __j) - { - if (!__found.load(std::memory_order_relaxed) && __f(__i, __j)) - { - __found.store(true, std::memory_order_relaxed); - __par_backend::__cancel_execution(); - } - }); - return __found; -} - -} // namespace __internal -} // namespace __pstl - -#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 - -#endif /* _PSTL_PARALLEL_IMPL_H */ diff --git a/libcxx/include/__pstl/internal/pstl_config.h b/libcxx/include/__pstl/internal/pstl_config.h deleted file mode 100644 index 763d1399764a6..0000000000000 --- a/libcxx/include/__pstl/internal/pstl_config.h +++ /dev/null @@ -1,55 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef _PSTL_CONFIG_H -#define _PSTL_CONFIG_H - -#include <__config> - -// TODO: Make this a proper configuration option -#define _PSTL_PAR_BACKEND_SERIAL - -#define _PSTL_PRAGMA(x) _Pragma(# x) - -// Enable SIMD for compilers that support OpenMP 4.0 -#if (defined(_OPENMP) && _OPENMP >= 201307) - -# define _PSTL_UDR_PRESENT -# define _PSTL_PRAGMA_SIMD _PSTL_PRAGMA(omp simd) -# define _PSTL_PRAGMA_DECLARE_SIMD _PSTL_PRAGMA(omp declare simd) -# define _PSTL_PRAGMA_SIMD_REDUCTION(PRM) _PSTL_PRAGMA(omp simd reduction(PRM)) -# define _PSTL_PRAGMA_SIMD_SCAN(PRM) _PSTL_PRAGMA(omp simd reduction(inscan, PRM)) -# define _PSTL_PRAGMA_SIMD_INCLUSIVE_SCAN(PRM) _PSTL_PRAGMA(omp scan inclusive(PRM)) -# define _PSTL_PRAGMA_SIMD_EXCLUSIVE_SCAN(PRM) _PSTL_PRAGMA(omp scan exclusive(PRM)) - -// Declaration of reduction functor, where -// NAME - the name of the functor -// OP - type of the callable object with the reduction operation -// omp_in - refers to the local partial result -// omp_out - refers to the final value of the combiner operator -// omp_priv - refers to the private copy of the initial value -// omp_orig - refers to the original variable to be reduced -# define _PSTL_PRAGMA_DECLARE_REDUCTION(NAME, OP) \ - _PSTL_PRAGMA(omp declare reduction(NAME:OP : omp_out(omp_in)) initializer(omp_priv = omp_orig)) - -#else // (defined(_OPENMP) && _OPENMP >= 201307) - -# define _PSTL_PRAGMA_SIMD -# define _PSTL_PRAGMA_DECLARE_SIMD -# define _PSTL_PRAGMA_SIMD_REDUCTION(PRM) -# define _PSTL_PRAGMA_SIMD_SCAN(PRM) -# define _PSTL_PRAGMA_SIMD_INCLUSIVE_SCAN(PRM) -# define _PSTL_PRAGMA_SIMD_EXCLUSIVE_SCAN(PRM) -# define _PSTL_PRAGMA_DECLARE_REDUCTION(NAME, OP) - -#endif // (defined(_OPENMP) && _OPENMP >= 201307) - -#define _PSTL_USE_NONTEMPORAL_STORES_IF_ALLOWED - -#endif /* _PSTL_CONFIG_H */ diff --git a/libcxx/include/__pstl/internal/unseq_backend_simd.h b/libcxx/include/__pstl/internal/unseq_backend_simd.h index c68a5b99806fa..268ea1d3e5daf 100644 --- a/libcxx/include/__pstl/internal/unseq_backend_simd.h +++ b/libcxx/include/__pstl/internal/unseq_backend_simd.h @@ -10,14 +10,17 @@ #ifndef _PSTL_UNSEQ_BACKEND_SIMD_H #define _PSTL_UNSEQ_BACKEND_SIMD_H +#include <__config> #include <__functional/operations.h> +#include <__iterator/iterator_traits.h> #include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_same.h> +#include <__utility/move.h> #include <__utility/pair.h> #include #include -#include "pstl_config.h" -#include "utils.h" +#include <__pstl/internal/utils.h> // This header defines the minimum set of vector routines required // to support parallel STL. @@ -95,52 +98,6 @@ __simd_or(_Index __first, _DifferenceType __n, _Pred __pred) noexcept return false; } -template -_LIBCPP_HIDE_FROM_ABI _Index -__simd_first(_Index __first, _DifferenceType __begin, _DifferenceType __end, _Compare __comp) noexcept -{ - // Experiments show good block sizes like this - const _DifferenceType __block_size = 8; - alignas(__lane_size) _DifferenceType __lane[__block_size] = {0}; - while (__end - __begin >= __block_size) - { - _DifferenceType __found = 0; - _PSTL_PRAGMA_SIMD_REDUCTION(| - : __found) for (_DifferenceType __i = __begin; __i < __begin + __block_size; - ++__i) - { - const _DifferenceType __t = __comp(__first, __i); - __lane[__i - __begin] = __t; - __found |= __t; - } - if (__found) - { - _DifferenceType __i; - // This will vectorize - for (__i = 0; __i < __block_size; ++__i) - { - if (__lane[__i]) - { - break; - } - } - return __first + __begin + __i; - } - __begin += __block_size; - } - - //Keep remainder scalar - while (__begin != __end) - { - if (__comp(__first, __begin)) - { - return __first + __begin; - } - ++__begin; - } - return __first + __end; -} - template _LIBCPP_HIDE_FROM_ABI std::pair<_Index1, _Index2> __simd_first(_Index1 __first1, _DifferenceType __n, _Index2 __first2, _Pred __pred) noexcept @@ -320,17 +277,6 @@ __simd_partition_by_mask(_InputIterator __first, _DifferenceType __n, _OutputIte } } -template -_LIBCPP_HIDE_FROM_ABI _Index -__simd_fill_n(_Index __first, _DifferenceType __n, const _Tp& __value) noexcept -{ - _PSTL_USE_NONTEMPORAL_STORES_IF_ALLOWED - _PSTL_PRAGMA_SIMD - for (_DifferenceType __i = 0; __i < __n; ++__i) - __first[__i] = __value; - return __first + __n; -} - template _LIBCPP_HIDE_FROM_ABI _Index __simd_generate_n(_Index __first, _DifferenceType __size, _Generator __g) noexcept @@ -513,11 +459,11 @@ __simd_scan(_InputIterator __first, _Size __n, _OutputIterator __result, _UnaryO _CombinerType __combined_init{__init, &__binary_op}; _PSTL_PRAGMA_DECLARE_REDUCTION(__bin_op, _CombinerType) - _PSTL_PRAGMA_SIMD_SCAN(__bin_op : __init_) + _PSTL_PRAGMA_SIMD_SCAN(__bin_op : __combined_init) for (_Size __i = 0; __i < __n; ++__i) { __result[__i] = __combined_init.__value_; - _PSTL_PRAGMA_SIMD_EXCLUSIVE_SCAN(__init_) + _PSTL_PRAGMA_SIMD_EXCLUSIVE_SCAN(__combined_init) __combined_init.__value_ = __binary_op(__combined_init.__value_, __unary_op(__first[__i])); } return std::make_pair(__result + __n, __combined_init.__value_); @@ -553,11 +499,11 @@ __simd_scan(_InputIterator __first, _Size __n, _OutputIterator __result, _UnaryO _CombinerType __combined_init{__init, &__binary_op}; _PSTL_PRAGMA_DECLARE_REDUCTION(__bin_op, _CombinerType) - _PSTL_PRAGMA_SIMD_SCAN(__bin_op : __init_) + _PSTL_PRAGMA_SIMD_SCAN(__bin_op : __combined_init) for (_Size __i = 0; __i < __n; ++__i) { __combined_init.__value_ = __binary_op(__combined_init.__value_, __unary_op(__first[__i])); - _PSTL_PRAGMA_SIMD_INCLUSIVE_SCAN(__init_) + _PSTL_PRAGMA_SIMD_INCLUSIVE_SCAN(__combined_init) __result[__i] = __combined_init.__value_; } return std::make_pair(__result + __n, __combined_init.__value_); diff --git a/libcxx/include/__pstl/internal/utils.h b/libcxx/include/__pstl/internal/utils.h index 6a926663772a3..92c8d48db5b1b 100644 --- a/libcxx/include/__pstl/internal/utils.h +++ b/libcxx/include/__pstl/internal/utils.h @@ -10,8 +10,8 @@ #ifndef _PSTL_UTILS_H #define _PSTL_UTILS_H +#include <__config> #include <__exception/terminate.h> -#include <__pstl/internal/pstl_config.h> #include <__utility/forward.h> #include diff --git a/libcxx/include/__ranges/container_compatible_range.h b/libcxx/include/__ranges/container_compatible_range.h new file mode 100644 index 0000000000000..a58f1119885e3 --- /dev/null +++ b/libcxx/include/__ranges/container_compatible_range.h @@ -0,0 +1,33 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___RANGES_CONTAINER_COMPATIBLE_RANGE_H +#define _LIBCPP___RANGES_CONTAINER_COMPATIBLE_RANGE_H + +#include <__concepts/convertible_to.h> +#include <__config> +#include <__ranges/concepts.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template +concept _ContainerCompatibleRange = + ranges::input_range<_Range> && convertible_to, _Tp>; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___RANGES_CONTAINER_COMPATIBLE_RANGE_H diff --git a/libcxx/include/__ranges/from_range.h b/libcxx/include/__ranges/from_range.h new file mode 100644 index 0000000000000..a6cb9e3d439eb --- /dev/null +++ b/libcxx/include/__ranges/from_range.h @@ -0,0 +1,33 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___RANGES_FROM_RANGE_H +#define _LIBCPP___RANGES_FROM_RANGE_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +struct from_range_t { + explicit from_range_t() = default; +}; + +inline constexpr from_range_t from_range{}; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___RANGES_FROM_RANGE_H diff --git a/libcxx/include/__ranges/iota_view.h b/libcxx/include/__ranges/iota_view.h index 52e8e822f566d..ebfa0220070a5 100644 --- a/libcxx/include/__ranges/iota_view.h +++ b/libcxx/include/__ranges/iota_view.h @@ -336,7 +336,7 @@ namespace ranges { _LIBCPP_HIDE_FROM_ABI constexpr _LIBCPP_EXPLICIT_SINCE_CXX23 iota_view(__iterator __first, __sentinel __last) - requires(!same_as<_Start, _BoundSentinel> && !same_as<_Start, unreachable_sentinel_t>) + requires(!same_as<_Start, _BoundSentinel> && !same_as<_BoundSentinel, unreachable_sentinel_t>) : iota_view(std::move(__first.__value_), std::move(__last.__bound_sentinel_)) {} _LIBCPP_HIDE_FROM_ABI diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer index c4f1315ee5bf2..5efc443a4b340 100644 --- a/libcxx/include/__split_buffer +++ b/libcxx/include/__split_buffer @@ -170,6 +170,14 @@ public: __enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value> __construct_at_end(_ForwardIterator __first, _ForwardIterator __last); + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + void __construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last); + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + void __construct_at_end_with_size(_Iterator __first, size_type __n); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_begin(pointer __new_begin) { __destruct_at_begin(__new_begin, is_trivially_destructible()); } @@ -279,6 +287,13 @@ template _LIBCPP_CONSTEXPR_SINCE_CXX20 __enable_if_t<__is_exactly_cpp17_input_iterator<_InputIter>::value> __split_buffer<_Tp, _Allocator>::__construct_at_end(_InputIter __first, _InputIter __last) { + __construct_at_end_with_sentinel(__first, __last); +} + +template +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 +void __split_buffer<_Tp, _Allocator>::__construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last) { __alloc_rr& __a = this->__alloc(); for (; __first != __last; ++__first) { @@ -296,13 +311,19 @@ __split_buffer<_Tp, _Allocator>::__construct_at_end(_InputIter __first, _InputIt ++this->__end_; } } - template template _LIBCPP_CONSTEXPR_SINCE_CXX20 __enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value> __split_buffer<_Tp, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last) { - _ConstructTransaction __tx(&this->__end_, _VSTD::distance(__first, __last)); + __construct_at_end_with_size(__first, std::distance(__first, __last)); +} + +template +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 +void __split_buffer<_Tp, _Allocator>::__construct_at_end_with_size(_ForwardIterator __first, size_type __n) { + _ConstructTransaction __tx(&this->__end_, __n); for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_, (void) ++__first) { __alloc_traits::construct(this->__alloc(), _VSTD::__to_address(__tx.__pos_), *__first); diff --git a/libcxx/include/__type_traits/is_execution_policy.h b/libcxx/include/__type_traits/is_execution_policy.h index fabc345b6c092..6884f17ba16c8 100644 --- a/libcxx/include/__type_traits/is_execution_policy.h +++ b/libcxx/include/__type_traits/is_execution_policy.h @@ -36,10 +36,21 @@ inline constexpr bool __is_parallel_execution_policy_impl = false; template inline constexpr bool __is_parallel_execution_policy_v = __is_parallel_execution_policy_impl<__remove_cvref_t<_Tp>>; +namespace execution { +struct __disable_user_instantiations_tag { + explicit __disable_user_instantiations_tag() = default; +}; +} // namespace execution + +// TODO: Remove default argument once algorithms are using the new backend dispatching +template +_LIBCPP_HIDE_FROM_ABI auto +__remove_parallel_policy(const _ExecutionPolicy& = _ExecutionPolicy{execution::__disable_user_instantiations_tag{}}); + // Removes the "parallel" part of an execution policy. // For example, turns par_unseq into unseq, and par into seq. template -_LIBCPP_HIDE_FROM_ABI const auto& __remove_parallel_policy(_ExecutionPolicy&&); +using __remove_parallel_policy_t = decltype(std::__remove_parallel_policy<_ExecutionPolicy>()); _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__functional/unwrap_ref.h b/libcxx/include/__type_traits/unwrap_ref.h similarity index 89% rename from libcxx/include/__functional/unwrap_ref.h rename to libcxx/include/__type_traits/unwrap_ref.h index 3abad73ac7f28..94cc8ea722edf 100644 --- a/libcxx/include/__functional/unwrap_ref.h +++ b/libcxx/include/__type_traits/unwrap_ref.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef _LIBCPP___FUNCTIONAL_UNWRAP_REF_H -#define _LIBCPP___FUNCTIONAL_UNWRAP_REF_H +#ifndef _LIBCPP___TYPE_TRAITS_UNWRAP_REF_H +#define _LIBCPP___TYPE_TRAITS_UNWRAP_REF_H #include <__config> #include <__type_traits/decay.h> @@ -42,7 +42,7 @@ struct unwrap_ref_decay : unwrap_reference<__decay_t<_Tp> > { }; template using unwrap_ref_decay_t = typename unwrap_ref_decay<_Tp>::type; -#endif // > C++17 +#endif // _LIBCPP_STD_VER >= 20 template struct __unwrap_ref_decay @@ -55,4 +55,4 @@ struct __unwrap_ref_decay _LIBCPP_END_NAMESPACE_STD -#endif // _LIBCPP___FUNCTIONAL_UNWRAP_REF_H +#endif // _LIBCPP___TYPE_TRAITS_UNWRAP_REF_H diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h index 0d009061575b3..bb4b75ab82d7c 100644 --- a/libcxx/include/__utility/pair.h +++ b/libcxx/include/__utility/pair.h @@ -13,7 +13,6 @@ #include <__compare/synth_three_way.h> #include <__concepts/different_from.h> #include <__config> -#include <__functional/unwrap_ref.h> #include <__fwd/array.h> #include <__fwd/get.h> #include <__fwd/subrange.h> @@ -45,6 +44,7 @@ #include <__type_traits/is_swappable.h> #include <__type_traits/nat.h> #include <__type_traits/remove_cvref.h> +#include <__type_traits/unwrap_ref.h> #include <__utility/declval.h> #include <__utility/forward.h> #include <__utility/move.h> @@ -105,6 +105,20 @@ struct _LIBCPP_TEMPLATE_VIS pair second = __p.second; return *this; } + + // Extension: This is provided in C++03 because it allows properly handling the + // assignment to a pair containing references, which would be a hard + // error otherwise. + template ::value && + is_assignable::value + > > + _LIBCPP_HIDE_FROM_ABI + pair& operator=(pair<_U1, _U2> const& __p) { + first = __p.first; + second = __p.second; + return *this; + } #else struct _CheckArgs { template diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm index 469bf17066281..280333e5b33d6 100644 --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -446,6 +446,18 @@ namespace ranges { indirect_unary_predicate, Proj>> Pred> constexpr bool ranges::none_of(R&& r, Pred pred, Proj proj = {}); // since C++20 + template S1, input_iterator I2, sentinel_for S2, + class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> + requires indirectly_comparable + constexpr bool ranges::starts_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, + Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++23 + + template + requires indirectly_comparable, iterator_t, Pred, Proj1, Proj2> + constexpr bool ranges::starts_with(R1&& r1, R2&& r2, Pred pred = {}, + Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++23 + template S1, random_access_iterator I2, sentinel_for S2, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> @@ -1792,6 +1804,7 @@ template #include <__algorithm/pstl_fill.h> #include <__algorithm/pstl_find.h> #include <__algorithm/pstl_for_each.h> +#include <__algorithm/pstl_transform.h> #include <__algorithm/push_heap.h> #include <__algorithm/ranges_adjacent_find.h> #include <__algorithm/ranges_all_of.h> @@ -1873,6 +1886,7 @@ template #include <__algorithm/ranges_sort_heap.h> #include <__algorithm/ranges_stable_partition.h> #include <__algorithm/ranges_stable_sort.h> +#include <__algorithm/ranges_starts_with.h> #include <__algorithm/ranges_swap_ranges.h> #include <__algorithm/ranges_transform.h> #include <__algorithm/ranges_unique.h> diff --git a/libcxx/include/execution b/libcxx/include/execution index d20fea0f05c89..56facc87379ef 100644 --- a/libcxx/include/execution +++ b/libcxx/include/execution @@ -48,10 +48,6 @@ namespace std { _LIBCPP_BEGIN_NAMESPACE_STD namespace execution { -struct __disable_user_instantiations_tag { - explicit __disable_user_instantiations_tag() = default; -}; - struct sequenced_policy { _LIBCPP_HIDE_FROM_ABI constexpr explicit sequenced_policy(__disable_user_instantiations_tag) {} sequenced_policy(const sequenced_policy&) = delete; @@ -135,12 +131,11 @@ template struct is_execution_policy : bool_constant> {}; template -_LIBCPP_HIDE_FROM_ABI const auto& __remove_parallel_policy(_ExecutionPolicy&&) { - using _ExecPol = __remove_cvref_t<_ExecutionPolicy>; - if constexpr (is_same_v<_ExecPol, execution::parallel_policy>) { - return execution::seq; - } else if constexpr (is_same_v<_ExecPol, execution::parallel_unsequenced_policy>) { - return execution::__unseq; +_LIBCPP_HIDE_FROM_ABI auto __remove_parallel_policy(const _ExecutionPolicy&) { + if constexpr (is_same_v<_ExecutionPolicy, execution::parallel_policy>) { + return execution::sequenced_policy(execution::__disable_user_instantiations_tag{}); + } else if constexpr (is_same_v<_ExecutionPolicy, execution::parallel_unsequenced_policy>) { + return execution::__unsequenced_policy{execution::__disable_user_instantiations_tag{}}; } } diff --git a/libcxx/include/functional b/libcxx/include/functional index 05d42fcff232e..63af88750491f 100644 --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -541,7 +541,7 @@ POLICY: For non-variadic implementations, the number of arguments is limited #include <__functional/reference_wrapper.h> #include <__functional/unary_function.h> #include <__functional/unary_negate.h> -#include <__functional/unwrap_ref.h> +#include <__type_traits/unwrap_ref.h> #include <__utility/forward.h> #include // TODO: find out why removing this breaks the modules build #include diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 3f96e685bdc98..af65d60227af9 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -320,6 +320,30 @@ module std [system] { module partition_point { private header "__algorithm/partition_point.h" } module pop_heap { private header "__algorithm/pop_heap.h" } module prev_permutation { private header "__algorithm/prev_permutation.h" } + module pstl_backends_cpu_backend { + private header "__algorithm/pstl_backends/cpu_backend.h" + export * + } + module pstl_backends_cpu_backends_any_of { + private header "__algorithm/pstl_backends/cpu_backends/any_of.h" + } + module pstl_backends_cpu_backends_backend { + private header "__algorithm/pstl_backends/cpu_backends/backend.h" + export * + } + module pstl_backends_cpu_backends_fill { private header "__algorithm/pstl_backends/cpu_backends/fill.h" } + module pstl_backends_cpu_backends_find_if { + private header "__algorithm/pstl_backends/cpu_backends/find_if.h" + } + module pstl_backends_cpu_backends_for_each { + private header "__algorithm/pstl_backends/cpu_backends/for_each.h" + } + module pstl_backends_cpu_backends_serial { + private header "__algorithm/pstl_backends/cpu_backends/serial.h" + } + module pstl_backends_cpu_backends_transform { + private header "__algorithm/pstl_backends/cpu_backends/transform.h" + } module push_heap { private header "__algorithm/push_heap.h" } module ranges_adjacent_find { private header "__algorithm/ranges_adjacent_find.h" } module ranges_all_of { private header "__algorithm/ranges_all_of.h" } @@ -554,6 +578,7 @@ module std [system] { private header "__algorithm/ranges_stable_sort.h" export functional.__functional.ranges_operations } + module ranges_starts_with { private header "__algorithm/ranges_starts_with.h" } module ranges_swap_ranges { private header "__algorithm/ranges_swap_ranges.h" export algorithm.__algorithm.in_in_result @@ -956,6 +981,8 @@ module std [system] { } module functional { header "functional" + // the contents of __type_traits/unwrap_ref.h should be available from functional too. + export type_traits.unwrap_ref export * module __functional { @@ -989,7 +1016,6 @@ module std [system] { module reference_wrapper { private header "__functional/reference_wrapper.h" } module unary_function { private header "__functional/unary_function.h" } module unary_negate { private header "__functional/unary_negate.h" } - module unwrap_ref { private header "__functional/unwrap_ref.h" } module weak_result_type { private header "__functional/weak_result_type.h" } } } @@ -1309,62 +1335,64 @@ module std [system] { export * module __ranges { - module access { private header "__ranges/access.h" } - module all { + module access { private header "__ranges/access.h" } + module all { private header "__ranges/all.h" export functional.__functional.compose export functional.__functional.perfect_forward } - module as_rvalue_view { private header "__ranges/as_rvalue_view.h" } - module common_view { private header "__ranges/common_view.h" } - module concepts { private header "__ranges/concepts.h" } - module copyable_box { private header "__ranges/copyable_box.h" } - module counted { + module as_rvalue_view { private header "__ranges/as_rvalue_view.h" } + module common_view { private header "__ranges/common_view.h" } + module concepts { private header "__ranges/concepts.h" } + module container_compatible_range { private header "__ranges/container_compatible_range.h" } + module copyable_box { private header "__ranges/copyable_box.h" } + module counted { private header "__ranges/counted.h" export span } - module dangling { private header "__ranges/dangling.h" } - module data { private header "__ranges/data.h" } - module drop_view { private header "__ranges/drop_view.h" } - module drop_while_view { private header "__ranges/drop_while_view.h" } - module elements_view { private header "__ranges/elements_view.h" } - module empty { private header "__ranges/empty.h" } - module empty_view { private header "__ranges/empty_view.h" } - module enable_borrowed_range { private header "__ranges/enable_borrowed_range.h" } - module enable_view { private header "__ranges/enable_view.h" } - module filter_view { private header "__ranges/filter_view.h" } - module iota_view { private header "__ranges/iota_view.h" } - module istream_view { + module dangling { private header "__ranges/dangling.h" } + module data { private header "__ranges/data.h" } + module drop_view { private header "__ranges/drop_view.h" } + module drop_while_view { private header "__ranges/drop_while_view.h" } + module elements_view { private header "__ranges/elements_view.h" } + module empty { private header "__ranges/empty.h" } + module empty_view { private header "__ranges/empty_view.h" } + module enable_borrowed_range { private header "__ranges/enable_borrowed_range.h" } + module enable_view { private header "__ranges/enable_view.h" } + module filter_view { private header "__ranges/filter_view.h" } + module from_range { private header "__ranges/from_range.h" } + module iota_view { private header "__ranges/iota_view.h" } + module istream_view { @requires_LIBCXX_ENABLE_LOCALIZATION@ private header "__ranges/istream_view.h" } - module join_view { private header "__ranges/join_view.h" } - module lazy_split_view { private header "__ranges/lazy_split_view.h" } - module non_propagating_cache { private header "__ranges/non_propagating_cache.h" } - module owning_view { private header "__ranges/owning_view.h" } - module range_adaptor { private header "__ranges/range_adaptor.h" } - module rbegin { private header "__ranges/rbegin.h" } - module ref_view { private header "__ranges/ref_view.h" } - module rend { private header "__ranges/rend.h" } - module reverse_view { private header "__ranges/reverse_view.h" } - module single_view { private header "__ranges/single_view.h" } - module size { private header "__ranges/size.h" } - module split_view { private header "__ranges/split_view.h" } - module subrange { + module join_view { private header "__ranges/join_view.h" } + module lazy_split_view { private header "__ranges/lazy_split_view.h" } + module non_propagating_cache { private header "__ranges/non_propagating_cache.h" } + module owning_view { private header "__ranges/owning_view.h" } + module range_adaptor { private header "__ranges/range_adaptor.h" } + module rbegin { private header "__ranges/rbegin.h" } + module ref_view { private header "__ranges/ref_view.h" } + module rend { private header "__ranges/rend.h" } + module reverse_view { private header "__ranges/reverse_view.h" } + module single_view { private header "__ranges/single_view.h" } + module size { private header "__ranges/size.h" } + module split_view { private header "__ranges/split_view.h" } + module subrange { private header "__ranges/subrange.h" export subrange_fwd } - module subrange_fwd { private header "__fwd/subrange.h" } - module take_view { private header "__ranges/take_view.h" } - module take_while_view { private header "__ranges/take_while_view.h" } - module transform_view { + module subrange_fwd { private header "__fwd/subrange.h" } + module take_view { private header "__ranges/take_view.h" } + module take_while_view { private header "__ranges/take_while_view.h" } + module transform_view { private header "__ranges/transform_view.h" export functional.__functional.bind_back export functional.__functional.perfect_forward } - module view_interface { private header "__ranges/view_interface.h" } - module views { private header "__ranges/views.h" } - module zip_view { private header "__ranges/zip_view.h" } + module view_interface { private header "__ranges/view_interface.h" } + module views { private header "__ranges/views.h" } + module zip_view { private header "__ranges/zip_view.h" } } } module ratio { @@ -1498,7 +1526,6 @@ module std [system] { } module type_traits { header "type_traits" - export functional.__functional.unwrap_ref export * module add_const { private header "__type_traits/add_const.h" } @@ -1659,6 +1686,7 @@ module std [system] { export type_traits } + module unwrap_ref { private header "__type_traits/unwrap_ref.h" } module void_t { private header "__type_traits/void_t.h" } } module typeindex { diff --git a/libcxx/include/ranges b/libcxx/include/ranges index 8f3b4b21f622c..38da82dc7581d 100644 --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -339,6 +339,9 @@ namespace std { struct tuple_element<1, const ranges::subrange> { using type = S; }; + + struct from_range_t { explicit from_range_t() = default; }; // Since C++23 + inline constexpr from_range_t from_range{}; // Since C++23 } */ @@ -360,6 +363,7 @@ namespace std { #include <__ranges/enable_borrowed_range.h> #include <__ranges/enable_view.h> #include <__ranges/filter_view.h> +#include <__ranges/from_range.h> #include <__ranges/iota_view.h> #include <__ranges/join_view.h> #include <__ranges/lazy_split_view.h> diff --git a/libcxx/include/thread b/libcxx/include/thread index 7b3b89c335ae9..33227ff9a216e 100644 --- a/libcxx/include/thread +++ b/libcxx/include/thread @@ -240,12 +240,13 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) template <__fmt_char_type _CharT> struct _LIBCPP_TEMPLATE_VIS formatter<__thread_id, _CharT> { public: - _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - return __parser_.__parse(__parse_ctx, __format_spec::__fields_fill_align_width); + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return __parser_.__parse(__ctx, __format_spec::__fields_fill_align_width); } - _LIBCPP_HIDE_FROM_ABI auto format(__thread_id __id, auto& __ctx) const -> decltype(__ctx.out()) { + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(__thread_id __id, _FormatContext& __ctx) const { // In __threading_support __libcpp_thread_id is either a // unsigned long long or a pthread_t. // diff --git a/libcxx/include/tuple b/libcxx/include/tuple index 3c9715f6f02fe..fe7432f443109 100644 --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -206,7 +206,6 @@ template #include <__compare/synth_three_way.h> #include <__config> #include <__functional/invoke.h> -#include <__functional/unwrap_ref.h> #include <__fwd/array.h> #include <__fwd/tuple.h> #include <__memory/allocator_arg_t.h> @@ -252,6 +251,7 @@ template #include <__type_traits/negation.h> #include <__type_traits/remove_cvref.h> #include <__type_traits/remove_reference.h> +#include <__type_traits/unwrap_ref.h> #include <__utility/forward.h> #include <__utility/integer_sequence.h> #include <__utility/move.h> diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits index 7646f5805980a..a157299481343 100644 --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -532,6 +532,7 @@ namespace std #include <__type_traits/result_of.h> #include <__type_traits/type_identity.h> #include <__type_traits/underlying_type.h> +#include <__type_traits/unwrap_ref.h> #include <__type_traits/void_t.h> #include <__utility/declval.h> #include diff --git a/libcxx/include/vector b/libcxx/include/vector index a1366d0a9c2d9..374a47c7173ca 100644 --- a/libcxx/include/vector +++ b/libcxx/include/vector @@ -41,6 +41,8 @@ public: vector(size_type n, const value_type& value, const allocator_type& = allocator_type()); template vector(InputIterator first, InputIterator last, const allocator_type& = allocator_type()); + template R> + constexpr vector(from_range_t, R&& rg, const Allocator& = Allocator()); // C++23 vector(const vector& x); vector(vector&& x) noexcept(is_nothrow_move_constructible::value); @@ -55,6 +57,8 @@ public: vector& operator=(initializer_list il); template void assign(InputIterator first, InputIterator last); + template R> + constexpr void assign_range(R&& rg); // C++23 void assign(size_type n, const value_type& u); void assign(initializer_list il); @@ -99,6 +103,8 @@ public: void push_back(value_type&& x); template reference emplace_back(Args&&... args); // reference in C++17 + template R> + constexpr void append_range(R&& rg); // C++23 void pop_back(); template iterator emplace(const_iterator position, Args&&... args); @@ -107,6 +113,8 @@ public: iterator insert(const_iterator position, size_type n, const value_type& x); template iterator insert(const_iterator position, InputIterator first, InputIterator last); + template R> + constexpr iterator insert_range(const_iterator position, R&& rg); // C++23 iterator insert(const_iterator position, initializer_list il); iterator erase(const_iterator position); @@ -165,6 +173,8 @@ public: vector(size_type n, const value_type& value, const allocator_type& = allocator_type()); template vector(InputIterator first, InputIterator last, const allocator_type& = allocator_type()); + template R> + constexpr vector(from_range_t, R&& rg, const Allocator& = Allocator()); vector(const vector& x); vector(vector&& x) noexcept(is_nothrow_move_constructible::value); @@ -179,6 +189,8 @@ public: vector& operator=(initializer_list il); template void assign(InputIterator first, InputIterator last); + template R> + constexpr void assign_range(R&& rg); // C++23 void assign(size_type n, const value_type& u); void assign(initializer_list il); @@ -218,6 +230,8 @@ public: void push_back(const value_type& x); template reference emplace_back(Args&&... args); // C++14; reference in C++17 + template R> + constexpr void append_range(R&& rg); // C++23 void pop_back(); template iterator emplace(const_iterator position, Args&&... args); // C++14 @@ -225,6 +239,8 @@ public: iterator insert(const_iterator position, size_type n, const value_type& x); template iterator insert(const_iterator position, InputIterator first, InputIterator last); + template R> + constexpr iterator insert_range(const_iterator position, R&& rg); // C++23 iterator insert(const_iterator position, initializer_list il); iterator erase(const_iterator position); @@ -247,6 +263,10 @@ template vector::value_type, Allocator>; // C++17 +template>> + vector(from_range_t, R&&, Allocator = Allocator()) + -> vector, Allocator>; // C++23 + template struct hash>; template bool operator==(const vector& x, const vector& y); @@ -281,6 +301,7 @@ template requires is-vector-bool-reference // Since C++ #include <__algorithm/copy.h> #include <__algorithm/equal.h> #include <__algorithm/fill_n.h> +#include <__algorithm/iterator_operations.h> #include <__algorithm/lexicographical_compare.h> #include <__algorithm/remove.h> #include <__algorithm/remove_if.h> @@ -297,6 +318,7 @@ template requires is-vector-bool-reference // Since C++ #include <__functional/hash.h> #include <__functional/unary_function.h> #include <__iterator/advance.h> +#include <__iterator/distance.h> #include <__iterator/iterator_traits.h> #include <__iterator/reverse_iterator.h> #include <__iterator/wrap_iter.h> @@ -308,6 +330,11 @@ template requires is-vector-bool-reference // Since C++ #include <__memory/temp_value.h> #include <__memory/uninitialized_algorithms.h> #include <__memory_resource/polymorphic_allocator.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/container_compatible_range.h> +#include <__ranges/from_range.h> +#include <__ranges/size.h> #include <__split_buffer> #include <__type_traits/is_allocator.h> #include <__type_traits/is_constructible.h> @@ -317,6 +344,7 @@ template requires is-vector-bool-reference // Since C++ #include <__utility/exception_guard.h> #include <__utility/forward.h> #include <__utility/move.h> +#include <__utility/pair.h> #include <__utility/swap.h> #include #include @@ -345,7 +373,6 @@ template requires is-vector-bool-reference // Since C++ _LIBCPP_PUSH_MACROS #include <__undef_macros> - _LIBCPP_BEGIN_NAMESPACE_STD template */> @@ -437,6 +464,20 @@ public: _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a); +#if _LIBCPP_STD_VER >= 23 + template <_ContainerCompatibleRange<_Tp> _Range> + _LIBCPP_HIDE_FROM_ABI constexpr vector(from_range_t, _Range&& __range, + const allocator_type& __alloc = allocator_type()) : __end_cap_(nullptr, __alloc) { + if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { + auto __n = static_cast(ranges::distance(__range)); + __init_with_size(ranges::begin(__range), ranges::end(__range), __n); + + } else { + __init_with_sentinel(ranges::begin(__range), ranges::end(__range)); + } + } +#endif + private: class __destroy_vector { public: @@ -502,6 +543,20 @@ public: int> = 0> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void assign(_ForwardIterator __first, _ForwardIterator __last); +#if _LIBCPP_STD_VER >= 23 + template <_ContainerCompatibleRange<_Tp> _Range> + _LIBCPP_HIDE_FROM_ABI + constexpr void assign_range(_Range&& __range) { + if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { + auto __n = static_cast(ranges::distance(__range)); + __assign_with_size(ranges::begin(__range), ranges::end(__range), __n); + + } else { + __assign_with_sentinel(ranges::begin(__range), ranges::end(__range)); + } + } +#endif + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void assign(size_type __n, const_reference __u); #ifndef _LIBCPP_CXX03_LANG @@ -604,6 +659,14 @@ public: void emplace_back(_Args&&... __args); #endif +#if _LIBCPP_STD_VER >= 23 + template <_ContainerCompatibleRange<_Tp> _Range> + _LIBCPP_HIDE_FROM_ABI + constexpr void append_range(_Range&& __range) { + insert_range(end(), std::forward<_Range>(__range)); + } +#endif + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_back(); @@ -623,6 +686,20 @@ public: _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __position, _InputIterator __first, _InputIterator __last); +#if _LIBCPP_STD_VER >= 23 + template <_ContainerCompatibleRange<_Tp> _Range> + _LIBCPP_HIDE_FROM_ABI + constexpr iterator insert_range(const_iterator __position, _Range&& __range) { + if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { + auto __n = static_cast(ranges::distance(__range)); + return __insert_with_size(__position, ranges::begin(__range), ranges::end(__range), __n); + + } else { + return __insert_with_sentinel(__position, ranges::begin(__range), ranges::end(__range)); + } + } +#endif + template < class _ForwardIterator, __enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value && @@ -702,9 +779,51 @@ private: _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(size_type __n, const_reference __x); - template ::value, int> = 0> - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void - __construct_at_end(_ForwardIterator __first, _ForwardIterator __last, size_type __n); + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + void __init_with_size(_InputIterator __first, _Sentinel __last, size_type __n) { + auto __guard = std::__make_exception_guard(__destroy_vector(*this)); + std::__debug_db_insert_c(this); + + if (__n > 0) { + __vallocate(__n); + __construct_at_end(__first, __last, __n); + } + + __guard.__complete(); + } + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + void __init_with_sentinel(_InputIterator __first, _Sentinel __last) { + auto __guard = std::__make_exception_guard(__destroy_vector(*this)); + std::__debug_db_insert_c(this); + + for (; __first != __last; ++__first) + emplace_back(*__first); + + __guard.__complete(); + } + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + void __assign_with_sentinel(_Iterator __first, _Sentinel __last); + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + void __assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __n); + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + iterator __insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last); + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + iterator __insert_with_size(const_iterator __position, _Iterator __first, _Sentinel __last, difference_type __n); + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + void __construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n); _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __append(size_type __n); _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __append(size_type __n, const_reference __x); @@ -911,6 +1030,15 @@ vector(_InputIterator, _InputIterator, _Alloc) -> vector<__iter_value_type<_InputIterator>, _Alloc>; #endif +#if _LIBCPP_STD_VER >= 23 +template >, + class = enable_if_t<__is_allocator<_Alloc>::value> + > +vector(from_range_t, _Range&&, _Alloc = _Alloc()) + -> vector, _Alloc>; +#endif + template _LIBCPP_CONSTEXPR_SINCE_CXX20 void @@ -1026,10 +1154,9 @@ vector<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x) } template -template ::value, int> > +template _LIBCPP_CONSTEXPR_SINCE_CXX20 void -vector<_Tp, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last, size_type __n) -{ +vector<_Tp, _Allocator>::__construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n) { _ConstructTransaction __tx(*this, __n); __tx.__pos_ = std::__uninitialized_allocator_copy(__alloc(), __first, __last, __tx.__pos_); } @@ -1126,11 +1253,7 @@ template ::vector(_InputIterator __first, _InputIterator __last) { - auto __guard = std::__make_exception_guard(__destroy_vector(*this)); - std::__debug_db_insert_c(this); - for (; __first != __last; ++__first) - emplace_back(*__first); - __guard.__complete(); + __init_with_sentinel(__first, __last); } template @@ -1141,11 +1264,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<_Tp, _Allocator>::vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a) : __end_cap_(nullptr, __a) { - auto __guard = std::__make_exception_guard(__destroy_vector(*this)); - std::__debug_db_insert_c(this); - for (; __first != __last; ++__first) - emplace_back(*__first); - __guard.__complete(); + __init_with_sentinel(__first, __last); } template @@ -1155,15 +1274,8 @@ template ::vector(_ForwardIterator __first, _ForwardIterator __last) { - auto __guard = std::__make_exception_guard(__destroy_vector(*this)); - std::__debug_db_insert_c(this); - size_type __n = static_cast(std::distance(__first, __last)); - if (__n > 0) - { - __vallocate(__n); - __construct_at_end(__first, __last, __n); - } - __guard.__complete(); + size_type __n = static_cast(std::distance(__first, __last)); + __init_with_size(__first, __last, __n); } template @@ -1174,15 +1286,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a) : __end_cap_(nullptr, __a) { - auto __guard = std::__make_exception_guard(__destroy_vector(*this)); - std::__debug_db_insert_c(this); - size_type __n = static_cast(std::distance(__first, __last)); - if (__n > 0) - { - __vallocate(__n); - __construct_at_end(__first, __last, __n); - } - __guard.__complete(); + size_type __n = static_cast(std::distance(__first, __last)); + __init_with_size(__first, __last, __n); } template @@ -1190,15 +1295,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<_Tp, _Allocator>::vector(const vector& __x) : __end_cap_(nullptr, __alloc_traits::select_on_container_copy_construction(__x.__alloc())) { - auto __guard = std::__make_exception_guard(__destroy_vector(*this)); - std::__debug_db_insert_c(this); - size_type __n = __x.size(); - if (__n > 0) - { - __vallocate(__n); - __construct_at_end(__x.__begin_, __x.__end_, __n); - } - __guard.__complete(); + __init_with_size(__x.__begin_, __x.__end_, __x.size()); } template @@ -1206,15 +1303,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<_Tp, _Allocator>::vector(const vector& __x, const __type_identity_t& __a) : __end_cap_(nullptr, __a) { - auto __guard = std::__make_exception_guard(__destroy_vector(*this)); - std::__debug_db_insert_c(this); - size_type __n = __x.size(); - if (__n > 0) - { - __vallocate(__n); - __construct_at_end(__x.__begin_, __x.__end_, __n); - } - __guard.__complete(); + __init_with_size(__x.__begin_, __x.__end_, __x.size()); } template @@ -1358,6 +1447,13 @@ template ::assign(_InputIterator __first, _InputIterator __last) { + __assign_with_sentinel(__first, __last); +} + +template +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI +void vector<_Tp, _Allocator>::__assign_with_sentinel(_Iterator __first, _Sentinel __last) { clear(); for (; __first != __last; ++__first) emplace_back(*__first); @@ -1370,22 +1466,27 @@ template ::assign(_ForwardIterator __first, _ForwardIterator __last) { - size_type __new_size = static_cast(std::distance(__first, __last)); + __assign_with_size(__first, __last, std::distance(__first, __last)); +} + +template +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI +void vector<_Tp, _Allocator>::__assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __n) { + size_type __new_size = static_cast(__n); if (__new_size <= capacity()) { - _ForwardIterator __mid = __last; - bool __growing = false; if (__new_size > size()) { - __growing = true; - __mid = __first; - std::advance(__mid, size()); - } - pointer __m = std::copy(__first, __mid, this->__begin_); - if (__growing) + _ForwardIterator __mid = std::next(__first, size()); + std::copy(__first, __mid, this->__begin_); __construct_at_end(__mid, __last, __new_size - size()); + } else + { + pointer __m = std::__copy<_ClassicAlgPolicy>(__first, __last, this->__begin_).second; this->__destruct_at_end(__m); + } } else { @@ -1815,7 +1916,6 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, size_type __n, const_ } return __make_iter(__p); } - template template ::value && is_constructible<_Tp, typename iterator_traits<_InputIterator>::reference>::value, @@ -1823,8 +1923,17 @@ template ::iterator vector<_Tp, _Allocator>::insert(const_iterator __position, _InputIterator __first, _InputIterator __last) { - _LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(std::addressof(__position)) == this, - "vector::insert(iterator, range) called with an iterator not referring to this vector"); + return __insert_with_sentinel(__position, __first, __last); +} + +template +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI +typename vector<_Tp, _Allocator>::iterator +vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last) { + _LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(std::addressof(__position)) == this, + "vector::insert called with an iterator not referring to this vector"); + difference_type __off = __position - begin(); pointer __p = this->__begin_ + __off; allocator_type& __a = this->__alloc(); @@ -1840,7 +1949,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, _InputIterator __firs try { #endif // _LIBCPP_HAS_NO_EXCEPTIONS - __v.__construct_at_end(__first, __last); + __v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last)); difference_type __old_size = __old_last - this->__begin_; difference_type __old_p = __p - this->__begin_; reserve(__recommend(size() + __v.size())); @@ -1868,17 +1977,27 @@ template ::iterator vector<_Tp, _Allocator>::insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last) { + return __insert_with_size(__position, __first, __last, std::distance(__first, __last)); +} + +template +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) { _LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(std::addressof(__position)) == this, - "vector::insert(iterator, range) called with an iterator not referring to this vector"); + "vector::insert called with an iterator not referring to this vector"); + + auto __insertion_size = __n; pointer __p = this->__begin_ + (__position - begin()); - difference_type __n = std::distance(__first, __last); if (__n > 0) { if (__n <= this->__end_cap() - this->__end_) { size_type __old_n = __n; pointer __old_last = this->__end_; - _ForwardIterator __m = __last; + _Iterator __m = std::next(__first, __n); difference_type __dx = this->__end_ - __p; if (__n > __dx) { @@ -1898,7 +2017,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, _ForwardIterator __fi { allocator_type& __a = this->__alloc(); __split_buffer __v(__recommend(size() + __n), __p - this->__begin_, __a); - __v.__construct_at_end(__first, __last); + __v.__construct_at_end_with_size(__first, __insertion_size); __p = __swap_out_circular_buffer(__v, __p); } } @@ -2146,6 +2265,23 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a, typename enable_if<__is_cpp17_forward_iterator<_ForwardIterator>::value>::type* = 0); +#if _LIBCPP_STD_VER >= 23 + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI constexpr + vector(from_range_t, _Range&& __range, const allocator_type& __a = allocator_type()) + : __begin_(nullptr), + __size_(0), + __cap_alloc_(0, static_cast<__storage_allocator>(__a)) { + if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { + auto __n = static_cast(ranges::distance(__range)); + __init_with_size(ranges::begin(__range), ranges::end(__range), __n); + + } else { + __init_with_sentinel(ranges::begin(__range), ranges::end(__range)); + } + } +#endif + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector(const vector& __v); _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector(const vector& __v, const allocator_type& __a); _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector& operator=(const vector& __v); @@ -2185,6 +2321,20 @@ public: >::type _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 assign(_ForwardIterator __first, _ForwardIterator __last); +#if _LIBCPP_STD_VER >= 23 + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI + constexpr void assign_range(_Range&& __range) { + if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { + auto __n = static_cast(ranges::distance(__range)); + __assign_with_size(ranges::begin(__range), ranges::end(__range), __n); + + } else { + __assign_with_sentinel(ranges::begin(__range), ranges::end(__range)); + } + } +#endif + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void assign(size_type __n, const value_type& __x); #ifndef _LIBCPP_CXX03_LANG @@ -2274,6 +2424,14 @@ public: } #endif +#if _LIBCPP_STD_VER >= 23 + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI + constexpr void append_range(_Range&& __range) { + insert_range(end(), std::forward<_Range>(__range)); + } +#endif + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void pop_back() {--__size_;} #if _LIBCPP_STD_VER >= 14 @@ -2297,6 +2455,20 @@ public: >::type _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last); +#if _LIBCPP_STD_VER >= 23 + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI + constexpr iterator insert_range(const_iterator __position, _Range&& __range) { + if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { + auto __n = static_cast(ranges::distance(__range)); + return __insert_with_size(__position, ranges::begin(__range), ranges::end(__range), __n); + + } else { + return __insert_with_sentinel(__position, ranges::begin(__range), ranges::end(__range)); + } + } +#endif + #ifndef _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator insert(const_iterator __position, initializer_list __il) @@ -2334,6 +2506,53 @@ private: std::__throw_out_of_range("vector"); } + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + void __init_with_size(_InputIterator __first, _Sentinel __last, size_type __n) { + auto __guard = std::__make_exception_guard(__destroy_vector(*this)); + + if (__n > 0) { + __vallocate(__n); + __construct_at_end(std::move(__first), std::move(__last), __n); + } + + __guard.__complete(); + } + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + void __init_with_sentinel(_InputIterator __first, _Sentinel __last) { +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + try { +#endif // _LIBCPP_HAS_NO_EXCEPTIONS + for (; __first != __last; ++__first) + push_back(*__first); +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + } catch (...) { + if (__begin_ != nullptr) + __storage_traits::deallocate(__alloc(), __begin_, __cap()); + std::__debug_db_invalidate_all(this); + throw; + } +#endif // _LIBCPP_HAS_NO_EXCEPTIONS + } + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + void __assign_with_sentinel(_Iterator __first, _Sentinel __last); + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + void __assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __ns); + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + iterator __insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last); + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + iterator __insert_with_size(const_iterator __position, _Iterator __first, _Sentinel __last, difference_type __n); + // Allocate space for __n objects // throws length_error if __n > max_size() // throws (probably bad_alloc) if memory run out @@ -2360,13 +2579,9 @@ private: {return (__new_size + (__bits_per_word-1)) & ~((size_type)__bits_per_word-1);} _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __recommend(size_type __new_size) const; _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_at_end(size_type __n, bool __x); - template - typename enable_if - < - __is_cpp17_forward_iterator<_ForwardIterator>::value, - void - >::type - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __construct_at_end(_ForwardIterator __first, _ForwardIterator __last); + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + void __construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n); _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __append(size_type __n, const_reference __x); _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference __make_ref(size_type __pos) _NOEXCEPT @@ -2496,17 +2711,11 @@ vector::__construct_at_end(size_type __n, bool __x) } template -template +template _LIBCPP_CONSTEXPR_SINCE_CXX20 -typename enable_if -< - __is_cpp17_forward_iterator<_ForwardIterator>::value, - void ->::type -vector::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last) -{ +void vector::__construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n) { size_type __old_size = this->__size_; - this->__size_ += std::distance(__first, __last); + this->__size_ += __n; if (__old_size == 0 || ((__old_size - 1) / __bits_per_word) != ((this->__size_ - 1) / __bits_per_word)) { if (this->__size_ <= __bits_per_word) @@ -2514,7 +2723,7 @@ vector::__construct_at_end(_ForwardIterator __first, _ForwardI else this->__begin_[(this->__size_ - 1) / __bits_per_word] = __storage_type(0); } - std::copy(__first, __last, __make_iter(__old_size)); + std::__copy<_ClassicAlgPolicy>(__first, __last, __make_iter(__old_size)); } template @@ -2608,22 +2817,7 @@ vector::vector(_InputIterator __first, _InputIterator __last, __size_(0), __cap_alloc_(0, __default_init_tag()) { -#ifndef _LIBCPP_HAS_NO_EXCEPTIONS - try - { -#endif // _LIBCPP_HAS_NO_EXCEPTIONS - for (; __first != __last; ++__first) - push_back(*__first); -#ifndef _LIBCPP_HAS_NO_EXCEPTIONS - } - catch (...) - { - if (__begin_ != nullptr) - __storage_traits::deallocate(__alloc(), __begin_, __cap()); - std::__debug_db_invalidate_all(this); - throw; - } -#endif // _LIBCPP_HAS_NO_EXCEPTIONS + __init_with_sentinel(__first, __last); } template @@ -2635,22 +2829,7 @@ vector::vector(_InputIterator __first, _InputIterator __last, __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) { -#ifndef _LIBCPP_HAS_NO_EXCEPTIONS - try - { -#endif // _LIBCPP_HAS_NO_EXCEPTIONS - for (; __first != __last; ++__first) - push_back(*__first); -#ifndef _LIBCPP_HAS_NO_EXCEPTIONS - } - catch (...) - { - if (__begin_ != nullptr) - __storage_traits::deallocate(__alloc(), __begin_, __cap()); - std::__debug_db_invalidate_all(this); - throw; - } -#endif // _LIBCPP_HAS_NO_EXCEPTIONS + __init_with_sentinel(__first, __last); } template @@ -2662,14 +2841,8 @@ vector::vector(_ForwardIterator __first, _ForwardIterator __la __size_(0), __cap_alloc_(0, __default_init_tag()) { - auto __guard = std::__make_exception_guard(__destroy_vector(*this)); - size_type __n = static_cast(std::distance(__first, __last)); - if (__n > 0) - { - __vallocate(__n); - __construct_at_end(__first, __last); - } - __guard.__complete(); + auto __n = static_cast(std::distance(__first, __last)); + __init_with_size(__first, __last, __n); } template @@ -2681,14 +2854,8 @@ vector::vector(_ForwardIterator __first, _ForwardIterator __la __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) { - auto __guard = std::__make_exception_guard(__destroy_vector(*this)); - size_type __n = static_cast(std::distance(__first, __last)); - if (__n > 0) - { - __vallocate(__n); - __construct_at_end(__first, __last); - } - __guard.__complete(); + auto __n = static_cast(std::distance(__first, __last)); + __init_with_size(__first, __last, __n); } #ifndef _LIBCPP_CXX03_LANG @@ -2704,7 +2871,7 @@ vector::vector(initializer_list __il) if (__n > 0) { __vallocate(__n); - __construct_at_end(__il.begin(), __il.end()); + __construct_at_end(__il.begin(), __il.end(), __n); } } @@ -2719,7 +2886,7 @@ vector::vector(initializer_list __il, const alloca if (__n > 0) { __vallocate(__n); - __construct_at_end(__il.begin(), __il.end()); + __construct_at_end(__il.begin(), __il.end(), __n); } } @@ -2735,7 +2902,7 @@ vector::vector(const vector& __v) if (__v.size() > 0) { __vallocate(__v.size()); - __construct_at_end(__v.begin(), __v.end()); + __construct_at_end(__v.begin(), __v.end(), __v.size()); } } @@ -2749,7 +2916,7 @@ vector::vector(const vector& __v, const allocator_type& __a) if (__v.size() > 0) { __vallocate(__v.size()); - __construct_at_end(__v.begin(), __v.end()); + __construct_at_end(__v.begin(), __v.end(), __v.size()); } } @@ -2808,7 +2975,7 @@ vector::vector(vector&& __v, const __type_identity_t 0) { __vallocate(__v.size()); - __construct_at_end(__v.begin(), __v.end()); + __construct_at_end(__v.begin(), __v.end(), __v.size()); } } @@ -2876,6 +3043,13 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 typename enable_if <__is_exactly_cpp17_input_itera >::type vector::assign(_InputIterator __first, _InputIterator __last) { + __assign_with_sentinel(__first, __last); +} + +template +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI +void vector::__assign_with_sentinel(_Iterator __first, _Sentinel __last) { clear(); for (; __first != __last; ++__first) push_back(*__first); @@ -2891,9 +3065,17 @@ typename enable_if >::type vector::assign(_ForwardIterator __first, _ForwardIterator __last) { - clear(); - difference_type __ns = std::distance(__first, __last); + __assign_with_size(__first, __last, std::distance(__first, __last)); +} + +template +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI +void vector::__assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __ns) { _LIBCPP_ASSERT(__ns >= 0, "invalid range specified"); + + clear(); + const size_t __n = static_cast(__ns); if (__n) { @@ -2902,7 +3084,7 @@ vector::assign(_ForwardIterator __first, _ForwardIterator __la __vdeallocate(); __vallocate(__n); } - __construct_at_end(__first, __last); + __construct_at_end(__first, __last, __n); } } @@ -2916,7 +3098,7 @@ vector::reserve(size_type __n) this->__throw_length_error(); vector __v(this->get_allocator()); __v.__vallocate(__n); - __v.__construct_at_end(this->begin(), this->end()); + __v.__construct_at_end(this->begin(), this->end(), this->size()); swap(__v); std::__debug_db_invalidate_all(this); } @@ -3028,6 +3210,14 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 typename enable_if <__is_exactly_cpp17_input_itera >::type vector::insert(const_iterator __position, _InputIterator __first, _InputIterator __last) { + return __insert_with_sentinel(__position, __first, __last); +} + +template +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI +typename vector::iterator +vector::__insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last) { difference_type __off = __position - begin(); iterator __p = __const_iterator_cast(__position); iterator __old_end = end(); @@ -3043,7 +3233,7 @@ vector::insert(const_iterator __position, _InputIterator __fir try { #endif // _LIBCPP_HAS_NO_EXCEPTIONS - __v.assign(__first, __last); + __v.__assign_with_sentinel(std::move(__first), std::move(__last)); difference_type __old_size = static_cast(__old_end - begin()); difference_type __old_p = __p - begin(); reserve(__recommend(size() + __v.size())); @@ -3073,7 +3263,15 @@ typename enable_if >::type vector::insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last) { - const difference_type __n_signed = std::distance(__first, __last); + return __insert_with_size(__position, __first, __last, std::distance(__first, __last)); +} + +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) { _LIBCPP_ASSERT(__n_signed >= 0, "invalid range specified"); const size_type __n = static_cast(__n_signed); iterator __r; @@ -3094,7 +3292,7 @@ vector::insert(const_iterator __position, _ForwardIterator __f std::copy_backward(__position, cend(), __v.end()); swap(__v); } - std::copy(__first, __last, __r); + std::__copy<_ClassicAlgPolicy>(__first, __last, __r); return __r; } diff --git a/libcxx/include/wchar.h b/libcxx/include/wchar.h index db624cea2bee3..eeccf3e937ff6 100644 --- a/libcxx/include/wchar.h +++ b/libcxx/include/wchar.h @@ -116,6 +116,8 @@ size_t wcsrtombs(char* restrict dst, const wchar_t** restrict src, size_t len, # pragma GCC system_header #endif +// We define this here to support older versions of glibc that do +// not define this for clang. #ifdef __cplusplus #define __CORRECT_ISO_CPP_WCHAR_H_PROTO #endif diff --git a/libcxx/test/libcxx/algorithms/alg.sorting/assert.sort.invalid_comparator.pass.cpp b/libcxx/test/libcxx/algorithms/alg.sorting/assert.sort.invalid_comparator.pass.cpp new file mode 100644 index 0000000000000..570a6e1d1e5ed --- /dev/null +++ b/libcxx/test/libcxx/algorithms/alg.sorting/assert.sort.invalid_comparator.pass.cpp @@ -0,0 +1,152 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: stdlib=libc++ + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// This test uses a specific combination of an invalid comparator and sequence of values to +// ensure that our sorting functions do not go out-of-bounds in that case. Instead, we should +// fail loud with an assertion. The specific issue we're looking for here is when the comparator +// does not satisfy the following property: +// +// comp(a, b) implies that !comp(b, a) +// +// In other words, +// +// a < b implies that !(b < a) +// +// If this is not satisfied, we have seen issues in the past where the std::sort implementation +// would proceed to do OOB reads. + +// When the debug mode is enabled, this test fails because we actually catch that the comparator +// is not a strict-weak ordering before we catch that we'd dereference out-of-bounds inside std::sort, +// which leads to different errors than the ones tested below. +// XFAIL: libcpp-has-debug-mode + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "check_assertion.h" + +std::string DATA = +# include "bad_comparator_values.dat" +; + +int main(int, char**) { + std::map> comparison_results; // terrible for performance, but really convenient + for (auto line : std::views::split(DATA, '\n') | std::views::filter([](auto const& line) { return !line.empty(); })) { + auto values = std::views::split(line, ' '); + auto it = values.begin(); + std::size_t left = std::stol(std::string((*it).data(), (*it).size())); + it = std::next(it); + std::size_t right = std::stol(std::string((*it).data(), (*it).size())); + it = std::next(it); + bool result = static_cast(std::stol(std::string((*it).data(), (*it).size()))); + comparison_results[left][right] = result; + } + auto predicate = [&](std::size_t* left, std::size_t* right) { + assert(left != nullptr && right != nullptr && "something is wrong with the test"); + assert(comparison_results.contains(*left) && comparison_results[*left].contains(*right) && "malformed input data?"); + return comparison_results[*left][*right]; + }; + + std::vector> elements; + std::set valid_ptrs; + for (std::size_t i = 0; i != comparison_results.size(); ++i) { + elements.push_back(std::make_unique(i)); + valid_ptrs.insert(elements.back().get()); + } + + auto checked_predicate = [&](size_t* left, size_t* right) { + // If the pointers passed to the comparator are not in the set of pointers we + // set up above, then we're being passed garbage values from the algorithm + // because we're reading OOB. + assert(valid_ptrs.contains(left)); + assert(valid_ptrs.contains(right)); + return predicate(left, right); + }; + + // Check the classic sorting algorithms + { + std::vector copy; + for (auto const& e : elements) + copy.push_back(e.get()); + TEST_LIBCPP_ASSERT_FAILURE(std::sort(copy.begin(), copy.end(), checked_predicate), "Would read out of bounds"); + } + { + std::vector copy; + for (auto const& e : elements) + copy.push_back(e.get()); + std::stable_sort(copy.begin(), copy.end(), checked_predicate); // doesn't go OOB even with invalid comparator + } + { + std::vector copy; + for (auto const& e : elements) + copy.push_back(e.get()); + std::partial_sort(copy.begin(), copy.begin(), copy.end(), checked_predicate); // doesn't go OOB even with invalid comparator + } + { + std::vector copy; + for (auto const& e : elements) + copy.push_back(e.get()); + std::vector results(copy.size(), nullptr); + std::partial_sort_copy(copy.begin(), copy.end(), results.begin(), results.end(), checked_predicate); // doesn't go OOB even with invalid comparator + } + { + std::vector copy; + for (auto const& e : elements) + copy.push_back(e.get()); + std::nth_element(copy.begin(), copy.end(), copy.end(), checked_predicate); // doesn't go OOB even with invalid comparator + } + + // Check the Ranges sorting algorithms + { + std::vector copy; + for (auto const& e : elements) + copy.push_back(e.get()); + TEST_LIBCPP_ASSERT_FAILURE(std::ranges::sort(copy, checked_predicate), "Would read out of bounds"); + } + { + std::vector copy; + for (auto const& e : elements) + copy.push_back(e.get()); + std::ranges::stable_sort(copy, checked_predicate); // doesn't go OOB even with invalid comparator + } + { + std::vector copy; + for (auto const& e : elements) + copy.push_back(e.get()); + std::ranges::partial_sort(copy, copy.begin(), checked_predicate); // doesn't go OOB even with invalid comparator + } + { + std::vector copy; + for (auto const& e : elements) + copy.push_back(e.get()); + std::vector results(copy.size(), nullptr); + std::ranges::partial_sort_copy(copy, results, checked_predicate); // doesn't go OOB even with invalid comparator + } + { + std::vector copy; + for (auto const& e : elements) + copy.push_back(e.get()); + std::ranges::nth_element(copy, copy.end(), checked_predicate); // doesn't go OOB even with invalid comparator + } + + return 0; +} diff --git a/libcxx/test/libcxx/algorithms/alg.sorting/bad_comparator_values.dat b/libcxx/test/libcxx/algorithms/alg.sorting/bad_comparator_values.dat new file mode 100644 index 0000000000000..05a4b21d2db98 --- /dev/null +++ b/libcxx/test/libcxx/algorithms/alg.sorting/bad_comparator_values.dat @@ -0,0 +1,3483 @@ +R"( +0 0 0 +0 1 1 +0 2 1 +0 3 1 +0 4 1 +0 5 1 +0 6 1 +0 7 1 +0 8 1 +0 9 1 +0 10 1 +0 11 1 +0 12 1 +0 13 1 +0 14 1 +0 15 1 +0 16 1 +0 17 1 +0 18 1 +0 19 1 +0 20 1 +0 21 1 +0 22 1 +0 23 1 +0 24 1 +0 25 1 +0 26 1 +0 27 1 +0 28 1 +0 29 1 +0 30 1 +0 31 1 +0 32 1 +0 33 1 +0 34 1 +0 35 1 +0 36 1 +0 37 1 +0 38 1 +0 39 1 +0 40 1 +0 41 1 +0 42 1 +0 43 1 +0 44 1 +0 45 1 +0 46 1 +0 47 1 +0 48 1 +0 49 1 +0 50 1 +0 51 1 +0 52 1 +0 53 1 +0 54 1 +0 55 1 +0 56 1 +0 57 1 +0 58 1 +1 0 0 +1 1 0 +1 2 1 +1 3 1 +1 4 1 +1 5 1 +1 6 1 +1 7 1 +1 8 1 +1 9 1 +1 10 1 +1 11 1 +1 12 1 +1 13 1 +1 14 1 +1 15 1 +1 16 1 +1 17 1 +1 18 1 +1 19 1 +1 20 1 +1 21 1 +1 22 1 +1 23 1 +1 24 1 +1 25 1 +1 26 1 +1 27 1 +1 28 1 +1 29 1 +1 30 1 +1 31 1 +1 32 1 +1 33 1 +1 34 1 +1 35 1 +1 36 1 +1 37 1 +1 38 1 +1 39 1 +1 40 1 +1 41 1 +1 42 1 +1 43 1 +1 44 1 +1 45 1 +1 46 1 +1 47 1 +1 48 1 +1 49 1 +1 50 1 +1 51 1 +1 52 1 +1 53 1 +1 54 1 +1 55 1 +1 56 1 +1 57 1 +1 58 1 +2 0 0 +2 1 0 +2 2 0 +2 3 1 +2 4 1 +2 5 1 +2 6 1 +2 7 1 +2 8 1 +2 9 1 +2 10 1 +2 11 1 +2 12 1 +2 13 1 +2 14 1 +2 15 1 +2 16 1 +2 17 1 +2 18 1 +2 19 1 +2 20 1 +2 21 1 +2 22 1 +2 23 1 +2 24 1 +2 25 1 +2 26 1 +2 27 1 +2 28 1 +2 29 1 +2 30 1 +2 31 1 +2 32 1 +2 33 1 +2 34 1 +2 35 1 +2 36 1 +2 37 1 +2 38 1 +2 39 1 +2 40 1 +2 41 1 +2 42 1 +2 43 1 +2 44 1 +2 45 1 +2 46 1 +2 47 1 +2 48 1 +2 49 1 +2 50 1 +2 51 1 +2 52 1 +2 53 1 +2 54 1 +2 55 1 +2 56 1 +2 57 1 +2 58 1 +3 0 0 +3 1 0 +3 2 0 +3 3 0 +3 4 1 +3 5 1 +3 6 1 +3 7 1 +3 8 1 +3 9 1 +3 10 1 +3 11 1 +3 12 1 +3 13 1 +3 14 1 +3 15 1 +3 16 1 +3 17 1 +3 18 1 +3 19 1 +3 20 1 +3 21 1 +3 22 1 +3 23 1 +3 24 1 +3 25 1 +3 26 1 +3 27 1 +3 28 1 +3 29 1 +3 30 1 +3 31 1 +3 32 1 +3 33 1 +3 34 1 +3 35 1 +3 36 1 +3 37 1 +3 38 1 +3 39 1 +3 40 1 +3 41 1 +3 42 1 +3 43 1 +3 44 1 +3 45 1 +3 46 1 +3 47 1 +3 48 1 +3 49 1 +3 50 1 +3 51 1 +3 52 1 +3 53 1 +3 54 1 +3 55 1 +3 56 1 +3 57 1 +3 58 1 +4 0 0 +4 1 0 +4 2 0 +4 3 0 +4 4 0 +4 5 1 +4 6 1 +4 7 1 +4 8 1 +4 9 1 +4 10 1 +4 11 1 +4 12 1 +4 13 1 +4 14 1 +4 15 1 +4 16 1 +4 17 1 +4 18 1 +4 19 1 +4 20 1 +4 21 1 +4 22 1 +4 23 1 +4 24 1 +4 25 1 +4 26 1 +4 27 1 +4 28 1 +4 29 1 +4 30 1 +4 31 1 +4 32 1 +4 33 1 +4 34 1 +4 35 1 +4 36 1 +4 37 1 +4 38 1 +4 39 1 +4 40 1 +4 41 1 +4 42 1 +4 43 1 +4 44 1 +4 45 1 +4 46 1 +4 47 1 +4 48 1 +4 49 1 +4 50 1 +4 51 1 +4 52 1 +4 53 1 +4 54 1 +4 55 1 +4 56 1 +4 57 1 +4 58 1 +5 0 0 +5 1 0 +5 2 0 +5 3 0 +5 4 0 +5 5 0 +5 6 1 +5 7 1 +5 8 1 +5 9 1 +5 10 1 +5 11 1 +5 12 1 +5 13 1 +5 14 1 +5 15 1 +5 16 1 +5 17 1 +5 18 1 +5 19 1 +5 20 1 +5 21 1 +5 22 1 +5 23 1 +5 24 1 +5 25 1 +5 26 1 +5 27 1 +5 28 1 +5 29 1 +5 30 1 +5 31 1 +5 32 1 +5 33 1 +5 34 1 +5 35 1 +5 36 1 +5 37 1 +5 38 1 +5 39 1 +5 40 1 +5 41 1 +5 42 1 +5 43 1 +5 44 1 +5 45 1 +5 46 1 +5 47 1 +5 48 1 +5 49 1 +5 50 1 +5 51 1 +5 52 1 +5 53 1 +5 54 1 +5 55 1 +5 56 1 +5 57 1 +5 58 1 +6 0 0 +6 1 0 +6 2 0 +6 3 0 +6 4 0 +6 5 0 +6 6 0 +6 7 1 +6 8 1 +6 9 1 +6 10 1 +6 11 1 +6 12 1 +6 13 1 +6 14 1 +6 15 1 +6 16 1 +6 17 1 +6 18 1 +6 19 1 +6 20 1 +6 21 1 +6 22 1 +6 23 1 +6 24 1 +6 25 1 +6 26 1 +6 27 1 +6 28 1 +6 29 1 +6 30 1 +6 31 1 +6 32 1 +6 33 1 +6 34 1 +6 35 1 +6 36 1 +6 37 1 +6 38 1 +6 39 1 +6 40 1 +6 41 1 +6 42 1 +6 43 1 +6 44 1 +6 45 1 +6 46 1 +6 47 1 +6 48 1 +6 49 1 +6 50 1 +6 51 1 +6 52 1 +6 53 1 +6 54 1 +6 55 1 +6 56 1 +6 57 1 +6 58 1 +7 0 0 +7 1 0 +7 2 0 +7 3 0 +7 4 0 +7 5 0 +7 6 0 +7 7 0 +7 8 1 +7 9 1 +7 10 1 +7 11 1 +7 12 1 +7 13 1 +7 14 1 +7 15 1 +7 16 1 +7 17 1 +7 18 1 +7 19 1 +7 20 1 +7 21 1 +7 22 1 +7 23 1 +7 24 1 +7 25 1 +7 26 1 +7 27 1 +7 28 1 +7 29 1 +7 30 1 +7 31 1 +7 32 1 +7 33 1 +7 34 1 +7 35 1 +7 36 1 +7 37 1 +7 38 1 +7 39 1 +7 40 1 +7 41 1 +7 42 1 +7 43 1 +7 44 1 +7 45 1 +7 46 1 +7 47 1 +7 48 1 +7 49 1 +7 50 1 +7 51 1 +7 52 1 +7 53 1 +7 54 1 +7 55 1 +7 56 1 +7 57 1 +7 58 1 +8 0 0 +8 1 0 +8 2 0 +8 3 0 +8 4 0 +8 5 0 +8 6 0 +8 7 0 +8 8 0 +8 9 1 +8 10 1 +8 11 1 +8 12 1 +8 13 1 +8 14 1 +8 15 1 +8 16 1 +8 17 1 +8 18 1 +8 19 1 +8 20 1 +8 21 1 +8 22 1 +8 23 1 +8 24 1 +8 25 1 +8 26 1 +8 27 1 +8 28 1 +8 29 1 +8 30 1 +8 31 1 +8 32 1 +8 33 1 +8 34 1 +8 35 1 +8 36 1 +8 37 1 +8 38 1 +8 39 1 +8 40 1 +8 41 1 +8 42 1 +8 43 1 +8 44 1 +8 45 1 +8 46 1 +8 47 1 +8 48 1 +8 49 1 +8 50 1 +8 51 1 +8 52 1 +8 53 1 +8 54 1 +8 55 1 +8 56 1 +8 57 1 +8 58 1 +9 0 0 +9 1 0 +9 2 0 +9 3 0 +9 4 0 +9 5 0 +9 6 0 +9 7 0 +9 8 0 +9 9 0 +9 10 1 +9 11 1 +9 12 1 +9 13 1 +9 14 1 +9 15 1 +9 16 1 +9 17 1 +9 18 1 +9 19 1 +9 20 1 +9 21 1 +9 22 1 +9 23 1 +9 24 1 +9 25 1 +9 26 1 +9 27 1 +9 28 1 +9 29 1 +9 30 1 +9 31 1 +9 32 1 +9 33 1 +9 34 1 +9 35 1 +9 36 1 +9 37 1 +9 38 1 +9 39 1 +9 40 1 +9 41 1 +9 42 1 +9 43 1 +9 44 1 +9 45 1 +9 46 1 +9 47 1 +9 48 1 +9 49 1 +9 50 1 +9 51 1 +9 52 1 +9 53 1 +9 54 1 +9 55 1 +9 56 1 +9 57 1 +9 58 1 +10 0 0 +10 1 0 +10 2 0 +10 3 0 +10 4 0 +10 5 0 +10 6 0 +10 7 0 +10 8 0 +10 9 0 +10 10 0 +10 11 1 +10 12 1 +10 13 1 +10 14 1 +10 15 1 +10 16 1 +10 17 1 +10 18 1 +10 19 1 +10 20 1 +10 21 1 +10 22 1 +10 23 1 +10 24 1 +10 25 1 +10 26 1 +10 27 1 +10 28 1 +10 29 1 +10 30 1 +10 31 1 +10 32 1 +10 33 1 +10 34 1 +10 35 1 +10 36 1 +10 37 1 +10 38 1 +10 39 1 +10 40 1 +10 41 1 +10 42 1 +10 43 1 +10 44 1 +10 45 1 +10 46 1 +10 47 1 +10 48 1 +10 49 1 +10 50 1 +10 51 1 +10 52 1 +10 53 1 +10 54 1 +10 55 1 +10 56 1 +10 57 1 +10 58 1 +11 0 0 +11 1 0 +11 2 0 +11 3 0 +11 4 0 +11 5 0 +11 6 0 +11 7 0 +11 8 0 +11 9 0 +11 10 0 +11 11 0 +11 12 1 +11 13 1 +11 14 1 +11 15 1 +11 16 1 +11 17 1 +11 18 1 +11 19 1 +11 20 1 +11 21 1 +11 22 1 +11 23 1 +11 24 1 +11 25 1 +11 26 1 +11 27 1 +11 28 1 +11 29 1 +11 30 1 +11 31 1 +11 32 1 +11 33 1 +11 34 1 +11 35 1 +11 36 1 +11 37 1 +11 38 1 +11 39 1 +11 40 1 +11 41 1 +11 42 1 +11 43 1 +11 44 1 +11 45 1 +11 46 1 +11 47 1 +11 48 1 +11 49 1 +11 50 1 +11 51 1 +11 52 1 +11 53 1 +11 54 1 +11 55 1 +11 56 1 +11 57 1 +11 58 1 +12 0 0 +12 1 0 +12 2 0 +12 3 0 +12 4 0 +12 5 0 +12 6 0 +12 7 0 +12 8 0 +12 9 0 +12 10 0 +12 11 0 +12 12 0 +12 13 1 +12 14 1 +12 15 1 +12 16 1 +12 17 1 +12 18 1 +12 19 1 +12 20 1 +12 21 1 +12 22 1 +12 23 1 +12 24 1 +12 25 1 +12 26 1 +12 27 1 +12 28 1 +12 29 1 +12 30 1 +12 31 1 +12 32 1 +12 33 1 +12 34 1 +12 35 1 +12 36 1 +12 37 1 +12 38 1 +12 39 1 +12 40 1 +12 41 1 +12 42 1 +12 43 1 +12 44 1 +12 45 1 +12 46 1 +12 47 1 +12 48 1 +12 49 1 +12 50 1 +12 51 1 +12 52 1 +12 53 1 +12 54 1 +12 55 1 +12 56 1 +12 57 1 +12 58 1 +13 0 0 +13 1 0 +13 2 0 +13 3 0 +13 4 0 +13 5 0 +13 6 0 +13 7 0 +13 8 0 +13 9 0 +13 10 0 +13 11 0 +13 12 0 +13 13 0 +13 14 1 +13 15 1 +13 16 1 +13 17 1 +13 18 1 +13 19 1 +13 20 1 +13 21 1 +13 22 1 +13 23 1 +13 24 1 +13 25 1 +13 26 1 +13 27 1 +13 28 1 +13 29 1 +13 30 1 +13 31 1 +13 32 1 +13 33 1 +13 34 1 +13 35 1 +13 36 1 +13 37 1 +13 38 1 +13 39 1 +13 40 1 +13 41 1 +13 42 1 +13 43 1 +13 44 1 +13 45 1 +13 46 1 +13 47 1 +13 48 1 +13 49 1 +13 50 1 +13 51 1 +13 52 1 +13 53 1 +13 54 1 +13 55 1 +13 56 1 +13 57 1 +13 58 1 +14 0 0 +14 1 0 +14 2 0 +14 3 0 +14 4 0 +14 5 0 +14 6 0 +14 7 0 +14 8 0 +14 9 0 +14 10 0 +14 11 0 +14 12 0 +14 13 0 +14 14 0 +14 15 1 +14 16 1 +14 17 1 +14 18 1 +14 19 1 +14 20 1 +14 21 1 +14 22 1 +14 23 1 +14 24 1 +14 25 1 +14 26 1 +14 27 1 +14 28 1 +14 29 1 +14 30 1 +14 31 1 +14 32 1 +14 33 1 +14 34 1 +14 35 1 +14 36 1 +14 37 1 +14 38 1 +14 39 1 +14 40 1 +14 41 1 +14 42 1 +14 43 1 +14 44 1 +14 45 1 +14 46 1 +14 47 1 +14 48 1 +14 49 1 +14 50 1 +14 51 1 +14 52 1 +14 53 1 +14 54 1 +14 55 1 +14 56 1 +14 57 1 +14 58 1 +15 0 0 +15 1 0 +15 2 0 +15 3 0 +15 4 0 +15 5 0 +15 6 0 +15 7 0 +15 8 0 +15 9 0 +15 10 0 +15 11 0 +15 12 0 +15 13 0 +15 14 0 +15 15 0 +15 16 1 +15 17 1 +15 18 1 +15 19 1 +15 20 1 +15 21 1 +15 22 1 +15 23 1 +15 24 1 +15 25 1 +15 26 1 +15 27 1 +15 28 1 +15 29 1 +15 30 1 +15 31 1 +15 32 1 +15 33 1 +15 34 1 +15 35 1 +15 36 1 +15 37 1 +15 38 1 +15 39 1 +15 40 1 +15 41 1 +15 42 1 +15 43 1 +15 44 1 +15 45 1 +15 46 1 +15 47 1 +15 48 1 +15 49 1 +15 50 1 +15 51 1 +15 52 1 +15 53 1 +15 54 1 +15 55 1 +15 56 1 +15 57 1 +15 58 1 +16 0 0 +16 1 0 +16 2 0 +16 3 0 +16 4 0 +16 5 0 +16 6 0 +16 7 0 +16 8 0 +16 9 0 +16 10 0 +16 11 0 +16 12 0 +16 13 0 +16 14 0 +16 15 0 +16 16 0 +16 17 1 +16 18 1 +16 19 1 +16 20 1 +16 21 1 +16 22 1 +16 23 1 +16 24 1 +16 25 1 +16 26 1 +16 27 1 +16 28 1 +16 29 1 +16 30 1 +16 31 1 +16 32 1 +16 33 1 +16 34 1 +16 35 1 +16 36 1 +16 37 1 +16 38 1 +16 39 1 +16 40 1 +16 41 1 +16 42 1 +16 43 1 +16 44 1 +16 45 1 +16 46 1 +16 47 1 +16 48 1 +16 49 1 +16 50 1 +16 51 1 +16 52 1 +16 53 1 +16 54 1 +16 55 1 +16 56 1 +16 57 1 +16 58 1 +17 0 0 +17 1 0 +17 2 0 +17 3 0 +17 4 0 +17 5 0 +17 6 0 +17 7 0 +17 8 0 +17 9 0 +17 10 0 +17 11 0 +17 12 0 +17 13 0 +17 14 0 +17 15 0 +17 16 0 +17 17 0 +17 18 1 +17 19 1 +17 20 1 +17 21 1 +17 22 1 +17 23 1 +17 24 1 +17 25 1 +17 26 1 +17 27 1 +17 28 1 +17 29 1 +17 30 1 +17 31 1 +17 32 1 +17 33 1 +17 34 1 +17 35 1 +17 36 1 +17 37 1 +17 38 1 +17 39 1 +17 40 1 +17 41 1 +17 42 1 +17 43 1 +17 44 1 +17 45 1 +17 46 1 +17 47 1 +17 48 1 +17 49 1 +17 50 1 +17 51 1 +17 52 1 +17 53 1 +17 54 1 +17 55 1 +17 56 1 +17 57 1 +17 58 1 +18 0 0 +18 1 0 +18 2 0 +18 3 0 +18 4 0 +18 5 0 +18 6 0 +18 7 0 +18 8 0 +18 9 0 +18 10 0 +18 11 0 +18 12 0 +18 13 0 +18 14 0 +18 15 0 +18 16 0 +18 17 0 +18 18 0 +18 19 1 +18 20 1 +18 21 1 +18 22 1 +18 23 1 +18 24 1 +18 25 1 +18 26 1 +18 27 1 +18 28 1 +18 29 1 +18 30 1 +18 31 1 +18 32 1 +18 33 1 +18 34 1 +18 35 1 +18 36 1 +18 37 1 +18 38 1 +18 39 1 +18 40 1 +18 41 1 +18 42 1 +18 43 1 +18 44 1 +18 45 1 +18 46 1 +18 47 1 +18 48 1 +18 49 1 +18 50 1 +18 51 1 +18 52 1 +18 53 1 +18 54 1 +18 55 1 +18 56 1 +18 57 1 +18 58 1 +19 0 0 +19 1 0 +19 2 0 +19 3 0 +19 4 0 +19 5 0 +19 6 0 +19 7 0 +19 8 0 +19 9 0 +19 10 0 +19 11 0 +19 12 0 +19 13 0 +19 14 0 +19 15 0 +19 16 0 +19 17 0 +19 18 0 +19 19 0 +19 20 1 +19 21 1 +19 22 1 +19 23 1 +19 24 1 +19 25 1 +19 26 1 +19 27 1 +19 28 1 +19 29 1 +19 30 1 +19 31 1 +19 32 1 +19 33 1 +19 34 1 +19 35 1 +19 36 1 +19 37 1 +19 38 1 +19 39 1 +19 40 1 +19 41 1 +19 42 1 +19 43 1 +19 44 1 +19 45 1 +19 46 1 +19 47 1 +19 48 1 +19 49 1 +19 50 1 +19 51 1 +19 52 1 +19 53 1 +19 54 1 +19 55 1 +19 56 1 +19 57 1 +19 58 1 +20 0 0 +20 1 0 +20 2 0 +20 3 0 +20 4 0 +20 5 0 +20 6 0 +20 7 0 +20 8 0 +20 9 0 +20 10 0 +20 11 0 +20 12 0 +20 13 0 +20 14 0 +20 15 0 +20 16 0 +20 17 0 +20 18 0 +20 19 0 +20 20 0 +20 21 1 +20 22 1 +20 23 1 +20 24 1 +20 25 1 +20 26 1 +20 27 1 +20 28 1 +20 29 1 +20 30 1 +20 31 1 +20 32 1 +20 33 1 +20 34 1 +20 35 1 +20 36 1 +20 37 1 +20 38 1 +20 39 1 +20 40 1 +20 41 1 +20 42 1 +20 43 1 +20 44 1 +20 45 1 +20 46 1 +20 47 1 +20 48 1 +20 49 1 +20 50 1 +20 51 1 +20 52 1 +20 53 1 +20 54 1 +20 55 1 +20 56 1 +20 57 1 +20 58 1 +21 0 0 +21 1 0 +21 2 0 +21 3 0 +21 4 0 +21 5 0 +21 6 0 +21 7 0 +21 8 0 +21 9 0 +21 10 0 +21 11 0 +21 12 0 +21 13 0 +21 14 0 +21 15 0 +21 16 0 +21 17 0 +21 18 0 +21 19 0 +21 20 0 +21 21 0 +21 22 1 +21 23 1 +21 24 1 +21 25 1 +21 26 1 +21 27 1 +21 28 1 +21 29 1 +21 30 1 +21 31 1 +21 32 1 +21 33 1 +21 34 1 +21 35 1 +21 36 1 +21 37 1 +21 38 1 +21 39 1 +21 40 1 +21 41 1 +21 42 1 +21 43 1 +21 44 1 +21 45 1 +21 46 1 +21 47 1 +21 48 1 +21 49 1 +21 50 1 +21 51 1 +21 52 1 +21 53 1 +21 54 1 +21 55 1 +21 56 1 +21 57 1 +21 58 1 +22 0 0 +22 1 0 +22 2 0 +22 3 0 +22 4 0 +22 5 0 +22 6 0 +22 7 0 +22 8 0 +22 9 0 +22 10 0 +22 11 0 +22 12 0 +22 13 0 +22 14 0 +22 15 0 +22 16 0 +22 17 0 +22 18 0 +22 19 0 +22 20 0 +22 21 0 +22 22 0 +22 23 1 +22 24 1 +22 25 1 +22 26 1 +22 27 1 +22 28 1 +22 29 1 +22 30 1 +22 31 1 +22 32 1 +22 33 1 +22 34 1 +22 35 1 +22 36 1 +22 37 1 +22 38 1 +22 39 1 +22 40 1 +22 41 1 +22 42 1 +22 43 1 +22 44 1 +22 45 1 +22 46 1 +22 47 1 +22 48 1 +22 49 1 +22 50 1 +22 51 1 +22 52 1 +22 53 1 +22 54 1 +22 55 1 +22 56 1 +22 57 1 +22 58 1 +23 0 0 +23 1 0 +23 2 0 +23 3 0 +23 4 0 +23 5 0 +23 6 0 +23 7 0 +23 8 0 +23 9 0 +23 10 0 +23 11 0 +23 12 0 +23 13 0 +23 14 0 +23 15 0 +23 16 0 +23 17 0 +23 18 0 +23 19 0 +23 20 0 +23 21 0 +23 22 0 +23 23 0 +23 24 1 +23 25 1 +23 26 1 +23 27 1 +23 28 1 +23 29 1 +23 30 1 +23 31 1 +23 32 1 +23 33 1 +23 34 1 +23 35 1 +23 36 1 +23 37 1 +23 38 1 +23 39 1 +23 40 1 +23 41 1 +23 42 1 +23 43 1 +23 44 1 +23 45 1 +23 46 1 +23 47 1 +23 48 1 +23 49 1 +23 50 1 +23 51 1 +23 52 1 +23 53 1 +23 54 1 +23 55 1 +23 56 1 +23 57 1 +23 58 1 +24 0 0 +24 1 0 +24 2 0 +24 3 0 +24 4 0 +24 5 0 +24 6 0 +24 7 0 +24 8 0 +24 9 0 +24 10 0 +24 11 0 +24 12 0 +24 13 0 +24 14 0 +24 15 0 +24 16 0 +24 17 0 +24 18 0 +24 19 0 +24 20 0 +24 21 0 +24 22 0 +24 23 0 +24 24 0 +24 25 1 +24 26 1 +24 27 1 +24 28 1 +24 29 1 +24 30 1 +24 31 1 +24 32 1 +24 33 1 +24 34 1 +24 35 1 +24 36 1 +24 37 1 +24 38 1 +24 39 1 +24 40 1 +24 41 1 +24 42 1 +24 43 1 +24 44 1 +24 45 1 +24 46 1 +24 47 1 +24 48 1 +24 49 1 +24 50 1 +24 51 1 +24 52 1 +24 53 1 +24 54 1 +24 55 1 +24 56 1 +24 57 1 +24 58 1 +25 0 0 +25 1 0 +25 2 0 +25 3 0 +25 4 0 +25 5 0 +25 6 0 +25 7 0 +25 8 0 +25 9 0 +25 10 0 +25 11 0 +25 12 0 +25 13 0 +25 14 0 +25 15 0 +25 16 0 +25 17 0 +25 18 0 +25 19 0 +25 20 0 +25 21 0 +25 22 0 +25 23 0 +25 24 0 +25 25 0 +25 26 1 +25 27 1 +25 28 1 +25 29 1 +25 30 1 +25 31 1 +25 32 1 +25 33 1 +25 34 1 +25 35 1 +25 36 1 +25 37 1 +25 38 1 +25 39 1 +25 40 1 +25 41 1 +25 42 1 +25 43 1 +25 44 1 +25 45 1 +25 46 1 +25 47 1 +25 48 1 +25 49 1 +25 50 1 +25 51 1 +25 52 1 +25 53 1 +25 54 1 +25 55 1 +25 56 1 +25 57 1 +25 58 1 +26 0 0 +26 1 0 +26 2 0 +26 3 0 +26 4 0 +26 5 0 +26 6 0 +26 7 0 +26 8 0 +26 9 0 +26 10 0 +26 11 0 +26 12 0 +26 13 0 +26 14 0 +26 15 0 +26 16 0 +26 17 0 +26 18 0 +26 19 0 +26 20 0 +26 21 0 +26 22 0 +26 23 0 +26 24 0 +26 25 0 +26 26 0 +26 27 1 +26 28 1 +26 29 1 +26 30 1 +26 31 1 +26 32 1 +26 33 1 +26 34 1 +26 35 1 +26 36 1 +26 37 1 +26 38 1 +26 39 1 +26 40 1 +26 41 1 +26 42 1 +26 43 1 +26 44 1 +26 45 1 +26 46 1 +26 47 1 +26 48 1 +26 49 1 +26 50 1 +26 51 1 +26 52 1 +26 53 1 +26 54 1 +26 55 1 +26 56 1 +26 57 1 +26 58 1 +27 0 0 +27 1 0 +27 2 0 +27 3 0 +27 4 0 +27 5 0 +27 6 0 +27 7 0 +27 8 0 +27 9 0 +27 10 0 +27 11 0 +27 12 0 +27 13 0 +27 14 0 +27 15 0 +27 16 0 +27 17 0 +27 18 0 +27 19 0 +27 20 0 +27 21 0 +27 22 0 +27 23 0 +27 24 0 +27 25 0 +27 26 0 +27 27 0 +27 28 1 +27 29 1 +27 30 1 +27 31 1 +27 32 1 +27 33 1 +27 34 1 +27 35 1 +27 36 1 +27 37 1 +27 38 1 +27 39 1 +27 40 1 +27 41 1 +27 42 1 +27 43 1 +27 44 1 +27 45 1 +27 46 1 +27 47 1 +27 48 1 +27 49 1 +27 50 1 +27 51 1 +27 52 1 +27 53 1 +27 54 1 +27 55 1 +27 56 1 +27 57 1 +27 58 1 +28 0 0 +28 1 0 +28 2 0 +28 3 0 +28 4 0 +28 5 0 +28 6 0 +28 7 0 +28 8 0 +28 9 0 +28 10 0 +28 11 0 +28 12 0 +28 13 0 +28 14 0 +28 15 0 +28 16 0 +28 17 0 +28 18 0 +28 19 0 +28 20 0 +28 21 0 +28 22 0 +28 23 0 +28 24 0 +28 25 0 +28 26 0 +28 27 0 +28 28 0 +28 29 1 +28 30 0 +28 31 0 +28 32 0 +28 33 0 +28 34 0 +28 35 0 +28 36 0 +28 37 0 +28 38 0 +28 39 0 +28 40 0 +28 41 0 +28 42 0 +28 43 0 +28 44 0 +28 45 0 +28 46 0 +28 47 0 +28 48 0 +28 49 0 +28 50 0 +28 51 0 +28 52 0 +28 53 0 +28 54 0 +28 55 0 +28 56 0 +28 57 0 +28 58 0 +29 0 0 +29 1 0 +29 2 0 +29 3 0 +29 4 0 +29 5 0 +29 6 0 +29 7 0 +29 8 0 +29 9 0 +29 10 0 +29 11 0 +29 12 0 +29 13 0 +29 14 0 +29 15 0 +29 16 0 +29 17 0 +29 18 0 +29 19 0 +29 20 0 +29 21 0 +29 22 0 +29 23 0 +29 24 0 +29 25 0 +29 26 0 +29 27 0 +29 28 1 +29 29 0 +29 30 1 +29 31 0 +29 32 0 +29 33 0 +29 34 0 +29 35 0 +29 36 0 +29 37 0 +29 38 0 +29 39 0 +29 40 0 +29 41 0 +29 42 0 +29 43 0 +29 44 0 +29 45 0 +29 46 0 +29 47 0 +29 48 0 +29 49 0 +29 50 0 +29 51 0 +29 52 0 +29 53 0 +29 54 0 +29 55 0 +29 56 0 +29 57 0 +29 58 0 +30 0 0 +30 1 0 +30 2 0 +30 3 0 +30 4 0 +30 5 0 +30 6 0 +30 7 0 +30 8 0 +30 9 0 +30 10 0 +30 11 0 +30 12 0 +30 13 0 +30 14 0 +30 15 0 +30 16 0 +30 17 0 +30 18 0 +30 19 0 +30 20 0 +30 21 0 +30 22 0 +30 23 0 +30 24 0 +30 25 0 +30 26 0 +30 27 0 +30 28 1 +30 29 1 +30 30 0 +30 31 1 +30 32 0 +30 33 0 +30 34 0 +30 35 0 +30 36 0 +30 37 0 +30 38 0 +30 39 0 +30 40 0 +30 41 0 +30 42 0 +30 43 0 +30 44 0 +30 45 0 +30 46 0 +30 47 0 +30 48 0 +30 49 0 +30 50 0 +30 51 0 +30 52 0 +30 53 0 +30 54 0 +30 55 0 +30 56 0 +30 57 0 +30 58 0 +31 0 0 +31 1 0 +31 2 0 +31 3 0 +31 4 0 +31 5 0 +31 6 0 +31 7 0 +31 8 0 +31 9 0 +31 10 0 +31 11 0 +31 12 0 +31 13 0 +31 14 0 +31 15 0 +31 16 0 +31 17 0 +31 18 0 +31 19 0 +31 20 0 +31 21 0 +31 22 0 +31 23 0 +31 24 0 +31 25 0 +31 26 0 +31 27 0 +31 28 1 +31 29 1 +31 30 1 +31 31 0 +31 32 1 +31 33 0 +31 34 0 +31 35 0 +31 36 0 +31 37 0 +31 38 0 +31 39 0 +31 40 0 +31 41 0 +31 42 0 +31 43 0 +31 44 0 +31 45 0 +31 46 0 +31 47 0 +31 48 0 +31 49 0 +31 50 0 +31 51 0 +31 52 0 +31 53 0 +31 54 0 +31 55 0 +31 56 0 +31 57 0 +31 58 0 +32 0 0 +32 1 0 +32 2 0 +32 3 0 +32 4 0 +32 5 0 +32 6 0 +32 7 0 +32 8 0 +32 9 0 +32 10 0 +32 11 0 +32 12 0 +32 13 0 +32 14 0 +32 15 0 +32 16 0 +32 17 0 +32 18 0 +32 19 0 +32 20 0 +32 21 0 +32 22 0 +32 23 0 +32 24 0 +32 25 0 +32 26 0 +32 27 0 +32 28 1 +32 29 1 +32 30 1 +32 31 1 +32 32 0 +32 33 1 +32 34 0 +32 35 0 +32 36 0 +32 37 0 +32 38 0 +32 39 0 +32 40 0 +32 41 0 +32 42 0 +32 43 0 +32 44 0 +32 45 0 +32 46 0 +32 47 0 +32 48 0 +32 49 0 +32 50 0 +32 51 0 +32 52 0 +32 53 0 +32 54 0 +32 55 0 +32 56 0 +32 57 0 +32 58 0 +33 0 0 +33 1 0 +33 2 0 +33 3 0 +33 4 0 +33 5 0 +33 6 0 +33 7 0 +33 8 0 +33 9 0 +33 10 0 +33 11 0 +33 12 0 +33 13 0 +33 14 0 +33 15 0 +33 16 0 +33 17 0 +33 18 0 +33 19 0 +33 20 0 +33 21 0 +33 22 0 +33 23 0 +33 24 0 +33 25 0 +33 26 0 +33 27 0 +33 28 1 +33 29 1 +33 30 1 +33 31 1 +33 32 1 +33 33 0 +33 34 1 +33 35 0 +33 36 0 +33 37 0 +33 38 0 +33 39 0 +33 40 0 +33 41 0 +33 42 0 +33 43 0 +33 44 0 +33 45 0 +33 46 0 +33 47 0 +33 48 0 +33 49 0 +33 50 0 +33 51 0 +33 52 0 +33 53 0 +33 54 0 +33 55 0 +33 56 0 +33 57 0 +33 58 0 +34 0 0 +34 1 0 +34 2 0 +34 3 0 +34 4 0 +34 5 0 +34 6 0 +34 7 0 +34 8 0 +34 9 0 +34 10 0 +34 11 0 +34 12 0 +34 13 0 +34 14 0 +34 15 0 +34 16 0 +34 17 0 +34 18 0 +34 19 0 +34 20 0 +34 21 0 +34 22 0 +34 23 0 +34 24 0 +34 25 0 +34 26 0 +34 27 0 +34 28 1 +34 29 1 +34 30 1 +34 31 1 +34 32 1 +34 33 1 +34 34 0 +34 35 1 +34 36 0 +34 37 0 +34 38 0 +34 39 0 +34 40 0 +34 41 0 +34 42 0 +34 43 0 +34 44 0 +34 45 0 +34 46 0 +34 47 0 +34 48 0 +34 49 0 +34 50 0 +34 51 0 +34 52 0 +34 53 0 +34 54 0 +34 55 0 +34 56 0 +34 57 0 +34 58 0 +35 0 0 +35 1 0 +35 2 0 +35 3 0 +35 4 0 +35 5 0 +35 6 0 +35 7 0 +35 8 0 +35 9 0 +35 10 0 +35 11 0 +35 12 0 +35 13 0 +35 14 0 +35 15 0 +35 16 0 +35 17 0 +35 18 0 +35 19 0 +35 20 0 +35 21 0 +35 22 0 +35 23 0 +35 24 0 +35 25 0 +35 26 0 +35 27 0 +35 28 1 +35 29 1 +35 30 1 +35 31 1 +35 32 1 +35 33 1 +35 34 1 +35 35 0 +35 36 1 +35 37 0 +35 38 0 +35 39 0 +35 40 0 +35 41 0 +35 42 0 +35 43 0 +35 44 0 +35 45 0 +35 46 0 +35 47 0 +35 48 0 +35 49 0 +35 50 0 +35 51 0 +35 52 0 +35 53 0 +35 54 0 +35 55 0 +35 56 0 +35 57 0 +35 58 0 +36 0 0 +36 1 0 +36 2 0 +36 3 0 +36 4 0 +36 5 0 +36 6 0 +36 7 0 +36 8 0 +36 9 0 +36 10 0 +36 11 0 +36 12 0 +36 13 0 +36 14 0 +36 15 0 +36 16 0 +36 17 0 +36 18 0 +36 19 0 +36 20 0 +36 21 0 +36 22 0 +36 23 0 +36 24 0 +36 25 0 +36 26 0 +36 27 0 +36 28 1 +36 29 1 +36 30 1 +36 31 1 +36 32 1 +36 33 1 +36 34 1 +36 35 1 +36 36 0 +36 37 1 +36 38 0 +36 39 0 +36 40 0 +36 41 0 +36 42 0 +36 43 0 +36 44 0 +36 45 0 +36 46 0 +36 47 0 +36 48 0 +36 49 0 +36 50 0 +36 51 0 +36 52 0 +36 53 0 +36 54 0 +36 55 0 +36 56 0 +36 57 0 +36 58 0 +37 0 0 +37 1 0 +37 2 0 +37 3 0 +37 4 0 +37 5 0 +37 6 0 +37 7 0 +37 8 0 +37 9 0 +37 10 0 +37 11 0 +37 12 0 +37 13 0 +37 14 0 +37 15 0 +37 16 0 +37 17 0 +37 18 0 +37 19 0 +37 20 0 +37 21 0 +37 22 0 +37 23 0 +37 24 0 +37 25 0 +37 26 0 +37 27 0 +37 28 1 +37 29 1 +37 30 1 +37 31 1 +37 32 1 +37 33 1 +37 34 1 +37 35 1 +37 36 1 +37 37 0 +37 38 1 +37 39 0 +37 40 0 +37 41 0 +37 42 0 +37 43 0 +37 44 0 +37 45 0 +37 46 0 +37 47 0 +37 48 0 +37 49 0 +37 50 0 +37 51 0 +37 52 0 +37 53 0 +37 54 0 +37 55 0 +37 56 0 +37 57 0 +37 58 0 +38 0 0 +38 1 0 +38 2 0 +38 3 0 +38 4 0 +38 5 0 +38 6 0 +38 7 0 +38 8 0 +38 9 0 +38 10 0 +38 11 0 +38 12 0 +38 13 0 +38 14 0 +38 15 0 +38 16 0 +38 17 0 +38 18 0 +38 19 0 +38 20 0 +38 21 0 +38 22 0 +38 23 0 +38 24 0 +38 25 0 +38 26 0 +38 27 0 +38 28 1 +38 29 1 +38 30 1 +38 31 1 +38 32 1 +38 33 1 +38 34 1 +38 35 1 +38 36 1 +38 37 1 +38 38 0 +38 39 1 +38 40 0 +38 41 0 +38 42 0 +38 43 0 +38 44 0 +38 45 0 +38 46 0 +38 47 0 +38 48 0 +38 49 0 +38 50 0 +38 51 0 +38 52 0 +38 53 0 +38 54 0 +38 55 0 +38 56 0 +38 57 0 +38 58 0 +39 0 0 +39 1 0 +39 2 0 +39 3 0 +39 4 0 +39 5 0 +39 6 0 +39 7 0 +39 8 0 +39 9 0 +39 10 0 +39 11 0 +39 12 0 +39 13 0 +39 14 0 +39 15 0 +39 16 0 +39 17 0 +39 18 0 +39 19 0 +39 20 0 +39 21 0 +39 22 0 +39 23 0 +39 24 0 +39 25 0 +39 26 0 +39 27 0 +39 28 1 +39 29 1 +39 30 1 +39 31 1 +39 32 1 +39 33 1 +39 34 1 +39 35 1 +39 36 1 +39 37 1 +39 38 1 +39 39 0 +39 40 1 +39 41 0 +39 42 0 +39 43 0 +39 44 0 +39 45 0 +39 46 0 +39 47 0 +39 48 0 +39 49 0 +39 50 0 +39 51 0 +39 52 0 +39 53 0 +39 54 0 +39 55 0 +39 56 0 +39 57 0 +39 58 0 +40 0 0 +40 1 0 +40 2 0 +40 3 0 +40 4 0 +40 5 0 +40 6 0 +40 7 0 +40 8 0 +40 9 0 +40 10 0 +40 11 0 +40 12 0 +40 13 0 +40 14 0 +40 15 0 +40 16 0 +40 17 0 +40 18 0 +40 19 0 +40 20 0 +40 21 0 +40 22 0 +40 23 0 +40 24 0 +40 25 0 +40 26 0 +40 27 0 +40 28 1 +40 29 1 +40 30 1 +40 31 1 +40 32 1 +40 33 1 +40 34 1 +40 35 1 +40 36 1 +40 37 1 +40 38 1 +40 39 1 +40 40 0 +40 41 1 +40 42 0 +40 43 0 +40 44 0 +40 45 0 +40 46 0 +40 47 0 +40 48 0 +40 49 0 +40 50 0 +40 51 0 +40 52 0 +40 53 0 +40 54 0 +40 55 0 +40 56 0 +40 57 0 +40 58 0 +41 0 0 +41 1 0 +41 2 0 +41 3 0 +41 4 0 +41 5 0 +41 6 0 +41 7 0 +41 8 0 +41 9 0 +41 10 0 +41 11 0 +41 12 0 +41 13 0 +41 14 0 +41 15 0 +41 16 0 +41 17 0 +41 18 0 +41 19 0 +41 20 0 +41 21 0 +41 22 0 +41 23 0 +41 24 0 +41 25 0 +41 26 0 +41 27 0 +41 28 1 +41 29 1 +41 30 1 +41 31 1 +41 32 1 +41 33 1 +41 34 1 +41 35 1 +41 36 1 +41 37 1 +41 38 1 +41 39 1 +41 40 1 +41 41 0 +41 42 1 +41 43 0 +41 44 0 +41 45 0 +41 46 0 +41 47 0 +41 48 0 +41 49 0 +41 50 0 +41 51 0 +41 52 0 +41 53 0 +41 54 0 +41 55 0 +41 56 0 +41 57 0 +41 58 0 +42 0 0 +42 1 0 +42 2 0 +42 3 0 +42 4 0 +42 5 0 +42 6 0 +42 7 0 +42 8 0 +42 9 0 +42 10 0 +42 11 0 +42 12 0 +42 13 0 +42 14 0 +42 15 0 +42 16 0 +42 17 0 +42 18 0 +42 19 0 +42 20 0 +42 21 0 +42 22 0 +42 23 0 +42 24 0 +42 25 0 +42 26 0 +42 27 0 +42 28 1 +42 29 1 +42 30 1 +42 31 1 +42 32 1 +42 33 1 +42 34 1 +42 35 1 +42 36 1 +42 37 1 +42 38 1 +42 39 1 +42 40 1 +42 41 1 +42 42 0 +42 43 1 +42 44 0 +42 45 0 +42 46 0 +42 47 0 +42 48 0 +42 49 0 +42 50 0 +42 51 0 +42 52 0 +42 53 0 +42 54 0 +42 55 0 +42 56 0 +42 57 0 +42 58 0 +43 0 0 +43 1 0 +43 2 0 +43 3 0 +43 4 0 +43 5 0 +43 6 0 +43 7 0 +43 8 0 +43 9 0 +43 10 0 +43 11 0 +43 12 0 +43 13 0 +43 14 0 +43 15 0 +43 16 0 +43 17 0 +43 18 0 +43 19 0 +43 20 0 +43 21 0 +43 22 0 +43 23 0 +43 24 0 +43 25 0 +43 26 0 +43 27 0 +43 28 1 +43 29 1 +43 30 1 +43 31 1 +43 32 1 +43 33 1 +43 34 1 +43 35 1 +43 36 1 +43 37 1 +43 38 1 +43 39 1 +43 40 1 +43 41 1 +43 42 1 +43 43 0 +43 44 1 +43 45 0 +43 46 0 +43 47 0 +43 48 0 +43 49 0 +43 50 0 +43 51 0 +43 52 0 +43 53 0 +43 54 0 +43 55 0 +43 56 0 +43 57 0 +43 58 0 +44 0 0 +44 1 0 +44 2 0 +44 3 0 +44 4 0 +44 5 0 +44 6 0 +44 7 0 +44 8 0 +44 9 0 +44 10 0 +44 11 0 +44 12 0 +44 13 0 +44 14 0 +44 15 0 +44 16 0 +44 17 0 +44 18 0 +44 19 0 +44 20 0 +44 21 0 +44 22 0 +44 23 0 +44 24 0 +44 25 0 +44 26 0 +44 27 0 +44 28 1 +44 29 1 +44 30 1 +44 31 1 +44 32 1 +44 33 1 +44 34 1 +44 35 1 +44 36 1 +44 37 1 +44 38 1 +44 39 1 +44 40 1 +44 41 1 +44 42 1 +44 43 1 +44 44 0 +44 45 1 +44 46 0 +44 47 0 +44 48 0 +44 49 0 +44 50 0 +44 51 0 +44 52 0 +44 53 0 +44 54 0 +44 55 0 +44 56 0 +44 57 0 +44 58 0 +45 0 0 +45 1 0 +45 2 0 +45 3 0 +45 4 0 +45 5 0 +45 6 0 +45 7 0 +45 8 0 +45 9 0 +45 10 0 +45 11 0 +45 12 0 +45 13 0 +45 14 0 +45 15 0 +45 16 0 +45 17 0 +45 18 0 +45 19 0 +45 20 0 +45 21 0 +45 22 0 +45 23 0 +45 24 0 +45 25 0 +45 26 0 +45 27 0 +45 28 1 +45 29 1 +45 30 1 +45 31 1 +45 32 1 +45 33 1 +45 34 1 +45 35 1 +45 36 1 +45 37 1 +45 38 1 +45 39 1 +45 40 1 +45 41 1 +45 42 1 +45 43 1 +45 44 1 +45 45 0 +45 46 1 +45 47 0 +45 48 0 +45 49 0 +45 50 0 +45 51 0 +45 52 0 +45 53 0 +45 54 0 +45 55 0 +45 56 0 +45 57 0 +45 58 0 +46 0 0 +46 1 0 +46 2 0 +46 3 0 +46 4 0 +46 5 0 +46 6 0 +46 7 0 +46 8 0 +46 9 0 +46 10 0 +46 11 0 +46 12 0 +46 13 0 +46 14 0 +46 15 0 +46 16 0 +46 17 0 +46 18 0 +46 19 0 +46 20 0 +46 21 0 +46 22 0 +46 23 0 +46 24 0 +46 25 0 +46 26 0 +46 27 0 +46 28 1 +46 29 1 +46 30 1 +46 31 1 +46 32 1 +46 33 1 +46 34 1 +46 35 1 +46 36 1 +46 37 1 +46 38 1 +46 39 1 +46 40 1 +46 41 1 +46 42 1 +46 43 1 +46 44 1 +46 45 1 +46 46 0 +46 47 1 +46 48 0 +46 49 0 +46 50 0 +46 51 0 +46 52 0 +46 53 0 +46 54 0 +46 55 0 +46 56 0 +46 57 0 +46 58 0 +47 0 0 +47 1 0 +47 2 0 +47 3 0 +47 4 0 +47 5 0 +47 6 0 +47 7 0 +47 8 0 +47 9 0 +47 10 0 +47 11 0 +47 12 0 +47 13 0 +47 14 0 +47 15 0 +47 16 0 +47 17 0 +47 18 0 +47 19 0 +47 20 0 +47 21 0 +47 22 0 +47 23 0 +47 24 0 +47 25 0 +47 26 0 +47 27 0 +47 28 1 +47 29 1 +47 30 1 +47 31 1 +47 32 1 +47 33 1 +47 34 1 +47 35 1 +47 36 1 +47 37 1 +47 38 1 +47 39 1 +47 40 1 +47 41 1 +47 42 1 +47 43 1 +47 44 1 +47 45 1 +47 46 1 +47 47 0 +47 48 1 +47 49 0 +47 50 0 +47 51 0 +47 52 0 +47 53 0 +47 54 0 +47 55 0 +47 56 0 +47 57 0 +47 58 0 +48 0 0 +48 1 0 +48 2 0 +48 3 0 +48 4 0 +48 5 0 +48 6 0 +48 7 0 +48 8 0 +48 9 0 +48 10 0 +48 11 0 +48 12 0 +48 13 0 +48 14 0 +48 15 0 +48 16 0 +48 17 0 +48 18 0 +48 19 0 +48 20 0 +48 21 0 +48 22 0 +48 23 0 +48 24 0 +48 25 0 +48 26 0 +48 27 0 +48 28 1 +48 29 1 +48 30 1 +48 31 1 +48 32 1 +48 33 1 +48 34 1 +48 35 1 +48 36 1 +48 37 1 +48 38 1 +48 39 1 +48 40 1 +48 41 1 +48 42 1 +48 43 1 +48 44 1 +48 45 1 +48 46 1 +48 47 1 +48 48 0 +48 49 1 +48 50 0 +48 51 0 +48 52 0 +48 53 0 +48 54 0 +48 55 0 +48 56 0 +48 57 0 +48 58 0 +49 0 0 +49 1 0 +49 2 0 +49 3 0 +49 4 0 +49 5 0 +49 6 0 +49 7 0 +49 8 0 +49 9 0 +49 10 0 +49 11 0 +49 12 0 +49 13 0 +49 14 0 +49 15 0 +49 16 0 +49 17 0 +49 18 0 +49 19 0 +49 20 0 +49 21 0 +49 22 0 +49 23 0 +49 24 0 +49 25 0 +49 26 0 +49 27 0 +49 28 1 +49 29 1 +49 30 1 +49 31 1 +49 32 1 +49 33 1 +49 34 1 +49 35 1 +49 36 1 +49 37 1 +49 38 1 +49 39 1 +49 40 1 +49 41 1 +49 42 1 +49 43 1 +49 44 1 +49 45 1 +49 46 1 +49 47 1 +49 48 1 +49 49 0 +49 50 1 +49 51 0 +49 52 0 +49 53 0 +49 54 0 +49 55 0 +49 56 0 +49 57 0 +49 58 0 +50 0 0 +50 1 0 +50 2 0 +50 3 0 +50 4 0 +50 5 0 +50 6 0 +50 7 0 +50 8 0 +50 9 0 +50 10 0 +50 11 0 +50 12 0 +50 13 0 +50 14 0 +50 15 0 +50 16 0 +50 17 0 +50 18 0 +50 19 0 +50 20 0 +50 21 0 +50 22 0 +50 23 0 +50 24 0 +50 25 0 +50 26 0 +50 27 0 +50 28 1 +50 29 1 +50 30 1 +50 31 1 +50 32 1 +50 33 1 +50 34 1 +50 35 1 +50 36 1 +50 37 1 +50 38 1 +50 39 1 +50 40 1 +50 41 1 +50 42 1 +50 43 1 +50 44 1 +50 45 1 +50 46 1 +50 47 1 +50 48 1 +50 49 1 +50 50 0 +50 51 1 +50 52 0 +50 53 0 +50 54 0 +50 55 0 +50 56 0 +50 57 0 +50 58 0 +51 0 0 +51 1 0 +51 2 0 +51 3 0 +51 4 0 +51 5 0 +51 6 0 +51 7 0 +51 8 0 +51 9 0 +51 10 0 +51 11 0 +51 12 0 +51 13 0 +51 14 0 +51 15 0 +51 16 0 +51 17 0 +51 18 0 +51 19 0 +51 20 0 +51 21 0 +51 22 0 +51 23 0 +51 24 0 +51 25 0 +51 26 0 +51 27 0 +51 28 1 +51 29 1 +51 30 1 +51 31 1 +51 32 1 +51 33 1 +51 34 1 +51 35 1 +51 36 1 +51 37 1 +51 38 1 +51 39 1 +51 40 1 +51 41 1 +51 42 1 +51 43 1 +51 44 1 +51 45 1 +51 46 1 +51 47 1 +51 48 1 +51 49 1 +51 50 1 +51 51 0 +51 52 1 +51 53 0 +51 54 0 +51 55 0 +51 56 0 +51 57 0 +51 58 0 +52 0 0 +52 1 0 +52 2 0 +52 3 0 +52 4 0 +52 5 0 +52 6 0 +52 7 0 +52 8 0 +52 9 0 +52 10 0 +52 11 0 +52 12 0 +52 13 0 +52 14 0 +52 15 0 +52 16 0 +52 17 0 +52 18 0 +52 19 0 +52 20 0 +52 21 0 +52 22 0 +52 23 0 +52 24 0 +52 25 0 +52 26 0 +52 27 0 +52 28 1 +52 29 1 +52 30 1 +52 31 1 +52 32 1 +52 33 1 +52 34 1 +52 35 1 +52 36 1 +52 37 1 +52 38 1 +52 39 1 +52 40 1 +52 41 1 +52 42 1 +52 43 1 +52 44 1 +52 45 1 +52 46 1 +52 47 1 +52 48 1 +52 49 1 +52 50 1 +52 51 1 +52 52 0 +52 53 1 +52 54 0 +52 55 0 +52 56 0 +52 57 0 +52 58 0 +53 0 0 +53 1 0 +53 2 0 +53 3 0 +53 4 0 +53 5 0 +53 6 0 +53 7 0 +53 8 0 +53 9 0 +53 10 0 +53 11 0 +53 12 0 +53 13 0 +53 14 0 +53 15 0 +53 16 0 +53 17 0 +53 18 0 +53 19 0 +53 20 0 +53 21 0 +53 22 0 +53 23 0 +53 24 0 +53 25 0 +53 26 0 +53 27 0 +53 28 1 +53 29 1 +53 30 1 +53 31 1 +53 32 1 +53 33 1 +53 34 1 +53 35 1 +53 36 1 +53 37 1 +53 38 1 +53 39 1 +53 40 1 +53 41 1 +53 42 1 +53 43 1 +53 44 1 +53 45 1 +53 46 1 +53 47 1 +53 48 1 +53 49 1 +53 50 1 +53 51 1 +53 52 1 +53 53 0 +53 54 1 +53 55 0 +53 56 0 +53 57 0 +53 58 0 +54 0 0 +54 1 0 +54 2 0 +54 3 0 +54 4 0 +54 5 0 +54 6 0 +54 7 0 +54 8 0 +54 9 0 +54 10 0 +54 11 0 +54 12 0 +54 13 0 +54 14 0 +54 15 0 +54 16 0 +54 17 0 +54 18 0 +54 19 0 +54 20 0 +54 21 0 +54 22 0 +54 23 0 +54 24 0 +54 25 0 +54 26 0 +54 27 0 +54 28 1 +54 29 1 +54 30 1 +54 31 1 +54 32 1 +54 33 1 +54 34 1 +54 35 1 +54 36 1 +54 37 1 +54 38 1 +54 39 1 +54 40 1 +54 41 1 +54 42 1 +54 43 1 +54 44 1 +54 45 1 +54 46 1 +54 47 1 +54 48 1 +54 49 1 +54 50 1 +54 51 1 +54 52 1 +54 53 1 +54 54 0 +54 55 1 +54 56 0 +54 57 0 +54 58 0 +55 0 0 +55 1 0 +55 2 0 +55 3 0 +55 4 0 +55 5 0 +55 6 0 +55 7 0 +55 8 0 +55 9 0 +55 10 0 +55 11 0 +55 12 0 +55 13 0 +55 14 0 +55 15 0 +55 16 0 +55 17 0 +55 18 0 +55 19 0 +55 20 0 +55 21 0 +55 22 0 +55 23 0 +55 24 0 +55 25 0 +55 26 0 +55 27 0 +55 28 1 +55 29 1 +55 30 1 +55 31 1 +55 32 1 +55 33 1 +55 34 1 +55 35 1 +55 36 1 +55 37 1 +55 38 1 +55 39 1 +55 40 1 +55 41 1 +55 42 1 +55 43 1 +55 44 1 +55 45 1 +55 46 1 +55 47 1 +55 48 1 +55 49 1 +55 50 1 +55 51 1 +55 52 1 +55 53 1 +55 54 1 +55 55 0 +55 56 1 +55 57 0 +55 58 0 +56 0 0 +56 1 0 +56 2 0 +56 3 0 +56 4 0 +56 5 0 +56 6 0 +56 7 0 +56 8 0 +56 9 0 +56 10 0 +56 11 0 +56 12 0 +56 13 0 +56 14 0 +56 15 0 +56 16 0 +56 17 0 +56 18 0 +56 19 0 +56 20 0 +56 21 0 +56 22 0 +56 23 0 +56 24 0 +56 25 0 +56 26 0 +56 27 0 +56 28 1 +56 29 1 +56 30 1 +56 31 1 +56 32 1 +56 33 1 +56 34 1 +56 35 1 +56 36 1 +56 37 1 +56 38 1 +56 39 1 +56 40 1 +56 41 1 +56 42 1 +56 43 1 +56 44 1 +56 45 1 +56 46 1 +56 47 1 +56 48 1 +56 49 1 +56 50 1 +56 51 1 +56 52 1 +56 53 1 +56 54 1 +56 55 1 +56 56 0 +56 57 1 +56 58 0 +57 0 0 +57 1 0 +57 2 0 +57 3 0 +57 4 0 +57 5 0 +57 6 0 +57 7 0 +57 8 0 +57 9 0 +57 10 0 +57 11 0 +57 12 0 +57 13 0 +57 14 0 +57 15 0 +57 16 0 +57 17 0 +57 18 0 +57 19 0 +57 20 0 +57 21 0 +57 22 0 +57 23 0 +57 24 0 +57 25 0 +57 26 0 +57 27 0 +57 28 1 +57 29 1 +57 30 1 +57 31 1 +57 32 1 +57 33 1 +57 34 1 +57 35 1 +57 36 1 +57 37 1 +57 38 1 +57 39 1 +57 40 1 +57 41 1 +57 42 1 +57 43 1 +57 44 1 +57 45 1 +57 46 1 +57 47 1 +57 48 1 +57 49 1 +57 50 1 +57 51 1 +57 52 1 +57 53 1 +57 54 1 +57 55 1 +57 56 1 +57 57 0 +57 58 1 +58 0 0 +58 1 0 +58 2 0 +58 3 0 +58 4 0 +58 5 0 +58 6 0 +58 7 0 +58 8 0 +58 9 0 +58 10 0 +58 11 0 +58 12 0 +58 13 0 +58 14 0 +58 15 0 +58 16 0 +58 17 0 +58 18 0 +58 19 0 +58 20 0 +58 21 0 +58 22 0 +58 23 0 +58 24 0 +58 25 0 +58 26 0 +58 27 0 +58 28 1 +58 29 1 +58 30 1 +58 31 1 +58 32 1 +58 33 1 +58 34 1 +58 35 1 +58 36 1 +58 37 1 +58 38 1 +58 39 1 +58 40 1 +58 41 1 +58 42 1 +58 43 1 +58 44 1 +58 45 1 +58 46 1 +58 47 1 +58 48 1 +58 49 1 +58 50 1 +58 51 1 +58 52 1 +58 53 1 +58 54 1 +58 55 1 +58 56 1 +58 57 1 +58 58 0 +)" diff --git a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp index d5d978d6a09d6..0a70bd2a24346 100644 --- a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp +++ b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp @@ -215,7 +215,8 @@ constexpr bool all_the_algorithms() if (!std::is_constant_evaluated()) { (void)std::ranges::stable_sort(first, last, Less(&copies)); assert(copies == 0); } if (!std::is_constant_evaluated()) { (void)std::ranges::stable_sort(a, Less(&copies)); assert(copies == 0); } #if TEST_STD_VER > 20 - //(void)std::ranges::starts_with(first, last, first2, last2, Equal(&copies)); assert(copies == 0); + (void)std::ranges::starts_with(first, last, first2, last2, Equal(&copies)); assert(copies == 0); + (void)std::ranges::starts_with(a, b, Equal(&copies)); assert(copies == 0); #endif (void)std::ranges::transform(first, last, first2, UnaryTransform(&copies)); assert(copies == 0); (void)std::ranges::transform(a, first2, UnaryTransform(&copies)); assert(copies == 0); diff --git a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp index 23d02f04c8357..111b0ff655f53 100644 --- a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp +++ b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp @@ -206,7 +206,8 @@ constexpr bool all_the_algorithms() if (!std::is_constant_evaluated()) { (void)std::ranges::stable_sort(first, last, Less(), Proj(&copies)); assert(copies == 0); } if (!std::is_constant_evaluated()) { (void)std::ranges::stable_sort(a, Less(), Proj(&copies)); assert(copies == 0); } #if TEST_STD_VER > 20 - //(void)std::ranges::starts_with(first, last, first2, last2, Equal(), Proj(&copies), Proj(&copies)); assert(copies == 0); + (void)std::ranges::starts_with(first, last, first2, last2, Equal(), Proj(&copies), Proj(&copies)); assert(copies == 0); + (void)std::ranges::starts_with(a, b, Equal(), Proj(&copies), Proj(&copies)); assert(copies == 0); #endif (void)std::ranges::transform(first, last, first2, UnaryTransform(), Proj(&copies)); assert(copies == 0); (void)std::ranges::transform(a, first2, UnaryTransform(), Proj(&copies)); assert(copies == 0); diff --git a/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp b/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp index 7eb8acbe98832..1f2a4650c9d52 100644 --- a/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp +++ b/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp @@ -40,11 +40,6 @@ END-SCRIPT #include <__config> -// Prevent from generating deprecated warnings for this test. -#if defined(__DEPRECATED) -# undef __DEPRECATED -#endif - int main(int, char**) { return 0; } // DO NOT MANUALLY EDIT ANYTHING BETWEEN THE MARKERS BELOW @@ -751,16 +746,4 @@ int main(int, char**) { return 0; } using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_138 -#if defined(TEST_138) -# include - using HandlerType = decltype(std::__libcpp_verbose_abort); -#endif - -// RUN: %{build} -DTEST_139 -#if defined(TEST_139) -# include - using HandlerType = decltype(std::__libcpp_verbose_abort); -#endif - // GENERATED-MARKER diff --git a/libcxx/test/libcxx/clang_tidy.sh.cpp b/libcxx/test/libcxx/clang_tidy.sh.cpp index 74df7af5c191b..ab9bbc6c39144 100644 --- a/libcxx/test/libcxx/clang_tidy.sh.cpp +++ b/libcxx/test/libcxx/clang_tidy.sh.cpp @@ -15,11 +15,6 @@ // RUN: %{clang-tidy} %s --warnings-as-errors=* -header-filter=.* --checks='-*,libcpp-*' --load=%{test-tools}/clang_tidy_checks/libcxx-tidy.plugin -- %{compile_flags} -fno-modules // RUN: %{clang-tidy} %s --warnings-as-errors=* -header-filter=.* --config-file=%S/../../.clang-tidy -- -Wweak-vtables %{compile_flags} -fno-modules -// Prevent from generating deprecated warnings for this test. -#if defined(__DEPRECATED) -# undef __DEPRECATED -#endif - /* BEGIN-SCRIPT @@ -262,6 +257,4 @@ END-SCRIPT #if __cplusplus >= 201103L # include #endif -#include -#include // GENERATED-MARKER diff --git a/libcxx/test/libcxx/containers/gnu_cxx/hash_map.pass.cpp b/libcxx/test/libcxx/containers/gnu_cxx/hash_map.pass.cpp index c175356cadcd3..27a226f4ce2b3 100644 --- a/libcxx/test/libcxx/containers/gnu_cxx/hash_map.pass.cpp +++ b/libcxx/test/libcxx/containers/gnu_cxx/hash_map.pass.cpp @@ -9,9 +9,7 @@ // UNSUPPORTED: modules-build // Prevent from generating deprecated warnings for this test. -#if defined(__DEPRECATED) -# undef __DEPRECATED -#endif +// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated #include #include diff --git a/libcxx/test/libcxx/containers/gnu_cxx/hash_map_name_lookup.pass.cpp b/libcxx/test/libcxx/containers/gnu_cxx/hash_map_name_lookup.pass.cpp index 02d84718ea98c..522f0273897b7 100644 --- a/libcxx/test/libcxx/containers/gnu_cxx/hash_map_name_lookup.pass.cpp +++ b/libcxx/test/libcxx/containers/gnu_cxx/hash_map_name_lookup.pass.cpp @@ -16,9 +16,7 @@ struct equal_to; struct unique_ptr; // Prevent from generating deprecated warnings for this test. -#if defined(__DEPRECATED) -# undef __DEPRECATED -#endif +// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated #include diff --git a/libcxx/test/libcxx/containers/gnu_cxx/hash_set.pass.cpp b/libcxx/test/libcxx/containers/gnu_cxx/hash_set.pass.cpp index 3f7698c5c3141..45b3e1bd99f13 100644 --- a/libcxx/test/libcxx/containers/gnu_cxx/hash_set.pass.cpp +++ b/libcxx/test/libcxx/containers/gnu_cxx/hash_set.pass.cpp @@ -9,9 +9,7 @@ // UNSUPPORTED: modules-build // Prevent from generating deprecated warnings for this test. -#if defined(__DEPRECATED) -# undef __DEPRECATED -#endif +// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated #include #include diff --git a/libcxx/test/libcxx/containers/gnu_cxx/hash_set_name_lookup.pass.cpp b/libcxx/test/libcxx/containers/gnu_cxx/hash_set_name_lookup.pass.cpp index b215e6c12034e..1f0d6c81894e4 100644 --- a/libcxx/test/libcxx/containers/gnu_cxx/hash_set_name_lookup.pass.cpp +++ b/libcxx/test/libcxx/containers/gnu_cxx/hash_set_name_lookup.pass.cpp @@ -16,9 +16,7 @@ struct equal_to; struct unique_ptr; // Prevent from generating deprecated warnings for this test. -#if defined(__DEPRECATED) -# undef __DEPRECATED -#endif +// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated #include diff --git a/libcxx/test/libcxx/double_include.sh.cpp b/libcxx/test/libcxx/double_include.sh.cpp index b6bbf4e960506..292f53a0d077a 100644 --- a/libcxx/test/libcxx/double_include.sh.cpp +++ b/libcxx/test/libcxx/double_include.sh.cpp @@ -13,11 +13,6 @@ // RUN: %{cxx} -o %t.exe %t.first.o %t.second.o %{flags} %{link_flags} // RUN: %{run} -// Prevent from generating deprecated warnings for this test. -#if defined(__DEPRECATED) -# undef __DEPRECATED -#endif - /* BEGIN-SCRIPT @@ -260,8 +255,6 @@ END-SCRIPT #if __cplusplus >= 201103L # include #endif -#include -#include // GENERATED-MARKER #if defined(WITH_MAIN) diff --git a/libcxx/test/libcxx/extensions/hash/specializations.pass.cpp b/libcxx/test/libcxx/extensions/hash/specializations.pass.cpp index 8e386ed672ce0..8e452e1e54ccd 100644 --- a/libcxx/test/libcxx/extensions/hash/specializations.pass.cpp +++ b/libcxx/test/libcxx/extensions/hash/specializations.pass.cpp @@ -8,8 +8,8 @@ // UNSUPPORTED: modules-build -// NOTE: Undefined __DEPRECATED to prevent this test from failing with -Werror -#undef __DEPRECATED +// Prevent from generating deprecated warnings for this test. +// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated #include #include #include diff --git a/libcxx/test/libcxx/lint/lint_modulemap.sh.py b/libcxx/test/libcxx/lint/lint_modulemap.sh.py index 8bcd663eb8a04..85d2c4b012786 100755 --- a/libcxx/test/libcxx/lint/lint_modulemap.sh.py +++ b/libcxx/test/libcxx/lint/lint_modulemap.sh.py @@ -29,6 +29,9 @@ elif re.match(r'^\s*module (\w+)_fwd\s+[{] private header "__fwd/\1[.]h" [}]', line): # It's a private submodule with forward declarations, such as <__fwd/span.h>. pass + elif re.match(r'^\s*module (?:\w+_)*(\w+)\s+[{] private (textual )?header "__(\w+/)*\1[.]h" [}]', line): + # It's a private pstl submodule, such as <__algorithm/pstl_backends/cpu_backend.h> + pass else: okay = False print("LINE DOESN'T MATCH REGEX in libcxx/include/module.modulemap.in!") diff --git a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp index 9dd434507ed38..d032e97f1ddc9 100644 --- a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp +++ b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp @@ -9,11 +9,6 @@ // Test that headers are not tripped up by the surrounding code defining the // min() and max() macros. -// Prevent from generating deprecated warnings for this test. -#if defined(__DEPRECATED) -# undef __DEPRECATED -#endif - #define TEST_MACROS() static_assert(min() == true && max() == true, "") #define min() true #define max() true @@ -398,8 +393,4 @@ TEST_MACROS(); # include TEST_MACROS(); #endif -#include -TEST_MACROS(); -#include -TEST_MACROS(); // GENERATED-MARKER diff --git a/libcxx/test/libcxx/modules_include.sh.cpp b/libcxx/test/libcxx/modules_include.sh.cpp index 1ef40a14c421d..3f3967aa418bb 100644 --- a/libcxx/test/libcxx/modules_include.sh.cpp +++ b/libcxx/test/libcxx/modules_include.sh.cpp @@ -20,11 +20,6 @@ // The Android headers don't appear to be compatible with modules yet // XFAIL: LIBCXX-ANDROID-FIXME -// Prevent from generating deprecated warnings for this test. -#if defined(__DEPRECATED) -# undef __DEPRECATED -#endif - #include <__config> /* @@ -868,18 +863,8 @@ END-SCRIPT #if defined(TEST_137) && __cplusplus >= 201103L #include #endif -// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_138 &' >> %t.sh -// RUN: echo 'TEST_138=$!' >> %t.sh // RUN: echo "wait $TEST_122" >> %t.sh -#if defined(TEST_138) -#include -#endif -// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_139 &' >> %t.sh -// RUN: echo 'TEST_139=$!' >> %t.sh // RUN: echo "wait $TEST_123" >> %t.sh -#if defined(TEST_139) -#include -#endif // RUN: echo "wait $TEST_124" >> %t.sh // RUN: echo "wait $TEST_125" >> %t.sh // RUN: echo "wait $TEST_126" >> %t.sh @@ -894,7 +879,5 @@ END-SCRIPT // RUN: echo "wait $TEST_135" >> %t.sh // RUN: echo "wait $TEST_136" >> %t.sh // RUN: echo "wait $TEST_137" >> %t.sh -// RUN: echo "wait $TEST_138" >> %t.sh -// RUN: echo "wait $TEST_139" >> %t.sh // RUN: bash %t.sh // GENERATED-MARKER diff --git a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp index 3e3e1340a7e34..5254e0d78e88b 100644 --- a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp +++ b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp @@ -9,11 +9,6 @@ // Test that headers are not tripped up by the surrounding code defining various // alphabetic macros. -// Prevent from generating deprecated warnings for this test. -#if defined(__DEPRECATED) -# undef __DEPRECATED -#endif - #define NASTY_MACRO This should not be expanded!!! // libc++ does not use single-letter names as a matter of principle. @@ -59,6 +54,7 @@ // Test that libc++ doesn't use names that collide with FreeBSD system macros. #ifndef __FreeBSD__ # define __null_sentinel NASTY_MACRO +# define __generic #endif // tchar.h defines these macros on Windows @@ -384,6 +380,4 @@ END-SCRIPT #if __cplusplus >= 201103L # include #endif -#include -#include // GENERATED-MARKER diff --git a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp index f92b78779f2ec..779a21a02dd50 100644 --- a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp +++ b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp @@ -9,11 +9,6 @@ // Ensure that none of the standard C++ headers implicitly include cassert or // assert.h (because assert() is implemented as a macro). -// Prevent from generating deprecated warnings for this test. -#if defined(__DEPRECATED) -# undef __DEPRECATED -#endif - /* BEGIN-SCRIPT @@ -257,8 +252,6 @@ END-SCRIPT #if __cplusplus >= 201103L # include #endif -#include -#include // GENERATED-MARKER #ifdef assert diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp index d8a8218939439..6762913512c72 100644 --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -114,6 +114,14 @@ END-SCRIPT #include <__algorithm/partition_point.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/partition_point.h'}} #include <__algorithm/pop_heap.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pop_heap.h'}} #include <__algorithm/prev_permutation.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/prev_permutation.h'}} +#include <__algorithm/pstl_backends/cpu_backend.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backend.h'}} +#include <__algorithm/pstl_backends/cpu_backends/any_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/any_of.h'}} +#include <__algorithm/pstl_backends/cpu_backends/backend.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/backend.h'}} +#include <__algorithm/pstl_backends/cpu_backends/fill.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/fill.h'}} +#include <__algorithm/pstl_backends/cpu_backends/find_if.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/find_if.h'}} +#include <__algorithm/pstl_backends/cpu_backends/for_each.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/for_each.h'}} +#include <__algorithm/pstl_backends/cpu_backends/serial.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/serial.h'}} +#include <__algorithm/pstl_backends/cpu_backends/transform.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/transform.h'}} #include <__algorithm/push_heap.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/push_heap.h'}} #include <__algorithm/ranges_adjacent_find.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_adjacent_find.h'}} #include <__algorithm/ranges_all_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_all_of.h'}} @@ -196,6 +204,7 @@ END-SCRIPT #include <__algorithm/ranges_sort_heap.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_sort_heap.h'}} #include <__algorithm/ranges_stable_partition.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_stable_partition.h'}} #include <__algorithm/ranges_stable_sort.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_stable_sort.h'}} +#include <__algorithm/ranges_starts_with.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_starts_with.h'}} #include <__algorithm/ranges_swap_ranges.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_swap_ranges.h'}} #include <__algorithm/ranges_transform.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_transform.h'}} #include <__algorithm/ranges_unique.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_unique.h'}} @@ -424,7 +433,6 @@ END-SCRIPT #include <__functional/reference_wrapper.h> // expected-error@*:* {{use of private header from outside its module: '__functional/reference_wrapper.h'}} #include <__functional/unary_function.h> // expected-error@*:* {{use of private header from outside its module: '__functional/unary_function.h'}} #include <__functional/unary_negate.h> // expected-error@*:* {{use of private header from outside its module: '__functional/unary_negate.h'}} -#include <__functional/unwrap_ref.h> // expected-error@*:* {{use of private header from outside its module: '__functional/unwrap_ref.h'}} #include <__functional/weak_result_type.h> // expected-error@*:* {{use of private header from outside its module: '__functional/weak_result_type.h'}} #include <__fwd/array.h> // expected-error@*:* {{use of private header from outside its module: '__fwd/array.h'}} #include <__fwd/fstream.h> // expected-error@*:* {{use of private header from outside its module: '__fwd/fstream.h'}} @@ -580,6 +588,7 @@ END-SCRIPT #include <__ranges/as_rvalue_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/as_rvalue_view.h'}} #include <__ranges/common_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/common_view.h'}} #include <__ranges/concepts.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/concepts.h'}} +#include <__ranges/container_compatible_range.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/container_compatible_range.h'}} #include <__ranges/copyable_box.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/copyable_box.h'}} #include <__ranges/counted.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/counted.h'}} #include <__ranges/dangling.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/dangling.h'}} @@ -592,6 +601,7 @@ END-SCRIPT #include <__ranges/enable_borrowed_range.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/enable_borrowed_range.h'}} #include <__ranges/enable_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/enable_view.h'}} #include <__ranges/filter_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/filter_view.h'}} +#include <__ranges/from_range.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/from_range.h'}} #include <__ranges/iota_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/iota_view.h'}} #include <__ranges/istream_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/istream_view.h'}} #include <__ranges/join_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/join_view.h'}} @@ -767,6 +777,7 @@ END-SCRIPT #include <__type_traits/type_identity.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/type_identity.h'}} #include <__type_traits/type_list.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/type_list.h'}} #include <__type_traits/underlying_type.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/underlying_type.h'}} +#include <__type_traits/unwrap_ref.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/unwrap_ref.h'}} #include <__type_traits/void_t.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/void_t.h'}} #include <__utility/as_const.h> // expected-error@*:* {{use of private header from outside its module: '__utility/as_const.h'}} #include <__utility/auto_cast.h> // expected-error@*:* {{use of private header from outside its module: '__utility/auto_cast.h'}} diff --git a/libcxx/test/libcxx/transitive_includes.sh.cpp b/libcxx/test/libcxx/transitive_includes.sh.cpp index 9e00408bd4fa6..1bbc906bb5072 100644 --- a/libcxx/test/libcxx/transitive_includes.sh.cpp +++ b/libcxx/test/libcxx/transitive_includes.sh.cpp @@ -32,11 +32,6 @@ // this test instead. // UNSUPPORTED: transitive-includes-disabled -// Prevent from generating deprecated warnings for this test. -#if defined(__DEPRECATED) -# undef __DEPRECATED -#endif - /* BEGIN-SCRIPT @@ -542,14 +537,6 @@ END-SCRIPT #if defined(TEST_137) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_138 > /dev/null 2> %t/header.ext_hash_map -#if defined(TEST_138) -#include -#endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_139 > /dev/null 2> %t/header.ext_hash_set -#if defined(TEST_139) -#include -#endif // RUN: %{python} %S/transitive_includes_to_csv.py %t > %t/transitive_includes.csv // RUN: diff -w %S/transitive_includes/%{cxx_std}.csv %t/transitive_includes.csv // GENERATED-MARKER diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv index 7460de6733c82..172f222d18cbc 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -7,6 +7,7 @@ algorithm cstdint algorithm cstdlib algorithm cstring algorithm ctime +algorithm execution algorithm initializer_list algorithm iosfwd algorithm iterator @@ -276,33 +277,6 @@ experimental/unordered_set unordered_set experimental/utility utility experimental/vector experimental/memory_resource experimental/vector vector -ext/hash_map algorithm -ext/hash_map cmath -ext/hash_map concepts -ext/hash_map cstddef -ext/hash_map cstdint -ext/hash_map cstring -ext/hash_map functional -ext/hash_map initializer_list -ext/hash_map iterator -ext/hash_map limits -ext/hash_map new -ext/hash_map stdexcept -ext/hash_map string -ext/hash_map type_traits -ext/hash_set algorithm -ext/hash_set cmath -ext/hash_set concepts -ext/hash_set cstddef -ext/hash_set cstdint -ext/hash_set cstring -ext/hash_set functional -ext/hash_set initializer_list -ext/hash_set iterator -ext/hash_set limits -ext/hash_set new -ext/hash_set string -ext/hash_set type_traits filesystem compare filesystem concepts filesystem cstddef diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv index 1a8c4214beb97..f75a9987622e6 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -7,6 +7,7 @@ algorithm cstdint algorithm cstdlib algorithm cstring algorithm ctime +algorithm execution algorithm initializer_list algorithm iosfwd algorithm iterator @@ -276,33 +277,6 @@ experimental/unordered_set unordered_set experimental/utility utility experimental/vector experimental/memory_resource experimental/vector vector -ext/hash_map algorithm -ext/hash_map cmath -ext/hash_map concepts -ext/hash_map cstddef -ext/hash_map cstdint -ext/hash_map cstring -ext/hash_map functional -ext/hash_map initializer_list -ext/hash_map iterator -ext/hash_map limits -ext/hash_map new -ext/hash_map stdexcept -ext/hash_map string -ext/hash_map type_traits -ext/hash_set algorithm -ext/hash_set cmath -ext/hash_set concepts -ext/hash_set cstddef -ext/hash_set cstdint -ext/hash_set cstring -ext/hash_set functional -ext/hash_set initializer_list -ext/hash_set iterator -ext/hash_set limits -ext/hash_set new -ext/hash_set string -ext/hash_set type_traits filesystem compare filesystem concepts filesystem cstddef diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv index 43888fe8f3037..f402f3e2e66d7 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -7,6 +7,7 @@ algorithm cstdint algorithm cstdlib algorithm cstring algorithm ctime +algorithm execution algorithm initializer_list algorithm iosfwd algorithm iterator @@ -278,33 +279,6 @@ experimental/unordered_set unordered_set experimental/utility utility experimental/vector experimental/memory_resource experimental/vector vector -ext/hash_map algorithm -ext/hash_map cmath -ext/hash_map concepts -ext/hash_map cstddef -ext/hash_map cstdint -ext/hash_map cstring -ext/hash_map functional -ext/hash_map initializer_list -ext/hash_map iterator -ext/hash_map limits -ext/hash_map new -ext/hash_map stdexcept -ext/hash_map string -ext/hash_map type_traits -ext/hash_set algorithm -ext/hash_set cmath -ext/hash_set concepts -ext/hash_set cstddef -ext/hash_set cstdint -ext/hash_set cstring -ext/hash_set functional -ext/hash_set initializer_list -ext/hash_set iterator -ext/hash_set limits -ext/hash_set new -ext/hash_set string -ext/hash_set type_traits filesystem compare filesystem concepts filesystem cstddef diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv index 43888fe8f3037..f402f3e2e66d7 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -7,6 +7,7 @@ algorithm cstdint algorithm cstdlib algorithm cstring algorithm ctime +algorithm execution algorithm initializer_list algorithm iosfwd algorithm iterator @@ -278,33 +279,6 @@ experimental/unordered_set unordered_set experimental/utility utility experimental/vector experimental/memory_resource experimental/vector vector -ext/hash_map algorithm -ext/hash_map cmath -ext/hash_map concepts -ext/hash_map cstddef -ext/hash_map cstdint -ext/hash_map cstring -ext/hash_map functional -ext/hash_map initializer_list -ext/hash_map iterator -ext/hash_map limits -ext/hash_map new -ext/hash_map stdexcept -ext/hash_map string -ext/hash_map type_traits -ext/hash_set algorithm -ext/hash_set cmath -ext/hash_set concepts -ext/hash_set cstddef -ext/hash_set cstdint -ext/hash_set cstring -ext/hash_set functional -ext/hash_set initializer_list -ext/hash_set iterator -ext/hash_set limits -ext/hash_set new -ext/hash_set string -ext/hash_set type_traits filesystem compare filesystem concepts filesystem cstddef diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv index cb65ac77ce4d9..79ad405068515 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx20.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -7,6 +7,7 @@ algorithm cstdint algorithm cstdlib algorithm cstring algorithm ctime +algorithm execution algorithm initializer_list algorithm iosfwd algorithm iterator @@ -285,33 +286,6 @@ experimental/unordered_set unordered_set experimental/utility utility experimental/vector experimental/memory_resource experimental/vector vector -ext/hash_map algorithm -ext/hash_map cmath -ext/hash_map concepts -ext/hash_map cstddef -ext/hash_map cstdint -ext/hash_map cstring -ext/hash_map functional -ext/hash_map initializer_list -ext/hash_map iterator -ext/hash_map limits -ext/hash_map new -ext/hash_map stdexcept -ext/hash_map string -ext/hash_map type_traits -ext/hash_set algorithm -ext/hash_set cmath -ext/hash_set concepts -ext/hash_set cstddef -ext/hash_set cstdint -ext/hash_set cstring -ext/hash_set functional -ext/hash_set initializer_list -ext/hash_set iterator -ext/hash_set limits -ext/hash_set new -ext/hash_set string -ext/hash_set type_traits filesystem compare filesystem concepts filesystem cstddef diff --git a/libcxx/test/libcxx/transitive_includes/cxx2b.csv b/libcxx/test/libcxx/transitive_includes/cxx2b.csv index 7c1c0f49a8ee1..833df27c70f5a 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx2b.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx2b.csv @@ -3,6 +3,7 @@ algorithm cstddef algorithm cstdint algorithm cstring algorithm ctime +algorithm execution algorithm initializer_list algorithm iosfwd algorithm limits @@ -184,27 +185,6 @@ experimental/unordered_set unordered_set experimental/utility utility experimental/vector experimental/memory_resource experimental/vector vector -ext/hash_map algorithm -ext/hash_map cmath -ext/hash_map cstddef -ext/hash_map cstdint -ext/hash_map cstring -ext/hash_map functional -ext/hash_map initializer_list -ext/hash_map limits -ext/hash_map new -ext/hash_map stdexcept -ext/hash_map string -ext/hash_set algorithm -ext/hash_set cmath -ext/hash_set cstddef -ext/hash_set cstdint -ext/hash_set cstring -ext/hash_set functional -ext/hash_set initializer_list -ext/hash_set limits -ext/hash_set new -ext/hash_set string filesystem compare filesystem cstddef filesystem cstdint diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.transform.binary.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.transform.binary.pass.cpp new file mode 100644 index 0000000000000..b2b98619fb964 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.transform.binary.pass.cpp @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// + +// template +// ForwardIterator +// transform(ExecutionPolicy&& exec, +// ForwardIterator1 first1, ForwardIterator1 last1, +// ForwardIterator2 first2, ForwardIterator result, +// BinaryOperation binary_op); + +#include +#include + +#include "test_macros.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +EXECUTION_POLICY_SFINAE_TEST(transform); + +static_assert(sfinae_test_transform); +static_assert(!sfinae_test_transform); + +template +struct Test { + template + void operator()(Policy&& policy) { + // simple test + for (const int size : {0, 1, 2, 100, 350}) { + std::vector a(size); + std::vector b(size); + for (int i = 0; i != size; ++i) { + a[i] = i + 1; + b[i] = i - 3; + } + + std::vector out(std::size(a)); + decltype(auto) ret = std::transform( + policy, + Iter1(std::data(a)), + Iter1(std::data(a) + std::size(a)), + Iter2(std::data(b)), + Iter3(std::data(out)), + [](int i, int j) { return i + j + 3; }); + static_assert(std::is_same_v); + assert(base(ret) == std::data(out) + std::size(out)); + for (int i = 0; i != size; ++i) { + assert(out[i] == i * 2 + 1); + } + } + } +}; + +int main(int, char**) { + types::for_each( + types::forward_iterator_list{}, types::apply_type_identity{[](auto v) { + using Iter3 = typename decltype(v)::type; + types::for_each( + types::forward_iterator_list{}, types::apply_type_identity{[](auto v2) { + using Iter2 = typename decltype(v2)::type; + types::for_each( + types::forward_iterator_list{}, + TestIteratorWithPolicies::template apply>{}); + }}); + }}); + + return 0; +} diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.transform.unary.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.transform.unary.pass.cpp new file mode 100644 index 0000000000000..03985c7d3673b --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.transform.unary.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// + +// template +// ForwardIterator2 +// transform(ExecutionPolicy&& exec, +// ForwardIterator1 first1, ForwardIterator1 last1, +// ForwardIterator2 result, UnaryOperation op); + +#include +#include +#include + +#include "test_macros.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +// We can't test the constraint on the execution policy, because that would conflict with the binary +// transform algorithm that doesn't take an execution policy, which is not constrained at all. + +template +struct Test { + template + void operator()(Policy&& policy) { + // simple test + for (const int size : {0, 1, 2, 100, 350}) { + std::vector a(size); + for (int i = 0; i != size; ++i) + a[i] = i + 1; + + std::vector out(std::size(a)); + decltype(auto) ret = std::transform( + policy, Iter1(std::data(a)), Iter1(std::data(a) + std::size(a)), Iter2(std::data(out)), [](int i) { + return i + 3; + }); + static_assert(std::is_same_v); + assert(base(ret) == std::data(out) + std::size(out)); + for (int i = 0; i != size; ++i) + assert(out[i] == i + 4); + } + } +}; + +int main(int, char**) { + types::for_each(types::forward_iterator_list{}, types::apply_type_identity{[](auto v) { + using Iter = typename decltype(v)::type; + types::for_each( + types::forward_iterator_list{}, + TestIteratorWithPolicies::template apply>{}); + }}); + + return 0; +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.starts_with/ranges.starts_with.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.starts_with/ranges.starts_with.pass.cpp new file mode 100644 index 0000000000000..3a9c1aeeaf878 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.starts_with/ranges.starts_with.pass.cpp @@ -0,0 +1,255 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template S1, input_iterator I2, sentinel_for S2, +// class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> +// requires indirectly_comparable +// constexpr bool ranges::starts_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, +// Proj1 proj1 = {}, Proj2 proj2 = {}); +// template +// requires indirectly_comparable, iterator_t, Pred, Proj1, Proj2> +// constexpr bool ranges::starts_with(R1&& r1, R2&& r2, Pred pred = {}, +// Proj1 proj1 = {}, Proj2 proj2 = {}); + +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "test_iterators.h" + +template +concept HasStartsWithIt = requires (Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { + std::ranges::starts_with(first1, last1, first2, last2); +}; + +static_assert(HasStartsWithIt); +static_assert(HasStartsWithIt); +static_assert(HasStartsWithIt); +static_assert(!HasStartsWithIt); +static_assert(!HasStartsWithIt); // not indirectly comparable +static_assert(!HasStartsWithIt); +static_assert(HasStartsWithIt); +static_assert(HasStartsWithIt); +static_assert(!HasStartsWithIt); +static_assert(!HasStartsWithIt); + +template > +concept HasStartsWithR = requires (Range1 range1, Range2 range2) { + std::ranges::starts_with(range1, range2); +}; + +static_assert(HasStartsWithR>); +static_assert(HasStartsWithR); +static_assert(!HasStartsWithR); +static_assert(!HasStartsWithR); +static_assert(!HasStartsWithR); +static_assert(!HasStartsWithR, UncheckedRange>); // not indirectly comparable +static_assert(HasStartsWithR, ForwardRangeNotDerivedFrom>); +static_assert(HasStartsWithR, ForwardRangeNotIncrementable>); +static_assert(!HasStartsWithR, ForwardRangeNotSentinelSemiregular>); +static_assert(!HasStartsWithR, ForwardRangeNotSentinelEqualityComparableWith>); + +template +constexpr void test_iterators() { + {// simply tests + {int a[] = {1, 2, 3, 4, 5, 6}; + int p[] = {1, 2}; + std::same_as decltype(auto) ret = + std::ranges::starts_with(Iter1(a), Sent1(Iter1(a + 6)), Iter2(p), Sent2(Iter2(p + 2))); + assert(ret); + } + { + int a[] = {1, 2, 3, 4, 5, 6}; + int p[] = {1, 2}; + auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); + auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); + std::same_as decltype(auto) ret = std::ranges::starts_with(whole, prefix); + assert(ret); + } + } + + {// prefix doesn't match + { + int a[] = {1, 2, 3, 4, 5, 6}; + int p[] = {4, 5, 6}; + std::same_as decltype(auto) ret = + std::ranges::starts_with(Iter1(a), Sent1(Iter1(a + 6)), Iter2(p), Sent2(Iter2(p + 3))); + assert(!ret); + } + { + int a[] = {1, 2, 3, 4, 5, 6}; + int p[] = {4, 5, 6}; + auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); + auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); + std::same_as decltype(auto) ret = std::ranges::starts_with(whole, prefix); + assert(!ret); + } + } + + {// range and prefix are identical + { + int a[] = {1, 2, 3, 4, 5, 6}; + int p[] = {1, 2, 3, 4, 5, 6}; + std::same_as decltype(auto) ret = + std::ranges::starts_with(Iter1(a), Sent1(Iter1(a + 6)), Iter2(p), Sent2(Iter2(p + 6))); + assert(ret); + } + { + int a[] = {1, 2, 3, 4, 5, 6}; + int p[] = {1, 2, 3, 4, 5, 6}; + auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); + auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 6))); + std::same_as decltype(auto) ret = std::ranges::starts_with(whole, prefix); + assert(ret); + } + } + + {// prefix is longer than range + { + int a[] = {1, 2, 3, 4, 5, 6}; + int p[] = {1, 2, 3, 4, 5, 6, 7, 8}; + std::same_as decltype(auto) ret = + std::ranges::starts_with(Iter1(a), Sent1(Iter1(a + 6)), Iter2(p), Sent2(Iter2(p + 8))); + assert(!ret); + } + { + int a[] = {1, 2, 3, 4, 5, 6}; + int p[] = {1, 2, 3, 4, 5, 6, 7, 8}; + auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); + auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); + std::same_as decltype(auto) ret = std::ranges::starts_with(whole, prefix); + assert(!ret); + } + } + + {// prefix has zero length + { + int a[] = {1, 2, 3, 4, 5, 6}; + int p[] = {}; + std::same_as decltype(auto) ret = + std::ranges::starts_with(Iter1(a), Sent1(Iter1(a + 6)), Iter2(p), Sent2(Iter2(p))); + assert(ret); + } + { + int a[] = {1, 2, 3, 4, 5, 6}; + int p[] = {}; + auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); + auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p))); + std::same_as decltype(auto) ret = std::ranges::starts_with(whole, prefix); + assert(ret); + } + } + + {// range has zero length + { + int a[] = {}; + int p[] = {1, 2, 3, 4, 5, 6, 7, 8}; + std::same_as decltype(auto) ret = + std::ranges::starts_with(Iter1(a), Sent1(Iter1(a)), Iter2(p), Sent2(Iter2(p + 8))); + assert(!ret); + } + { + int a[] = {}; + int p[] = {1, 2, 3, 4, 5, 6, 7, 8}; + auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a))); + auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); + std::same_as decltype(auto) ret = std::ranges::starts_with(whole, prefix); + assert(!ret); + } + } + + {// check that the predicate is used + { + int a[] = {11, 8, 3, 4, 0, 6}; + int p[] = {1, 12}; + std::same_as decltype(auto) ret = std::ranges::starts_with( + Iter1(a), Sent1(Iter1(a + 6)), Iter2(p), Sent2(Iter2(p + 2)), [](int l, int r) { return l > r; }); + assert(!ret); + } + { + int a[] = {11, 8, 3, 4, 0, 6}; + int p[] = {1, 12}; + auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); + auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); + std::same_as decltype(auto) ret = std::ranges::starts_with(whole, prefix, [](int l, int r) { return l > r; }); + assert(!ret); + } + } + + {// check that the projections are used + { + int a[] = {1, 3, 5, 1, 5, 6}; + int p[] = {2, 3, 4}; + std::same_as decltype(auto) ret = std::ranges::starts_with( + Iter1(a), + Sent1(Iter1(a + 6)), + Iter2(p), + Sent2(Iter2(p + 3)), + {}, + [](int i) { return i + 3; }, + [](int i) { return i * 2; }); + assert(ret); + } + { + int a[] = {1, 3, 5, 1, 5, 6}; + int p[] = {2, 3, 4}; + auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); + auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); + std::same_as decltype(auto) ret = std::ranges::starts_with( + whole, prefix, {}, [](int i) { return i + 3; }, [](int i) { return i * 2; }); + assert(ret); + } + } +} + +constexpr bool test() { + types::for_each(types::forward_iterator_list{}, []() { + types::for_each(types::forward_iterator_list{}, []() { + test_iterators(); + test_iterators, I2, I2>(); + test_iterators>(); + test_iterators, I2, sized_sentinel>(); + }); +}); + + { // check that std::invoke is used + struct S { + int i; + + constexpr S identity() { return *this; } + + constexpr bool compare(const S& s) { return i == s.i; } + }; + { + S a[] = {{1}, {2}, {3}, {4}}; + S p[] = {{1}, {2}}; + auto ret = std::ranges::starts_with(a, a + 4, p, p + 2, &S::compare, &S::identity, &S::identity); + assert(ret); + } + { + S a[] = {{1}, {2}, {3}, {4}}; + S p[] = {{1}, {2}}; + auto ret = std::ranges::starts_with(a, p, &S::compare, &S::identity, &S::identity); + assert(ret); + } + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/algorithms/ranges_robust_against_differing_projections.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_differing_projections.pass.cpp index d940a7ab97006..4c90387443df7 100644 --- a/libcxx/test/std/algorithms/ranges_robust_against_differing_projections.pass.cpp +++ b/libcxx/test/std/algorithms/ranges_robust_against_differing_projections.pass.cpp @@ -20,6 +20,7 @@ #include #include #include +#include "test_macros.h" // (in1, in2, ...) template @@ -74,8 +75,10 @@ constexpr bool test_all() { test(std::ranges::set_symmetric_difference, in, in2, out2, less, proj1, proj2); test(std::ranges::set_union, in, in2, out, less, proj1, proj2); test(std::ranges::set_union, in, in2, out2, less, proj1, proj2); - //test(std::ranges::starts_with, in, in2, eq, proj1, proj2); - //test(std::ranges::ends_with, in, in2, eq, proj1, proj2); +#if TEST_STD_VER > 20 + test(std::ranges::starts_with, in, in2, eq, proj1, proj2); + // test(std::ranges::ends_with, in, in2, eq, proj1, proj2); +#endif return true; } diff --git a/libcxx/test/std/containers/container.adaptors/container.adaptors.format/types.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/container.adaptors.format/types.compile.pass.cpp new file mode 100644 index 0000000000000..a3ed6b1fa3295 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/container.adaptors.format/types.compile.pass.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: libcpp-has-no-incomplete-format + +// [container.adaptors.format]/1 +// For each of queue, priority_queue, and stack, the library provides the +// following formatter specialization where adaptor-type is the name of the +// template: +// template Container, class... U> +// struct formatter, charT>; +// +// Note it is unspecified in which header the adaptor formatters reside. In +// libc++ they are in . However their own headers are still required for +// the declarations of these types. + +// [format.formatter.spec]/4 +// If the library provides an explicit or partial specialization of +// formatter, that specialization is enabled and meets the +// Formatter requirements except as noted otherwise. +// +// Tests parts of the BasicFormatter requirements. Like the formattable concept +// it uses the semiregular concept. The test does not use the formattable +// concept to be similar to tests for formatters not provided by the +// header. + +#include +#include +#include +#include + +#include "test_macros.h" + +static_assert(std::semiregular, char>>); +static_assert(std::semiregular, char>>); +static_assert(std::semiregular, char>>); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(std::semiregular, wchar_t>>); +static_assert(std::semiregular, wchar_t>>); +static_assert(std::semiregular, wchar_t>>); +#endif // TEST_HAS_NO_WIDE_CHARACTERS diff --git a/libcxx/test/std/containers/from_range_helpers.h b/libcxx/test/std/containers/from_range_helpers.h new file mode 100644 index 0000000000000..9bd72acfad09b --- /dev/null +++ b/libcxx/test/std/containers/from_range_helpers.h @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SUPPORT_FROM_RANGE_HELPERS_H +#define SUPPORT_FROM_RANGE_HELPERS_H + +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "type_algorithms.h" + +struct Empty {}; + +template +struct InputRange { + cpp20_input_iterator begin(); + sentinel_wrapper> end(); +}; + +template +constexpr auto wrap_input(Range&& input) { + auto b = Iter(std::ranges::begin(input)); + auto e = Sent(Iter(std::ranges::end(input))); + return std::ranges::subrange(std::move(b), std::move(e)); +} + +template +constexpr auto wrap_input(std::vector& input) { + auto b = Iter(input.data()); + auto e = Sent(Iter(input.data() + input.size())); + return std::ranges::subrange(std::move(b), std::move(e)); +} + +struct KeyValue { + int key; // Only the key is considered for equality comparison. + char value; // Allows distinguishing equivalent instances. + + bool operator<(const KeyValue& other) const { return key < other.key; } + bool operator==(const KeyValue& other) const { return key == other.key; } +}; + +template <> +struct std::hash { + std::size_t operator()(const KeyValue& kv) const { + return kv.key; + } +}; + +#if !defined(TEST_HAS_NO_EXCEPTIONS) +template +struct ThrowingCopy { + static bool throwing_enabled; + static int created_by_copying; + static int destroyed; + int x = 0; // Allows distinguishing between different instances. + + ThrowingCopy() = default; + ThrowingCopy(int value) : x(value) {} + ~ThrowingCopy() { + ++destroyed; + } + + ThrowingCopy(const ThrowingCopy& other) : x(other.x) { + ++created_by_copying; + if (throwing_enabled && created_by_copying == N) { + throw -1; + } + } + + // Defined to silence GCC warnings. For test purposes, only copy construction is considered `created_by_copying`. + ThrowingCopy& operator=(const ThrowingCopy& other) { + x = other.x; + return *this; + } + + friend auto operator<=>(const ThrowingCopy&, const ThrowingCopy&) = default; + + static void reset() { + created_by_copying = destroyed = 0; + } +}; + +template +struct std::hash> { + std::size_t operator()(const ThrowingCopy& value) const { + return value.x; + } +}; + +template +bool ThrowingCopy::throwing_enabled = true; +template +int ThrowingCopy::created_by_copying = 0; +template +int ThrowingCopy::destroyed = 0; + +template +struct ThrowingAllocator { + using value_type = T; + using char_type = T; + using is_always_equal = std::false_type; + + ThrowingAllocator() = default; + + template + ThrowingAllocator(const ThrowingAllocator&) {} + + T* allocate(std::size_t) { throw 1; } + void deallocate(T*, std::size_t) {} + + template + friend bool operator==(const ThrowingAllocator&, const ThrowingAllocator&) { + return true; + } +}; +#endif + +template +constexpr void for_all_iterators_and_allocators(Func f) { + using Iterators = types::type_list< + cpp20_input_iterator, + forward_iterator, + bidirectional_iterator, + random_access_iterator, + contiguous_iterator, + T* + >; + + types::for_each(Iterators{}, [=]() { + f.template operator(), std::allocator>(); + f.template operator(), test_allocator>(); + f.template operator(), min_allocator>(); + f.template operator(), safe_allocator>(); + + if constexpr (std::sentinel_for) { + f.template operator()>(); + f.template operator()>(); + f.template operator()>(); + f.template operator()>(); + } + }); +} + +#endif // SUPPORT_FROM_RANGE_HELPERS_H diff --git a/libcxx/test/std/containers/insert_range_helpers.h b/libcxx/test/std/containers/insert_range_helpers.h new file mode 100644 index 0000000000000..2c4e14ce8b737 --- /dev/null +++ b/libcxx/test/std/containers/insert_range_helpers.h @@ -0,0 +1,123 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SUPPORT_INSERT_RANGE_HELPERS_H +#define SUPPORT_INSERT_RANGE_HELPERS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "from_range_helpers.h" +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "type_algorithms.h" + +// A simple literal-type container. It can be used as a `constexpr` global variable (which isn't supported by +// `std::vector`). +template +class Buffer { + public: + constexpr Buffer() = default; + + constexpr Buffer(std::initializer_list input) { + assert(input.size() <= N); + std::ranges::copy(input, data_); + size_ = input.size(); + } + + // Makes initializing `Buffer` nicer -- allows writing `buf = "abc"` instead of `buf = {'a', 'b', 'c'}`. + // To make the two forms equivalent, omits the terminating null. + template + constexpr Buffer(const char (&input) [N2]) + requires std::same_as { + static_assert(N2 <= N); + std::ranges::copy(input, data_); + // Omit the terminating null. + size_ = input[N2 - 1] == '\0' ? N2 - 1 : N2; + } + + constexpr const T* begin() const { return data_; } + constexpr const T* end() const { return data_ + size_; } + constexpr std::size_t size() const { return size_; } + + private: + std::size_t size_ = 0; + T data_[N] = {}; +}; + +template +struct TestCase { + Buffer initial; + std::size_t index = 0; + Buffer input; + Buffer expected; +}; + +template +constexpr void for_all_iterators_and_allocators(Func f) { + using Iterators = types::type_list< + cpp20_input_iterator, + forward_iterator, + bidirectional_iterator, + random_access_iterator, + contiguous_iterator, + PtrT + >; + + types::for_each(Iterators{}, [=]() { + f.template operator(), std::allocator>(); + f.template operator(), test_allocator>(); + f.template operator(), min_allocator>(); + f.template operator(), safe_allocator>(); + + if constexpr (std::sentinel_for) { + f.template operator()>(); + f.template operator()>(); + f.template operator()>(); + f.template operator()>(); + } + }); +} + +// Uses a shorter list of iterator types for use in `constexpr` mode for cases when running the full set in would take +// too long. +template +constexpr void for_all_iterators_and_allocators_constexpr(Func f) { + using Iterators = types::type_list< + cpp20_input_iterator, + forward_iterator, + PtrT + >; + + types::for_each(Iterators{}, [=]() { + f.template operator(), std::allocator>(); + f.template operator(), test_allocator>(); + f.template operator(), min_allocator>(); + f.template operator(), safe_allocator>(); + + if constexpr (std::sentinel_for) { + f.template operator()>(); + f.template operator()>(); + f.template operator()>(); + f.template operator()>(); + } + }); +} + +#endif // SUPPORT_INSERT_RANGE_HELPERS_H diff --git a/libcxx/test/std/containers/sequences/from_range_sequence_containers.h b/libcxx/test/std/containers/sequences/from_range_sequence_containers.h new file mode 100644 index 0000000000000..7106cb8077332 --- /dev/null +++ b/libcxx/test/std/containers/sequences/from_range_sequence_containers.h @@ -0,0 +1,161 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SUPPORT_FROM_RANGE_SEQUENCE_CONTAINERS_H +#define SUPPORT_FROM_RANGE_SEQUENCE_CONTAINERS_H + +#include +#include +#include +#include +#include +#include +#include + +#include "../from_range_helpers.h" +#include "MoveOnly.h" +#include "almost_satisfies_types.h" +#include "count_new.h" +#include "test_iterators.h" +#include "test_macros.h" + +template +concept HasSize = requires (const T& value) { value.size(); }; + +template +concept HasFromRangeCtr = requires (Range&& range) { + Container(std::from_range, std::forward(range)); + Container(std::from_range, std::forward(range), std::allocator()); +}; + +template