diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2572,7 +2572,11 @@ */ CXCursor_OMPTileDirective = 288, - CXCursor_LastStmt = CXCursor_OMPTileDirective, + /** OpenMP canonical loop. + */ + CXCursor_OMPCanonicalLoop = 289, + + CXCursor_LastStmt = CXCursor_OMPCanonicalLoop, /** * Cursor that represents the translation unit itself. diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2787,6 +2787,14 @@ return true; } +DEF_TRAVERSE_STMT(OMPCanonicalLoop, { + if (!getDerived().shouldVisitImplicitCode()) { + // Visit only the syntactical loop. + TRY_TO(TraverseStmt(S->getLoopStmt())); + ShouldVisitChildren = false; + } +}) + template bool RecursiveASTVisitor::TraverseOMPLoopDirective(OMPLoopDirective *S) { diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -28,6 +28,238 @@ // AST classes for directives. //===----------------------------------------------------------------------===// +/// Representation of an OpenMP canonical loop. +/// +/// OpenMP 1.0 C/C++, section 2.4.1 for Construct; canonical-shape +/// OpenMP 2.0 C/C++, section 2.4.1 for Construct; canonical-shape +/// OpenMP 2.5, section 2.5.1 Loop Construct; canonical form +/// OpenMP 3.1, section 2.5.1 Loop Construct; canonical form +/// OpenMP 4.0, section 2.6 Canonical Loop Form +/// OpenMP 4.5, section 2.6 Canonical Loop Form +/// OpenMP 5.0, section 2.9.1 Canonical Loop Form +/// OpenMP 5.1, section 2.11.1 Canonical Loop Nest Form +/// +/// An OpenMP canonical loop is a for-statement or range-based for-statement +/// with additional requirements that ensure that the number of iterations is +/// known before entering the loop and allow skipping to an arbitrary iteration. +/// The OMPCanonicalLoop AST node wraps a ForStmt or CXXForRangeStmt that is +/// known to fulfill OpenMP's canonical loop requirements because of being +/// associated to an OMPLoopBasedDirective. That is, the general structure is: +/// +/// OMPLoopBasedDirective +/// [`- CapturedStmt ] +/// [ `- CapturedDecl] +/// ` OMPCanonicalLoop +/// `- ForStmt/CXXForRangeStmt +/// `- Stmt +/// +/// One or multiple CapturedStmt/CapturedDecl pairs may be inserted by some +/// directives such as OMPParallelForDirective, but others do not need them +/// (such as OMPTileDirective). In The OMPCanonicalLoop and +/// ForStmt/CXXForRangeStmt pair is repeated for loop associated with the +/// directive. A OMPCanonicalLoop must not appear in the AST unless associated +/// with a OMPLoopBasedDirective. In an imperfectly nested loop nest, the +/// OMPCanonicalLoop may also be wrapped in a CompoundStmt: +/// +/// [...] +/// ` OMPCanonicalLoop +/// `- ForStmt/CXXForRangeStmt +/// `- CompoundStmt +/// |- Leading in-between code (if any) +/// |- OMPCanonicalLoop +/// | `- ForStmt/CXXForRangeStmt +/// | `- ... +/// `- Trailing in-between code (if any) +/// +/// The leading/trailing in-between code must not itself be a OMPCanonicalLoop +/// to avoid confusion which loop belongs to the nesting. +/// +/// There are three different kinds of iteration variables for different +/// purposes: +/// * Loop user variable: The user-accessible variable with different value for +/// each iteration. +/// * Loop iteration variable: The variable used to identify a loop iteration; +/// for range-based for-statement, this is the hidden iterator '__begin'. For +/// other loops, it is identical to the loop user variable. Must be a +/// random-access iterator, pointer or integer type. +/// * Logical iteration counter: Normalized loop counter starting at 0 and +/// incrementing by one at each iteration. Allows abstracting over the type +/// of the loop iteration variable and is always an unsigned integer type +/// appropriate to represent the range of the loop iteration variable. Its +/// value corresponds to the logical iteration number in the OpenMP +/// specification. +/// +/// This AST node provides two captured statements: +/// * The distance function which computes the number of iterations. +/// * The loop user variable function that computes the loop user variable when +/// given a logical iteration number. +/// +/// These captured statements provide the link between C/C++ semantics and the +/// logical iteration counters used by the OpenMPIRBuilder which is +/// language-agnostic and therefore does not know e.g. how to advance a +/// random-access iterator. The OpenMPIRBuilder will use this information to +/// apply simd, workshare-loop, distribute, taskloop and loop directives to the +/// loop. For compatibility with the non-OpenMPIRBuilder codegen path, an +/// OMPCanonicalLoop can itself also be wrapped into the CapturedStmts of an +/// OMPLoopDirective and skipped when searching for the associated syntactical +/// loop. +/// +/// Example: +/// +/// std::vector Container{1,2,3}; +/// for (std::string Str : Container) +/// Body(Str); +/// +/// which is syntactic sugar for approximately: +/// +/// auto &&__range = Container; +/// auto __begin = std::begin(__range); +/// auto __end = std::end(__range); +/// for (; __begin != __end; ++__begin) { +/// std::String Str = *__begin; +/// Body(Str); +/// } +/// +/// In this example, the loop user variable is `Str`, the loop iteration +/// variable is `__begin` of type `std::vector::iterator` and the +/// logical iteration number type is `size_t` (unsigned version of +/// `std::vector::iterator::difference_type` aka `ptrdiff_t`). +/// Therefore, the distance function will be +/// +/// [&](size_t &Result) { Result = __end - __begin; } +/// +/// and the loop variable function is +/// +/// [&,__begin](std::vector::iterator &Result, size_t Logical) { +/// Result = __begin + Logical; +/// } +/// +/// The variable `__begin`, aka the loop iteration variable, is captured by +/// value because it is modified in the loop body, but both functions require +/// the initial value. The OpenMP specification explicitly leaves unspecified +/// when the loop expressions are evaluated such that a capture by reference is +/// sufficient. +class OMPCanonicalLoop : public Stmt { + friend class ASTStmtReader; + friend class ASTStmtWriter; + + /// Children of this AST node. + enum { + LOOP_STMT, + DISTANCE_FUNC, + LOOPVAR_FUNC, + LOOPVAR_REF, + LastSubStmt = LOOPVAR_REF + }; + +private: + /// This AST node's children. + Stmt *SubStmts[LastSubStmt + 1] = {}; + + OMPCanonicalLoop() : Stmt(StmtClass::OMPCanonicalLoopClass) {} + +public: + /// Create a new OMPCanonicalLoop. + static OMPCanonicalLoop *create(const ASTContext &Ctx, Stmt *LoopStmt, + CapturedStmt *DistanceFunc, + CapturedStmt *LoopVarFunc, + DeclRefExpr *LoopVarRef) { + OMPCanonicalLoop *S = new (Ctx) OMPCanonicalLoop(); + S->setLoopStmt(LoopStmt); + S->setDistanceFunc(DistanceFunc); + S->setLoopVarFunc(LoopVarFunc); + S->setLoopVarRef(LoopVarRef); + return S; + } + + /// Create an empty OMPCanonicalLoop for deserialization. + static OMPCanonicalLoop *createEmpty(const ASTContext &Ctx) { + return new (Ctx) OMPCanonicalLoop(); + } + + static bool classof(const Stmt *S) { + return S->getStmtClass() == StmtClass::OMPCanonicalLoopClass; + } + + SourceLocation getBeginLoc() const { return getLoopStmt()->getBeginLoc(); } + SourceLocation getEndLoc() const { return getLoopStmt()->getEndLoc(); } + + /// Return this AST node's children. + /// @{ + child_range children() { + return child_range(&SubStmts[0], &SubStmts[0] + LastSubStmt + 1); + } + const_child_range children() const { + return const_child_range(&SubStmts[0], &SubStmts[0] + LastSubStmt + 1); + } + /// @} + + /// The wrapped syntactic loop statement (ForStmt or CXXForRangeStmt). + /// @{ + Stmt *getLoopStmt() { return SubStmts[LOOP_STMT]; } + const Stmt *getLoopStmt() const { return SubStmts[LOOP_STMT]; } + void setLoopStmt(Stmt *S) { + assert((isa(S) || isa(S)) && + "Canonical loop must be a for loop (range-based or otherwise)"); + SubStmts[LOOP_STMT] = S; + } + /// @} + + /// The function that computes the number of loop iterations. Can be evaluated + /// before entering the loop but after the syntactical loop's init + /// statement(s). + /// + /// Function signature: void(LogicalTy &Result) + /// Any values necessary to compute the distance are captures of the closure. + /// @{ + CapturedStmt *getDistanceFunc() { + return cast(SubStmts[DISTANCE_FUNC]); + } + const CapturedStmt *getDistanceFunc() const { + return cast(SubStmts[DISTANCE_FUNC]); + } + void setDistanceFunc(CapturedStmt *S) { + assert(S && "Expected non-null captured statement"); + SubStmts[DISTANCE_FUNC] = S; + } + /// @} + + /// The function that computes the loop user variable from a logical iteration + /// counter. Can be evaluated as first statement in the loop. + /// + /// Function signature: void(LoopVarTy &Result, LogicalTy Number) + /// Any other values required to compute the loop user variable (such as start + /// value, step size) are captured by the closure. In particular, the initial + /// value of loop iteration variable is captured by value to be unaffected by + /// previous iterations. + /// @{ + CapturedStmt *getLoopVarFunc() { + return cast(SubStmts[LOOPVAR_FUNC]); + } + const CapturedStmt *getLoopVarFunc() const { + return cast(SubStmts[LOOPVAR_FUNC]); + } + void setLoopVarFunc(CapturedStmt *S) { + assert(S && "Expected non-null captured statement"); + SubStmts[LOOPVAR_FUNC] = S; + } + /// @} + + /// Reference to the loop user variable as accessed in the loop body. + /// @{ + DeclRefExpr *getLoopVarRef() { + return cast(SubStmts[LOOPVAR_REF]); + } + const DeclRefExpr *getLoopVarRef() const { + return cast(SubStmts[LOOPVAR_REF]); + } + void setLoopVarRef(DeclRefExpr *E) { + assert(E && "Expected non-null loop variable"); + SubStmts[LOOPVAR_REF] = E; + } + /// @} +}; + /// This is a basic class for representing single OpenMP executable /// directive. /// diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -216,6 +216,7 @@ def AsTypeExpr : StmtNode; // OpenMP Directives. +def OMPCanonicalLoop : StmtNode; def OMPExecutableDirective : StmtNode; def OMPLoopBasedDirective : StmtNode; def OMPLoopDirective : StmtNode; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10486,6 +10486,11 @@ /// Initialization of captured region for OpenMP region. void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope); + + /// Called for syntactical loops (ForStmt or CXXForRangeStmt) associated to + /// an OpenMP loop directive. + StmtResult ActOnOpenMPCanonicalLoop(Stmt *AStmt); + /// End of OpenMP region. /// /// \param S Statement associated with the current OpenMP region. diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -109,2021 +109,2015 @@ } }; - /// A structure for putting "fast"-unqualified QualTypes into a - /// DenseMap. This uses the standard pointer hash function. - struct UnsafeQualTypeDenseMapInfo { - static bool isEqual(QualType A, QualType B) { return A == B; } - - static QualType getEmptyKey() { - return QualType::getFromOpaquePtr((void*) 1); - } - - static QualType getTombstoneKey() { - return QualType::getFromOpaquePtr((void*) 2); - } - - static unsigned getHashValue(QualType T) { - assert(!T.getLocalFastQualifiers() && - "hash invalid for types with fast quals"); - uintptr_t v = reinterpret_cast(T.getAsOpaquePtr()); - return (unsigned(v) >> 4) ^ (unsigned(v) >> 9); - } - }; - - /// An ID number that refers to an identifier in an AST file. - using IdentID = uint32_t; - - /// The number of predefined identifier IDs. - const unsigned int NUM_PREDEF_IDENT_IDS = 1; - - /// An ID number that refers to a macro in an AST file. - using MacroID = uint32_t; - - /// A global ID number that refers to a macro in an AST file. - using GlobalMacroID = uint32_t; - - /// A local to a module ID number that refers to a macro in an - /// AST file. - using LocalMacroID = uint32_t; - - /// The number of predefined macro IDs. - const unsigned int NUM_PREDEF_MACRO_IDS = 1; - - /// An ID number that refers to an ObjC selector in an AST file. - using SelectorID = uint32_t; - - /// The number of predefined selector IDs. - const unsigned int NUM_PREDEF_SELECTOR_IDS = 1; - - /// An ID number that refers to a set of CXXBaseSpecifiers in an - /// AST file. - using CXXBaseSpecifiersID = uint32_t; - - /// An ID number that refers to a list of CXXCtorInitializers in an - /// AST file. - using CXXCtorInitializersID = uint32_t; - - /// An ID number that refers to an entity in the detailed - /// preprocessing record. - using PreprocessedEntityID = uint32_t; - - /// An ID number that refers to a submodule in a module file. - using SubmoduleID = uint32_t; - - /// The number of predefined submodule IDs. - const unsigned int NUM_PREDEF_SUBMODULE_IDS = 1; - - /// Source range/offset of a preprocessed entity. - struct PPEntityOffset { - /// Raw source location of beginning of range. - unsigned Begin; - - /// Raw source location of end of range. - unsigned End; - - /// Offset in the AST file relative to ModuleFile::MacroOffsetsBase. - uint32_t BitOffset; - - PPEntityOffset(SourceRange R, uint32_t BitOffset) - : Begin(R.getBegin().getRawEncoding()), - End(R.getEnd().getRawEncoding()), BitOffset(BitOffset) {} - - SourceLocation getBegin() const { - return SourceLocation::getFromRawEncoding(Begin); - } - - SourceLocation getEnd() const { - return SourceLocation::getFromRawEncoding(End); - } - }; - - /// Source range of a skipped preprocessor region - struct PPSkippedRange { - /// Raw source location of beginning of range. - unsigned Begin; - /// Raw source location of end of range. - unsigned End; - - PPSkippedRange(SourceRange R) - : Begin(R.getBegin().getRawEncoding()), - End(R.getEnd().getRawEncoding()) { } - - SourceLocation getBegin() const { - return SourceLocation::getFromRawEncoding(Begin); - } - SourceLocation getEnd() const { - return SourceLocation::getFromRawEncoding(End); - } - }; - - /// Offset in the AST file. Use splitted 64-bit integer into low/high - /// parts to keep structure alignment 32-bit (it is important because - /// blobs in bitstream are 32-bit aligned). This structure is serialized - /// "as is" to the AST file. - struct UnderalignedInt64 { - uint32_t BitOffsetLow = 0; - uint32_t BitOffsetHigh = 0; - - UnderalignedInt64() = default; - UnderalignedInt64(uint64_t BitOffset) { setBitOffset(BitOffset); } - - void setBitOffset(uint64_t Offset) { - BitOffsetLow = Offset; - BitOffsetHigh = Offset >> 32; - } - - uint64_t getBitOffset() const { - return BitOffsetLow | (uint64_t(BitOffsetHigh) << 32); - } - }; - - /// Source location and bit offset of a declaration. - struct DeclOffset { - /// Raw source location. - unsigned Loc = 0; - - /// Offset relative to the start of the DECLTYPES_BLOCK block. Keep - /// structure alignment 32-bit and avoid padding gap because undefined - /// value in the padding affects AST hash. - UnderalignedInt64 BitOffset; - - DeclOffset() = default; - DeclOffset(SourceLocation Loc, uint64_t BitOffset, - uint64_t DeclTypesBlockStartOffset) { - setLocation(Loc); - setBitOffset(BitOffset, DeclTypesBlockStartOffset); - } - - void setLocation(SourceLocation L) { - Loc = L.getRawEncoding(); - } - - SourceLocation getLocation() const { - return SourceLocation::getFromRawEncoding(Loc); - } - - void setBitOffset(uint64_t Offset, - const uint64_t DeclTypesBlockStartOffset) { - BitOffset.setBitOffset(Offset - DeclTypesBlockStartOffset); - } - - uint64_t getBitOffset(const uint64_t DeclTypesBlockStartOffset) const { - return BitOffset.getBitOffset() + DeclTypesBlockStartOffset; - } - }; - - /// The number of predefined preprocessed entity IDs. - const unsigned int NUM_PREDEF_PP_ENTITY_IDS = 1; - - /// Describes the various kinds of blocks that occur within - /// an AST file. - enum BlockIDs { - /// The AST block, which acts as a container around the - /// full AST block. - AST_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, - - /// The block containing information about the source - /// manager. - SOURCE_MANAGER_BLOCK_ID, - - /// The block containing information about the - /// preprocessor. - PREPROCESSOR_BLOCK_ID, - - /// The block containing the definitions of all of the - /// types and decls used within the AST file. - DECLTYPES_BLOCK_ID, - - /// The block containing the detailed preprocessing record. - PREPROCESSOR_DETAIL_BLOCK_ID, - - /// The block containing the submodule structure. - SUBMODULE_BLOCK_ID, - - /// The block containing comments. - COMMENTS_BLOCK_ID, - - /// The control block, which contains all of the - /// information that needs to be validated prior to committing - /// to loading the AST file. - CONTROL_BLOCK_ID, - - /// The block of input files, which were used as inputs - /// to create this AST file. - /// - /// This block is part of the control block. - INPUT_FILES_BLOCK_ID, - - /// The block of configuration options, used to check that - /// a module is being used in a configuration compatible with the - /// configuration in which it was built. - /// - /// This block is part of the control block. - OPTIONS_BLOCK_ID, - - /// A block containing a module file extension. - EXTENSION_BLOCK_ID, - - /// A block with unhashed content. - /// - /// These records should not change the \a ASTFileSignature. See \a - /// UnhashedControlBlockRecordTypes for the list of records. - UNHASHED_CONTROL_BLOCK_ID, - }; - - /// Record types that occur within the control block. - enum ControlRecordTypes { - /// AST file metadata, including the AST file version number - /// and information about the compiler used to build this AST file. - METADATA = 1, - - /// Record code for the list of other AST files imported by - /// this AST file. - IMPORTS, - - /// Record code for the original file that was used to - /// generate the AST file, including both its file ID and its - /// name. - ORIGINAL_FILE, - - /// The directory that the PCH was originally created in. - ORIGINAL_PCH_DIR, - - /// Record code for file ID of the file or buffer that was used to - /// generate the AST file. - ORIGINAL_FILE_ID, - - /// Offsets into the input-files block where input files - /// reside. - INPUT_FILE_OFFSETS, - - /// Record code for the module name. - MODULE_NAME, - - /// Record code for the module map file that was used to build this - /// AST file. - MODULE_MAP_FILE, - - /// Record code for the module build directory. - MODULE_DIRECTORY, - }; - - /// Record types that occur within the options block inside - /// the control block. - enum OptionsRecordTypes { - /// Record code for the language options table. - /// - /// The record with this code contains the contents of the - /// LangOptions structure. We serialize the entire contents of - /// the structure, and let the reader decide which options are - /// actually important to check. - LANGUAGE_OPTIONS = 1, - - /// Record code for the target options table. - TARGET_OPTIONS, - - /// Record code for the filesystem options table. - FILE_SYSTEM_OPTIONS, - - /// Record code for the headers search options table. - HEADER_SEARCH_OPTIONS, - - /// Record code for the preprocessor options table. - PREPROCESSOR_OPTIONS, - }; - - /// Record codes for the unhashed control block. - enum UnhashedControlBlockRecordTypes { - /// Record code for the signature that identifiers this AST file. - SIGNATURE = 1, - - /// Record code for the content hash of the AST block. - AST_BLOCK_HASH, - - /// Record code for the diagnostic options table. - DIAGNOSTIC_OPTIONS, - - /// Record code for \#pragma diagnostic mappings. - DIAG_PRAGMA_MAPPINGS, - }; - - /// Record code for extension blocks. - enum ExtensionBlockRecordTypes { - /// Metadata describing this particular extension. - EXTENSION_METADATA = 1, - - /// The first record ID allocated to the extensions themselves. - FIRST_EXTENSION_RECORD_ID = 4 - }; - - /// Record types that occur within the input-files block - /// inside the control block. - enum InputFileRecordTypes { - /// An input file. - INPUT_FILE = 1, - - /// The input file content hash - INPUT_FILE_HASH - }; - - /// Record types that occur within the AST block itself. - enum ASTRecordTypes { - /// Record code for the offsets of each type. - /// - /// The TYPE_OFFSET constant describes the record that occurs - /// within the AST block. The record itself is an array of offsets that - /// point into the declarations and types block (identified by - /// DECLTYPES_BLOCK_ID). The index into the array is based on the ID - /// of a type. For a given type ID @c T, the lower three bits of - /// @c T are its qualifiers (const, volatile, restrict), as in - /// the QualType class. The upper bits, after being shifted and - /// subtracting NUM_PREDEF_TYPE_IDS, are used to index into the - /// TYPE_OFFSET block to determine the offset of that type's - /// corresponding record within the DECLTYPES_BLOCK_ID block. - TYPE_OFFSET = 1, - - /// Record code for the offsets of each decl. - /// - /// The DECL_OFFSET constant describes the record that occurs - /// within the block identified by DECL_OFFSETS_BLOCK_ID within - /// the AST block. The record itself is an array of offsets that - /// point into the declarations and types block (identified by - /// DECLTYPES_BLOCK_ID). The declaration ID is an index into this - /// record, after subtracting one to account for the use of - /// declaration ID 0 for a NULL declaration pointer. Index 0 is - /// reserved for the translation unit declaration. - DECL_OFFSET = 2, - - /// Record code for the table of offsets of each - /// identifier ID. - /// - /// The offset table contains offsets into the blob stored in - /// the IDENTIFIER_TABLE record. Each offset points to the - /// NULL-terminated string that corresponds to that identifier. - IDENTIFIER_OFFSET = 3, - - /// This is so that older clang versions, before the introduction - /// of the control block, can read and reject the newer PCH format. - /// *DON'T CHANGE THIS NUMBER*. - METADATA_OLD_FORMAT = 4, - - /// Record code for the identifier table. - /// - /// The identifier table is a simple blob that contains - /// NULL-terminated strings for all of the identifiers - /// referenced by the AST file. The IDENTIFIER_OFFSET table - /// contains the mapping from identifier IDs to the characters - /// in this blob. Note that the starting offsets of all of the - /// identifiers are odd, so that, when the identifier offset - /// table is loaded in, we can use the low bit to distinguish - /// between offsets (for unresolved identifier IDs) and - /// IdentifierInfo pointers (for already-resolved identifier - /// IDs). - IDENTIFIER_TABLE = 5, - - /// Record code for the array of eagerly deserialized decls. - /// - /// The AST file contains a list of all of the declarations that should be - /// eagerly deserialized present within the parsed headers, stored as an - /// array of declaration IDs. These declarations will be - /// reported to the AST consumer after the AST file has been - /// read, since their presence can affect the semantics of the - /// program (e.g., for code generation). - EAGERLY_DESERIALIZED_DECLS = 6, - - /// Record code for the set of non-builtin, special - /// types. - /// - /// This record contains the type IDs for the various type nodes - /// that are constructed during semantic analysis (e.g., - /// __builtin_va_list). The SPECIAL_TYPE_* constants provide - /// offsets into this record. - SPECIAL_TYPES = 7, - - /// Record code for the extra statistics we gather while - /// generating an AST file. - STATISTICS = 8, - - /// Record code for the array of tentative definitions. - TENTATIVE_DEFINITIONS = 9, - - // ID 10 used to be for a list of extern "C" declarations. - - /// Record code for the table of offsets into the - /// Objective-C method pool. - SELECTOR_OFFSETS = 11, - - /// Record code for the Objective-C method pool, - METHOD_POOL = 12, - - /// The value of the next __COUNTER__ to dispense. - /// [PP_COUNTER_VALUE, Val] - PP_COUNTER_VALUE = 13, - - /// Record code for the table of offsets into the block - /// of source-location information. - SOURCE_LOCATION_OFFSETS = 14, - - /// Record code for the set of source location entries - /// that need to be preloaded by the AST reader. - /// - /// This set contains the source location entry for the - /// predefines buffer and for any file entries that need to be - /// preloaded. - SOURCE_LOCATION_PRELOADS = 15, - - /// Record code for the set of ext_vector type names. - EXT_VECTOR_DECLS = 16, - - /// Record code for the array of unused file scoped decls. - UNUSED_FILESCOPED_DECLS = 17, - - /// Record code for the table of offsets to entries in the - /// preprocessing record. - PPD_ENTITIES_OFFSETS = 18, - - /// Record code for the array of VTable uses. - VTABLE_USES = 19, - - // ID 20 used to be for a list of dynamic classes. - - /// Record code for referenced selector pool. - REFERENCED_SELECTOR_POOL = 21, - - /// Record code for an update to the TU's lexically contained - /// declarations. - TU_UPDATE_LEXICAL = 22, - - // ID 23 used to be for a list of local redeclarations. - - /// Record code for declarations that Sema keeps references of. - SEMA_DECL_REFS = 24, - - /// Record code for weak undeclared identifiers. - WEAK_UNDECLARED_IDENTIFIERS = 25, +/// A structure for putting "fast"-unqualified QualTypes into a +/// DenseMap. This uses the standard pointer hash function. +struct UnsafeQualTypeDenseMapInfo { + static bool isEqual(QualType A, QualType B) { return A == B; } - /// Record code for pending implicit instantiations. - PENDING_IMPLICIT_INSTANTIATIONS = 26, + static QualType getEmptyKey() { + return QualType::getFromOpaquePtr((void *)1); + } + + static QualType getTombstoneKey() { + return QualType::getFromOpaquePtr((void *)2); + } + + static unsigned getHashValue(QualType T) { + assert(!T.getLocalFastQualifiers() && + "hash invalid for types with fast quals"); + uintptr_t v = reinterpret_cast(T.getAsOpaquePtr()); + return (unsigned(v) >> 4) ^ (unsigned(v) >> 9); + } +}; + +/// An ID number that refers to an identifier in an AST file. +using IdentID = uint32_t; + +/// The number of predefined identifier IDs. +const unsigned int NUM_PREDEF_IDENT_IDS = 1; + +/// An ID number that refers to a macro in an AST file. +using MacroID = uint32_t; + +/// A global ID number that refers to a macro in an AST file. +using GlobalMacroID = uint32_t; + +/// A local to a module ID number that refers to a macro in an +/// AST file. +using LocalMacroID = uint32_t; + +/// The number of predefined macro IDs. +const unsigned int NUM_PREDEF_MACRO_IDS = 1; + +/// An ID number that refers to an ObjC selector in an AST file. +using SelectorID = uint32_t; + +/// The number of predefined selector IDs. +const unsigned int NUM_PREDEF_SELECTOR_IDS = 1; + +/// An ID number that refers to a set of CXXBaseSpecifiers in an +/// AST file. +using CXXBaseSpecifiersID = uint32_t; + +/// An ID number that refers to a list of CXXCtorInitializers in an +/// AST file. +using CXXCtorInitializersID = uint32_t; + +/// An ID number that refers to an entity in the detailed +/// preprocessing record. +using PreprocessedEntityID = uint32_t; + +/// An ID number that refers to a submodule in a module file. +using SubmoduleID = uint32_t; + +/// The number of predefined submodule IDs. +const unsigned int NUM_PREDEF_SUBMODULE_IDS = 1; + +/// Source range/offset of a preprocessed entity. +struct PPEntityOffset { + /// Raw source location of beginning of range. + unsigned Begin; + + /// Raw source location of end of range. + unsigned End; + + /// Offset in the AST file relative to ModuleFile::MacroOffsetsBase. + uint32_t BitOffset; + + PPEntityOffset(SourceRange R, uint32_t BitOffset) + : Begin(R.getBegin().getRawEncoding()), End(R.getEnd().getRawEncoding()), + BitOffset(BitOffset) {} + + SourceLocation getBegin() const { + return SourceLocation::getFromRawEncoding(Begin); + } + + SourceLocation getEnd() const { + return SourceLocation::getFromRawEncoding(End); + } +}; + +/// Source range of a skipped preprocessor region +struct PPSkippedRange { + /// Raw source location of beginning of range. + unsigned Begin; + /// Raw source location of end of range. + unsigned End; + + PPSkippedRange(SourceRange R) + : Begin(R.getBegin().getRawEncoding()), End(R.getEnd().getRawEncoding()) { + } + + SourceLocation getBegin() const { + return SourceLocation::getFromRawEncoding(Begin); + } + SourceLocation getEnd() const { + return SourceLocation::getFromRawEncoding(End); + } +}; + +/// Offset in the AST file. Use splitted 64-bit integer into low/high +/// parts to keep structure alignment 32-bit (it is important because +/// blobs in bitstream are 32-bit aligned). This structure is serialized +/// "as is" to the AST file. +struct UnderalignedInt64 { + uint32_t BitOffsetLow = 0; + uint32_t BitOffsetHigh = 0; + + UnderalignedInt64() = default; + UnderalignedInt64(uint64_t BitOffset) { setBitOffset(BitOffset); } + + void setBitOffset(uint64_t Offset) { + BitOffsetLow = Offset; + BitOffsetHigh = Offset >> 32; + } + + uint64_t getBitOffset() const { + return BitOffsetLow | (uint64_t(BitOffsetHigh) << 32); + } +}; + +/// Source location and bit offset of a declaration. +struct DeclOffset { + /// Raw source location. + unsigned Loc = 0; + + /// Offset relative to the start of the DECLTYPES_BLOCK block. Keep + /// structure alignment 32-bit and avoid padding gap because undefined + /// value in the padding affects AST hash. + UnderalignedInt64 BitOffset; + + DeclOffset() = default; + DeclOffset(SourceLocation Loc, uint64_t BitOffset, + uint64_t DeclTypesBlockStartOffset) { + setLocation(Loc); + setBitOffset(BitOffset, DeclTypesBlockStartOffset); + } + + void setLocation(SourceLocation L) { Loc = L.getRawEncoding(); } + + SourceLocation getLocation() const { + return SourceLocation::getFromRawEncoding(Loc); + } + + void setBitOffset(uint64_t Offset, const uint64_t DeclTypesBlockStartOffset) { + BitOffset.setBitOffset(Offset - DeclTypesBlockStartOffset); + } + + uint64_t getBitOffset(const uint64_t DeclTypesBlockStartOffset) const { + return BitOffset.getBitOffset() + DeclTypesBlockStartOffset; + } +}; + +/// The number of predefined preprocessed entity IDs. +const unsigned int NUM_PREDEF_PP_ENTITY_IDS = 1; + +/// Describes the various kinds of blocks that occur within +/// an AST file. +enum BlockIDs { + /// The AST block, which acts as a container around the + /// full AST block. + AST_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, + + /// The block containing information about the source + /// manager. + SOURCE_MANAGER_BLOCK_ID, + + /// The block containing information about the + /// preprocessor. + PREPROCESSOR_BLOCK_ID, + + /// The block containing the definitions of all of the + /// types and decls used within the AST file. + DECLTYPES_BLOCK_ID, + + /// The block containing the detailed preprocessing record. + PREPROCESSOR_DETAIL_BLOCK_ID, + + /// The block containing the submodule structure. + SUBMODULE_BLOCK_ID, + + /// The block containing comments. + COMMENTS_BLOCK_ID, + + /// The control block, which contains all of the + /// information that needs to be validated prior to committing + /// to loading the AST file. + CONTROL_BLOCK_ID, + + /// The block of input files, which were used as inputs + /// to create this AST file. + /// + /// This block is part of the control block. + INPUT_FILES_BLOCK_ID, + + /// The block of configuration options, used to check that + /// a module is being used in a configuration compatible with the + /// configuration in which it was built. + /// + /// This block is part of the control block. + OPTIONS_BLOCK_ID, + + /// A block containing a module file extension. + EXTENSION_BLOCK_ID, + + /// A block with unhashed content. + /// + /// These records should not change the \a ASTFileSignature. See \a + /// UnhashedControlBlockRecordTypes for the list of records. + UNHASHED_CONTROL_BLOCK_ID, +}; + +/// Record types that occur within the control block. +enum ControlRecordTypes { + /// AST file metadata, including the AST file version number + /// and information about the compiler used to build this AST file. + METADATA = 1, + + /// Record code for the list of other AST files imported by + /// this AST file. + IMPORTS, + + /// Record code for the original file that was used to + /// generate the AST file, including both its file ID and its + /// name. + ORIGINAL_FILE, + + /// The directory that the PCH was originally created in. + ORIGINAL_PCH_DIR, + + /// Record code for file ID of the file or buffer that was used to + /// generate the AST file. + ORIGINAL_FILE_ID, + + /// Offsets into the input-files block where input files + /// reside. + INPUT_FILE_OFFSETS, + + /// Record code for the module name. + MODULE_NAME, + + /// Record code for the module map file that was used to build this + /// AST file. + MODULE_MAP_FILE, + + /// Record code for the module build directory. + MODULE_DIRECTORY, +}; + +/// Record types that occur within the options block inside +/// the control block. +enum OptionsRecordTypes { + /// Record code for the language options table. + /// + /// The record with this code contains the contents of the + /// LangOptions structure. We serialize the entire contents of + /// the structure, and let the reader decide which options are + /// actually important to check. + LANGUAGE_OPTIONS = 1, + + /// Record code for the target options table. + TARGET_OPTIONS, + + /// Record code for the filesystem options table. + FILE_SYSTEM_OPTIONS, + + /// Record code for the headers search options table. + HEADER_SEARCH_OPTIONS, + + /// Record code for the preprocessor options table. + PREPROCESSOR_OPTIONS, +}; + +/// Record codes for the unhashed control block. +enum UnhashedControlBlockRecordTypes { + /// Record code for the signature that identifiers this AST file. + SIGNATURE = 1, + + /// Record code for the content hash of the AST block. + AST_BLOCK_HASH, + + /// Record code for the diagnostic options table. + DIAGNOSTIC_OPTIONS, + + /// Record code for \#pragma diagnostic mappings. + DIAG_PRAGMA_MAPPINGS, +}; + +/// Record code for extension blocks. +enum ExtensionBlockRecordTypes { + /// Metadata describing this particular extension. + EXTENSION_METADATA = 1, + + /// The first record ID allocated to the extensions themselves. + FIRST_EXTENSION_RECORD_ID = 4 +}; - // ID 27 used to be for a list of replacement decls. +/// Record types that occur within the input-files block +/// inside the control block. +enum InputFileRecordTypes { + /// An input file. + INPUT_FILE = 1, - /// Record code for an update to a decl context's lookup table. - /// - /// In practice, this should only be used for the TU and namespaces. - UPDATE_VISIBLE = 28, + /// The input file content hash + INPUT_FILE_HASH +}; - /// Record for offsets of DECL_UPDATES records for declarations - /// that were modified after being deserialized and need updates. - DECL_UPDATE_OFFSETS = 29, +/// Record types that occur within the AST block itself. +enum ASTRecordTypes { + /// Record code for the offsets of each type. + /// + /// The TYPE_OFFSET constant describes the record that occurs + /// within the AST block. The record itself is an array of offsets that + /// point into the declarations and types block (identified by + /// DECLTYPES_BLOCK_ID). The index into the array is based on the ID + /// of a type. For a given type ID @c T, the lower three bits of + /// @c T are its qualifiers (const, volatile, restrict), as in + /// the QualType class. The upper bits, after being shifted and + /// subtracting NUM_PREDEF_TYPE_IDS, are used to index into the + /// TYPE_OFFSET block to determine the offset of that type's + /// corresponding record within the DECLTYPES_BLOCK_ID block. + TYPE_OFFSET = 1, + + /// Record code for the offsets of each decl. + /// + /// The DECL_OFFSET constant describes the record that occurs + /// within the block identified by DECL_OFFSETS_BLOCK_ID within + /// the AST block. The record itself is an array of offsets that + /// point into the declarations and types block (identified by + /// DECLTYPES_BLOCK_ID). The declaration ID is an index into this + /// record, after subtracting one to account for the use of + /// declaration ID 0 for a NULL declaration pointer. Index 0 is + /// reserved for the translation unit declaration. + DECL_OFFSET = 2, + + /// Record code for the table of offsets of each + /// identifier ID. + /// + /// The offset table contains offsets into the blob stored in + /// the IDENTIFIER_TABLE record. Each offset points to the + /// NULL-terminated string that corresponds to that identifier. + IDENTIFIER_OFFSET = 3, + + /// This is so that older clang versions, before the introduction + /// of the control block, can read and reject the newer PCH format. + /// *DON'T CHANGE THIS NUMBER*. + METADATA_OLD_FORMAT = 4, + + /// Record code for the identifier table. + /// + /// The identifier table is a simple blob that contains + /// NULL-terminated strings for all of the identifiers + /// referenced by the AST file. The IDENTIFIER_OFFSET table + /// contains the mapping from identifier IDs to the characters + /// in this blob. Note that the starting offsets of all of the + /// identifiers are odd, so that, when the identifier offset + /// table is loaded in, we can use the low bit to distinguish + /// between offsets (for unresolved identifier IDs) and + /// IdentifierInfo pointers (for already-resolved identifier + /// IDs). + IDENTIFIER_TABLE = 5, + + /// Record code for the array of eagerly deserialized decls. + /// + /// The AST file contains a list of all of the declarations that should be + /// eagerly deserialized present within the parsed headers, stored as an + /// array of declaration IDs. These declarations will be + /// reported to the AST consumer after the AST file has been + /// read, since their presence can affect the semantics of the + /// program (e.g., for code generation). + EAGERLY_DESERIALIZED_DECLS = 6, + + /// Record code for the set of non-builtin, special + /// types. + /// + /// This record contains the type IDs for the various type nodes + /// that are constructed during semantic analysis (e.g., + /// __builtin_va_list). The SPECIAL_TYPE_* constants provide + /// offsets into this record. + SPECIAL_TYPES = 7, + + /// Record code for the extra statistics we gather while + /// generating an AST file. + STATISTICS = 8, + + /// Record code for the array of tentative definitions. + TENTATIVE_DEFINITIONS = 9, + + // ID 10 used to be for a list of extern "C" declarations. + + /// Record code for the table of offsets into the + /// Objective-C method pool. + SELECTOR_OFFSETS = 11, + + /// Record code for the Objective-C method pool, + METHOD_POOL = 12, + + /// The value of the next __COUNTER__ to dispense. + /// [PP_COUNTER_VALUE, Val] + PP_COUNTER_VALUE = 13, + + /// Record code for the table of offsets into the block + /// of source-location information. + SOURCE_LOCATION_OFFSETS = 14, + + /// Record code for the set of source location entries + /// that need to be preloaded by the AST reader. + /// + /// This set contains the source location entry for the + /// predefines buffer and for any file entries that need to be + /// preloaded. + SOURCE_LOCATION_PRELOADS = 15, + + /// Record code for the set of ext_vector type names. + EXT_VECTOR_DECLS = 16, + + /// Record code for the array of unused file scoped decls. + UNUSED_FILESCOPED_DECLS = 17, + + /// Record code for the table of offsets to entries in the + /// preprocessing record. + PPD_ENTITIES_OFFSETS = 18, + + /// Record code for the array of VTable uses. + VTABLE_USES = 19, + + // ID 20 used to be for a list of dynamic classes. + + /// Record code for referenced selector pool. + REFERENCED_SELECTOR_POOL = 21, + + /// Record code for an update to the TU's lexically contained + /// declarations. + TU_UPDATE_LEXICAL = 22, + + // ID 23 used to be for a list of local redeclarations. + + /// Record code for declarations that Sema keeps references of. + SEMA_DECL_REFS = 24, + + /// Record code for weak undeclared identifiers. + WEAK_UNDECLARED_IDENTIFIERS = 25, - // ID 30 used to be a decl update record. These are now in the DECLTYPES - // block. + /// Record code for pending implicit instantiations. + PENDING_IMPLICIT_INSTANTIATIONS = 26, - // ID 31 used to be a list of offsets to DECL_CXX_BASE_SPECIFIERS records. + // ID 27 used to be for a list of replacement decls. - // ID 32 used to be the code for \#pragma diagnostic mappings. + /// Record code for an update to a decl context's lookup table. + /// + /// In practice, this should only be used for the TU and namespaces. + UPDATE_VISIBLE = 28, - /// Record code for special CUDA declarations. - CUDA_SPECIAL_DECL_REFS = 33, + /// Record for offsets of DECL_UPDATES records for declarations + /// that were modified after being deserialized and need updates. + DECL_UPDATE_OFFSETS = 29, - /// Record code for header search information. - HEADER_SEARCH_TABLE = 34, + // ID 30 used to be a decl update record. These are now in the DECLTYPES + // block. - /// Record code for floating point \#pragma options. - FP_PRAGMA_OPTIONS = 35, + // ID 31 used to be a list of offsets to DECL_CXX_BASE_SPECIFIERS records. - /// Record code for enabled OpenCL extensions. - OPENCL_EXTENSIONS = 36, + // ID 32 used to be the code for \#pragma diagnostic mappings. - /// The list of delegating constructor declarations. - DELEGATING_CTORS = 37, + /// Record code for special CUDA declarations. + CUDA_SPECIAL_DECL_REFS = 33, - /// Record code for the set of known namespaces, which are used - /// for typo correction. - KNOWN_NAMESPACES = 38, + /// Record code for header search information. + HEADER_SEARCH_TABLE = 34, - /// Record code for the remapping information used to relate - /// loaded modules to the various offsets and IDs(e.g., source location - /// offests, declaration and type IDs) that are used in that module to - /// refer to other modules. - MODULE_OFFSET_MAP = 39, + /// Record code for floating point \#pragma options. + FP_PRAGMA_OPTIONS = 35, - /// Record code for the source manager line table information, - /// which stores information about \#line directives. - SOURCE_MANAGER_LINE_TABLE = 40, + /// Record code for enabled OpenCL extensions. + OPENCL_EXTENSIONS = 36, - /// Record code for map of Objective-C class definition IDs to the - /// ObjC categories in a module that are attached to that class. - OBJC_CATEGORIES_MAP = 41, + /// The list of delegating constructor declarations. + DELEGATING_CTORS = 37, - /// Record code for a file sorted array of DeclIDs in a module. - FILE_SORTED_DECLS = 42, + /// Record code for the set of known namespaces, which are used + /// for typo correction. + KNOWN_NAMESPACES = 38, - /// Record code for an array of all of the (sub)modules that were - /// imported by the AST file. - IMPORTED_MODULES = 43, + /// Record code for the remapping information used to relate + /// loaded modules to the various offsets and IDs(e.g., source location + /// offests, declaration and type IDs) that are used in that module to + /// refer to other modules. + MODULE_OFFSET_MAP = 39, - // ID 44 used to be a table of merged canonical declarations. - // ID 45 used to be a list of declaration IDs of local redeclarations. + /// Record code for the source manager line table information, + /// which stores information about \#line directives. + SOURCE_MANAGER_LINE_TABLE = 40, - /// Record code for the array of Objective-C categories (including - /// extensions). - /// - /// This array can only be interpreted properly using the Objective-C - /// categories map. - OBJC_CATEGORIES = 46, + /// Record code for map of Objective-C class definition IDs to the + /// ObjC categories in a module that are attached to that class. + OBJC_CATEGORIES_MAP = 41, - /// Record code for the table of offsets of each macro ID. - /// - /// The offset table contains offsets into the blob stored in - /// the preprocessor block. Each offset points to the corresponding - /// macro definition. - MACRO_OFFSET = 47, + /// Record code for a file sorted array of DeclIDs in a module. + FILE_SORTED_DECLS = 42, - /// A list of "interesting" identifiers. Only used in C++ (where we - /// don't normally do lookups into the serialized identifier table). These - /// are eagerly deserialized. - INTERESTING_IDENTIFIERS = 48, + /// Record code for an array of all of the (sub)modules that were + /// imported by the AST file. + IMPORTED_MODULES = 43, - /// Record code for undefined but used functions and variables that - /// need a definition in this TU. - UNDEFINED_BUT_USED = 49, + // ID 44 used to be a table of merged canonical declarations. + // ID 45 used to be a list of declaration IDs of local redeclarations. - /// Record code for late parsed template functions. - LATE_PARSED_TEMPLATE = 50, + /// Record code for the array of Objective-C categories (including + /// extensions). + /// + /// This array can only be interpreted properly using the Objective-C + /// categories map. + OBJC_CATEGORIES = 46, - /// Record code for \#pragma optimize options. - OPTIMIZE_PRAGMA_OPTIONS = 51, + /// Record code for the table of offsets of each macro ID. + /// + /// The offset table contains offsets into the blob stored in + /// the preprocessor block. Each offset points to the corresponding + /// macro definition. + MACRO_OFFSET = 47, - /// Record code for potentially unused local typedef names. - UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES = 52, + /// A list of "interesting" identifiers. Only used in C++ (where we + /// don't normally do lookups into the serialized identifier table). These + /// are eagerly deserialized. + INTERESTING_IDENTIFIERS = 48, - // ID 53 used to be a table of constructor initializer records. + /// Record code for undefined but used functions and variables that + /// need a definition in this TU. + UNDEFINED_BUT_USED = 49, - /// Delete expressions that will be analyzed later. - DELETE_EXPRS_TO_ANALYZE = 54, + /// Record code for late parsed template functions. + LATE_PARSED_TEMPLATE = 50, - /// Record code for \#pragma ms_struct options. - MSSTRUCT_PRAGMA_OPTIONS = 55, + /// Record code for \#pragma optimize options. + OPTIMIZE_PRAGMA_OPTIONS = 51, - /// Record code for \#pragma ms_struct options. - POINTERS_TO_MEMBERS_PRAGMA_OPTIONS = 56, + /// Record code for potentially unused local typedef names. + UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES = 52, - /// Number of unmatched #pragma clang cuda_force_host_device begin - /// directives we've seen. - CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH = 57, + // ID 53 used to be a table of constructor initializer records. - /// Record code for types associated with OpenCL extensions. - OPENCL_EXTENSION_TYPES = 58, + /// Delete expressions that will be analyzed later. + DELETE_EXPRS_TO_ANALYZE = 54, - /// Record code for declarations associated with OpenCL extensions. - OPENCL_EXTENSION_DECLS = 59, + /// Record code for \#pragma ms_struct options. + MSSTRUCT_PRAGMA_OPTIONS = 55, - MODULAR_CODEGEN_DECLS = 60, + /// Record code for \#pragma ms_struct options. + POINTERS_TO_MEMBERS_PRAGMA_OPTIONS = 56, - /// Record code for \#pragma align/pack options. - ALIGN_PACK_PRAGMA_OPTIONS = 61, + /// Number of unmatched #pragma clang cuda_force_host_device begin + /// directives we've seen. + CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH = 57, - /// The stack of open #ifs/#ifdefs recorded in a preamble. - PP_CONDITIONAL_STACK = 62, + /// Record code for types associated with OpenCL extensions. + OPENCL_EXTENSION_TYPES = 58, - /// A table of skipped ranges within the preprocessing record. - PPD_SKIPPED_RANGES = 63, + /// Record code for declarations associated with OpenCL extensions. + OPENCL_EXTENSION_DECLS = 59, - /// Record code for the Decls to be checked for deferred diags. - DECLS_TO_CHECK_FOR_DEFERRED_DIAGS = 64, + MODULAR_CODEGEN_DECLS = 60, - /// Record code for \#pragma float_control options. - FLOAT_CONTROL_PRAGMA_OPTIONS = 65, - }; + /// Record code for \#pragma align/pack options. + ALIGN_PACK_PRAGMA_OPTIONS = 61, - /// Record types used within a source manager block. - enum SourceManagerRecordTypes { - /// Describes a source location entry (SLocEntry) for a - /// file. - SM_SLOC_FILE_ENTRY = 1, + /// The stack of open #ifs/#ifdefs recorded in a preamble. + PP_CONDITIONAL_STACK = 62, - /// Describes a source location entry (SLocEntry) for a - /// buffer. - SM_SLOC_BUFFER_ENTRY = 2, + /// A table of skipped ranges within the preprocessing record. + PPD_SKIPPED_RANGES = 63, - /// Describes a blob that contains the data for a buffer - /// entry. This kind of record always directly follows a - /// SM_SLOC_BUFFER_ENTRY record or a SM_SLOC_FILE_ENTRY with an - /// overridden buffer. - SM_SLOC_BUFFER_BLOB = 3, + /// Record code for the Decls to be checked for deferred diags. + DECLS_TO_CHECK_FOR_DEFERRED_DIAGS = 64, - /// Describes a zlib-compressed blob that contains the data for - /// a buffer entry. - SM_SLOC_BUFFER_BLOB_COMPRESSED = 4, + /// Record code for \#pragma float_control options. + FLOAT_CONTROL_PRAGMA_OPTIONS = 65, +}; - /// Describes a source location entry (SLocEntry) for a - /// macro expansion. - SM_SLOC_EXPANSION_ENTRY = 5 - }; +/// Record types used within a source manager block. +enum SourceManagerRecordTypes { + /// Describes a source location entry (SLocEntry) for a + /// file. + SM_SLOC_FILE_ENTRY = 1, + + /// Describes a source location entry (SLocEntry) for a + /// buffer. + SM_SLOC_BUFFER_ENTRY = 2, + + /// Describes a blob that contains the data for a buffer + /// entry. This kind of record always directly follows a + /// SM_SLOC_BUFFER_ENTRY record or a SM_SLOC_FILE_ENTRY with an + /// overridden buffer. + SM_SLOC_BUFFER_BLOB = 3, + + /// Describes a zlib-compressed blob that contains the data for + /// a buffer entry. + SM_SLOC_BUFFER_BLOB_COMPRESSED = 4, + + /// Describes a source location entry (SLocEntry) for a + /// macro expansion. + SM_SLOC_EXPANSION_ENTRY = 5 +}; - /// Record types used within a preprocessor block. - enum PreprocessorRecordTypes { - // The macros in the PP section are a PP_MACRO_* instance followed by a - // list of PP_TOKEN instances for each token in the definition. +/// Record types used within a preprocessor block. +enum PreprocessorRecordTypes { + // The macros in the PP section are a PP_MACRO_* instance followed by a + // list of PP_TOKEN instances for each token in the definition. - /// An object-like macro definition. - /// [PP_MACRO_OBJECT_LIKE, IdentInfoID, SLoc, IsUsed] - PP_MACRO_OBJECT_LIKE = 1, + /// An object-like macro definition. + /// [PP_MACRO_OBJECT_LIKE, IdentInfoID, SLoc, IsUsed] + PP_MACRO_OBJECT_LIKE = 1, - /// A function-like macro definition. - /// [PP_MACRO_FUNCTION_LIKE, \, IsC99Varargs, - /// IsGNUVarars, NumArgs, ArgIdentInfoID* ] - PP_MACRO_FUNCTION_LIKE = 2, + /// A function-like macro definition. + /// [PP_MACRO_FUNCTION_LIKE, \, IsC99Varargs, + /// IsGNUVarars, NumArgs, ArgIdentInfoID* ] + PP_MACRO_FUNCTION_LIKE = 2, - /// Describes one token. - /// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags] - PP_TOKEN = 3, + /// Describes one token. + /// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags] + PP_TOKEN = 3, - /// The macro directives history for a particular identifier. - PP_MACRO_DIRECTIVE_HISTORY = 4, + /// The macro directives history for a particular identifier. + PP_MACRO_DIRECTIVE_HISTORY = 4, - /// A macro directive exported by a module. - /// [PP_MODULE_MACRO, SubmoduleID, MacroID, (Overridden SubmoduleID)*] - PP_MODULE_MACRO = 5, - }; + /// A macro directive exported by a module. + /// [PP_MODULE_MACRO, SubmoduleID, MacroID, (Overridden SubmoduleID)*] + PP_MODULE_MACRO = 5, +}; - /// Record types used within a preprocessor detail block. - enum PreprocessorDetailRecordTypes { - /// Describes a macro expansion within the preprocessing record. - PPD_MACRO_EXPANSION = 0, +/// Record types used within a preprocessor detail block. +enum PreprocessorDetailRecordTypes { + /// Describes a macro expansion within the preprocessing record. + PPD_MACRO_EXPANSION = 0, - /// Describes a macro definition within the preprocessing record. - PPD_MACRO_DEFINITION = 1, + /// Describes a macro definition within the preprocessing record. + PPD_MACRO_DEFINITION = 1, - /// Describes an inclusion directive within the preprocessing - /// record. - PPD_INCLUSION_DIRECTIVE = 2 - }; + /// Describes an inclusion directive within the preprocessing + /// record. + PPD_INCLUSION_DIRECTIVE = 2 +}; - /// Record types used within a submodule description block. - enum SubmoduleRecordTypes { - /// Metadata for submodules as a whole. - SUBMODULE_METADATA = 0, +/// Record types used within a submodule description block. +enum SubmoduleRecordTypes { + /// Metadata for submodules as a whole. + SUBMODULE_METADATA = 0, - /// Defines the major attributes of a submodule, including its - /// name and parent. - SUBMODULE_DEFINITION = 1, + /// Defines the major attributes of a submodule, including its + /// name and parent. + SUBMODULE_DEFINITION = 1, - /// Specifies the umbrella header used to create this module, - /// if any. - SUBMODULE_UMBRELLA_HEADER = 2, + /// Specifies the umbrella header used to create this module, + /// if any. + SUBMODULE_UMBRELLA_HEADER = 2, - /// Specifies a header that falls into this (sub)module. - SUBMODULE_HEADER = 3, + /// Specifies a header that falls into this (sub)module. + SUBMODULE_HEADER = 3, - /// Specifies a top-level header that falls into this (sub)module. - SUBMODULE_TOPHEADER = 4, + /// Specifies a top-level header that falls into this (sub)module. + SUBMODULE_TOPHEADER = 4, - /// Specifies an umbrella directory. - SUBMODULE_UMBRELLA_DIR = 5, + /// Specifies an umbrella directory. + SUBMODULE_UMBRELLA_DIR = 5, - /// Specifies the submodules that are imported by this - /// submodule. - SUBMODULE_IMPORTS = 6, + /// Specifies the submodules that are imported by this + /// submodule. + SUBMODULE_IMPORTS = 6, - /// Specifies the submodules that are re-exported from this - /// submodule. - SUBMODULE_EXPORTS = 7, + /// Specifies the submodules that are re-exported from this + /// submodule. + SUBMODULE_EXPORTS = 7, - /// Specifies a required feature. - SUBMODULE_REQUIRES = 8, + /// Specifies a required feature. + SUBMODULE_REQUIRES = 8, - /// Specifies a header that has been explicitly excluded - /// from this submodule. - SUBMODULE_EXCLUDED_HEADER = 9, + /// Specifies a header that has been explicitly excluded + /// from this submodule. + SUBMODULE_EXCLUDED_HEADER = 9, - /// Specifies a library or framework to link against. - SUBMODULE_LINK_LIBRARY = 10, + /// Specifies a library or framework to link against. + SUBMODULE_LINK_LIBRARY = 10, - /// Specifies a configuration macro for this module. - SUBMODULE_CONFIG_MACRO = 11, + /// Specifies a configuration macro for this module. + SUBMODULE_CONFIG_MACRO = 11, - /// Specifies a conflict with another module. - SUBMODULE_CONFLICT = 12, + /// Specifies a conflict with another module. + SUBMODULE_CONFLICT = 12, - /// Specifies a header that is private to this submodule. - SUBMODULE_PRIVATE_HEADER = 13, + /// Specifies a header that is private to this submodule. + SUBMODULE_PRIVATE_HEADER = 13, - /// Specifies a header that is part of the module but must be - /// textually included. - SUBMODULE_TEXTUAL_HEADER = 14, + /// Specifies a header that is part of the module but must be + /// textually included. + SUBMODULE_TEXTUAL_HEADER = 14, - /// Specifies a header that is private to this submodule but - /// must be textually included. - SUBMODULE_PRIVATE_TEXTUAL_HEADER = 15, + /// Specifies a header that is private to this submodule but + /// must be textually included. + SUBMODULE_PRIVATE_TEXTUAL_HEADER = 15, - /// Specifies some declarations with initializers that must be - /// emitted to initialize the module. - SUBMODULE_INITIALIZERS = 16, + /// Specifies some declarations with initializers that must be + /// emitted to initialize the module. + SUBMODULE_INITIALIZERS = 16, - /// Specifies the name of the module that will eventually - /// re-export the entities in this module. - SUBMODULE_EXPORT_AS = 17, - }; + /// Specifies the name of the module that will eventually + /// re-export the entities in this module. + SUBMODULE_EXPORT_AS = 17, +}; - /// Record types used within a comments block. - enum CommentRecordTypes { - COMMENTS_RAW_COMMENT = 0 - }; +/// Record types used within a comments block. +enum CommentRecordTypes { COMMENTS_RAW_COMMENT = 0 }; - /// \defgroup ASTAST AST file AST constants - /// - /// The constants in this group describe various components of the - /// abstract syntax tree within an AST file. - /// - /// @{ +/// \defgroup ASTAST AST file AST constants +/// +/// The constants in this group describe various components of the +/// abstract syntax tree within an AST file. +/// +/// @{ - /// Predefined type IDs. - /// - /// These type IDs correspond to predefined types in the AST - /// context, such as built-in types (int) and special place-holder - /// types (the \ and \ type markers). Such - /// types are never actually serialized, since they will be built - /// by the AST context when it is created. - enum PredefinedTypeIDs { - /// The NULL type. - PREDEF_TYPE_NULL_ID = 0, +/// Predefined type IDs. +/// +/// These type IDs correspond to predefined types in the AST +/// context, such as built-in types (int) and special place-holder +/// types (the \ and \ type markers). Such +/// types are never actually serialized, since they will be built +/// by the AST context when it is created. +enum PredefinedTypeIDs { + /// The NULL type. + PREDEF_TYPE_NULL_ID = 0, - /// The void type. - PREDEF_TYPE_VOID_ID = 1, + /// The void type. + PREDEF_TYPE_VOID_ID = 1, - /// The 'bool' or '_Bool' type. - PREDEF_TYPE_BOOL_ID = 2, + /// The 'bool' or '_Bool' type. + PREDEF_TYPE_BOOL_ID = 2, - /// The 'char' type, when it is unsigned. - PREDEF_TYPE_CHAR_U_ID = 3, + /// The 'char' type, when it is unsigned. + PREDEF_TYPE_CHAR_U_ID = 3, - /// The 'unsigned char' type. - PREDEF_TYPE_UCHAR_ID = 4, + /// The 'unsigned char' type. + PREDEF_TYPE_UCHAR_ID = 4, - /// The 'unsigned short' type. - PREDEF_TYPE_USHORT_ID = 5, + /// The 'unsigned short' type. + PREDEF_TYPE_USHORT_ID = 5, - /// The 'unsigned int' type. - PREDEF_TYPE_UINT_ID = 6, + /// The 'unsigned int' type. + PREDEF_TYPE_UINT_ID = 6, - /// The 'unsigned long' type. - PREDEF_TYPE_ULONG_ID = 7, + /// The 'unsigned long' type. + PREDEF_TYPE_ULONG_ID = 7, - /// The 'unsigned long long' type. - PREDEF_TYPE_ULONGLONG_ID = 8, + /// The 'unsigned long long' type. + PREDEF_TYPE_ULONGLONG_ID = 8, - /// The 'char' type, when it is signed. - PREDEF_TYPE_CHAR_S_ID = 9, + /// The 'char' type, when it is signed. + PREDEF_TYPE_CHAR_S_ID = 9, - /// The 'signed char' type. - PREDEF_TYPE_SCHAR_ID = 10, + /// The 'signed char' type. + PREDEF_TYPE_SCHAR_ID = 10, - /// The C++ 'wchar_t' type. - PREDEF_TYPE_WCHAR_ID = 11, + /// The C++ 'wchar_t' type. + PREDEF_TYPE_WCHAR_ID = 11, - /// The (signed) 'short' type. - PREDEF_TYPE_SHORT_ID = 12, + /// The (signed) 'short' type. + PREDEF_TYPE_SHORT_ID = 12, - /// The (signed) 'int' type. - PREDEF_TYPE_INT_ID = 13, + /// The (signed) 'int' type. + PREDEF_TYPE_INT_ID = 13, - /// The (signed) 'long' type. - PREDEF_TYPE_LONG_ID = 14, + /// The (signed) 'long' type. + PREDEF_TYPE_LONG_ID = 14, - /// The (signed) 'long long' type. - PREDEF_TYPE_LONGLONG_ID = 15, + /// The (signed) 'long long' type. + PREDEF_TYPE_LONGLONG_ID = 15, - /// The 'float' type. - PREDEF_TYPE_FLOAT_ID = 16, + /// The 'float' type. + PREDEF_TYPE_FLOAT_ID = 16, - /// The 'double' type. - PREDEF_TYPE_DOUBLE_ID = 17, + /// The 'double' type. + PREDEF_TYPE_DOUBLE_ID = 17, - /// The 'long double' type. - PREDEF_TYPE_LONGDOUBLE_ID = 18, + /// The 'long double' type. + PREDEF_TYPE_LONGDOUBLE_ID = 18, - /// The placeholder type for overloaded function sets. - PREDEF_TYPE_OVERLOAD_ID = 19, + /// The placeholder type for overloaded function sets. + PREDEF_TYPE_OVERLOAD_ID = 19, - /// The placeholder type for dependent types. - PREDEF_TYPE_DEPENDENT_ID = 20, + /// The placeholder type for dependent types. + PREDEF_TYPE_DEPENDENT_ID = 20, - /// The '__uint128_t' type. - PREDEF_TYPE_UINT128_ID = 21, + /// The '__uint128_t' type. + PREDEF_TYPE_UINT128_ID = 21, - /// The '__int128_t' type. - PREDEF_TYPE_INT128_ID = 22, + /// The '__int128_t' type. + PREDEF_TYPE_INT128_ID = 22, - /// The type of 'nullptr'. - PREDEF_TYPE_NULLPTR_ID = 23, + /// The type of 'nullptr'. + PREDEF_TYPE_NULLPTR_ID = 23, - /// The C++ 'char16_t' type. - PREDEF_TYPE_CHAR16_ID = 24, + /// The C++ 'char16_t' type. + PREDEF_TYPE_CHAR16_ID = 24, - /// The C++ 'char32_t' type. - PREDEF_TYPE_CHAR32_ID = 25, + /// The C++ 'char32_t' type. + PREDEF_TYPE_CHAR32_ID = 25, - /// The ObjC 'id' type. - PREDEF_TYPE_OBJC_ID = 26, + /// The ObjC 'id' type. + PREDEF_TYPE_OBJC_ID = 26, - /// The ObjC 'Class' type. - PREDEF_TYPE_OBJC_CLASS = 27, + /// The ObjC 'Class' type. + PREDEF_TYPE_OBJC_CLASS = 27, - /// The ObjC 'SEL' type. - PREDEF_TYPE_OBJC_SEL = 28, + /// The ObjC 'SEL' type. + PREDEF_TYPE_OBJC_SEL = 28, - /// The 'unknown any' placeholder type. - PREDEF_TYPE_UNKNOWN_ANY = 29, + /// The 'unknown any' placeholder type. + PREDEF_TYPE_UNKNOWN_ANY = 29, - /// The placeholder type for bound member functions. - PREDEF_TYPE_BOUND_MEMBER = 30, + /// The placeholder type for bound member functions. + PREDEF_TYPE_BOUND_MEMBER = 30, - /// The "auto" deduction type. - PREDEF_TYPE_AUTO_DEDUCT = 31, + /// The "auto" deduction type. + PREDEF_TYPE_AUTO_DEDUCT = 31, - /// The "auto &&" deduction type. - PREDEF_TYPE_AUTO_RREF_DEDUCT = 32, + /// The "auto &&" deduction type. + PREDEF_TYPE_AUTO_RREF_DEDUCT = 32, - /// The OpenCL 'half' / ARM NEON __fp16 type. - PREDEF_TYPE_HALF_ID = 33, + /// The OpenCL 'half' / ARM NEON __fp16 type. + PREDEF_TYPE_HALF_ID = 33, - /// ARC's unbridged-cast placeholder type. - PREDEF_TYPE_ARC_UNBRIDGED_CAST = 34, + /// ARC's unbridged-cast placeholder type. + PREDEF_TYPE_ARC_UNBRIDGED_CAST = 34, - /// The pseudo-object placeholder type. - PREDEF_TYPE_PSEUDO_OBJECT = 35, + /// The pseudo-object placeholder type. + PREDEF_TYPE_PSEUDO_OBJECT = 35, - /// The placeholder type for builtin functions. - PREDEF_TYPE_BUILTIN_FN = 36, + /// The placeholder type for builtin functions. + PREDEF_TYPE_BUILTIN_FN = 36, - /// OpenCL event type. - PREDEF_TYPE_EVENT_ID = 37, + /// OpenCL event type. + PREDEF_TYPE_EVENT_ID = 37, - /// OpenCL clk event type. - PREDEF_TYPE_CLK_EVENT_ID = 38, + /// OpenCL clk event type. + PREDEF_TYPE_CLK_EVENT_ID = 38, - /// OpenCL sampler type. - PREDEF_TYPE_SAMPLER_ID = 39, + /// OpenCL sampler type. + PREDEF_TYPE_SAMPLER_ID = 39, - /// OpenCL queue type. - PREDEF_TYPE_QUEUE_ID = 40, + /// OpenCL queue type. + PREDEF_TYPE_QUEUE_ID = 40, - /// OpenCL reserve_id type. - PREDEF_TYPE_RESERVE_ID_ID = 41, + /// OpenCL reserve_id type. + PREDEF_TYPE_RESERVE_ID_ID = 41, - /// The placeholder type for OpenMP array section. - PREDEF_TYPE_OMP_ARRAY_SECTION = 42, + /// The placeholder type for OpenMP array section. + PREDEF_TYPE_OMP_ARRAY_SECTION = 42, - /// The '__float128' type - PREDEF_TYPE_FLOAT128_ID = 43, + /// The '__float128' type + PREDEF_TYPE_FLOAT128_ID = 43, - /// The '_Float16' type - PREDEF_TYPE_FLOAT16_ID = 44, + /// The '_Float16' type + PREDEF_TYPE_FLOAT16_ID = 44, - /// The C++ 'char8_t' type. - PREDEF_TYPE_CHAR8_ID = 45, + /// The C++ 'char8_t' type. + PREDEF_TYPE_CHAR8_ID = 45, - /// \brief The 'short _Accum' type - PREDEF_TYPE_SHORT_ACCUM_ID = 46, + /// \brief The 'short _Accum' type + PREDEF_TYPE_SHORT_ACCUM_ID = 46, - /// \brief The '_Accum' type - PREDEF_TYPE_ACCUM_ID = 47, + /// \brief The '_Accum' type + PREDEF_TYPE_ACCUM_ID = 47, - /// \brief The 'long _Accum' type - PREDEF_TYPE_LONG_ACCUM_ID = 48, + /// \brief The 'long _Accum' type + PREDEF_TYPE_LONG_ACCUM_ID = 48, - /// \brief The 'unsigned short _Accum' type - PREDEF_TYPE_USHORT_ACCUM_ID = 49, + /// \brief The 'unsigned short _Accum' type + PREDEF_TYPE_USHORT_ACCUM_ID = 49, - /// \brief The 'unsigned _Accum' type - PREDEF_TYPE_UACCUM_ID = 50, + /// \brief The 'unsigned _Accum' type + PREDEF_TYPE_UACCUM_ID = 50, - /// \brief The 'unsigned long _Accum' type - PREDEF_TYPE_ULONG_ACCUM_ID = 51, + /// \brief The 'unsigned long _Accum' type + PREDEF_TYPE_ULONG_ACCUM_ID = 51, - /// \brief The 'short _Fract' type - PREDEF_TYPE_SHORT_FRACT_ID = 52, + /// \brief The 'short _Fract' type + PREDEF_TYPE_SHORT_FRACT_ID = 52, - /// \brief The '_Fract' type - PREDEF_TYPE_FRACT_ID = 53, + /// \brief The '_Fract' type + PREDEF_TYPE_FRACT_ID = 53, - /// \brief The 'long _Fract' type - PREDEF_TYPE_LONG_FRACT_ID = 54, + /// \brief The 'long _Fract' type + PREDEF_TYPE_LONG_FRACT_ID = 54, - /// \brief The 'unsigned short _Fract' type - PREDEF_TYPE_USHORT_FRACT_ID = 55, + /// \brief The 'unsigned short _Fract' type + PREDEF_TYPE_USHORT_FRACT_ID = 55, - /// \brief The 'unsigned _Fract' type - PREDEF_TYPE_UFRACT_ID = 56, + /// \brief The 'unsigned _Fract' type + PREDEF_TYPE_UFRACT_ID = 56, - /// \brief The 'unsigned long _Fract' type - PREDEF_TYPE_ULONG_FRACT_ID = 57, + /// \brief The 'unsigned long _Fract' type + PREDEF_TYPE_ULONG_FRACT_ID = 57, - /// \brief The '_Sat short _Accum' type - PREDEF_TYPE_SAT_SHORT_ACCUM_ID = 58, + /// \brief The '_Sat short _Accum' type + PREDEF_TYPE_SAT_SHORT_ACCUM_ID = 58, - /// \brief The '_Sat _Accum' type - PREDEF_TYPE_SAT_ACCUM_ID = 59, + /// \brief The '_Sat _Accum' type + PREDEF_TYPE_SAT_ACCUM_ID = 59, - /// \brief The '_Sat long _Accum' type - PREDEF_TYPE_SAT_LONG_ACCUM_ID = 60, + /// \brief The '_Sat long _Accum' type + PREDEF_TYPE_SAT_LONG_ACCUM_ID = 60, - /// \brief The '_Sat unsigned short _Accum' type - PREDEF_TYPE_SAT_USHORT_ACCUM_ID = 61, + /// \brief The '_Sat unsigned short _Accum' type + PREDEF_TYPE_SAT_USHORT_ACCUM_ID = 61, - /// \brief The '_Sat unsigned _Accum' type - PREDEF_TYPE_SAT_UACCUM_ID = 62, + /// \brief The '_Sat unsigned _Accum' type + PREDEF_TYPE_SAT_UACCUM_ID = 62, - /// \brief The '_Sat unsigned long _Accum' type - PREDEF_TYPE_SAT_ULONG_ACCUM_ID = 63, + /// \brief The '_Sat unsigned long _Accum' type + PREDEF_TYPE_SAT_ULONG_ACCUM_ID = 63, - /// \brief The '_Sat short _Fract' type - PREDEF_TYPE_SAT_SHORT_FRACT_ID = 64, + /// \brief The '_Sat short _Fract' type + PREDEF_TYPE_SAT_SHORT_FRACT_ID = 64, - /// \brief The '_Sat _Fract' type - PREDEF_TYPE_SAT_FRACT_ID = 65, + /// \brief The '_Sat _Fract' type + PREDEF_TYPE_SAT_FRACT_ID = 65, - /// \brief The '_Sat long _Fract' type - PREDEF_TYPE_SAT_LONG_FRACT_ID = 66, + /// \brief The '_Sat long _Fract' type + PREDEF_TYPE_SAT_LONG_FRACT_ID = 66, - /// \brief The '_Sat unsigned short _Fract' type - PREDEF_TYPE_SAT_USHORT_FRACT_ID = 67, + /// \brief The '_Sat unsigned short _Fract' type + PREDEF_TYPE_SAT_USHORT_FRACT_ID = 67, - /// \brief The '_Sat unsigned _Fract' type - PREDEF_TYPE_SAT_UFRACT_ID = 68, + /// \brief The '_Sat unsigned _Fract' type + PREDEF_TYPE_SAT_UFRACT_ID = 68, - /// \brief The '_Sat unsigned long _Fract' type - PREDEF_TYPE_SAT_ULONG_FRACT_ID = 69, + /// \brief The '_Sat unsigned long _Fract' type + PREDEF_TYPE_SAT_ULONG_FRACT_ID = 69, - /// The placeholder type for OpenMP array shaping operation. - PREDEF_TYPE_OMP_ARRAY_SHAPING = 70, + /// The placeholder type for OpenMP array shaping operation. + PREDEF_TYPE_OMP_ARRAY_SHAPING = 70, - /// The placeholder type for OpenMP iterator expression. - PREDEF_TYPE_OMP_ITERATOR = 71, + /// The placeholder type for OpenMP iterator expression. + PREDEF_TYPE_OMP_ITERATOR = 71, - /// A placeholder type for incomplete matrix index operations. - PREDEF_TYPE_INCOMPLETE_MATRIX_IDX = 72, + /// A placeholder type for incomplete matrix index operations. + PREDEF_TYPE_INCOMPLETE_MATRIX_IDX = 72, - /// \brief The '__bf16' type - PREDEF_TYPE_BFLOAT16_ID = 73, + /// \brief The '__bf16' type + PREDEF_TYPE_BFLOAT16_ID = 73, - /// OpenCL image types with auto numeration -#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ - PREDEF_TYPE_##Id##_ID, +/// OpenCL image types with auto numeration +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + PREDEF_TYPE_##Id##_ID, #include "clang/Basic/OpenCLImageTypes.def" - /// \brief OpenCL extension types with auto numeration -#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ - PREDEF_TYPE_##Id##_ID, +/// \brief OpenCL extension types with auto numeration +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) PREDEF_TYPE_##Id##_ID, #include "clang/Basic/OpenCLExtensionTypes.def" - // \brief SVE types with auto numeration +// \brief SVE types with auto numeration #define SVE_TYPE(Name, Id, SingletonId) PREDEF_TYPE_##Id##_ID, #include "clang/Basic/AArch64SVEACLETypes.def" - // \brief PowerPC MMA types with auto numeration +// \brief PowerPC MMA types with auto numeration #define PPC_VECTOR_TYPE(Name, Id, Size) PREDEF_TYPE_##Id##_ID, #include "clang/Basic/PPCTypes.def" - // \brief RISC-V V types with auto numeration +// \brief RISC-V V types with auto numeration #define RVV_TYPE(Name, Id, SingletonId) PREDEF_TYPE_##Id##_ID, #include "clang/Basic/RISCVVTypes.def" - }; - - /// The number of predefined type IDs that are reserved for - /// the PREDEF_TYPE_* constants. - /// - /// Type IDs for non-predefined types will start at - /// NUM_PREDEF_TYPE_IDs. - const unsigned NUM_PREDEF_TYPE_IDS = 300; - - /// Record codes for each kind of type. - /// - /// These constants describe the type records that can occur within a - /// block identified by DECLTYPES_BLOCK_ID in the AST file. Each - /// constant describes a record for a specific type class in the - /// AST. Note that DeclCode values share this code space. - enum TypeCode { -#define TYPE_BIT_CODE(CLASS_ID, CODE_ID, CODE_VALUE) \ - TYPE_##CODE_ID = CODE_VALUE, +}; + +/// The number of predefined type IDs that are reserved for +/// the PREDEF_TYPE_* constants. +/// +/// Type IDs for non-predefined types will start at +/// NUM_PREDEF_TYPE_IDs. +const unsigned NUM_PREDEF_TYPE_IDS = 300; + +/// Record codes for each kind of type. +/// +/// These constants describe the type records that can occur within a +/// block identified by DECLTYPES_BLOCK_ID in the AST file. Each +/// constant describes a record for a specific type class in the +/// AST. Note that DeclCode values share this code space. +enum TypeCode { +#define TYPE_BIT_CODE(CLASS_ID, CODE_ID, CODE_VALUE) \ + TYPE_##CODE_ID = CODE_VALUE, #include "clang/Serialization/TypeBitCodes.def" - /// An ExtQualType record. - TYPE_EXT_QUAL = 1 - }; + /// An ExtQualType record. + TYPE_EXT_QUAL = 1 +}; + +/// The type IDs for special types constructed by semantic +/// analysis. +/// +/// The constants in this enumeration are indices into the +/// SPECIAL_TYPES record. +enum SpecialTypeIDs { + /// CFConstantString type + SPECIAL_TYPE_CF_CONSTANT_STRING = 0, + + /// C FILE typedef type + SPECIAL_TYPE_FILE = 1, + + /// C jmp_buf typedef type + SPECIAL_TYPE_JMP_BUF = 2, + + /// C sigjmp_buf typedef type + SPECIAL_TYPE_SIGJMP_BUF = 3, - /// The type IDs for special types constructed by semantic - /// analysis. - /// - /// The constants in this enumeration are indices into the - /// SPECIAL_TYPES record. - enum SpecialTypeIDs { - /// CFConstantString type - SPECIAL_TYPE_CF_CONSTANT_STRING = 0, + /// Objective-C "id" redefinition type + SPECIAL_TYPE_OBJC_ID_REDEFINITION = 4, - /// C FILE typedef type - SPECIAL_TYPE_FILE = 1, + /// Objective-C "Class" redefinition type + SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 5, - /// C jmp_buf typedef type - SPECIAL_TYPE_JMP_BUF = 2, + /// Objective-C "SEL" redefinition type + SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 6, - /// C sigjmp_buf typedef type - SPECIAL_TYPE_SIGJMP_BUF = 3, + /// C ucontext_t typedef type + SPECIAL_TYPE_UCONTEXT_T = 7 +}; + +/// The number of special type IDs. +const unsigned NumSpecialTypeIDs = 8; + +/// Predefined declaration IDs. +/// +/// These declaration IDs correspond to predefined declarations in the AST +/// context, such as the NULL declaration ID. Such declarations are never +/// actually serialized, since they will be built by the AST context when +/// it is created. +enum PredefinedDeclIDs { + /// The NULL declaration. + PREDEF_DECL_NULL_ID = 0, + + /// The translation unit. + PREDEF_DECL_TRANSLATION_UNIT_ID = 1, - /// Objective-C "id" redefinition type - SPECIAL_TYPE_OBJC_ID_REDEFINITION = 4, + /// The Objective-C 'id' type. + PREDEF_DECL_OBJC_ID_ID = 2, - /// Objective-C "Class" redefinition type - SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 5, + /// The Objective-C 'SEL' type. + PREDEF_DECL_OBJC_SEL_ID = 3, - /// Objective-C "SEL" redefinition type - SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 6, + /// The Objective-C 'Class' type. + PREDEF_DECL_OBJC_CLASS_ID = 4, - /// C ucontext_t typedef type - SPECIAL_TYPE_UCONTEXT_T = 7 - }; + /// The Objective-C 'Protocol' type. + PREDEF_DECL_OBJC_PROTOCOL_ID = 5, - /// The number of special type IDs. - const unsigned NumSpecialTypeIDs = 8; + /// The signed 128-bit integer type. + PREDEF_DECL_INT_128_ID = 6, - /// Predefined declaration IDs. - /// - /// These declaration IDs correspond to predefined declarations in the AST - /// context, such as the NULL declaration ID. Such declarations are never - /// actually serialized, since they will be built by the AST context when - /// it is created. - enum PredefinedDeclIDs { - /// The NULL declaration. - PREDEF_DECL_NULL_ID = 0, + /// The unsigned 128-bit integer type. + PREDEF_DECL_UNSIGNED_INT_128_ID = 7, - /// The translation unit. - PREDEF_DECL_TRANSLATION_UNIT_ID = 1, + /// The internal 'instancetype' typedef. + PREDEF_DECL_OBJC_INSTANCETYPE_ID = 8, - /// The Objective-C 'id' type. - PREDEF_DECL_OBJC_ID_ID = 2, + /// The internal '__builtin_va_list' typedef. + PREDEF_DECL_BUILTIN_VA_LIST_ID = 9, - /// The Objective-C 'SEL' type. - PREDEF_DECL_OBJC_SEL_ID = 3, + /// The internal '__va_list_tag' struct, if any. + PREDEF_DECL_VA_LIST_TAG = 10, - /// The Objective-C 'Class' type. - PREDEF_DECL_OBJC_CLASS_ID = 4, + /// The internal '__builtin_ms_va_list' typedef. + PREDEF_DECL_BUILTIN_MS_VA_LIST_ID = 11, - /// The Objective-C 'Protocol' type. - PREDEF_DECL_OBJC_PROTOCOL_ID = 5, + /// The predeclared '_GUID' struct. + PREDEF_DECL_BUILTIN_MS_GUID_ID = 12, - /// The signed 128-bit integer type. - PREDEF_DECL_INT_128_ID = 6, + /// The extern "C" context. + PREDEF_DECL_EXTERN_C_CONTEXT_ID = 13, + + /// The internal '__make_integer_seq' template. + PREDEF_DECL_MAKE_INTEGER_SEQ_ID = 14, + + /// The internal '__NSConstantString' typedef. + PREDEF_DECL_CF_CONSTANT_STRING_ID = 15, + + /// The internal '__NSConstantString' tag type. + PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID = 16, + + /// The internal '__type_pack_element' template. + PREDEF_DECL_TYPE_PACK_ELEMENT_ID = 17, +}; - /// The unsigned 128-bit integer type. - PREDEF_DECL_UNSIGNED_INT_128_ID = 7, +/// The number of declaration IDs that are predefined. +/// +/// For more information about predefined declarations, see the +/// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants. +const unsigned int NUM_PREDEF_DECL_IDS = 18; - /// The internal 'instancetype' typedef. - PREDEF_DECL_OBJC_INSTANCETYPE_ID = 8, +/// Record of updates for a declaration that was modified after +/// being deserialized. This can occur within DECLTYPES_BLOCK_ID. +const unsigned int DECL_UPDATES = 49; - /// The internal '__builtin_va_list' typedef. - PREDEF_DECL_BUILTIN_VA_LIST_ID = 9, +/// Record code for a list of local redeclarations of a declaration. +/// This can occur within DECLTYPES_BLOCK_ID. +const unsigned int LOCAL_REDECLARATIONS = 50; - /// The internal '__va_list_tag' struct, if any. - PREDEF_DECL_VA_LIST_TAG = 10, +/// Record codes for each kind of declaration. +/// +/// These constants describe the declaration records that can occur within +/// a declarations block (identified by DECLTYPES_BLOCK_ID). Each +/// constant describes a record for a specific declaration class +/// in the AST. Note that TypeCode values share this code space. +enum DeclCode { + /// A TypedefDecl record. + DECL_TYPEDEF = 51, + /// A TypeAliasDecl record. - /// The internal '__builtin_ms_va_list' typedef. - PREDEF_DECL_BUILTIN_MS_VA_LIST_ID = 11, + DECL_TYPEALIAS, - /// The predeclared '_GUID' struct. - PREDEF_DECL_BUILTIN_MS_GUID_ID = 12, + /// An EnumDecl record. + DECL_ENUM, - /// The extern "C" context. - PREDEF_DECL_EXTERN_C_CONTEXT_ID = 13, + /// A RecordDecl record. + DECL_RECORD, - /// The internal '__make_integer_seq' template. - PREDEF_DECL_MAKE_INTEGER_SEQ_ID = 14, + /// An EnumConstantDecl record. + DECL_ENUM_CONSTANT, - /// The internal '__NSConstantString' typedef. - PREDEF_DECL_CF_CONSTANT_STRING_ID = 15, + /// A FunctionDecl record. + DECL_FUNCTION, - /// The internal '__NSConstantString' tag type. - PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID = 16, + /// A ObjCMethodDecl record. + DECL_OBJC_METHOD, - /// The internal '__type_pack_element' template. - PREDEF_DECL_TYPE_PACK_ELEMENT_ID = 17, - }; + /// A ObjCInterfaceDecl record. + DECL_OBJC_INTERFACE, - /// The number of declaration IDs that are predefined. - /// - /// For more information about predefined declarations, see the - /// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants. - const unsigned int NUM_PREDEF_DECL_IDS = 18; + /// A ObjCProtocolDecl record. + DECL_OBJC_PROTOCOL, - /// Record of updates for a declaration that was modified after - /// being deserialized. This can occur within DECLTYPES_BLOCK_ID. - const unsigned int DECL_UPDATES = 49; + /// A ObjCIvarDecl record. + DECL_OBJC_IVAR, - /// Record code for a list of local redeclarations of a declaration. - /// This can occur within DECLTYPES_BLOCK_ID. - const unsigned int LOCAL_REDECLARATIONS = 50; + /// A ObjCAtDefsFieldDecl record. + DECL_OBJC_AT_DEFS_FIELD, - /// Record codes for each kind of declaration. - /// - /// These constants describe the declaration records that can occur within - /// a declarations block (identified by DECLTYPES_BLOCK_ID). Each - /// constant describes a record for a specific declaration class - /// in the AST. Note that TypeCode values share this code space. - enum DeclCode { - /// A TypedefDecl record. - DECL_TYPEDEF = 51, - /// A TypeAliasDecl record. + /// A ObjCCategoryDecl record. + DECL_OBJC_CATEGORY, - DECL_TYPEALIAS, + /// A ObjCCategoryImplDecl record. + DECL_OBJC_CATEGORY_IMPL, - /// An EnumDecl record. - DECL_ENUM, + /// A ObjCImplementationDecl record. + DECL_OBJC_IMPLEMENTATION, - /// A RecordDecl record. - DECL_RECORD, + /// A ObjCCompatibleAliasDecl record. + DECL_OBJC_COMPATIBLE_ALIAS, - /// An EnumConstantDecl record. - DECL_ENUM_CONSTANT, + /// A ObjCPropertyDecl record. + DECL_OBJC_PROPERTY, - /// A FunctionDecl record. - DECL_FUNCTION, + /// A ObjCPropertyImplDecl record. + DECL_OBJC_PROPERTY_IMPL, - /// A ObjCMethodDecl record. - DECL_OBJC_METHOD, + /// A FieldDecl record. + DECL_FIELD, - /// A ObjCInterfaceDecl record. - DECL_OBJC_INTERFACE, + /// A MSPropertyDecl record. + DECL_MS_PROPERTY, - /// A ObjCProtocolDecl record. - DECL_OBJC_PROTOCOL, + /// A MSGuidDecl record. + DECL_MS_GUID, - /// A ObjCIvarDecl record. - DECL_OBJC_IVAR, + /// A TemplateParamObjectDecl record. + DECL_TEMPLATE_PARAM_OBJECT, - /// A ObjCAtDefsFieldDecl record. - DECL_OBJC_AT_DEFS_FIELD, + /// A VarDecl record. + DECL_VAR, - /// A ObjCCategoryDecl record. - DECL_OBJC_CATEGORY, + /// An ImplicitParamDecl record. + DECL_IMPLICIT_PARAM, - /// A ObjCCategoryImplDecl record. - DECL_OBJC_CATEGORY_IMPL, + /// A ParmVarDecl record. + DECL_PARM_VAR, - /// A ObjCImplementationDecl record. - DECL_OBJC_IMPLEMENTATION, + /// A DecompositionDecl record. + DECL_DECOMPOSITION, - /// A ObjCCompatibleAliasDecl record. - DECL_OBJC_COMPATIBLE_ALIAS, + /// A BindingDecl record. + DECL_BINDING, - /// A ObjCPropertyDecl record. - DECL_OBJC_PROPERTY, + /// A FileScopeAsmDecl record. + DECL_FILE_SCOPE_ASM, - /// A ObjCPropertyImplDecl record. - DECL_OBJC_PROPERTY_IMPL, + /// A BlockDecl record. + DECL_BLOCK, - /// A FieldDecl record. - DECL_FIELD, + /// A CapturedDecl record. + DECL_CAPTURED, - /// A MSPropertyDecl record. - DECL_MS_PROPERTY, + /// A record that stores the set of declarations that are + /// lexically stored within a given DeclContext. + /// + /// The record itself is a blob that is an array of declaration IDs, + /// in the order in which those declarations were added to the + /// declaration context. This data is used when iterating over + /// the contents of a DeclContext, e.g., via + /// DeclContext::decls_begin() and DeclContext::decls_end(). + DECL_CONTEXT_LEXICAL, - /// A MSGuidDecl record. - DECL_MS_GUID, + /// A record that stores the set of declarations that are + /// visible from a given DeclContext. + /// + /// The record itself stores a set of mappings, each of which + /// associates a declaration name with one or more declaration + /// IDs. This data is used when performing qualified name lookup + /// into a DeclContext via DeclContext::lookup. + DECL_CONTEXT_VISIBLE, - /// A TemplateParamObjectDecl record. - DECL_TEMPLATE_PARAM_OBJECT, + /// A LabelDecl record. + DECL_LABEL, - /// A VarDecl record. - DECL_VAR, + /// A NamespaceDecl record. + DECL_NAMESPACE, - /// An ImplicitParamDecl record. - DECL_IMPLICIT_PARAM, + /// A NamespaceAliasDecl record. + DECL_NAMESPACE_ALIAS, - /// A ParmVarDecl record. - DECL_PARM_VAR, + /// A UsingDecl record. + DECL_USING, - /// A DecompositionDecl record. - DECL_DECOMPOSITION, + /// A UsingPackDecl record. + DECL_USING_PACK, - /// A BindingDecl record. - DECL_BINDING, + /// A UsingShadowDecl record. + DECL_USING_SHADOW, - /// A FileScopeAsmDecl record. - DECL_FILE_SCOPE_ASM, + /// A ConstructorUsingShadowDecl record. + DECL_CONSTRUCTOR_USING_SHADOW, - /// A BlockDecl record. - DECL_BLOCK, + /// A UsingDirecitveDecl record. + DECL_USING_DIRECTIVE, - /// A CapturedDecl record. - DECL_CAPTURED, + /// An UnresolvedUsingValueDecl record. + DECL_UNRESOLVED_USING_VALUE, - /// A record that stores the set of declarations that are - /// lexically stored within a given DeclContext. - /// - /// The record itself is a blob that is an array of declaration IDs, - /// in the order in which those declarations were added to the - /// declaration context. This data is used when iterating over - /// the contents of a DeclContext, e.g., via - /// DeclContext::decls_begin() and DeclContext::decls_end(). - DECL_CONTEXT_LEXICAL, + /// An UnresolvedUsingTypenameDecl record. + DECL_UNRESOLVED_USING_TYPENAME, - /// A record that stores the set of declarations that are - /// visible from a given DeclContext. - /// - /// The record itself stores a set of mappings, each of which - /// associates a declaration name with one or more declaration - /// IDs. This data is used when performing qualified name lookup - /// into a DeclContext via DeclContext::lookup. - DECL_CONTEXT_VISIBLE, + /// A LinkageSpecDecl record. + DECL_LINKAGE_SPEC, - /// A LabelDecl record. - DECL_LABEL, + /// An ExportDecl record. + DECL_EXPORT, - /// A NamespaceDecl record. - DECL_NAMESPACE, + /// A CXXRecordDecl record. + DECL_CXX_RECORD, - /// A NamespaceAliasDecl record. - DECL_NAMESPACE_ALIAS, + /// A CXXDeductionGuideDecl record. + DECL_CXX_DEDUCTION_GUIDE, - /// A UsingDecl record. - DECL_USING, + /// A CXXMethodDecl record. + DECL_CXX_METHOD, - /// A UsingPackDecl record. - DECL_USING_PACK, + /// A CXXConstructorDecl record. + DECL_CXX_CONSTRUCTOR, - /// A UsingShadowDecl record. - DECL_USING_SHADOW, + /// A CXXDestructorDecl record. + DECL_CXX_DESTRUCTOR, - /// A ConstructorUsingShadowDecl record. - DECL_CONSTRUCTOR_USING_SHADOW, + /// A CXXConversionDecl record. + DECL_CXX_CONVERSION, - /// A UsingDirecitveDecl record. - DECL_USING_DIRECTIVE, + /// An AccessSpecDecl record. + DECL_ACCESS_SPEC, - /// An UnresolvedUsingValueDecl record. - DECL_UNRESOLVED_USING_VALUE, + /// A FriendDecl record. + DECL_FRIEND, - /// An UnresolvedUsingTypenameDecl record. - DECL_UNRESOLVED_USING_TYPENAME, + /// A FriendTemplateDecl record. + DECL_FRIEND_TEMPLATE, - /// A LinkageSpecDecl record. - DECL_LINKAGE_SPEC, + /// A ClassTemplateDecl record. + DECL_CLASS_TEMPLATE, - /// An ExportDecl record. - DECL_EXPORT, + /// A ClassTemplateSpecializationDecl record. + DECL_CLASS_TEMPLATE_SPECIALIZATION, - /// A CXXRecordDecl record. - DECL_CXX_RECORD, + /// A ClassTemplatePartialSpecializationDecl record. + DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION, - /// A CXXDeductionGuideDecl record. - DECL_CXX_DEDUCTION_GUIDE, + /// A VarTemplateDecl record. + DECL_VAR_TEMPLATE, - /// A CXXMethodDecl record. - DECL_CXX_METHOD, + /// A VarTemplateSpecializationDecl record. + DECL_VAR_TEMPLATE_SPECIALIZATION, - /// A CXXConstructorDecl record. - DECL_CXX_CONSTRUCTOR, + /// A VarTemplatePartialSpecializationDecl record. + DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION, - /// A CXXDestructorDecl record. - DECL_CXX_DESTRUCTOR, + /// A FunctionTemplateDecl record. + DECL_FUNCTION_TEMPLATE, - /// A CXXConversionDecl record. - DECL_CXX_CONVERSION, + /// A TemplateTypeParmDecl record. + DECL_TEMPLATE_TYPE_PARM, - /// An AccessSpecDecl record. - DECL_ACCESS_SPEC, + /// A NonTypeTemplateParmDecl record. + DECL_NON_TYPE_TEMPLATE_PARM, - /// A FriendDecl record. - DECL_FRIEND, + /// A TemplateTemplateParmDecl record. + DECL_TEMPLATE_TEMPLATE_PARM, - /// A FriendTemplateDecl record. - DECL_FRIEND_TEMPLATE, + /// A TypeAliasTemplateDecl record. + DECL_TYPE_ALIAS_TEMPLATE, - /// A ClassTemplateDecl record. - DECL_CLASS_TEMPLATE, + /// \brief A ConceptDecl record. + DECL_CONCEPT, - /// A ClassTemplateSpecializationDecl record. - DECL_CLASS_TEMPLATE_SPECIALIZATION, + /// \brief A StaticAssertDecl record. + DECL_STATIC_ASSERT, - /// A ClassTemplatePartialSpecializationDecl record. - DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION, + /// A record containing CXXBaseSpecifiers. + DECL_CXX_BASE_SPECIFIERS, - /// A VarTemplateDecl record. - DECL_VAR_TEMPLATE, + /// A record containing CXXCtorInitializers. + DECL_CXX_CTOR_INITIALIZERS, - /// A VarTemplateSpecializationDecl record. - DECL_VAR_TEMPLATE_SPECIALIZATION, + /// A IndirectFieldDecl record. + DECL_INDIRECTFIELD, - /// A VarTemplatePartialSpecializationDecl record. - DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION, + /// A NonTypeTemplateParmDecl record that stores an expanded + /// non-type template parameter pack. + DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK, - /// A FunctionTemplateDecl record. - DECL_FUNCTION_TEMPLATE, + /// A TemplateTemplateParmDecl record that stores an expanded + /// template template parameter pack. + DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK, - /// A TemplateTypeParmDecl record. - DECL_TEMPLATE_TYPE_PARM, + /// A ClassScopeFunctionSpecializationDecl record a class scope + /// function specialization. (Microsoft extension). + DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION, - /// A NonTypeTemplateParmDecl record. - DECL_NON_TYPE_TEMPLATE_PARM, + /// An ImportDecl recording a module import. + DECL_IMPORT, - /// A TemplateTemplateParmDecl record. - DECL_TEMPLATE_TEMPLATE_PARM, + /// An OMPThreadPrivateDecl record. + DECL_OMP_THREADPRIVATE, - /// A TypeAliasTemplateDecl record. - DECL_TYPE_ALIAS_TEMPLATE, + /// An OMPRequiresDecl record. + DECL_OMP_REQUIRES, - /// \brief A ConceptDecl record. - DECL_CONCEPT, + /// An OMPAllocateDcl record. + DECL_OMP_ALLOCATE, - /// \brief A StaticAssertDecl record. - DECL_STATIC_ASSERT, + /// An EmptyDecl record. + DECL_EMPTY, - /// A record containing CXXBaseSpecifiers. - DECL_CXX_BASE_SPECIFIERS, + /// An LifetimeExtendedTemporaryDecl record. + DECL_LIFETIME_EXTENDED_TEMPORARY, - /// A record containing CXXCtorInitializers. - DECL_CXX_CTOR_INITIALIZERS, + /// A RequiresExprBodyDecl record. + DECL_REQUIRES_EXPR_BODY, - /// A IndirectFieldDecl record. - DECL_INDIRECTFIELD, + /// An ObjCTypeParamDecl record. + DECL_OBJC_TYPE_PARAM, - /// A NonTypeTemplateParmDecl record that stores an expanded - /// non-type template parameter pack. - DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK, + /// An OMPCapturedExprDecl record. + DECL_OMP_CAPTUREDEXPR, - /// A TemplateTemplateParmDecl record that stores an expanded - /// template template parameter pack. - DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK, + /// A PragmaCommentDecl record. + DECL_PRAGMA_COMMENT, - /// A ClassScopeFunctionSpecializationDecl record a class scope - /// function specialization. (Microsoft extension). - DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION, + /// A PragmaDetectMismatchDecl record. + DECL_PRAGMA_DETECT_MISMATCH, - /// An ImportDecl recording a module import. - DECL_IMPORT, + /// An OMPDeclareMapperDecl record. + DECL_OMP_DECLARE_MAPPER, - /// An OMPThreadPrivateDecl record. - DECL_OMP_THREADPRIVATE, + /// An OMPDeclareReductionDecl record. + DECL_OMP_DECLARE_REDUCTION, - /// An OMPRequiresDecl record. - DECL_OMP_REQUIRES, + DECL_LAST = DECL_OMP_DECLARE_REDUCTION +}; - /// An OMPAllocateDcl record. - DECL_OMP_ALLOCATE, +/// Record codes for each kind of statement or expression. +/// +/// These constants describe the records that describe statements +/// or expressions. These records occur within type and declarations +/// block, so they begin with record values of 128. Each constant +/// describes a record for a specific statement or expression class in the +/// AST. +enum StmtCode { + /// A marker record that indicates that we are at the end + /// of an expression. + STMT_STOP = DECL_LAST + 1, - /// An EmptyDecl record. - DECL_EMPTY, + /// A NULL expression. + STMT_NULL_PTR, - /// An LifetimeExtendedTemporaryDecl record. - DECL_LIFETIME_EXTENDED_TEMPORARY, + /// A reference to a previously [de]serialized Stmt record. + STMT_REF_PTR, - /// A RequiresExprBodyDecl record. - DECL_REQUIRES_EXPR_BODY, + /// A NullStmt record. + STMT_NULL, - /// An ObjCTypeParamDecl record. - DECL_OBJC_TYPE_PARAM, + /// A CompoundStmt record. + STMT_COMPOUND, - /// An OMPCapturedExprDecl record. - DECL_OMP_CAPTUREDEXPR, + /// A CaseStmt record. + STMT_CASE, - /// A PragmaCommentDecl record. - DECL_PRAGMA_COMMENT, + /// A DefaultStmt record. + STMT_DEFAULT, - /// A PragmaDetectMismatchDecl record. - DECL_PRAGMA_DETECT_MISMATCH, + /// A LabelStmt record. + STMT_LABEL, - /// An OMPDeclareMapperDecl record. - DECL_OMP_DECLARE_MAPPER, + /// An AttributedStmt record. + STMT_ATTRIBUTED, - /// An OMPDeclareReductionDecl record. - DECL_OMP_DECLARE_REDUCTION, + /// An IfStmt record. + STMT_IF, - DECL_LAST = DECL_OMP_DECLARE_REDUCTION - }; + /// A SwitchStmt record. + STMT_SWITCH, - /// Record codes for each kind of statement or expression. - /// - /// These constants describe the records that describe statements - /// or expressions. These records occur within type and declarations - /// block, so they begin with record values of 128. Each constant - /// describes a record for a specific statement or expression class in the - /// AST. - enum StmtCode { - /// A marker record that indicates that we are at the end - /// of an expression. - STMT_STOP = DECL_LAST + 1, + /// A WhileStmt record. + STMT_WHILE, - /// A NULL expression. - STMT_NULL_PTR, + /// A DoStmt record. + STMT_DO, - /// A reference to a previously [de]serialized Stmt record. - STMT_REF_PTR, + /// A ForStmt record. + STMT_FOR, - /// A NullStmt record. - STMT_NULL, + /// A GotoStmt record. + STMT_GOTO, - /// A CompoundStmt record. - STMT_COMPOUND, + /// An IndirectGotoStmt record. + STMT_INDIRECT_GOTO, - /// A CaseStmt record. - STMT_CASE, + /// A ContinueStmt record. + STMT_CONTINUE, - /// A DefaultStmt record. - STMT_DEFAULT, + /// A BreakStmt record. + STMT_BREAK, - /// A LabelStmt record. - STMT_LABEL, + /// A ReturnStmt record. + STMT_RETURN, - /// An AttributedStmt record. - STMT_ATTRIBUTED, + /// A DeclStmt record. + STMT_DECL, - /// An IfStmt record. - STMT_IF, + /// A CapturedStmt record. + STMT_CAPTURED, - /// A SwitchStmt record. - STMT_SWITCH, + /// A GCC-style AsmStmt record. + STMT_GCCASM, - /// A WhileStmt record. - STMT_WHILE, + /// A MS-style AsmStmt record. + STMT_MSASM, - /// A DoStmt record. - STMT_DO, + /// A constant expression context. + EXPR_CONSTANT, - /// A ForStmt record. - STMT_FOR, + /// A PredefinedExpr record. + EXPR_PREDEFINED, - /// A GotoStmt record. - STMT_GOTO, + /// A DeclRefExpr record. + EXPR_DECL_REF, - /// An IndirectGotoStmt record. - STMT_INDIRECT_GOTO, + /// An IntegerLiteral record. + EXPR_INTEGER_LITERAL, - /// A ContinueStmt record. - STMT_CONTINUE, + /// A FloatingLiteral record. + EXPR_FLOATING_LITERAL, - /// A BreakStmt record. - STMT_BREAK, + /// An ImaginaryLiteral record. + EXPR_IMAGINARY_LITERAL, - /// A ReturnStmt record. - STMT_RETURN, + /// A StringLiteral record. + EXPR_STRING_LITERAL, - /// A DeclStmt record. - STMT_DECL, + /// A CharacterLiteral record. + EXPR_CHARACTER_LITERAL, - /// A CapturedStmt record. - STMT_CAPTURED, + /// A ParenExpr record. + EXPR_PAREN, - /// A GCC-style AsmStmt record. - STMT_GCCASM, + /// A ParenListExpr record. + EXPR_PAREN_LIST, - /// A MS-style AsmStmt record. - STMT_MSASM, + /// A UnaryOperator record. + EXPR_UNARY_OPERATOR, - /// A constant expression context. - EXPR_CONSTANT, + /// An OffsetOfExpr record. + EXPR_OFFSETOF, - /// A PredefinedExpr record. - EXPR_PREDEFINED, + /// A SizefAlignOfExpr record. + EXPR_SIZEOF_ALIGN_OF, - /// A DeclRefExpr record. - EXPR_DECL_REF, + /// An ArraySubscriptExpr record. + EXPR_ARRAY_SUBSCRIPT, - /// An IntegerLiteral record. - EXPR_INTEGER_LITERAL, + /// An MatrixSubscriptExpr record. + EXPR_MATRIX_SUBSCRIPT, - /// A FloatingLiteral record. - EXPR_FLOATING_LITERAL, + /// A CallExpr record. + EXPR_CALL, - /// An ImaginaryLiteral record. - EXPR_IMAGINARY_LITERAL, + /// A MemberExpr record. + EXPR_MEMBER, - /// A StringLiteral record. - EXPR_STRING_LITERAL, + /// A BinaryOperator record. + EXPR_BINARY_OPERATOR, - /// A CharacterLiteral record. - EXPR_CHARACTER_LITERAL, + /// A CompoundAssignOperator record. + EXPR_COMPOUND_ASSIGN_OPERATOR, - /// A ParenExpr record. - EXPR_PAREN, + /// A ConditionOperator record. + EXPR_CONDITIONAL_OPERATOR, - /// A ParenListExpr record. - EXPR_PAREN_LIST, + /// An ImplicitCastExpr record. + EXPR_IMPLICIT_CAST, - /// A UnaryOperator record. - EXPR_UNARY_OPERATOR, + /// A CStyleCastExpr record. + EXPR_CSTYLE_CAST, - /// An OffsetOfExpr record. - EXPR_OFFSETOF, + /// A CompoundLiteralExpr record. + EXPR_COMPOUND_LITERAL, - /// A SizefAlignOfExpr record. - EXPR_SIZEOF_ALIGN_OF, + /// An ExtVectorElementExpr record. + EXPR_EXT_VECTOR_ELEMENT, - /// An ArraySubscriptExpr record. - EXPR_ARRAY_SUBSCRIPT, + /// An InitListExpr record. + EXPR_INIT_LIST, - /// An MatrixSubscriptExpr record. - EXPR_MATRIX_SUBSCRIPT, + /// A DesignatedInitExpr record. + EXPR_DESIGNATED_INIT, - /// A CallExpr record. - EXPR_CALL, + /// A DesignatedInitUpdateExpr record. + EXPR_DESIGNATED_INIT_UPDATE, - /// A MemberExpr record. - EXPR_MEMBER, + /// An NoInitExpr record. + EXPR_NO_INIT, - /// A BinaryOperator record. - EXPR_BINARY_OPERATOR, + /// An ArrayInitLoopExpr record. + EXPR_ARRAY_INIT_LOOP, - /// A CompoundAssignOperator record. - EXPR_COMPOUND_ASSIGN_OPERATOR, + /// An ArrayInitIndexExpr record. + EXPR_ARRAY_INIT_INDEX, - /// A ConditionOperator record. - EXPR_CONDITIONAL_OPERATOR, + /// An ImplicitValueInitExpr record. + EXPR_IMPLICIT_VALUE_INIT, - /// An ImplicitCastExpr record. - EXPR_IMPLICIT_CAST, + /// A VAArgExpr record. + EXPR_VA_ARG, - /// A CStyleCastExpr record. - EXPR_CSTYLE_CAST, + /// An AddrLabelExpr record. + EXPR_ADDR_LABEL, - /// A CompoundLiteralExpr record. - EXPR_COMPOUND_LITERAL, + /// A StmtExpr record. + EXPR_STMT, - /// An ExtVectorElementExpr record. - EXPR_EXT_VECTOR_ELEMENT, + /// A ChooseExpr record. + EXPR_CHOOSE, - /// An InitListExpr record. - EXPR_INIT_LIST, + /// A GNUNullExpr record. + EXPR_GNU_NULL, - /// A DesignatedInitExpr record. - EXPR_DESIGNATED_INIT, + /// A SourceLocExpr record. + EXPR_SOURCE_LOC, - /// A DesignatedInitUpdateExpr record. - EXPR_DESIGNATED_INIT_UPDATE, + /// A ShuffleVectorExpr record. + EXPR_SHUFFLE_VECTOR, - /// An NoInitExpr record. - EXPR_NO_INIT, + /// A ConvertVectorExpr record. + EXPR_CONVERT_VECTOR, - /// An ArrayInitLoopExpr record. - EXPR_ARRAY_INIT_LOOP, + /// BlockExpr + EXPR_BLOCK, - /// An ArrayInitIndexExpr record. - EXPR_ARRAY_INIT_INDEX, + /// A GenericSelectionExpr record. + EXPR_GENERIC_SELECTION, - /// An ImplicitValueInitExpr record. - EXPR_IMPLICIT_VALUE_INIT, + /// A PseudoObjectExpr record. + EXPR_PSEUDO_OBJECT, - /// A VAArgExpr record. - EXPR_VA_ARG, + /// An AtomicExpr record. + EXPR_ATOMIC, - /// An AddrLabelExpr record. - EXPR_ADDR_LABEL, + /// A RecoveryExpr record. + EXPR_RECOVERY, - /// A StmtExpr record. - EXPR_STMT, + // Objective-C - /// A ChooseExpr record. - EXPR_CHOOSE, + /// An ObjCStringLiteral record. + EXPR_OBJC_STRING_LITERAL, - /// A GNUNullExpr record. - EXPR_GNU_NULL, + EXPR_OBJC_BOXED_EXPRESSION, + EXPR_OBJC_ARRAY_LITERAL, + EXPR_OBJC_DICTIONARY_LITERAL, - /// A SourceLocExpr record. - EXPR_SOURCE_LOC, + /// An ObjCEncodeExpr record. + EXPR_OBJC_ENCODE, - /// A ShuffleVectorExpr record. - EXPR_SHUFFLE_VECTOR, + /// An ObjCSelectorExpr record. + EXPR_OBJC_SELECTOR_EXPR, - /// A ConvertVectorExpr record. - EXPR_CONVERT_VECTOR, + /// An ObjCProtocolExpr record. + EXPR_OBJC_PROTOCOL_EXPR, - /// BlockExpr - EXPR_BLOCK, + /// An ObjCIvarRefExpr record. + EXPR_OBJC_IVAR_REF_EXPR, - /// A GenericSelectionExpr record. - EXPR_GENERIC_SELECTION, + /// An ObjCPropertyRefExpr record. + EXPR_OBJC_PROPERTY_REF_EXPR, - /// A PseudoObjectExpr record. - EXPR_PSEUDO_OBJECT, + /// An ObjCSubscriptRefExpr record. + EXPR_OBJC_SUBSCRIPT_REF_EXPR, - /// An AtomicExpr record. - EXPR_ATOMIC, + /// UNUSED + EXPR_OBJC_KVC_REF_EXPR, - /// A RecoveryExpr record. - EXPR_RECOVERY, + /// An ObjCMessageExpr record. + EXPR_OBJC_MESSAGE_EXPR, - // Objective-C + /// An ObjCIsa Expr record. + EXPR_OBJC_ISA, - /// An ObjCStringLiteral record. - EXPR_OBJC_STRING_LITERAL, + /// An ObjCIndirectCopyRestoreExpr record. + EXPR_OBJC_INDIRECT_COPY_RESTORE, - EXPR_OBJC_BOXED_EXPRESSION, - EXPR_OBJC_ARRAY_LITERAL, - EXPR_OBJC_DICTIONARY_LITERAL, + /// An ObjCForCollectionStmt record. + STMT_OBJC_FOR_COLLECTION, - /// An ObjCEncodeExpr record. - EXPR_OBJC_ENCODE, + /// An ObjCAtCatchStmt record. + STMT_OBJC_CATCH, - /// An ObjCSelectorExpr record. - EXPR_OBJC_SELECTOR_EXPR, + /// An ObjCAtFinallyStmt record. + STMT_OBJC_FINALLY, - /// An ObjCProtocolExpr record. - EXPR_OBJC_PROTOCOL_EXPR, + /// An ObjCAtTryStmt record. + STMT_OBJC_AT_TRY, - /// An ObjCIvarRefExpr record. - EXPR_OBJC_IVAR_REF_EXPR, + /// An ObjCAtSynchronizedStmt record. + STMT_OBJC_AT_SYNCHRONIZED, - /// An ObjCPropertyRefExpr record. - EXPR_OBJC_PROPERTY_REF_EXPR, + /// An ObjCAtThrowStmt record. + STMT_OBJC_AT_THROW, - /// An ObjCSubscriptRefExpr record. - EXPR_OBJC_SUBSCRIPT_REF_EXPR, + /// An ObjCAutoreleasePoolStmt record. + STMT_OBJC_AUTORELEASE_POOL, - /// UNUSED - EXPR_OBJC_KVC_REF_EXPR, + /// An ObjCBoolLiteralExpr record. + EXPR_OBJC_BOOL_LITERAL, - /// An ObjCMessageExpr record. - EXPR_OBJC_MESSAGE_EXPR, + /// An ObjCAvailabilityCheckExpr record. + EXPR_OBJC_AVAILABILITY_CHECK, - /// An ObjCIsa Expr record. - EXPR_OBJC_ISA, + // C++ - /// An ObjCIndirectCopyRestoreExpr record. - EXPR_OBJC_INDIRECT_COPY_RESTORE, + /// A CXXCatchStmt record. + STMT_CXX_CATCH, - /// An ObjCForCollectionStmt record. - STMT_OBJC_FOR_COLLECTION, + /// A CXXTryStmt record. + STMT_CXX_TRY, + /// A CXXForRangeStmt record. - /// An ObjCAtCatchStmt record. - STMT_OBJC_CATCH, + STMT_CXX_FOR_RANGE, - /// An ObjCAtFinallyStmt record. - STMT_OBJC_FINALLY, + /// A CXXOperatorCallExpr record. + EXPR_CXX_OPERATOR_CALL, - /// An ObjCAtTryStmt record. - STMT_OBJC_AT_TRY, + /// A CXXMemberCallExpr record. + EXPR_CXX_MEMBER_CALL, - /// An ObjCAtSynchronizedStmt record. - STMT_OBJC_AT_SYNCHRONIZED, + /// A CXXRewrittenBinaryOperator record. + EXPR_CXX_REWRITTEN_BINARY_OPERATOR, - /// An ObjCAtThrowStmt record. - STMT_OBJC_AT_THROW, + /// A CXXConstructExpr record. + EXPR_CXX_CONSTRUCT, - /// An ObjCAutoreleasePoolStmt record. - STMT_OBJC_AUTORELEASE_POOL, + /// A CXXInheritedCtorInitExpr record. + EXPR_CXX_INHERITED_CTOR_INIT, - /// An ObjCBoolLiteralExpr record. - EXPR_OBJC_BOOL_LITERAL, + /// A CXXTemporaryObjectExpr record. + EXPR_CXX_TEMPORARY_OBJECT, - /// An ObjCAvailabilityCheckExpr record. - EXPR_OBJC_AVAILABILITY_CHECK, + /// A CXXStaticCastExpr record. + EXPR_CXX_STATIC_CAST, - // C++ + /// A CXXDynamicCastExpr record. + EXPR_CXX_DYNAMIC_CAST, - /// A CXXCatchStmt record. - STMT_CXX_CATCH, + /// A CXXReinterpretCastExpr record. + EXPR_CXX_REINTERPRET_CAST, - /// A CXXTryStmt record. - STMT_CXX_TRY, - /// A CXXForRangeStmt record. + /// A CXXConstCastExpr record. + EXPR_CXX_CONST_CAST, - STMT_CXX_FOR_RANGE, + /// A CXXAddrspaceCastExpr record. + EXPR_CXX_ADDRSPACE_CAST, + + /// A CXXFunctionalCastExpr record. + EXPR_CXX_FUNCTIONAL_CAST, + + /// A BuiltinBitCastExpr record. + EXPR_BUILTIN_BIT_CAST, + + /// A UserDefinedLiteral record. + EXPR_USER_DEFINED_LITERAL, + + /// A CXXStdInitializerListExpr record. + EXPR_CXX_STD_INITIALIZER_LIST, + + /// A CXXBoolLiteralExpr record. + EXPR_CXX_BOOL_LITERAL, + + EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr + EXPR_CXX_TYPEID_EXPR, // CXXTypeidExpr (of expr). + EXPR_CXX_TYPEID_TYPE, // CXXTypeidExpr (of type). + EXPR_CXX_THIS, // CXXThisExpr + EXPR_CXX_THROW, // CXXThrowExpr + EXPR_CXX_DEFAULT_ARG, // CXXDefaultArgExpr + EXPR_CXX_DEFAULT_INIT, // CXXDefaultInitExpr + EXPR_CXX_BIND_TEMPORARY, // CXXBindTemporaryExpr + + EXPR_CXX_SCALAR_VALUE_INIT, // CXXScalarValueInitExpr + EXPR_CXX_NEW, // CXXNewExpr + EXPR_CXX_DELETE, // CXXDeleteExpr + EXPR_CXX_PSEUDO_DESTRUCTOR, // CXXPseudoDestructorExpr + + EXPR_EXPR_WITH_CLEANUPS, // ExprWithCleanups + + EXPR_CXX_DEPENDENT_SCOPE_MEMBER, // CXXDependentScopeMemberExpr + EXPR_CXX_DEPENDENT_SCOPE_DECL_REF, // DependentScopeDeclRefExpr + EXPR_CXX_UNRESOLVED_CONSTRUCT, // CXXUnresolvedConstructExpr + EXPR_CXX_UNRESOLVED_MEMBER, // UnresolvedMemberExpr + EXPR_CXX_UNRESOLVED_LOOKUP, // UnresolvedLookupExpr + + EXPR_CXX_EXPRESSION_TRAIT, // ExpressionTraitExpr + EXPR_CXX_NOEXCEPT, // CXXNoexceptExpr + + EXPR_OPAQUE_VALUE, // OpaqueValueExpr + EXPR_BINARY_CONDITIONAL_OPERATOR, // BinaryConditionalOperator + EXPR_TYPE_TRAIT, // TypeTraitExpr + EXPR_ARRAY_TYPE_TRAIT, // ArrayTypeTraitIntExpr + + EXPR_PACK_EXPANSION, // PackExpansionExpr + EXPR_SIZEOF_PACK, // SizeOfPackExpr + EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr + EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK, // SubstNonTypeTemplateParmPackExpr + EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr + EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr + EXPR_CXX_FOLD, // CXXFoldExpr + EXPR_CONCEPT_SPECIALIZATION, // ConceptSpecializationExpr + EXPR_REQUIRES, // RequiresExpr + + // CUDA + EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr + + // OpenCL + EXPR_ASTYPE, // AsTypeExpr + + // Microsoft + EXPR_CXX_PROPERTY_REF_EXPR, // MSPropertyRefExpr + EXPR_CXX_PROPERTY_SUBSCRIPT_EXPR, // MSPropertySubscriptExpr + EXPR_CXX_UUIDOF_EXPR, // CXXUuidofExpr (of expr). + EXPR_CXX_UUIDOF_TYPE, // CXXUuidofExpr (of type). + STMT_SEH_LEAVE, // SEHLeaveStmt + STMT_SEH_EXCEPT, // SEHExceptStmt + STMT_SEH_FINALLY, // SEHFinallyStmt + STMT_SEH_TRY, // SEHTryStmt + + // OpenMP directives + STMT_OMP_CANONICAL_LOOP, + STMT_OMP_PARALLEL_DIRECTIVE, + STMT_OMP_SIMD_DIRECTIVE, + STMT_OMP_TILE_DIRECTIVE, + STMT_OMP_FOR_DIRECTIVE, + STMT_OMP_FOR_SIMD_DIRECTIVE, + STMT_OMP_SECTIONS_DIRECTIVE, + STMT_OMP_SECTION_DIRECTIVE, + STMT_OMP_SINGLE_DIRECTIVE, + STMT_OMP_MASTER_DIRECTIVE, + STMT_OMP_CRITICAL_DIRECTIVE, + STMT_OMP_PARALLEL_FOR_DIRECTIVE, + STMT_OMP_PARALLEL_FOR_SIMD_DIRECTIVE, + STMT_OMP_PARALLEL_MASTER_DIRECTIVE, + STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE, + STMT_OMP_TASK_DIRECTIVE, + STMT_OMP_TASKYIELD_DIRECTIVE, + STMT_OMP_BARRIER_DIRECTIVE, + STMT_OMP_TASKWAIT_DIRECTIVE, + STMT_OMP_FLUSH_DIRECTIVE, + STMT_OMP_DEPOBJ_DIRECTIVE, + STMT_OMP_SCAN_DIRECTIVE, + STMT_OMP_ORDERED_DIRECTIVE, + STMT_OMP_ATOMIC_DIRECTIVE, + STMT_OMP_TARGET_DIRECTIVE, + STMT_OMP_TARGET_DATA_DIRECTIVE, + STMT_OMP_TARGET_ENTER_DATA_DIRECTIVE, + STMT_OMP_TARGET_EXIT_DATA_DIRECTIVE, + STMT_OMP_TARGET_PARALLEL_DIRECTIVE, + STMT_OMP_TARGET_PARALLEL_FOR_DIRECTIVE, + STMT_OMP_TEAMS_DIRECTIVE, + STMT_OMP_TASKGROUP_DIRECTIVE, + STMT_OMP_CANCELLATION_POINT_DIRECTIVE, + STMT_OMP_CANCEL_DIRECTIVE, + STMT_OMP_TASKLOOP_DIRECTIVE, + STMT_OMP_TASKLOOP_SIMD_DIRECTIVE, + STMT_OMP_MASTER_TASKLOOP_DIRECTIVE, + STMT_OMP_MASTER_TASKLOOP_SIMD_DIRECTIVE, + STMT_OMP_PARALLEL_MASTER_TASKLOOP_DIRECTIVE, + STMT_OMP_PARALLEL_MASTER_TASKLOOP_SIMD_DIRECTIVE, + STMT_OMP_DISTRIBUTE_DIRECTIVE, + STMT_OMP_TARGET_UPDATE_DIRECTIVE, + STMT_OMP_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE, + STMT_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE, + STMT_OMP_DISTRIBUTE_SIMD_DIRECTIVE, + STMT_OMP_TARGET_PARALLEL_FOR_SIMD_DIRECTIVE, + STMT_OMP_TARGET_SIMD_DIRECTIVE, + STMT_OMP_TEAMS_DISTRIBUTE_DIRECTIVE, + STMT_OMP_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE, + STMT_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE, + STMT_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE, + STMT_OMP_TARGET_TEAMS_DIRECTIVE, + STMT_OMP_TARGET_TEAMS_DISTRIBUTE_DIRECTIVE, + STMT_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE, + STMT_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE, + STMT_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE, + EXPR_OMP_ARRAY_SECTION, + EXPR_OMP_ARRAY_SHAPING, + EXPR_OMP_ITERATOR, + + // ARC + EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr + + STMT_MS_DEPENDENT_EXISTS, // MSDependentExistsStmt + EXPR_LAMBDA, // LambdaExpr + STMT_COROUTINE_BODY, + STMT_CORETURN, + EXPR_COAWAIT, + EXPR_COYIELD, + EXPR_DEPENDENT_COAWAIT, + + // FixedPointLiteral + EXPR_FIXEDPOINT_LITERAL, +}; - /// A CXXOperatorCallExpr record. - EXPR_CXX_OPERATOR_CALL, +/// The kinds of designators that can occur in a +/// DesignatedInitExpr. +enum DesignatorTypes { + /// Field designator where only the field name is known. + DESIG_FIELD_NAME = 0, - /// A CXXMemberCallExpr record. - EXPR_CXX_MEMBER_CALL, + /// Field designator where the field has been resolved to + /// a declaration. + DESIG_FIELD_DECL = 1, - /// A CXXRewrittenBinaryOperator record. - EXPR_CXX_REWRITTEN_BINARY_OPERATOR, + /// Array designator. + DESIG_ARRAY = 2, - /// A CXXConstructExpr record. - EXPR_CXX_CONSTRUCT, + /// GNU array range designator. + DESIG_ARRAY_RANGE = 3 +}; - /// A CXXInheritedCtorInitExpr record. - EXPR_CXX_INHERITED_CTOR_INIT, +/// The different kinds of data that can occur in a +/// CtorInitializer. +enum CtorInitializerType { + CTOR_INITIALIZER_BASE, + CTOR_INITIALIZER_DELEGATING, + CTOR_INITIALIZER_MEMBER, + CTOR_INITIALIZER_INDIRECT_MEMBER +}; - /// A CXXTemporaryObjectExpr record. - EXPR_CXX_TEMPORARY_OBJECT, +/// Kinds of cleanup objects owned by ExprWithCleanups. +enum CleanupObjectKind { COK_Block, COK_CompoundLiteral }; - /// A CXXStaticCastExpr record. - EXPR_CXX_STATIC_CAST, +/// Describes the redeclarations of a declaration. +struct LocalRedeclarationsInfo { + // The ID of the first declaration + DeclID FirstID; - /// A CXXDynamicCastExpr record. - EXPR_CXX_DYNAMIC_CAST, + // Offset into the array of redeclaration chains. + unsigned Offset; - /// A CXXReinterpretCastExpr record. - EXPR_CXX_REINTERPRET_CAST, + friend bool operator<(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID < Y.FirstID; + } - /// A CXXConstCastExpr record. - EXPR_CXX_CONST_CAST, + friend bool operator>(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID > Y.FirstID; + } - /// A CXXAddrspaceCastExpr record. - EXPR_CXX_ADDRSPACE_CAST, - - /// A CXXFunctionalCastExpr record. - EXPR_CXX_FUNCTIONAL_CAST, - - /// A BuiltinBitCastExpr record. - EXPR_BUILTIN_BIT_CAST, - - /// A UserDefinedLiteral record. - EXPR_USER_DEFINED_LITERAL, - - /// A CXXStdInitializerListExpr record. - EXPR_CXX_STD_INITIALIZER_LIST, - - /// A CXXBoolLiteralExpr record. - EXPR_CXX_BOOL_LITERAL, - - EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr - EXPR_CXX_TYPEID_EXPR, // CXXTypeidExpr (of expr). - EXPR_CXX_TYPEID_TYPE, // CXXTypeidExpr (of type). - EXPR_CXX_THIS, // CXXThisExpr - EXPR_CXX_THROW, // CXXThrowExpr - EXPR_CXX_DEFAULT_ARG, // CXXDefaultArgExpr - EXPR_CXX_DEFAULT_INIT, // CXXDefaultInitExpr - EXPR_CXX_BIND_TEMPORARY, // CXXBindTemporaryExpr - - EXPR_CXX_SCALAR_VALUE_INIT, // CXXScalarValueInitExpr - EXPR_CXX_NEW, // CXXNewExpr - EXPR_CXX_DELETE, // CXXDeleteExpr - EXPR_CXX_PSEUDO_DESTRUCTOR, // CXXPseudoDestructorExpr - - EXPR_EXPR_WITH_CLEANUPS, // ExprWithCleanups - - EXPR_CXX_DEPENDENT_SCOPE_MEMBER, // CXXDependentScopeMemberExpr - EXPR_CXX_DEPENDENT_SCOPE_DECL_REF, // DependentScopeDeclRefExpr - EXPR_CXX_UNRESOLVED_CONSTRUCT, // CXXUnresolvedConstructExpr - EXPR_CXX_UNRESOLVED_MEMBER, // UnresolvedMemberExpr - EXPR_CXX_UNRESOLVED_LOOKUP, // UnresolvedLookupExpr - - EXPR_CXX_EXPRESSION_TRAIT, // ExpressionTraitExpr - EXPR_CXX_NOEXCEPT, // CXXNoexceptExpr - - EXPR_OPAQUE_VALUE, // OpaqueValueExpr - EXPR_BINARY_CONDITIONAL_OPERATOR, // BinaryConditionalOperator - EXPR_TYPE_TRAIT, // TypeTraitExpr - EXPR_ARRAY_TYPE_TRAIT, // ArrayTypeTraitIntExpr - - EXPR_PACK_EXPANSION, // PackExpansionExpr - EXPR_SIZEOF_PACK, // SizeOfPackExpr - EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr - EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr - EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr - EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr - EXPR_CXX_FOLD, // CXXFoldExpr - EXPR_CONCEPT_SPECIALIZATION,// ConceptSpecializationExpr - EXPR_REQUIRES, // RequiresExpr - - // CUDA - EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr - - // OpenCL - EXPR_ASTYPE, // AsTypeExpr - - // Microsoft - EXPR_CXX_PROPERTY_REF_EXPR, // MSPropertyRefExpr - EXPR_CXX_PROPERTY_SUBSCRIPT_EXPR, // MSPropertySubscriptExpr - EXPR_CXX_UUIDOF_EXPR, // CXXUuidofExpr (of expr). - EXPR_CXX_UUIDOF_TYPE, // CXXUuidofExpr (of type). - STMT_SEH_LEAVE, // SEHLeaveStmt - STMT_SEH_EXCEPT, // SEHExceptStmt - STMT_SEH_FINALLY, // SEHFinallyStmt - STMT_SEH_TRY, // SEHTryStmt - - // OpenMP directives - STMT_OMP_PARALLEL_DIRECTIVE, - STMT_OMP_SIMD_DIRECTIVE, - STMT_OMP_TILE_DIRECTIVE, - STMT_OMP_FOR_DIRECTIVE, - STMT_OMP_FOR_SIMD_DIRECTIVE, - STMT_OMP_SECTIONS_DIRECTIVE, - STMT_OMP_SECTION_DIRECTIVE, - STMT_OMP_SINGLE_DIRECTIVE, - STMT_OMP_MASTER_DIRECTIVE, - STMT_OMP_CRITICAL_DIRECTIVE, - STMT_OMP_PARALLEL_FOR_DIRECTIVE, - STMT_OMP_PARALLEL_FOR_SIMD_DIRECTIVE, - STMT_OMP_PARALLEL_MASTER_DIRECTIVE, - STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE, - STMT_OMP_TASK_DIRECTIVE, - STMT_OMP_TASKYIELD_DIRECTIVE, - STMT_OMP_BARRIER_DIRECTIVE, - STMT_OMP_TASKWAIT_DIRECTIVE, - STMT_OMP_FLUSH_DIRECTIVE, - STMT_OMP_DEPOBJ_DIRECTIVE, - STMT_OMP_SCAN_DIRECTIVE, - STMT_OMP_ORDERED_DIRECTIVE, - STMT_OMP_ATOMIC_DIRECTIVE, - STMT_OMP_TARGET_DIRECTIVE, - STMT_OMP_TARGET_DATA_DIRECTIVE, - STMT_OMP_TARGET_ENTER_DATA_DIRECTIVE, - STMT_OMP_TARGET_EXIT_DATA_DIRECTIVE, - STMT_OMP_TARGET_PARALLEL_DIRECTIVE, - STMT_OMP_TARGET_PARALLEL_FOR_DIRECTIVE, - STMT_OMP_TEAMS_DIRECTIVE, - STMT_OMP_TASKGROUP_DIRECTIVE, - STMT_OMP_CANCELLATION_POINT_DIRECTIVE, - STMT_OMP_CANCEL_DIRECTIVE, - STMT_OMP_TASKLOOP_DIRECTIVE, - STMT_OMP_TASKLOOP_SIMD_DIRECTIVE, - STMT_OMP_MASTER_TASKLOOP_DIRECTIVE, - STMT_OMP_MASTER_TASKLOOP_SIMD_DIRECTIVE, - STMT_OMP_PARALLEL_MASTER_TASKLOOP_DIRECTIVE, - STMT_OMP_PARALLEL_MASTER_TASKLOOP_SIMD_DIRECTIVE, - STMT_OMP_DISTRIBUTE_DIRECTIVE, - STMT_OMP_TARGET_UPDATE_DIRECTIVE, - STMT_OMP_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE, - STMT_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE, - STMT_OMP_DISTRIBUTE_SIMD_DIRECTIVE, - STMT_OMP_TARGET_PARALLEL_FOR_SIMD_DIRECTIVE, - STMT_OMP_TARGET_SIMD_DIRECTIVE, - STMT_OMP_TEAMS_DISTRIBUTE_DIRECTIVE, - STMT_OMP_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE, - STMT_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE, - STMT_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE, - STMT_OMP_TARGET_TEAMS_DIRECTIVE, - STMT_OMP_TARGET_TEAMS_DISTRIBUTE_DIRECTIVE, - STMT_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE, - STMT_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE, - STMT_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE, - EXPR_OMP_ARRAY_SECTION, - EXPR_OMP_ARRAY_SHAPING, - EXPR_OMP_ITERATOR, - - // ARC - EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr - - STMT_MS_DEPENDENT_EXISTS, // MSDependentExistsStmt - EXPR_LAMBDA, // LambdaExpr - STMT_COROUTINE_BODY, - STMT_CORETURN, - EXPR_COAWAIT, - EXPR_COYIELD, - EXPR_DEPENDENT_COAWAIT, - - // FixedPointLiteral - EXPR_FIXEDPOINT_LITERAL, - }; - - /// The kinds of designators that can occur in a - /// DesignatedInitExpr. - enum DesignatorTypes { - /// Field designator where only the field name is known. - DESIG_FIELD_NAME = 0, - - /// Field designator where the field has been resolved to - /// a declaration. - DESIG_FIELD_DECL = 1, - - /// Array designator. - DESIG_ARRAY = 2, - - /// GNU array range designator. - DESIG_ARRAY_RANGE = 3 - }; - - /// The different kinds of data that can occur in a - /// CtorInitializer. - enum CtorInitializerType { - CTOR_INITIALIZER_BASE, - CTOR_INITIALIZER_DELEGATING, - CTOR_INITIALIZER_MEMBER, - CTOR_INITIALIZER_INDIRECT_MEMBER - }; - - /// Kinds of cleanup objects owned by ExprWithCleanups. - enum CleanupObjectKind { COK_Block, COK_CompoundLiteral }; - - /// Describes the redeclarations of a declaration. - struct LocalRedeclarationsInfo { - // The ID of the first declaration - DeclID FirstID; - - // Offset into the array of redeclaration chains. - unsigned Offset; - - friend bool operator<(const LocalRedeclarationsInfo &X, - const LocalRedeclarationsInfo &Y) { - return X.FirstID < Y.FirstID; - } - - friend bool operator>(const LocalRedeclarationsInfo &X, - const LocalRedeclarationsInfo &Y) { - return X.FirstID > Y.FirstID; - } - - friend bool operator<=(const LocalRedeclarationsInfo &X, - const LocalRedeclarationsInfo &Y) { - return X.FirstID <= Y.FirstID; - } - - friend bool operator>=(const LocalRedeclarationsInfo &X, - const LocalRedeclarationsInfo &Y) { - return X.FirstID >= Y.FirstID; - } - }; - - /// Describes the categories of an Objective-C class. - struct ObjCCategoriesInfo { - // The ID of the definition - DeclID DefinitionID; - - // Offset into the array of category lists. - unsigned Offset; - - friend bool operator<(const ObjCCategoriesInfo &X, - const ObjCCategoriesInfo &Y) { - return X.DefinitionID < Y.DefinitionID; - } - - friend bool operator>(const ObjCCategoriesInfo &X, - const ObjCCategoriesInfo &Y) { - return X.DefinitionID > Y.DefinitionID; - } - - friend bool operator<=(const ObjCCategoriesInfo &X, - const ObjCCategoriesInfo &Y) { - return X.DefinitionID <= Y.DefinitionID; - } - - friend bool operator>=(const ObjCCategoriesInfo &X, - const ObjCCategoriesInfo &Y) { - return X.DefinitionID >= Y.DefinitionID; - } - }; - - /// A key used when looking up entities by \ref DeclarationName. - /// - /// Different \ref DeclarationNames are mapped to different keys, but the - /// same key can occasionally represent multiple names (for names that - /// contain types, in particular). - class DeclarationNameKey { - using NameKind = unsigned; - - NameKind Kind = 0; - uint64_t Data = 0; - - public: - DeclarationNameKey() = default; - DeclarationNameKey(DeclarationName Name); - DeclarationNameKey(NameKind Kind, uint64_t Data) - : Kind(Kind), Data(Data) {} - - NameKind getKind() const { return Kind; } - - IdentifierInfo *getIdentifier() const { - assert(Kind == DeclarationName::Identifier || - Kind == DeclarationName::CXXLiteralOperatorName || - Kind == DeclarationName::CXXDeductionGuideName); - return (IdentifierInfo *)Data; - } - - Selector getSelector() const { - assert(Kind == DeclarationName::ObjCZeroArgSelector || - Kind == DeclarationName::ObjCOneArgSelector || - Kind == DeclarationName::ObjCMultiArgSelector); - return Selector(Data); - } - - OverloadedOperatorKind getOperatorKind() const { - assert(Kind == DeclarationName::CXXOperatorName); - return (OverloadedOperatorKind)Data; - } - - /// Compute a fingerprint of this key for use in on-disk hash table. - unsigned getHash() const; - - friend bool operator==(const DeclarationNameKey &A, - const DeclarationNameKey &B) { - return A.Kind == B.Kind && A.Data == B.Data; - } - }; - - /// @} + friend bool operator<=(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID <= Y.FirstID; + } + + friend bool operator>=(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID >= Y.FirstID; + } +}; + +/// Describes the categories of an Objective-C class. +struct ObjCCategoriesInfo { + // The ID of the definition + DeclID DefinitionID; + + // Offset into the array of category lists. + unsigned Offset; + + friend bool operator<(const ObjCCategoriesInfo &X, + const ObjCCategoriesInfo &Y) { + return X.DefinitionID < Y.DefinitionID; + } + + friend bool operator>(const ObjCCategoriesInfo &X, + const ObjCCategoriesInfo &Y) { + return X.DefinitionID > Y.DefinitionID; + } + + friend bool operator<=(const ObjCCategoriesInfo &X, + const ObjCCategoriesInfo &Y) { + return X.DefinitionID <= Y.DefinitionID; + } + + friend bool operator>=(const ObjCCategoriesInfo &X, + const ObjCCategoriesInfo &Y) { + return X.DefinitionID >= Y.DefinitionID; + } +}; + +/// A key used when looking up entities by \ref DeclarationName. +/// +/// Different \ref DeclarationNames are mapped to different keys, but the +/// same key can occasionally represent multiple names (for names that +/// contain types, in particular). +class DeclarationNameKey { + using NameKind = unsigned; + + NameKind Kind = 0; + uint64_t Data = 0; + +public: + DeclarationNameKey() = default; + DeclarationNameKey(DeclarationName Name); + DeclarationNameKey(NameKind Kind, uint64_t Data) : Kind(Kind), Data(Data) {} + + NameKind getKind() const { return Kind; } + + IdentifierInfo *getIdentifier() const { + assert(Kind == DeclarationName::Identifier || + Kind == DeclarationName::CXXLiteralOperatorName || + Kind == DeclarationName::CXXDeductionGuideName); + return (IdentifierInfo *)Data; + } + + Selector getSelector() const { + assert(Kind == DeclarationName::ObjCZeroArgSelector || + Kind == DeclarationName::ObjCOneArgSelector || + Kind == DeclarationName::ObjCMultiArgSelector); + return Selector(Data); + } + + OverloadedOperatorKind getOperatorKind() const { + assert(Kind == DeclarationName::CXXOperatorName); + return (OverloadedOperatorKind)Data; + } + + /// Compute a fingerprint of this key for use in on-disk hash table. + unsigned getHash() const; + + friend bool operator==(const DeclarationNameKey &A, + const DeclarationNameKey &B) { + return A.Kind == B.Kind && A.Data == B.Data; + } +}; + +/// @} } // namespace serialization } // namespace clang namespace llvm { - template <> struct DenseMapInfo { - static clang::serialization::DeclarationNameKey getEmptyKey() { - return clang::serialization::DeclarationNameKey(-1, 1); - } - - static clang::serialization::DeclarationNameKey getTombstoneKey() { - return clang::serialization::DeclarationNameKey(-1, 2); - } - - static unsigned - getHashValue(const clang::serialization::DeclarationNameKey &Key) { - return Key.getHash(); - } - - static bool isEqual(const clang::serialization::DeclarationNameKey &L, - const clang::serialization::DeclarationNameKey &R) { - return L == R; - } - }; +template <> struct DenseMapInfo { + static clang::serialization::DeclarationNameKey getEmptyKey() { + return clang::serialization::DeclarationNameKey(-1, 1); + } + + static clang::serialization::DeclarationNameKey getTombstoneKey() { + return clang::serialization::DeclarationNameKey(-1, 2); + } + + static unsigned + getHashValue(const clang::serialization::DeclarationNameKey &Key) { + return Key.getHash(); + } + + static bool isEqual(const clang::serialization::DeclarationNameKey &L, + const clang::serialization::DeclarationNameKey &R) { + return L == R; + } +}; } // namespace llvm diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -1266,13 +1266,6 @@ break; case VCK_ByCopy: assert(Var && "capturing by copy must have a variable!"); - assert( - (Var->getType()->isScalarType() || (Var->getType()->isReferenceType() && - Var->getType() - ->castAs() - ->getPointeeType() - ->isScalarType())) && - "captures by copy are expected to have a scalar type!"); break; case VCK_VLAType: assert(!Var && diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -92,6 +92,8 @@ for (Stmt *S : CS->body()) { if (!S) continue; + if (auto *CanonLoop = dyn_cast(S)) + S = CanonLoop->getLoopStmt(); if (isa(S) || isa(S) || (isa(S) && !isa(S))) { // Only single loop construct is allowed. @@ -127,6 +129,8 @@ for (unsigned Cnt = 0; Cnt < NumLoops; ++Cnt) { if (auto *Dir = dyn_cast(CurStmt)) CurStmt = Dir->getTransformedStmt(); + if (auto *CanonLoop = dyn_cast(CurStmt)) + CurStmt = CanonLoop->getLoopStmt(); if (Callback(Cnt, CurStmt)) return false; // Move on to the next nested for loop, or to the loop body. @@ -161,6 +165,8 @@ "Expected canonical for or range-based for loops."); Body = cast(Loop)->getBody(); } + if (auto *CanonLoop = dyn_cast(Body)) + Body = CanonLoop->getLoopStmt(); Callback(Cnt, Loop, Body); return false; }); diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -636,6 +636,10 @@ // OpenMP directives printing methods //===----------------------------------------------------------------------===// +void StmtPrinter::VisitOMPCanonicalLoop(OMPCanonicalLoop *Node) { + PrintStmt(Node->getLoopStmt()); +} + void StmtPrinter::PrintOMPExecutableDirective(OMPExecutableDirective *S, bool ForceNoStmt) { OMPClausePrinter Printer(OS, Policy); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -854,6 +854,10 @@ P.Visit(*I); } +void StmtProfiler::VisitOMPCanonicalLoop(const OMPCanonicalLoop *L) { + VisitStmt(L); +} + void StmtProfiler::VisitOMPLoopBasedDirective(const OMPLoopBasedDirective *S) { VisitOMPExecutableDirective(S); } diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -194,6 +194,9 @@ case Stmt::SEHTryStmtClass: EmitSEHTryStmt(cast(*S)); break; + case Stmt::OMPCanonicalLoopClass: + EmitOMPCanonicalLoop(cast(S)); + break; case Stmt::OMPParallelDirectiveClass: EmitOMPParallelDirective(cast(*S)); break; diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -1803,6 +1803,8 @@ SimplifiedS); if (auto *Dir = dyn_cast(SimplifiedS)) SimplifiedS = Dir->getTransformedStmt(); + if (const auto *CanonLoop = dyn_cast(SimplifiedS)) + SimplifiedS = CanonLoop->getLoopStmt(); if (const auto *For = dyn_cast(SimplifiedS)) { S = For->getBody(); } else { @@ -1890,6 +1892,121 @@ BreakContinueStack.pop_back(); } +using EmittedClosureTy = std::pair; + +/// Emit a captured statement and return the function as well as its captured +/// closure context. +static EmittedClosureTy emitCapturedStmtFunc(CodeGenFunction &ParentCGF, + const CapturedStmt *S) { + LValue CapStruct = ParentCGF.InitCapturedStruct(*S); + CodeGenFunction CGF(ParentCGF.CGM, /*suppressNewContext=*/true); + std::unique_ptr CSI = + std::make_unique(*S); + CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, CSI.get()); + llvm::Function *F = CGF.GenerateCapturedStmtFunction(*S); + + return {F, CapStruct.getPointer(ParentCGF)}; +} + +/// Emit a call to a previously captured closure. +static llvm::CallInst * +emitCapturedStmtCall(CodeGenFunction &ParentCGF, EmittedClosureTy Cap, + llvm::ArrayRef Args) { + // Append the closure context to the argument. + SmallVector EffectiveArgs; + EffectiveArgs.reserve(Args.size() + 1); + llvm::append_range(EffectiveArgs, Args); + EffectiveArgs.push_back(Cap.second); + + return ParentCGF.Builder.CreateCall(Cap.first, EffectiveArgs); +} + +llvm::CanonicalLoopInfo * +CodeGenFunction::EmitOMPCollapsedCanonicalLoopNest(const Stmt *S, int Depth) { + assert(Depth == 1 && "Nested loops with OpenMPIRBuilder not yet implemented"); + + EmitStmt(S); + assert(OMPLoopNestStack.size() >= (size_t)Depth && "Found too few loops"); + + // The last added loop is the outermost one. + return OMPLoopNestStack.back(); +} + +void CodeGenFunction::EmitOMPCanonicalLoop(const OMPCanonicalLoop *S) { + const Stmt *SyntacticalLoop = S->getLoopStmt(); + if (!getLangOpts().OpenMPIRBuilder) { + // Ignore if OpenMPIRBuilder is not enabled. + EmitStmt(SyntacticalLoop); + return; + } + + LexicalScope ForScope(*this, S->getSourceRange()); + + // Emit init statements. The Distance/LoopVar funcs may reference variable + // declarations they contain. + const Stmt *BodyStmt; + if (const auto *For = dyn_cast(SyntacticalLoop)) { + if (const Stmt *InitStmt = For->getInit()) + EmitStmt(InitStmt); + BodyStmt = For->getBody(); + } else if (const auto *RangeFor = + dyn_cast(SyntacticalLoop)) { + if (const DeclStmt *RangeStmt = RangeFor->getRangeStmt()) + EmitStmt(RangeStmt); + if (const DeclStmt *BeginStmt = RangeFor->getBeginStmt()) + EmitStmt(BeginStmt); + if (const DeclStmt *EndStmt = RangeFor->getEndStmt()) + EmitStmt(EndStmt); + if (const DeclStmt *LoopVarStmt = RangeFor->getLoopVarStmt()) + EmitStmt(LoopVarStmt); + BodyStmt = RangeFor->getBody(); + } else + llvm_unreachable("Expected for-stmt or range-based for-stmt"); + + // Emit closure for later use. By-value captures will be captured here. + const CapturedStmt *DistanceFunc = S->getDistanceFunc(); + EmittedClosureTy DistanceClosure = emitCapturedStmtFunc(*this, DistanceFunc); + const CapturedStmt *LoopVarFunc = S->getLoopVarFunc(); + EmittedClosureTy LoopVarClosure = emitCapturedStmtFunc(*this, LoopVarFunc); + + // Call the distance function to get the number of iterations of the loop to + // come. + QualType LogicalTy = DistanceFunc->getCapturedDecl() + ->getParam(0) + ->getType() + .getNonReferenceType(); + Address CountAddr = CreateMemTemp(LogicalTy, ".count.addr"); + emitCapturedStmtCall(*this, DistanceClosure, {CountAddr.getPointer()}); + llvm::Value *DistVal = Builder.CreateLoad(CountAddr, ".count"); + + // Emit the loop structure. + llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder(); + auto BodyGen = [&, this](llvm::OpenMPIRBuilder::InsertPointTy CodeGenIP, + llvm::Value *IndVar) { + Builder.restoreIP(CodeGenIP); + + // Emit the loop body: Convert the logical iteration number to the loop + // variable and emit the body. + const DeclRefExpr *LoopVarRef = S->getLoopVarRef(); + LValue LCVal = EmitLValue(LoopVarRef); + Address LoopVarAddress = LCVal.getAddress(*this); + emitCapturedStmtCall(*this, LoopVarClosure, + {LoopVarAddress.getPointer(), IndVar}); + + RunCleanupsScope BodyScope(*this); + EmitStmt(BodyStmt); + }; + llvm::CanonicalLoopInfo *CL = + OMPBuilder.createCanonicalLoop(Builder, BodyGen, DistVal); + + // Finish up the loop. + Builder.restoreIP(CL->getAfterIP()); + ForScope.ForceCleanup(); + + // Remember the CanonicalLoopInfo for parent AST nodes consuming it. + OMPLoopNestStack.push_back(CL); +} + void CodeGenFunction::EmitOMPInnerLoop( const OMPExecutableDirective &S, bool RequiresCleanup, const Expr *LoopCond, const Expr *IncExpr, @@ -1907,6 +2024,7 @@ const CapturedStmt *ICS = OMPED.getInnermostCapturedStmt(); const Stmt *SS = ICS->getCapturedStmt(); const AttributedStmt *AS = dyn_cast_or_null(SS); + OMPLoopNestStack.clear(); if (AS) LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), AS->getAttrs(), SourceLocToDebugLoc(R.getBegin()), @@ -2461,6 +2579,7 @@ llvm::BasicBlock *CondBlock = createBasicBlock("omp.dispatch.cond"); EmitBlock(CondBlock); const SourceRange R = S.getSourceRange(); + OMPLoopNestStack.clear(); LoopStack.push(CondBlock, SourceLocToDebugLoc(R.getBegin()), SourceLocToDebugLoc(R.getEnd())); @@ -2544,6 +2663,7 @@ } EmitBranch(CondBlock); + OMPLoopNestStack.clear(); LoopStack.pop(); // Emit the fall-through block. EmitBlock(LoopExit.getBlock()); @@ -3386,10 +3506,38 @@ return HasLastprivates; } +static bool isSupportedByOpenMPIRBuilder(const OMPForDirective &S) { + if (S.hasCancel()) + return false; + for (OMPClause *C : S.clauses()) + if (!isa(C)) + return false; + + return true; +} + void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) { bool HasLastprivates = false; - auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF, - PrePostActionTy &) { + bool UseOMPIRBuilder = + CGM.getLangOpts().OpenMPIRBuilder && isSupportedByOpenMPIRBuilder(S); + auto &&CodeGen = [this, &S, &HasLastprivates, + UseOMPIRBuilder](CodeGenFunction &CGF, PrePostActionTy &) { + // Use the OpenMPIRBuilder if enabled. + if (UseOMPIRBuilder) { + // Emit the associated statement and get its loop representation. + const Stmt *Inner = S.getRawStmt(); + llvm::CanonicalLoopInfo *CLI = + EmitOMPCollapsedCanonicalLoopNest(Inner, 1); + + bool NeedsBarrier = !S.getSingleClause(); + llvm::OpenMPIRBuilder &OMPBuilder = + CGM.getOpenMPRuntime().getOMPBuilder(); + llvm::OpenMPIRBuilder::InsertPointTy AllocaIP( + AllocaInsertPt->getParent(), AllocaInsertPt->getIterator()); + OMPBuilder.createWorkshareLoop(Builder, CLI, AllocaIP, NeedsBarrier); + return; + } + HasLastprivates = emitWorksharingDirective(CGF, S, S.hasCancel()); }; { @@ -3400,9 +3548,11 @@ S.hasCancel()); } - // Emit an implicit barrier at the end. - if (!S.getSingleClause() || HasLastprivates) - CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_for); + if (!UseOMPIRBuilder) { + // Emit an implicit barrier at the end. + if (!S.getSingleClause() || HasLastprivates) + CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_for); + } // Check for outer lastprivate conditional update. checkForLastprivateConditionalUpdate(*this, S); } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -50,6 +50,7 @@ class SwitchInst; class Twine; class Value; +class CanonicalLoopInfo; } namespace clang { @@ -276,6 +277,20 @@ // because of jumps. VarBypassDetector Bypasses; + /// List of recently emitted OMPCanonicalLoops. + /// + /// Since OMPCanonicalLoops are nested inside other statements (in particular + /// CapturedStmt generated by OMPExecutableDirective and non-perfectly nested + /// loops), we cannot directly call OMPEmitOMPCanonicalLoop and receive its + /// llvm::CanonicalLoopInfo. Instead, we call EmitStmt and any + /// OMPEmitOMPCanonicalLoop called by it will add its CanonicalLoopInfo to + /// this stack when done. Entering a new loop requires clearing this list; it + /// either means we start parsing a new loop nest (in which case the previous + /// loop nest goes out of scope) or a second loop in the same level in which + /// case it would be ambiguous into which of the two (or more) loops the loop + /// nest would extend. + SmallVector OMPLoopNestStack; + // CodeGen lambda for loops and support for ordered clause typedef llvm::function_ref @@ -3511,6 +3526,18 @@ static void EmitOMPTargetTeamsDistributeParallelForDeviceFunction( CodeGenModule &CGM, StringRef ParentName, const OMPTargetTeamsDistributeParallelForDirective &S); + + /// Emit the Stmt \p S and return its topmost canonical loop, if any. + /// TODO: The \p Depth paramter is not yet implemented and must be 1. In the + /// future it is meant to be the number of loops expected in the loop nests + /// (usually specified by the "collapse" clause) that are collapsed to a + /// single loop by this function. + llvm::CanonicalLoopInfo *EmitOMPCollapsedCanonicalLoopNest(const Stmt *S, + int Depth); + + /// Emit an OMPCanonicalLoop using the OpenMPIRBuilder. + void EmitOMPCanonicalLoop(const OMPCanonicalLoop *S); + /// Emit inner loop of the worksharing/simd construct. /// /// \param S Directive, for which the inner loop must be emitted. diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -91,8 +91,8 @@ // seems to be a reasonable spot. We do it here, as opposed to the deletion // time of the CodeGenModule, because we have to ensure the IR has not yet // been "emitted" to the outside, thus, modifications are still sensible. - if (CGM.getLangOpts().OpenMPIRBuilder) - CGM.getOpenMPRuntime().getOMPBuilder().finalize(); + if (CGM.getLangOpts().OpenMPIRBuilder && CurFn) + CGM.getOpenMPRuntime().getOMPBuilder().finalize(CurFn); } // Map the LangOption for exception behavior into diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2536,7 +2536,15 @@ // the captured region. Code elsewhere assumes that any FunctionScopeInfo // should have at least one compound statement scope within it. ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false); - AssociatedStmt = (Sema::CompoundScopeRAII(Actions), ParseStatement()); + { + Sema::CompoundScopeRAII Scope(Actions); + AssociatedStmt = ParseStatement(); + + if (AssociatedStmt.isUsable() && isOpenMPLoopDirective(DKind) && + getLangOpts().OpenMPIRBuilder) + AssociatedStmt = + Actions.ActOnOpenMPCanonicalLoop(AssociatedStmt.get()); + } AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); } else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data || DKind == OMPD_target_exit_data) { diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1448,6 +1448,7 @@ case Stmt::OMPMasterTaskLoopDirectiveClass: case Stmt::OMPMasterTaskLoopSimdDirectiveClass: case Stmt::OMPOrderedDirectiveClass: + case Stmt::OMPCanonicalLoopClass: case Stmt::OMPParallelDirectiveClass: case Stmt::OMPParallelForDirectiveClass: case Stmt::OMPParallelForSimdDirectiveClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -17284,18 +17284,17 @@ /// Capture the given variable in the captured region. -static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, - VarDecl *Var, - SourceLocation Loc, - const bool BuildAndDiagnose, - QualType &CaptureType, - QualType &DeclRefType, - const bool RefersToCapturedVariable, - Sema &S, bool Invalid) { +static bool captureInCapturedRegion( + CapturedRegionScopeInfo *RSI, VarDecl *Var, SourceLocation Loc, + const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, + const bool RefersToCapturedVariable, Sema::TryCaptureKind Kind, + bool IsTopScope, Sema &S, bool Invalid) { // By default, capture variables by reference. bool ByRef = true; - // Using an LValue reference type is consistent with Lambdas (see below). - if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) { + if (IsTopScope && Kind != Sema::TryCapture_Implicit) { + ByRef = (Kind == Sema::TryCapture_ExplicitByRef); + } else if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) { + // Using an LValue reference type is consistent with Lambdas (see below). if (S.isOpenMPCapturedDecl(Var)) { bool HasConst = DeclRefType.isConstQualified(); DeclRefType = DeclRefType.getUnqualifiedType(); @@ -17641,9 +17640,9 @@ DeclRefType, Nested, *this, Invalid); Nested = true; } else if (CapturedRegionScopeInfo *RSI = dyn_cast(CSI)) { - Invalid = !captureInCapturedRegion(RSI, Var, ExprLoc, BuildAndDiagnose, - CaptureType, DeclRefType, Nested, - *this, Invalid); + Invalid = !captureInCapturedRegion( + RSI, Var, ExprLoc, BuildAndDiagnose, CaptureType, DeclRefType, Nested, + Kind, /*IsTopScope*/ I == N - 1, *this, Invalid); Nested = true; } else { LambdaScopeInfo *LSI = cast(CSI); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -5151,6 +5151,393 @@ } } +namespace { +/// Rewrite statements and expressions for Sema \p Actions CurContext. +/// +/// Used to wrap already parsed statements/expressions into a new CapturedStmt +/// context. DeclRefExpr used inside the new context are changed to refer to the +/// captured variable instead. +class CaptureVars : public TreeTransform { + using BaseTransform = TreeTransform; + +public: + CaptureVars(Sema &Actions) : BaseTransform(Actions) {} + + bool AlwaysRebuild() { return true; } +}; +} // namespace + +static VarDecl *precomputeExpr(Sema &Actions, + SmallVectorImpl &BodyStmts, Expr *E, + StringRef Name) { + Expr *NewE = AssertSuccess(CaptureVars(Actions).TransformExpr(E)); + VarDecl *NewVar = buildVarDecl(Actions, {}, NewE->getType(), Name, nullptr, + dyn_cast(E->IgnoreImplicit())); + auto *NewDeclStmt = cast(AssertSuccess( + Actions.ActOnDeclStmt(Actions.ConvertDeclToDeclGroup(NewVar), {}, {}))); + Actions.AddInitializerToDecl(NewDeclStmt->getSingleDecl(), NewE, false); + BodyStmts.push_back(NewDeclStmt); + return NewVar; +} + +/// Create a closure that computes the number of iterations of a loop. +/// +/// \param Actions The Sema object. +/// \param LogicalTy Type for the logical iteration number. +/// \param Rel Comparison operator of the loop condition. +/// \param StartExpr Value of the loop counter at the first iteration. +/// \param StopExpr Expression the loop counter is compared against in the loop +/// condition. \param Step Amount of increment after each iteration. +/// +/// \return Closure (CapturedStmt) of the distance calculation. +static CapturedStmt *buildDistanceFunc(Sema &Actions, QualType LogicalTy, + BinaryOperator::Opcode Rel, + Expr *StartExpr, Expr *StopExpr, + Expr *StepExpr) { + ASTContext &Ctx = Actions.getASTContext(); + TypeSourceInfo *LogicalTSI = Ctx.getTrivialTypeSourceInfo(LogicalTy); + + // Captured regions currently don't support return values, we use an + // out-parameter instead. All inputs are implicit captures. + // TODO: Instead of capturing each DeclRefExpr occurring in + // StartExpr/StopExpr/Step, these could also be passed as a value capture. + QualType ResultTy = Ctx.getLValueReferenceType(LogicalTy); + Sema::CapturedParamNameType Params[] = {{"Distance", ResultTy}, + {StringRef(), QualType()}}; + Actions.ActOnCapturedRegionStart({}, nullptr, CR_Default, Params); + + Stmt *Body; + { + Sema::CompoundScopeRAII CompoundScope(Actions); + CapturedDecl *CS = cast(Actions.CurContext); + + // Get the LValue expression for the result. + ImplicitParamDecl *DistParam = CS->getParam(0); + DeclRefExpr *DistRef = Actions.BuildDeclRefExpr( + DistParam, LogicalTy, VK_LValue, {}, nullptr, nullptr, {}, nullptr); + + SmallVector BodyStmts; + + // Capture all referenced variable references. + // TODO: Instead of computing NewStart/NewStop/NewStep inside the + // CapturedStmt, we could compute them before and capture the result, to be + // used jointly with the LoopVar function. + VarDecl *NewStart = precomputeExpr(Actions, BodyStmts, StartExpr, ".start"); + VarDecl *NewStop = precomputeExpr(Actions, BodyStmts, StopExpr, ".stop"); + VarDecl *NewStep = precomputeExpr(Actions, BodyStmts, StepExpr, ".step"); + auto BuildVarRef = [&](VarDecl *VD) { + return buildDeclRefExpr(Actions, VD, VD->getType(), {}); + }; + + IntegerLiteral *Zero = IntegerLiteral::Create( + Ctx, llvm::APInt(Ctx.getIntWidth(LogicalTy), 0), LogicalTy, {}); + Expr *Dist; + if (Rel == BO_NE) { + // When using a != comparison, the increment can be +1 or -1. This can be + // dynamic at runtime, so we need to check for the direction. + Expr *IsNegStep = AssertSuccess( + Actions.BuildBinOp(nullptr, {}, BO_LT, BuildVarRef(NewStep), Zero)); + + // Positive increment. + Expr *ForwardRange = AssertSuccess(Actions.BuildBinOp( + nullptr, {}, BO_Sub, BuildVarRef(NewStop), BuildVarRef(NewStart))); + ForwardRange = AssertSuccess( + Actions.BuildCStyleCastExpr({}, LogicalTSI, {}, ForwardRange)); + Expr *ForwardDist = AssertSuccess(Actions.BuildBinOp( + nullptr, {}, BO_Div, ForwardRange, BuildVarRef(NewStep))); + + // Negative increment. + Expr *BackwardRange = AssertSuccess(Actions.BuildBinOp( + nullptr, {}, BO_Sub, BuildVarRef(NewStart), BuildVarRef(NewStop))); + BackwardRange = AssertSuccess( + Actions.BuildCStyleCastExpr({}, LogicalTSI, {}, BackwardRange)); + Expr *NegIncAmount = AssertSuccess( + Actions.BuildUnaryOp(nullptr, {}, UO_Minus, BuildVarRef(NewStep))); + Expr *BackwardDist = AssertSuccess( + Actions.BuildBinOp(nullptr, {}, BO_Div, BackwardRange, NegIncAmount)); + + // Use the appropriate case. + Dist = AssertSuccess(Actions.ActOnConditionalOp( + {}, {}, IsNegStep, BackwardDist, ForwardDist)); + } else { + assert((Rel == BO_LT || Rel == BO_LE || Rel == BO_GE || Rel == BO_GT) && + "Expected one of these relational operators"); + + // We can derive the direction from any other comparison operator. It is + // non well-formed OpenMP if Step increments/decrements in the other + // directions. Whether at least the first iteration passes the loop + // condition. + Expr *HasAnyIteration = AssertSuccess(Actions.BuildBinOp( + nullptr, {}, Rel, BuildVarRef(NewStart), BuildVarRef(NewStop))); + + // Compute the range between first and last counter value. + Expr *Range; + if (Rel == BO_GE || Rel == BO_GT) + Range = AssertSuccess(Actions.BuildBinOp( + nullptr, {}, BO_Sub, BuildVarRef(NewStart), BuildVarRef(NewStop))); + else + Range = AssertSuccess(Actions.BuildBinOp( + nullptr, {}, BO_Sub, BuildVarRef(NewStop), BuildVarRef(NewStart))); + + // Ensure unsigned range space. + Range = + AssertSuccess(Actions.BuildCStyleCastExpr({}, LogicalTSI, {}, Range)); + + if (Rel == BO_LE || Rel == BO_GE) { + // Add one to the range if the relational operator is inclusive. + Range = + AssertSuccess(Actions.BuildUnaryOp(nullptr, {}, UO_PreInc, Range)); + } + + // Divide by the absolute step amount. + Expr *Divisor = BuildVarRef(NewStep); + if (Rel == BO_GE || Rel == BO_GT) + Divisor = + AssertSuccess(Actions.BuildUnaryOp(nullptr, {}, UO_Minus, Divisor)); + Dist = AssertSuccess( + Actions.BuildBinOp(nullptr, {}, BO_Div, Range, Divisor)); + + // If there is not at least one iteration, the range contains garbage. Fix + // to zero in this case. + Dist = AssertSuccess( + Actions.ActOnConditionalOp({}, {}, HasAnyIteration, Dist, Zero)); + } + + // Assign the result to the out-parameter. + Stmt *ResultAssign = AssertSuccess(Actions.BuildBinOp( + Actions.getCurScope(), {}, BO_Assign, DistRef, Dist)); + BodyStmts.push_back(ResultAssign); + + Body = AssertSuccess(Actions.ActOnCompoundStmt({}, {}, BodyStmts, false)); + } + + return cast( + AssertSuccess(Actions.ActOnCapturedRegionEnd(Body))); +} + +/// Create a closure that computes the loop variable from the logical iteration +/// number. +/// +/// \param Actions The Sema object. +/// \param LoopVarTy Type for the loop variable used for result value. +/// \param LogicalTy Type for the logical iteration number. +/// \param StartExpr Value of the loop counter at the first iteration. +/// \param Step Amount of increment after each iteration. +/// \param Deref Whether the loop variable is a dereference of the loop +/// counter variable. +/// +/// \return Closure (CapturedStmt) of the loop value calculation. +static CapturedStmt *buildLoopVarFunc(Sema &Actions, QualType LoopVarTy, + QualType LogicalTy, + DeclRefExpr *StartExpr, Expr *Step, + bool Deref) { + ASTContext &Ctx = Actions.getASTContext(); + + // Pass the result as an out-parameter. Passing as return value would require + // the OpenMPIRBuilder to know additional C/C++ semantics, such as how to + // invoke a copy constructor. + QualType TargetParamTy = Ctx.getLValueReferenceType(LoopVarTy); + Sema::CapturedParamNameType Params[] = {{"LoopVar", TargetParamTy}, + {"Logical", LogicalTy}, + {StringRef(), QualType()}}; + Actions.ActOnCapturedRegionStart({}, nullptr, CR_Default, Params); + + // Capture the initial iterator which represents the LoopVar value at the + // zero's logical iteration. Since the original ForStmt/CXXForRangeStmt update + // it in every iteration, capture it by value before it is modified. + VarDecl *StartVar = cast(StartExpr->getDecl()); + bool Invalid = Actions.tryCaptureVariable(StartVar, {}, + Sema::TryCapture_ExplicitByVal, {}); + (void)Invalid; + assert(!Invalid && "Expecting capture-by-value to work."); + + Expr *Body; + { + Sema::CompoundScopeRAII CompoundScope(Actions); + auto *CS = cast(Actions.CurContext); + + ImplicitParamDecl *TargetParam = CS->getParam(0); + DeclRefExpr *TargetRef = Actions.BuildDeclRefExpr( + TargetParam, LoopVarTy, VK_LValue, {}, nullptr, nullptr, {}, nullptr); + ImplicitParamDecl *IndvarParam = CS->getParam(1); + DeclRefExpr *LogicalRef = Actions.BuildDeclRefExpr( + IndvarParam, LogicalTy, VK_LValue, {}, nullptr, nullptr, {}, nullptr); + + // Capture the Start expression. + CaptureVars Recap(Actions); + Expr *NewStart = AssertSuccess(Recap.TransformExpr(StartExpr)); + Expr *NewStep = AssertSuccess(Recap.TransformExpr(Step)); + + Expr *Skip = AssertSuccess( + Actions.BuildBinOp(nullptr, {}, BO_Mul, NewStep, LogicalRef)); + // TODO: Explicitly cast to the iterator's difference_type instead of + // relying on implicit conversion. + Expr *Advanced = + AssertSuccess(Actions.BuildBinOp(nullptr, {}, BO_Add, NewStart, Skip)); + + if (Deref) { + // For range-based for-loops convert the loop counter value to a concrete + // loop variable value by dereferencing the iterator. + Advanced = + AssertSuccess(Actions.BuildUnaryOp(nullptr, {}, UO_Deref, Advanced)); + } + + // Assign the result to the output parameter. + Body = AssertSuccess(Actions.BuildBinOp(Actions.getCurScope(), {}, + BO_Assign, TargetRef, Advanced)); + } + return cast( + AssertSuccess(Actions.ActOnCapturedRegionEnd(Body))); +} + +StmtResult Sema::ActOnOpenMPCanonicalLoop(Stmt *AStmt) { + ASTContext &Ctx = getASTContext(); + + // Extract the common elements of ForStmt and CXXForRangeStmt: + // Loop variable, repeat condition, increment + Expr *Cond, *Inc; + VarDecl *LIVDecl, *LUVDecl; + if (auto *For = dyn_cast(AStmt)) { + Stmt *Init = For->getInit(); + if (auto *LCVarDeclStmt = dyn_cast(Init)) { + // For statement declares loop variable. + LIVDecl = cast(LCVarDeclStmt->getSingleDecl()); + } else if (auto *LCAssign = dyn_cast(Init)) { + // For statement reuses variable. + assert(LCAssign->getOpcode() == BO_Assign && + "init part must be a loop variable assignment"); + auto *CounterRef = cast(LCAssign->getLHS()); + LIVDecl = cast(CounterRef->getDecl()); + } else + llvm_unreachable("Cannot determine loop variable"); + LUVDecl = LIVDecl; + + Cond = For->getCond(); + Inc = For->getInc(); + } else if (auto *RangeFor = dyn_cast(AStmt)) { + DeclStmt *BeginStmt = RangeFor->getBeginStmt(); + LIVDecl = cast(BeginStmt->getSingleDecl()); + LUVDecl = RangeFor->getLoopVariable(); + + Cond = RangeFor->getCond(); + Inc = RangeFor->getInc(); + } else + llvm_unreachable("unhandled kind of loop"); + + QualType CounterTy = LIVDecl->getType(); + QualType LVTy = LUVDecl->getType(); + + // Analyze the loop condition. + Expr *LHS, *RHS; + BinaryOperator::Opcode CondRel; + Cond = Cond->IgnoreImplicit(); + if (auto *CondBinExpr = dyn_cast(Cond)) { + LHS = CondBinExpr->getLHS(); + RHS = CondBinExpr->getRHS(); + CondRel = CondBinExpr->getOpcode(); + } else if (auto *CondCXXOp = dyn_cast(Cond)) { + assert(CondCXXOp->getNumArgs() == 2 && "Comparison should have 2 operands"); + LHS = CondCXXOp->getArg(0); + RHS = CondCXXOp->getArg(1); + switch (CondCXXOp->getOperator()) { + case OO_ExclaimEqual: + CondRel = BO_NE; + break; + case OO_Less: + CondRel = BO_LT; + break; + case OO_LessEqual: + CondRel = BO_LE; + break; + case OO_Greater: + CondRel = BO_GT; + break; + case OO_GreaterEqual: + CondRel = BO_GE; + break; + default: + llvm_unreachable("unexpected iterator operator"); + } + } else + llvm_unreachable("unexpected loop condition"); + + // Normalize such that the loop counter is on the LHS. + if (!isa(LHS->IgnoreImplicit()) || + cast(LHS->IgnoreImplicit())->getDecl() != LIVDecl) { + std::swap(LHS, RHS); + CondRel = BinaryOperator::reverseComparisonOp(CondRel); + } + auto *CounterRef = cast(LHS->IgnoreImplicit()); + + // Decide the bit width for the logical iteration counter. By default use the + // unsigned ptrdiff_t integer size (for iterators and pointers). + // TODO: For iterators, use iterator::difference_type, + // std::iterator_traits<>::difference_type or decltype(it - end). + QualType LogicalTy = Ctx.getUnsignedPointerDiffType(); + if (CounterTy->isIntegerType()) { + unsigned BitWidth = Ctx.getIntWidth(CounterTy); + LogicalTy = Ctx.getIntTypeForBitwidth(BitWidth, false); + } + + // Analyze the loop increment. + Expr *Step; + if (auto *IncUn = dyn_cast(Inc)) { + int Direction; + switch (IncUn->getOpcode()) { + case UO_PreInc: + case UO_PostInc: + Direction = 1; + break; + case UO_PreDec: + case UO_PostDec: + Direction = -1; + break; + default: + llvm_unreachable("unhandled unary increment operator"); + } + Step = IntegerLiteral::Create( + Ctx, llvm::APInt(Ctx.getIntWidth(LogicalTy), Direction), LogicalTy, {}); + } else if (auto *IncBin = dyn_cast(Inc)) { + if (IncBin->getOpcode() == BO_AddAssign) { + Step = IncBin->getRHS(); + } else if (IncBin->getOpcode() == BO_SubAssign) { + Step = + AssertSuccess(BuildUnaryOp(nullptr, {}, UO_Minus, IncBin->getRHS())); + } else + llvm_unreachable("unhandled binary increment operator"); + } else if (auto *CondCXXOp = dyn_cast(Inc)) { + switch (CondCXXOp->getOperator()) { + case OO_PlusPlus: + Step = IntegerLiteral::Create( + Ctx, llvm::APInt(Ctx.getIntWidth(LogicalTy), 1), LogicalTy, {}); + break; + case OO_MinusMinus: + Step = IntegerLiteral::Create( + Ctx, llvm::APInt(Ctx.getIntWidth(LogicalTy), -1), LogicalTy, {}); + break; + case OO_PlusEqual: + Step = CondCXXOp->getArg(1); + break; + case OO_MinusEqual: + Step = AssertSuccess( + BuildUnaryOp(nullptr, {}, UO_Minus, CondCXXOp->getArg(1))); + break; + default: + llvm_unreachable("unhandled overloaded increment operator"); + } + } else + llvm_unreachable("unknown increment expression"); + + CapturedStmt *DistanceFunc = + buildDistanceFunc(*this, LogicalTy, CondRel, LHS, RHS, Step); + CapturedStmt *LoopVarFunc = buildLoopVarFunc( + *this, LVTy, LogicalTy, CounterRef, Step, isa(AStmt)); + DeclRefExpr *LVRef = BuildDeclRefExpr(LUVDecl, LUVDecl->getType(), VK_LValue, + {}, nullptr, nullptr, {}, nullptr); + return OMPCanonicalLoop::create(getASTContext(), AStmt, DistanceFunc, + LoopVarFunc, LVRef); +} + static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S, CXXScopeSpec &MapperIdScopeSpec, const DeclarationNameInfo &MapperId, @@ -8130,6 +8517,8 @@ // OpenMP [2.9.1, Canonical Loop Form] // for (init-expr; test-expr; incr-expr) structured-block // for (range-decl: range-expr) structured-block + if (auto *CanonLoop = dyn_cast_or_null(S)) + S = CanonLoop->getLoopStmt(); auto *For = dyn_cast_or_null(S); auto *CXXFor = dyn_cast_or_null(S); // Ranged for is supported only in OpenMP 5.0. diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1546,6 +1546,14 @@ return getSema().BuildObjCAtThrowStmt(AtLoc, Operand); } + /// Build a new OpenMP Canonical loop. + /// + /// Ensures that the outermost loop in @p LoopStmt is wrapped by a + /// OMPCanonicalLoop. + StmtResult RebuildOMPCanonicalLoop(Stmt *LoopStmt) { + return getSema().ActOnOpenMPCanonicalLoop(LoopStmt); + } + /// Build a new OpenMP executable directive. /// /// By default, performs semantic analysis to build the new statement. @@ -8321,6 +8329,16 @@ //===----------------------------------------------------------------------===// // OpenMP directive transformation //===----------------------------------------------------------------------===// + +template +StmtResult +TreeTransform::TransformOMPCanonicalLoop(OMPCanonicalLoop *L) { + // OMPCanonicalLoops are eliminated during transformation, since they will be + // recomputed by semantic analysis of the associated OMPLoopBasedDirective + // after transformation. + return getDerived().TransformStmt(L->getLoopStmt()); +} + template StmtResult TreeTransform::TransformOMPExecutableDirective( OMPExecutableDirective *D) { @@ -8357,6 +8375,9 @@ else CS = D->getRawStmt(); Body = getDerived().TransformStmt(CS); + if (Body.isUsable() && isOpenMPLoopDirective(D->getDirectiveKind()) && + getSema().getLangOpts().OpenMPIRBuilder) + Body = getDerived().RebuildOMPCanonicalLoop(Body.get()); } AssociatedStmt = getDerived().getSema().ActOnOpenMPRegionEnd(Body, TClauses); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2273,6 +2273,12 @@ // OpenMP Directives. //===----------------------------------------------------------------------===// +void ASTStmtReader::VisitOMPCanonicalLoop(OMPCanonicalLoop *S) { + VisitStmt(S); + for (Stmt *&SubStmt : S->SubStmts) + SubStmt = Record.readSubStmt(); +} + void ASTStmtReader::VisitOMPExecutableDirective(OMPExecutableDirective *E) { Record.readOMPChildren(E->Data); E->setLocStart(readSourceLocation()); @@ -3138,6 +3144,10 @@ nullptr); break; + case STMT_OMP_CANONICAL_LOOP: + S = OMPCanonicalLoop::createEmpty(Context); + break; + case STMT_OMP_PARALLEL_DIRECTIVE: S = OMPParallelDirective::CreateEmpty(Context, diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -2170,6 +2170,13 @@ // OpenMP Directives. //===----------------------------------------------------------------------===// +void ASTStmtWriter::VisitOMPCanonicalLoop(OMPCanonicalLoop *S) { + VisitStmt(S); + for (Stmt *SubStmt : S->SubStmts) + Record.AddStmt(SubStmt); + Code = serialization::STMT_OMP_CANONICAL_LOOP; +} + void ASTStmtWriter::VisitOMPExecutableDirective(OMPExecutableDirective *E) { Record.writeOMPChildren(E->Data); Record.AddSourceLocation(E->getBeginLoc()); diff --git a/clang/test/OpenMP/irbuilder_for_iterator.cpp b/clang/test/OpenMP/irbuilder_for_iterator.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/irbuilder_for_iterator.cpp @@ -0,0 +1,166 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs +// RUN: %clang_cc1 -fopenmp-enable-irbuilder -verify -fopenmp -fopenmp-version=50 -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +struct MyIterator { + MyIterator(unsigned pos); + MyIterator(const MyIterator &other); + const MyIterator &operator=(const MyIterator &that); + MyIterator &operator++(); + int operator-(const MyIterator &that) const; + MyIterator &operator+=(unsigned a); + MyIterator operator+(unsigned a) const; + bool operator==(const MyIterator &that) const; + bool operator!=(const MyIterator &that) const; + unsigned operator*() const; +}; + +extern "C" void workshareloop_iterator(float *a, float *b, float *c) { +#pragma omp for + for (MyIterator it = MyIterator(7); it != MyIterator(41); ++it) { + unsigned i = *it; + a[i] = b[i] * c[i]; + } +} + +#endif // HEADER +// CHECK-LABEL: define {{[^@]+}}@workshareloop_iterator +// CHECK-SAME: (float* [[A:%.*]], float* [[B:%.*]], float* [[C:%.*]]) [[ATTR0:#.*]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca float*, align 8 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca float*, align 8 +// CHECK-NEXT: [[C_ADDR:%.*]] = alloca float*, align 8 +// CHECK-NEXT: [[IT:%.*]] = alloca [[STRUCT_MYITERATOR:%.*]], align 1 +// CHECK-NEXT: [[AGG_CAPTURED:%.*]] = alloca [[STRUCT_ANON:%.*]], align 8 +// CHECK-NEXT: [[AGG_CAPTURED1:%.*]] = alloca [[STRUCT_ANON_0:%.*]], align 1 +// CHECK-NEXT: [[DOTCOUNT_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[P_LASTITER:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[P_LOWERBOUND:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[P_UPPERBOUND:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[P_STRIDE:%.*]] = alloca i64, align 8 +// CHECK-NEXT: store float* [[A]], float** [[A_ADDR]], align 8 +// CHECK-NEXT: store float* [[B]], float** [[B_ADDR]], align 8 +// CHECK-NEXT: store float* [[C]], float** [[C_ADDR]], align 8 +// CHECK-NEXT: call void @_ZN10MyIteratorC1Ej(%struct.MyIterator* nonnull dereferenceable(1) [[IT]], i32 7) +// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ANON]], %struct.anon* [[AGG_CAPTURED]], i32 0, i32 0 +// CHECK-NEXT: store %struct.MyIterator* [[IT]], %struct.MyIterator** [[TMP0]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ANON_0]], %struct.anon.0* [[AGG_CAPTURED1]], i32 0, i32 0 +// CHECK-NEXT: call void @_ZN10MyIteratorC1ERKS_(%struct.MyIterator* nonnull dereferenceable(1) [[TMP1]], %struct.MyIterator* nonnull align 1 dereferenceable(1) [[IT]]) +// CHECK-NEXT: call void @__captured_stmt(i64* [[DOTCOUNT_ADDR]], %struct.anon* [[AGG_CAPTURED]]) +// CHECK-NEXT: [[DOTCOUNT:%.*]] = load i64, i64* [[DOTCOUNT_ADDR]], align 8 +// CHECK-NEXT: br label [[OMP_LOOP_PREHEADER:%.*]] +// CHECK: omp_loop.preheader: +// CHECK-NEXT: store i64 0, i64* [[P_LOWERBOUND]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = sub i64 [[DOTCOUNT]], 1 +// CHECK-NEXT: store i64 [[TMP2]], i64* [[P_UPPERBOUND]], align 8 +// CHECK-NEXT: store i64 1, i64* [[P_STRIDE]], align 8 +// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1:@.*]]) +// CHECK-NEXT: call void @__kmpc_for_static_init_8u(%struct.ident_t* [[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]], i32 34, i32* [[P_LASTITER]], i64* [[P_LOWERBOUND]], i64* [[P_UPPERBOUND]], i64* [[P_STRIDE]], i64 1, i64 1) +// CHECK-NEXT: [[TMP3:%.*]] = load i64, i64* [[P_LOWERBOUND]], align 8 +// CHECK-NEXT: [[TMP4:%.*]] = load i64, i64* [[P_UPPERBOUND]], align 8 +// CHECK-NEXT: [[TMP5:%.*]] = sub i64 [[TMP4]], [[TMP3]] +// CHECK-NEXT: [[TMP6:%.*]] = add i64 [[TMP5]], 1 +// CHECK-NEXT: br label [[OMP_LOOP_HEADER:%.*]] +// CHECK: omp_loop.header: +// CHECK-NEXT: [[OMP_LOOP_IV:%.*]] = phi i64 [ 0, [[OMP_LOOP_PREHEADER]] ], [ [[OMP_LOOP_NEXT:%.*]], [[OMP_LOOP_INC:%.*]] ] +// CHECK-NEXT: br label [[OMP_LOOP_COND:%.*]] +// CHECK: omp_loop.cond: +// CHECK-NEXT: [[OMP_LOOP_CMP:%.*]] = icmp ult i64 [[OMP_LOOP_IV]], [[TMP6]] +// CHECK-NEXT: br i1 [[OMP_LOOP_CMP]], label [[OMP_LOOP_BODY:%.*]], label [[OMP_LOOP_EXIT:%.*]] +// CHECK: omp_loop.body: +// CHECK-NEXT: [[TMP7:%.*]] = add i64 [[OMP_LOOP_IV]], [[TMP3]] +// CHECK-NEXT: call void @__captured_stmt.1(%struct.MyIterator* [[IT]], i64 [[TMP7]], %struct.anon.0* [[AGG_CAPTURED1]]) +// CHECK-NEXT: [[CALL:%.*]] = call i32 @_ZNK10MyIteratordeEv(%struct.MyIterator* nonnull dereferenceable(1) [[IT]]) +// CHECK-NEXT: store i32 [[CALL]], i32* [[I]], align 4 +// CHECK-NEXT: [[TMP8:%.*]] = load float*, float** [[B_ADDR]], align 8 +// CHECK-NEXT: [[TMP9:%.*]] = load i32, i32* [[I]], align 4 +// CHECK-NEXT: [[IDXPROM:%.*]] = zext i32 [[TMP9]] to i64 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[TMP8]], i64 [[IDXPROM]] +// CHECK-NEXT: [[TMP10:%.*]] = load float, float* [[ARRAYIDX]], align 4 +// CHECK-NEXT: [[TMP11:%.*]] = load float*, float** [[C_ADDR]], align 8 +// CHECK-NEXT: [[TMP12:%.*]] = load i32, i32* [[I]], align 4 +// CHECK-NEXT: [[IDXPROM2:%.*]] = zext i32 [[TMP12]] to i64 +// CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds float, float* [[TMP11]], i64 [[IDXPROM2]] +// CHECK-NEXT: [[TMP13:%.*]] = load float, float* [[ARRAYIDX3]], align 4 +// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP10]], [[TMP13]] +// CHECK-NEXT: [[TMP14:%.*]] = load float*, float** [[A_ADDR]], align 8 +// CHECK-NEXT: [[TMP15:%.*]] = load i32, i32* [[I]], align 4 +// CHECK-NEXT: [[IDXPROM4:%.*]] = zext i32 [[TMP15]] to i64 +// CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds float, float* [[TMP14]], i64 [[IDXPROM4]] +// CHECK-NEXT: store float [[MUL]], float* [[ARRAYIDX5]], align 4 +// CHECK-NEXT: br label [[OMP_LOOP_INC]] +// CHECK: omp_loop.inc: +// CHECK-NEXT: [[OMP_LOOP_NEXT]] = add nuw i64 [[OMP_LOOP_IV]], 1 +// CHECK-NEXT: br label [[OMP_LOOP_HEADER]] +// CHECK: omp_loop.exit: +// CHECK-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* [[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]]) +// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM6:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) +// CHECK-NEXT: call void @__kmpc_barrier(%struct.ident_t* [[GLOB2:@.*]], i32 [[OMP_GLOBAL_THREAD_NUM6]]) +// CHECK-NEXT: br label [[OMP_LOOP_AFTER:%.*]] +// CHECK: omp_loop.after: +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@__captured_stmt +// CHECK-SAME: (i64* nonnull align 8 dereferenceable(8) [[DISTANCE:%.*]], %struct.anon* noalias [[__CONTEXT:%.*]]) [[ATTR2:#.*]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DISTANCE_ADDR:%.*]] = alloca i64*, align 8 +// CHECK-NEXT: [[__CONTEXT_ADDR:%.*]] = alloca %struct.anon*, align 8 +// CHECK-NEXT: [[DOTSTART:%.*]] = alloca [[STRUCT_MYITERATOR:%.*]], align 1 +// CHECK-NEXT: [[DOTSTOP:%.*]] = alloca [[STRUCT_MYITERATOR]], align 1 +// CHECK-NEXT: [[DOTSTEP:%.*]] = alloca i64, align 8 +// CHECK-NEXT: store i64* [[DISTANCE]], i64** [[DISTANCE_ADDR]], align 8 +// CHECK-NEXT: store %struct.anon* [[__CONTEXT]], %struct.anon** [[__CONTEXT_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load %struct.anon*, %struct.anon** [[__CONTEXT_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], %struct.anon* [[TMP0]], i32 0, i32 0 +// CHECK-NEXT: [[TMP2:%.*]] = load %struct.MyIterator*, %struct.MyIterator** [[TMP1]], align 8 +// CHECK-NEXT: call void @_ZN10MyIteratorC1ERKS_(%struct.MyIterator* nonnull dereferenceable(1) [[DOTSTART]], %struct.MyIterator* nonnull align 1 dereferenceable(1) [[TMP2]]) +// CHECK-NEXT: call void @_ZN10MyIteratorC1Ej(%struct.MyIterator* nonnull dereferenceable(1) [[DOTSTOP]], i32 41) +// CHECK-NEXT: store i64 1, i64* [[DOTSTEP]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = load i64, i64* [[DOTSTEP]], align 8 +// CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[TMP3]], 0 +// CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] +// CHECK: cond.true: +// CHECK-NEXT: [[CALL:%.*]] = call i32 @_ZNK10MyIteratormiERKS_(%struct.MyIterator* nonnull dereferenceable(1) [[DOTSTART]], %struct.MyIterator* nonnull align 1 dereferenceable(1) [[DOTSTOP]]) +// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[CALL]] to i64 +// CHECK-NEXT: [[TMP4:%.*]] = load i64, i64* [[DOTSTEP]], align 8 +// CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[TMP4]] +// CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[CONV]], [[SUB]] +// CHECK-NEXT: br label [[COND_END:%.*]] +// CHECK: cond.false: +// CHECK-NEXT: [[CALL1:%.*]] = call i32 @_ZNK10MyIteratormiERKS_(%struct.MyIterator* nonnull dereferenceable(1) [[DOTSTOP]], %struct.MyIterator* nonnull align 1 dereferenceable(1) [[DOTSTART]]) +// CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[CALL1]] to i64 +// CHECK-NEXT: [[TMP5:%.*]] = load i64, i64* [[DOTSTEP]], align 8 +// CHECK-NEXT: [[DIV3:%.*]] = udiv i64 [[CONV2]], [[TMP5]] +// CHECK-NEXT: br label [[COND_END]] +// CHECK: cond.end: +// CHECK-NEXT: [[COND:%.*]] = phi i64 [ [[DIV]], [[COND_TRUE]] ], [ [[DIV3]], [[COND_FALSE]] ] +// CHECK-NEXT: [[TMP6:%.*]] = load i64*, i64** [[DISTANCE_ADDR]], align 8 +// CHECK-NEXT: store i64 [[COND]], i64* [[TMP6]], align 8 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@__captured_stmt.1 +// CHECK-SAME: (%struct.MyIterator* nonnull align 1 dereferenceable(1) [[LOOPVAR:%.*]], i64 [[LOGICAL:%.*]], %struct.anon.0* noalias [[__CONTEXT:%.*]]) [[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[LOOPVAR_ADDR:%.*]] = alloca %struct.MyIterator*, align 8 +// CHECK-NEXT: [[LOGICAL_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[__CONTEXT_ADDR:%.*]] = alloca %struct.anon.0*, align 8 +// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_MYITERATOR:%.*]], align 1 +// CHECK-NEXT: store %struct.MyIterator* [[LOOPVAR]], %struct.MyIterator** [[LOOPVAR_ADDR]], align 8 +// CHECK-NEXT: store i64 [[LOGICAL]], i64* [[LOGICAL_ADDR]], align 8 +// CHECK-NEXT: store %struct.anon.0* [[__CONTEXT]], %struct.anon.0** [[__CONTEXT_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load %struct.anon.0*, %struct.anon.0** [[__CONTEXT_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ANON_0:%.*]], %struct.anon.0* [[TMP0]], i32 0, i32 0 +// CHECK-NEXT: [[TMP2:%.*]] = load i64, i64* [[LOGICAL_ADDR]], align 8 +// CHECK-NEXT: [[MUL:%.*]] = mul i64 1, [[TMP2]] +// CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[MUL]] to i32 +// CHECK-NEXT: call void @_ZNK10MyIteratorplEj(%struct.MyIterator* sret(%struct.MyIterator) align 1 [[REF_TMP]], %struct.MyIterator* nonnull dereferenceable(1) [[TMP1]], i32 [[CONV]]) +// CHECK-NEXT: [[TMP3:%.*]] = load %struct.MyIterator*, %struct.MyIterator** [[LOOPVAR_ADDR]], align 8 +// CHECK-NEXT: [[CALL:%.*]] = call nonnull align 1 dereferenceable(1) %struct.MyIterator* @_ZN10MyIteratoraSERKS_(%struct.MyIterator* nonnull dereferenceable(1) [[TMP3]], %struct.MyIterator* nonnull align 1 dereferenceable(1) [[REF_TMP]]) +// CHECK-NEXT: ret void +// diff --git a/clang/test/OpenMP/irbuilder_for_rangefor.cpp b/clang/test/OpenMP/irbuilder_for_rangefor.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/irbuilder_for_rangefor.cpp @@ -0,0 +1,185 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs +// RUN: %clang_cc1 -fopenmp-enable-irbuilder -verify -fopenmp -fopenmp-version=50 -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +struct MyIterator { + MyIterator(unsigned pos); + MyIterator(const MyIterator &other); + const MyIterator &operator=(const MyIterator &that); + MyIterator &operator++(); + int operator-(const MyIterator &that) const; + MyIterator &operator+=(unsigned a); + MyIterator operator+(unsigned a) const; + bool operator==(const MyIterator &that) const; + bool operator!=(const MyIterator &that) const; + unsigned operator*() const; +}; + +struct MyRange { + MyRange(int n); + + MyIterator begin(); + MyIterator end(); +}; + +extern "C" void workshareloop_rangefor(float *a, float *b, float *c) { +#pragma omp for + for (unsigned i : MyRange(42)) { + a[i] = b[i] * c[i]; + } +} + +#endif // HEADER +// CHECK-LABEL: define {{[^@]+}}@workshareloop_rangefor +// CHECK-SAME: (float* [[A:%.*]], float* [[B:%.*]], float* [[C:%.*]]) [[ATTR0:#.*]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca float*, align 8 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca float*, align 8 +// CHECK-NEXT: [[C_ADDR:%.*]] = alloca float*, align 8 +// CHECK-NEXT: [[__RANGE2:%.*]] = alloca %struct.MyRange*, align 8 +// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_MYRANGE:%.*]], align 1 +// CHECK-NEXT: [[__BEGIN2:%.*]] = alloca [[STRUCT_MYITERATOR:%.*]], align 1 +// CHECK-NEXT: [[__END2:%.*]] = alloca [[STRUCT_MYITERATOR]], align 1 +// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[AGG_CAPTURED:%.*]] = alloca [[STRUCT_ANON:%.*]], align 8 +// CHECK-NEXT: [[AGG_CAPTURED1:%.*]] = alloca [[STRUCT_ANON_0:%.*]], align 1 +// CHECK-NEXT: [[DOTCOUNT_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[P_LASTITER:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[P_LOWERBOUND:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[P_UPPERBOUND:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[P_STRIDE:%.*]] = alloca i64, align 8 +// CHECK-NEXT: store float* [[A]], float** [[A_ADDR]], align 8 +// CHECK-NEXT: store float* [[B]], float** [[B_ADDR]], align 8 +// CHECK-NEXT: store float* [[C]], float** [[C_ADDR]], align 8 +// CHECK-NEXT: call void @_ZN7MyRangeC1Ei(%struct.MyRange* nonnull dereferenceable(1) [[REF_TMP]], i32 42) +// CHECK-NEXT: store %struct.MyRange* [[REF_TMP]], %struct.MyRange** [[__RANGE2]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load %struct.MyRange*, %struct.MyRange** [[__RANGE2]], align 8 +// CHECK-NEXT: call void @_ZN7MyRange5beginEv(%struct.MyIterator* sret(%struct.MyIterator) align 1 [[__BEGIN2]], %struct.MyRange* nonnull dereferenceable(1) [[TMP0]]) +// CHECK-NEXT: [[TMP1:%.*]] = load %struct.MyRange*, %struct.MyRange** [[__RANGE2]], align 8 +// CHECK-NEXT: call void @_ZN7MyRange3endEv(%struct.MyIterator* sret(%struct.MyIterator) align 1 [[__END2]], %struct.MyRange* nonnull dereferenceable(1) [[TMP1]]) +// CHECK-NEXT: [[CALL:%.*]] = call i32 @_ZNK10MyIteratordeEv(%struct.MyIterator* nonnull dereferenceable(1) [[__BEGIN2]]) +// CHECK-NEXT: store i32 [[CALL]], i32* [[I]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_ANON]], %struct.anon* [[AGG_CAPTURED]], i32 0, i32 0 +// CHECK-NEXT: store %struct.MyIterator* [[__BEGIN2]], %struct.MyIterator** [[TMP2]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds [[STRUCT_ANON]], %struct.anon* [[AGG_CAPTURED]], i32 0, i32 1 +// CHECK-NEXT: store %struct.MyIterator* [[__END2]], %struct.MyIterator** [[TMP3]], align 8 +// CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds [[STRUCT_ANON_0]], %struct.anon.0* [[AGG_CAPTURED1]], i32 0, i32 0 +// CHECK-NEXT: call void @_ZN10MyIteratorC1ERKS_(%struct.MyIterator* nonnull dereferenceable(1) [[TMP4]], %struct.MyIterator* nonnull align 1 dereferenceable(1) [[__BEGIN2]]) +// CHECK-NEXT: call void @__captured_stmt(i64* [[DOTCOUNT_ADDR]], %struct.anon* [[AGG_CAPTURED]]) +// CHECK-NEXT: [[DOTCOUNT:%.*]] = load i64, i64* [[DOTCOUNT_ADDR]], align 8 +// CHECK-NEXT: br label [[OMP_LOOP_PREHEADER:%.*]] +// CHECK: omp_loop.preheader: +// CHECK-NEXT: store i64 0, i64* [[P_LOWERBOUND]], align 8 +// CHECK-NEXT: [[TMP5:%.*]] = sub i64 [[DOTCOUNT]], 1 +// CHECK-NEXT: store i64 [[TMP5]], i64* [[P_UPPERBOUND]], align 8 +// CHECK-NEXT: store i64 1, i64* [[P_STRIDE]], align 8 +// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1:@.*]]) +// CHECK-NEXT: call void @__kmpc_for_static_init_8u(%struct.ident_t* [[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]], i32 34, i32* [[P_LASTITER]], i64* [[P_LOWERBOUND]], i64* [[P_UPPERBOUND]], i64* [[P_STRIDE]], i64 1, i64 1) +// CHECK-NEXT: [[TMP6:%.*]] = load i64, i64* [[P_LOWERBOUND]], align 8 +// CHECK-NEXT: [[TMP7:%.*]] = load i64, i64* [[P_UPPERBOUND]], align 8 +// CHECK-NEXT: [[TMP8:%.*]] = sub i64 [[TMP7]], [[TMP6]] +// CHECK-NEXT: [[TMP9:%.*]] = add i64 [[TMP8]], 1 +// CHECK-NEXT: br label [[OMP_LOOP_HEADER:%.*]] +// CHECK: omp_loop.header: +// CHECK-NEXT: [[OMP_LOOP_IV:%.*]] = phi i64 [ 0, [[OMP_LOOP_PREHEADER]] ], [ [[OMP_LOOP_NEXT:%.*]], [[OMP_LOOP_INC:%.*]] ] +// CHECK-NEXT: br label [[OMP_LOOP_COND:%.*]] +// CHECK: omp_loop.cond: +// CHECK-NEXT: [[OMP_LOOP_CMP:%.*]] = icmp ult i64 [[OMP_LOOP_IV]], [[TMP9]] +// CHECK-NEXT: br i1 [[OMP_LOOP_CMP]], label [[OMP_LOOP_BODY:%.*]], label [[OMP_LOOP_EXIT:%.*]] +// CHECK: omp_loop.body: +// CHECK-NEXT: [[TMP10:%.*]] = add i64 [[OMP_LOOP_IV]], [[TMP6]] +// CHECK-NEXT: call void @__captured_stmt.1(i32* [[I]], i64 [[TMP10]], %struct.anon.0* [[AGG_CAPTURED1]]) +// CHECK-NEXT: [[TMP11:%.*]] = load float*, float** [[B_ADDR]], align 8 +// CHECK-NEXT: [[TMP12:%.*]] = load i32, i32* [[I]], align 4 +// CHECK-NEXT: [[IDXPROM:%.*]] = zext i32 [[TMP12]] to i64 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[TMP11]], i64 [[IDXPROM]] +// CHECK-NEXT: [[TMP13:%.*]] = load float, float* [[ARRAYIDX]], align 4 +// CHECK-NEXT: [[TMP14:%.*]] = load float*, float** [[C_ADDR]], align 8 +// CHECK-NEXT: [[TMP15:%.*]] = load i32, i32* [[I]], align 4 +// CHECK-NEXT: [[IDXPROM2:%.*]] = zext i32 [[TMP15]] to i64 +// CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds float, float* [[TMP14]], i64 [[IDXPROM2]] +// CHECK-NEXT: [[TMP16:%.*]] = load float, float* [[ARRAYIDX3]], align 4 +// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP13]], [[TMP16]] +// CHECK-NEXT: [[TMP17:%.*]] = load float*, float** [[A_ADDR]], align 8 +// CHECK-NEXT: [[TMP18:%.*]] = load i32, i32* [[I]], align 4 +// CHECK-NEXT: [[IDXPROM4:%.*]] = zext i32 [[TMP18]] to i64 +// CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds float, float* [[TMP17]], i64 [[IDXPROM4]] +// CHECK-NEXT: store float [[MUL]], float* [[ARRAYIDX5]], align 4 +// CHECK-NEXT: br label [[OMP_LOOP_INC]] +// CHECK: omp_loop.inc: +// CHECK-NEXT: [[OMP_LOOP_NEXT]] = add nuw i64 [[OMP_LOOP_IV]], 1 +// CHECK-NEXT: br label [[OMP_LOOP_HEADER]] +// CHECK: omp_loop.exit: +// CHECK-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* [[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]]) +// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM6:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) +// CHECK-NEXT: call void @__kmpc_barrier(%struct.ident_t* [[GLOB2:@.*]], i32 [[OMP_GLOBAL_THREAD_NUM6]]) +// CHECK-NEXT: br label [[OMP_LOOP_AFTER:%.*]] +// CHECK: omp_loop.after: +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@__captured_stmt +// CHECK-SAME: (i64* nonnull align 8 dereferenceable(8) [[DISTANCE:%.*]], %struct.anon* noalias [[__CONTEXT:%.*]]) [[ATTR2:#.*]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DISTANCE_ADDR:%.*]] = alloca i64*, align 8 +// CHECK-NEXT: [[__CONTEXT_ADDR:%.*]] = alloca %struct.anon*, align 8 +// CHECK-NEXT: [[DOTSTART:%.*]] = alloca [[STRUCT_MYITERATOR:%.*]], align 1 +// CHECK-NEXT: [[DOTSTOP:%.*]] = alloca [[STRUCT_MYITERATOR]], align 1 +// CHECK-NEXT: [[DOTSTEP:%.*]] = alloca i64, align 8 +// CHECK-NEXT: store i64* [[DISTANCE]], i64** [[DISTANCE_ADDR]], align 8 +// CHECK-NEXT: store %struct.anon* [[__CONTEXT]], %struct.anon** [[__CONTEXT_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load %struct.anon*, %struct.anon** [[__CONTEXT_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], %struct.anon* [[TMP0]], i32 0, i32 0 +// CHECK-NEXT: [[TMP2:%.*]] = load %struct.MyIterator*, %struct.MyIterator** [[TMP1]], align 8 +// CHECK-NEXT: call void @_ZN10MyIteratorC1ERKS_(%struct.MyIterator* nonnull dereferenceable(1) [[DOTSTART]], %struct.MyIterator* nonnull align 1 dereferenceable(1) [[TMP2]]) +// CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds [[STRUCT_ANON]], %struct.anon* [[TMP0]], i32 0, i32 1 +// CHECK-NEXT: [[TMP4:%.*]] = load %struct.MyIterator*, %struct.MyIterator** [[TMP3]], align 8 +// CHECK-NEXT: call void @_ZN10MyIteratorC1ERKS_(%struct.MyIterator* nonnull dereferenceable(1) [[DOTSTOP]], %struct.MyIterator* nonnull align 1 dereferenceable(1) [[TMP4]]) +// CHECK-NEXT: store i64 1, i64* [[DOTSTEP]], align 8 +// CHECK-NEXT: [[TMP5:%.*]] = load i64, i64* [[DOTSTEP]], align 8 +// CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[TMP5]], 0 +// CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] +// CHECK: cond.true: +// CHECK-NEXT: [[CALL:%.*]] = call i32 @_ZNK10MyIteratormiERKS_(%struct.MyIterator* nonnull dereferenceable(1) [[DOTSTART]], %struct.MyIterator* nonnull align 1 dereferenceable(1) [[DOTSTOP]]) +// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[CALL]] to i64 +// CHECK-NEXT: [[TMP6:%.*]] = load i64, i64* [[DOTSTEP]], align 8 +// CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[TMP6]] +// CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[CONV]], [[SUB]] +// CHECK-NEXT: br label [[COND_END:%.*]] +// CHECK: cond.false: +// CHECK-NEXT: [[CALL1:%.*]] = call i32 @_ZNK10MyIteratormiERKS_(%struct.MyIterator* nonnull dereferenceable(1) [[DOTSTOP]], %struct.MyIterator* nonnull align 1 dereferenceable(1) [[DOTSTART]]) +// CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[CALL1]] to i64 +// CHECK-NEXT: [[TMP7:%.*]] = load i64, i64* [[DOTSTEP]], align 8 +// CHECK-NEXT: [[DIV3:%.*]] = udiv i64 [[CONV2]], [[TMP7]] +// CHECK-NEXT: br label [[COND_END]] +// CHECK: cond.end: +// CHECK-NEXT: [[COND:%.*]] = phi i64 [ [[DIV]], [[COND_TRUE]] ], [ [[DIV3]], [[COND_FALSE]] ] +// CHECK-NEXT: [[TMP8:%.*]] = load i64*, i64** [[DISTANCE_ADDR]], align 8 +// CHECK-NEXT: store i64 [[COND]], i64* [[TMP8]], align 8 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@__captured_stmt.1 +// CHECK-SAME: (i32* nonnull align 4 dereferenceable(4) [[LOOPVAR:%.*]], i64 [[LOGICAL:%.*]], %struct.anon.0* noalias [[__CONTEXT:%.*]]) [[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[LOOPVAR_ADDR:%.*]] = alloca i32*, align 8 +// CHECK-NEXT: [[LOGICAL_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[__CONTEXT_ADDR:%.*]] = alloca %struct.anon.0*, align 8 +// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_MYITERATOR:%.*]], align 1 +// CHECK-NEXT: store i32* [[LOOPVAR]], i32** [[LOOPVAR_ADDR]], align 8 +// CHECK-NEXT: store i64 [[LOGICAL]], i64* [[LOGICAL_ADDR]], align 8 +// CHECK-NEXT: store %struct.anon.0* [[__CONTEXT]], %struct.anon.0** [[__CONTEXT_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load %struct.anon.0*, %struct.anon.0** [[__CONTEXT_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ANON_0:%.*]], %struct.anon.0* [[TMP0]], i32 0, i32 0 +// CHECK-NEXT: [[TMP2:%.*]] = load i64, i64* [[LOGICAL_ADDR]], align 8 +// CHECK-NEXT: [[MUL:%.*]] = mul i64 1, [[TMP2]] +// CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[MUL]] to i32 +// CHECK-NEXT: call void @_ZNK10MyIteratorplEj(%struct.MyIterator* sret(%struct.MyIterator) align 1 [[REF_TMP]], %struct.MyIterator* nonnull dereferenceable(1) [[TMP1]], i32 [[CONV]]) +// CHECK-NEXT: [[CALL:%.*]] = call i32 @_ZNK10MyIteratordeEv(%struct.MyIterator* nonnull dereferenceable(1) [[REF_TMP]]) +// CHECK-NEXT: [[TMP3:%.*]] = load i32*, i32** [[LOOPVAR_ADDR]], align 8 +// CHECK-NEXT: store i32 [[CALL]], i32* [[TMP3]], align 4 +// CHECK-NEXT: ret void +// diff --git a/clang/test/OpenMP/irbuilder_for_unsigned.c b/clang/test/OpenMP/irbuilder_for_unsigned.c new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/irbuilder_for_unsigned.c @@ -0,0 +1,155 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs +// RUN: %clang_cc1 -fopenmp-enable-irbuilder -verify -fopenmp -fopenmp-version=45 -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +extern "C" void workshareloop_unsigned(float *a, float *b, float *c, float *d) { +#pragma omp for + for (unsigned i = 33; i < 32000000; i += 7) { + a[i] = b[i] * c[i] * d[i]; + } +} + +#endif // HEADER +// CHECK-LABEL: define {{[^@]+}}@workshareloop_unsigned +// CHECK-SAME: (float* [[A:%.*]], float* [[B:%.*]], float* [[C:%.*]], float* [[D:%.*]]) [[ATTR0:#.*]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca float*, align 8 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca float*, align 8 +// CHECK-NEXT: [[C_ADDR:%.*]] = alloca float*, align 8 +// CHECK-NEXT: [[D_ADDR:%.*]] = alloca float*, align 8 +// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[AGG_CAPTURED:%.*]] = alloca [[STRUCT_ANON:%.*]], align 8 +// CHECK-NEXT: [[AGG_CAPTURED1:%.*]] = alloca [[STRUCT_ANON_0:%.*]], align 4 +// CHECK-NEXT: [[DOTCOUNT_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[P_LASTITER:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[P_LOWERBOUND:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[P_UPPERBOUND:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[P_STRIDE:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store float* [[A]], float** [[A_ADDR]], align 8 +// CHECK-NEXT: store float* [[B]], float** [[B_ADDR]], align 8 +// CHECK-NEXT: store float* [[C]], float** [[C_ADDR]], align 8 +// CHECK-NEXT: store float* [[D]], float** [[D_ADDR]], align 8 +// CHECK-NEXT: store i32 33, i32* [[I]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ANON]], %struct.anon* [[AGG_CAPTURED]], i32 0, i32 0 +// CHECK-NEXT: store i32* [[I]], i32** [[TMP0]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ANON_0]], %struct.anon.0* [[AGG_CAPTURED1]], i32 0, i32 0 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[I]], align 4 +// CHECK-NEXT: store i32 [[TMP2]], i32* [[TMP1]], align 4 +// CHECK-NEXT: call void @__captured_stmt(i32* [[DOTCOUNT_ADDR]], %struct.anon* [[AGG_CAPTURED]]) +// CHECK-NEXT: [[DOTCOUNT:%.*]] = load i32, i32* [[DOTCOUNT_ADDR]], align 4 +// CHECK-NEXT: br label [[OMP_LOOP_PREHEADER:%.*]] +// CHECK: omp_loop.preheader: +// CHECK-NEXT: store i32 0, i32* [[P_LOWERBOUND]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = sub i32 [[DOTCOUNT]], 1 +// CHECK-NEXT: store i32 [[TMP3]], i32* [[P_UPPERBOUND]], align 4 +// CHECK-NEXT: store i32 1, i32* [[P_STRIDE]], align 4 +// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1:@.*]]) +// CHECK-NEXT: call void @__kmpc_for_static_init_4u(%struct.ident_t* [[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]], i32 34, i32* [[P_LASTITER]], i32* [[P_LOWERBOUND]], i32* [[P_UPPERBOUND]], i32* [[P_STRIDE]], i32 1, i32 1) +// CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[P_LOWERBOUND]], align 4 +// CHECK-NEXT: [[TMP5:%.*]] = load i32, i32* [[P_UPPERBOUND]], align 4 +// CHECK-NEXT: [[TMP6:%.*]] = sub i32 [[TMP5]], [[TMP4]] +// CHECK-NEXT: [[TMP7:%.*]] = add i32 [[TMP6]], 1 +// CHECK-NEXT: br label [[OMP_LOOP_HEADER:%.*]] +// CHECK: omp_loop.header: +// CHECK-NEXT: [[OMP_LOOP_IV:%.*]] = phi i32 [ 0, [[OMP_LOOP_PREHEADER]] ], [ [[OMP_LOOP_NEXT:%.*]], [[OMP_LOOP_INC:%.*]] ] +// CHECK-NEXT: br label [[OMP_LOOP_COND:%.*]] +// CHECK: omp_loop.cond: +// CHECK-NEXT: [[OMP_LOOP_CMP:%.*]] = icmp ult i32 [[OMP_LOOP_IV]], [[TMP7]] +// CHECK-NEXT: br i1 [[OMP_LOOP_CMP]], label [[OMP_LOOP_BODY:%.*]], label [[OMP_LOOP_EXIT:%.*]] +// CHECK: omp_loop.body: +// CHECK-NEXT: [[TMP8:%.*]] = add i32 [[OMP_LOOP_IV]], [[TMP4]] +// CHECK-NEXT: call void @__captured_stmt.1(i32* [[I]], i32 [[TMP8]], %struct.anon.0* [[AGG_CAPTURED1]]) +// CHECK-NEXT: [[TMP9:%.*]] = load float*, float** [[B_ADDR]], align 8 +// CHECK-NEXT: [[TMP10:%.*]] = load i32, i32* [[I]], align 4 +// CHECK-NEXT: [[IDXPROM:%.*]] = zext i32 [[TMP10]] to i64 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[TMP9]], i64 [[IDXPROM]] +// CHECK-NEXT: [[TMP11:%.*]] = load float, float* [[ARRAYIDX]], align 4 +// CHECK-NEXT: [[TMP12:%.*]] = load float*, float** [[C_ADDR]], align 8 +// CHECK-NEXT: [[TMP13:%.*]] = load i32, i32* [[I]], align 4 +// CHECK-NEXT: [[IDXPROM2:%.*]] = zext i32 [[TMP13]] to i64 +// CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds float, float* [[TMP12]], i64 [[IDXPROM2]] +// CHECK-NEXT: [[TMP14:%.*]] = load float, float* [[ARRAYIDX3]], align 4 +// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP11]], [[TMP14]] +// CHECK-NEXT: [[TMP15:%.*]] = load float*, float** [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP16:%.*]] = load i32, i32* [[I]], align 4 +// CHECK-NEXT: [[IDXPROM4:%.*]] = zext i32 [[TMP16]] to i64 +// CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds float, float* [[TMP15]], i64 [[IDXPROM4]] +// CHECK-NEXT: [[TMP17:%.*]] = load float, float* [[ARRAYIDX5]], align 4 +// CHECK-NEXT: [[MUL6:%.*]] = fmul float [[MUL]], [[TMP17]] +// CHECK-NEXT: [[TMP18:%.*]] = load float*, float** [[A_ADDR]], align 8 +// CHECK-NEXT: [[TMP19:%.*]] = load i32, i32* [[I]], align 4 +// CHECK-NEXT: [[IDXPROM7:%.*]] = zext i32 [[TMP19]] to i64 +// CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds float, float* [[TMP18]], i64 [[IDXPROM7]] +// CHECK-NEXT: store float [[MUL6]], float* [[ARRAYIDX8]], align 4 +// CHECK-NEXT: br label [[OMP_LOOP_INC]] +// CHECK: omp_loop.inc: +// CHECK-NEXT: [[OMP_LOOP_NEXT]] = add nuw i32 [[OMP_LOOP_IV]], 1 +// CHECK-NEXT: br label [[OMP_LOOP_HEADER]] +// CHECK: omp_loop.exit: +// CHECK-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* [[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]]) +// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM9:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) +// CHECK-NEXT: call void @__kmpc_barrier(%struct.ident_t* [[GLOB2:@.*]], i32 [[OMP_GLOBAL_THREAD_NUM9]]) +// CHECK-NEXT: br label [[OMP_LOOP_AFTER:%.*]] +// CHECK: omp_loop.after: +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@__captured_stmt +// CHECK-SAME: (i32* nonnull align 4 dereferenceable(4) [[DISTANCE:%.*]], %struct.anon* noalias [[__CONTEXT:%.*]]) [[ATTR1:#.*]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DISTANCE_ADDR:%.*]] = alloca i32*, align 8 +// CHECK-NEXT: [[__CONTEXT_ADDR:%.*]] = alloca %struct.anon*, align 8 +// CHECK-NEXT: [[DOTSTART:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTSTOP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTSTEP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32* [[DISTANCE]], i32** [[DISTANCE_ADDR]], align 8 +// CHECK-NEXT: store %struct.anon* [[__CONTEXT]], %struct.anon** [[__CONTEXT_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load %struct.anon*, %struct.anon** [[__CONTEXT_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], %struct.anon* [[TMP0]], i32 0, i32 0 +// CHECK-NEXT: [[TMP2:%.*]] = load i32*, i32** [[TMP1]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4 +// CHECK-NEXT: store i32 [[TMP3]], i32* [[DOTSTART]], align 4 +// CHECK-NEXT: store i32 32000000, i32* [[DOTSTOP]], align 4 +// CHECK-NEXT: store i32 7, i32* [[DOTSTEP]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[DOTSTART]], align 4 +// CHECK-NEXT: [[TMP5:%.*]] = load i32, i32* [[DOTSTOP]], align 4 +// CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP4]], [[TMP5]] +// CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] +// CHECK: cond.true: +// CHECK-NEXT: [[TMP6:%.*]] = load i32, i32* [[DOTSTOP]], align 4 +// CHECK-NEXT: [[TMP7:%.*]] = load i32, i32* [[DOTSTART]], align 4 +// CHECK-NEXT: [[SUB:%.*]] = sub i32 [[TMP6]], [[TMP7]] +// CHECK-NEXT: [[TMP8:%.*]] = load i32, i32* [[DOTSTEP]], align 4 +// CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[SUB]], [[TMP8]] +// CHECK-NEXT: br label [[COND_END:%.*]] +// CHECK: cond.false: +// CHECK-NEXT: br label [[COND_END]] +// CHECK: cond.end: +// CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[DIV]], [[COND_TRUE]] ], [ 0, [[COND_FALSE]] ] +// CHECK-NEXT: [[TMP9:%.*]] = load i32*, i32** [[DISTANCE_ADDR]], align 8 +// CHECK-NEXT: store i32 [[COND]], i32* [[TMP9]], align 4 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@__captured_stmt.1 +// CHECK-SAME: (i32* nonnull align 4 dereferenceable(4) [[LOOPVAR:%.*]], i32 [[LOGICAL:%.*]], %struct.anon.0* noalias [[__CONTEXT:%.*]]) [[ATTR1]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[LOOPVAR_ADDR:%.*]] = alloca i32*, align 8 +// CHECK-NEXT: [[LOGICAL_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[__CONTEXT_ADDR:%.*]] = alloca %struct.anon.0*, align 8 +// CHECK-NEXT: store i32* [[LOOPVAR]], i32** [[LOOPVAR_ADDR]], align 8 +// CHECK-NEXT: store i32 [[LOGICAL]], i32* [[LOGICAL_ADDR]], align 4 +// CHECK-NEXT: store %struct.anon.0* [[__CONTEXT]], %struct.anon.0** [[__CONTEXT_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load %struct.anon.0*, %struct.anon.0** [[__CONTEXT_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ANON_0:%.*]], %struct.anon.0* [[TMP0]], i32 0, i32 0 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP1]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[LOGICAL_ADDR]], align 4 +// CHECK-NEXT: [[MUL:%.*]] = mul i32 7, [[TMP3]] +// CHECK-NEXT: [[ADD:%.*]] = add i32 [[TMP2]], [[MUL]] +// CHECK-NEXT: [[TMP4:%.*]] = load i32*, i32** [[LOOPVAR_ADDR]], align 8 +// CHECK-NEXT: store i32 [[ADD]], i32* [[TMP4]], align 4 +// CHECK-NEXT: ret void +// diff --git a/clang/test/OpenMP/irbuilder_nested_parallel_for.c b/clang/test/OpenMP/irbuilder_nested_parallel_for.c --- a/clang/test/OpenMP/irbuilder_nested_parallel_for.c +++ b/clang/test/OpenMP/irbuilder_nested_parallel_for.c @@ -23,15 +23,15 @@ // // CHECK-DEBUG-LABEL: @_Z14parallel_for_0v( // CHECK-DEBUG-NEXT: entry: -// CHECK-DEBUG-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1:@.*]]), [[DBG10:!dbg !.*]] +// CHECK-DEBUG-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1:@.*]]), [[DBG12:!dbg !.*]] // CHECK-DEBUG-NEXT: br label [[OMP_PARALLEL:%.*]] // CHECK-DEBUG: omp_parallel: -// CHECK-DEBUG-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* [[GLOB1]], i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @_Z14parallel_for_0v..omp_par to void (i32*, i32*, ...)*)), [[DBG11:!dbg !.*]] +// CHECK-DEBUG-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* [[GLOB1]], i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @_Z14parallel_for_0v..omp_par to void (i32*, i32*, ...)*)), [[DBG13:!dbg !.*]] // CHECK-DEBUG-NEXT: br label [[OMP_PAR_OUTLINED_EXIT:%.*]] // CHECK-DEBUG: omp.par.outlined.exit: // CHECK-DEBUG-NEXT: br label [[OMP_PAR_EXIT_SPLIT:%.*]] // CHECK-DEBUG: omp.par.exit.split: -// CHECK-DEBUG-NEXT: ret void, [[DBG14:!dbg !.*]] +// CHECK-DEBUG-NEXT: ret void, [[DBG17:!dbg !.*]] // void parallel_for_0(void) { #pragma omp parallel @@ -53,9 +53,9 @@ // CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) // CHECK-NEXT: br label [[OMP_PARALLEL:%.*]] // CHECK: omp_parallel: -// CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* [[GLOB1]], i32 3, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, double*, float**)* @_Z14parallel_for_1Pfid..omp_par.1 to void (i32*, i32*, ...)*), i32* [[A_ADDR]], double* [[B_ADDR]], float** [[R_ADDR]]) -// CHECK-NEXT: br label [[OMP_PAR_OUTLINED_EXIT19:%.*]] -// CHECK: omp.par.outlined.exit19: +// CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* [[GLOB1]], i32 3, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, double*, float**)* @_Z14parallel_for_1Pfid..omp_par.4 to void (i32*, i32*, ...)*), i32* [[A_ADDR]], double* [[B_ADDR]], float** [[R_ADDR]]) +// CHECK-NEXT: br label [[OMP_PAR_OUTLINED_EXIT16:%.*]] +// CHECK: omp.par.outlined.exit16: // CHECK-NEXT: br label [[OMP_PAR_EXIT_SPLIT:%.*]] // CHECK: omp.par.exit.split: // CHECK-NEXT: ret void @@ -66,20 +66,20 @@ // CHECK-DEBUG-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 // CHECK-DEBUG-NEXT: [[B_ADDR:%.*]] = alloca double, align 8 // CHECK-DEBUG-NEXT: store float* [[R:%.*]], float** [[R_ADDR]], align 8 -// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata float** [[R_ADDR]], [[META41:metadata !.*]], metadata !DIExpression()), [[DBG42:!dbg !.*]] +// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata float** [[R_ADDR]], [[META72:metadata !.*]], metadata !DIExpression()), [[DBG73:!dbg !.*]] // CHECK-DEBUG-NEXT: store i32 [[A:%.*]], i32* [[A_ADDR]], align 4 -// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata i32* [[A_ADDR]], [[META43:metadata !.*]], metadata !DIExpression()), [[DBG44:!dbg !.*]] +// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata i32* [[A_ADDR]], [[META74:metadata !.*]], metadata !DIExpression()), [[DBG75:!dbg !.*]] // CHECK-DEBUG-NEXT: store double [[B:%.*]], double* [[B_ADDR]], align 8 -// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata double* [[B_ADDR]], [[META45:metadata !.*]], metadata !DIExpression()), [[DBG46:!dbg !.*]] -// CHECK-DEBUG-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB10:@.*]]), [[DBG47:!dbg !.*]] +// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata double* [[B_ADDR]], [[META76:metadata !.*]], metadata !DIExpression()), [[DBG77:!dbg !.*]] +// CHECK-DEBUG-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB6:@.*]]), [[DBG78:!dbg !.*]] // CHECK-DEBUG-NEXT: br label [[OMP_PARALLEL:%.*]] // CHECK-DEBUG: omp_parallel: -// CHECK-DEBUG-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* [[GLOB10]], i32 3, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, double*, float**)* @_Z14parallel_for_1Pfid..omp_par.1 to void (i32*, i32*, ...)*), i32* [[A_ADDR]], double* [[B_ADDR]], float** [[R_ADDR]]), [[DBG48:!dbg !.*]] -// CHECK-DEBUG-NEXT: br label [[OMP_PAR_OUTLINED_EXIT19:%.*]] -// CHECK-DEBUG: omp.par.outlined.exit19: +// CHECK-DEBUG-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* [[GLOB6]], i32 3, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, double*, float**)* @_Z14parallel_for_1Pfid..omp_par.4 to void (i32*, i32*, ...)*), i32* [[A_ADDR]], double* [[B_ADDR]], float** [[R_ADDR]]), [[DBG79:!dbg !.*]] +// CHECK-DEBUG-NEXT: br label [[OMP_PAR_OUTLINED_EXIT16:%.*]] +// CHECK-DEBUG: omp.par.outlined.exit16: // CHECK-DEBUG-NEXT: br label [[OMP_PAR_EXIT_SPLIT:%.*]] // CHECK-DEBUG: omp.par.exit.split: -// CHECK-DEBUG-NEXT: ret void, [[DBG50:!dbg !.*]] +// CHECK-DEBUG-NEXT: ret void, [[DBG81:!dbg !.*]] // void parallel_for_1(float *r, int a, double b) { #pragma omp parallel @@ -99,76 +99,72 @@ // CHECK-NEXT: [[R_ADDR:%.*]] = alloca float*, align 8 // CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 // CHECK-NEXT: [[B_ADDR:%.*]] = alloca double, align 8 -// CHECK-NEXT: [[DOTOMP_IV212:%.*]] = alloca i32, align 4 -// CHECK-NEXT: [[TMP213:%.*]] = alloca i32, align 4 -// CHECK-NEXT: [[DOTOMP_LB214:%.*]] = alloca i32, align 4 -// CHECK-NEXT: [[DOTOMP_UB215:%.*]] = alloca i32, align 4 -// CHECK-NEXT: [[DOTOMP_STRIDE216:%.*]] = alloca i32, align 4 -// CHECK-NEXT: [[DOTOMP_IS_LAST217:%.*]] = alloca i32, align 4 -// CHECK-NEXT: [[I218:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[I185:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[AGG_CAPTURED186:%.*]] = alloca [[STRUCT_ANON_17:%.*]], align 8 +// CHECK-NEXT: [[AGG_CAPTURED187:%.*]] = alloca [[STRUCT_ANON_18:%.*]], align 4 +// CHECK-NEXT: [[DOTCOUNT_ADDR188:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[P_LASTITER203:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[P_LOWERBOUND204:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[P_UPPERBOUND205:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[P_STRIDE206:%.*]] = alloca i32, align 4 // CHECK-NEXT: store float* [[R:%.*]], float** [[R_ADDR]], align 8 // CHECK-NEXT: store i32 [[A:%.*]], i32* [[A_ADDR]], align 4 // CHECK-NEXT: store double [[B:%.*]], double* [[B_ADDR]], align 8 // CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) // CHECK-NEXT: br label [[OMP_PARALLEL:%.*]] // CHECK: omp_parallel: -// CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* [[GLOB1]], i32 3, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, double*, float**)* @_Z14parallel_for_2Pfid..omp_par.4 to void (i32*, i32*, ...)*), i32* [[A_ADDR]], double* [[B_ADDR]], float** [[R_ADDR]]) -// CHECK-NEXT: br label [[OMP_PAR_OUTLINED_EXIT211:%.*]] -// CHECK: omp.par.outlined.exit211: +// CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* [[GLOB1]], i32 3, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, double*, float**)* @_Z14parallel_for_2Pfid..omp_par.23 to void (i32*, i32*, ...)*), i32* [[A_ADDR]], double* [[B_ADDR]], float** [[R_ADDR]]) +// CHECK-NEXT: br label [[OMP_PAR_OUTLINED_EXIT184:%.*]] +// CHECK: omp.par.outlined.exit184: // CHECK-NEXT: br label [[OMP_PAR_EXIT_SPLIT:%.*]] // CHECK: omp.par.exit.split: -// CHECK-NEXT: store i32 0, i32* [[DOTOMP_LB214]], align 4 -// CHECK-NEXT: store i32 99, i32* [[DOTOMP_UB215]], align 4 -// CHECK-NEXT: store i32 1, i32* [[DOTOMP_STRIDE216]], align 4 -// CHECK-NEXT: store i32 0, i32* [[DOTOMP_IS_LAST217]], align 4 -// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM219:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB41:@.*]]) -// CHECK-NEXT: call void @__kmpc_for_static_init_4(%struct.ident_t* [[GLOB2:@.*]], i32 [[OMP_GLOBAL_THREAD_NUM219]], i32 34, i32* [[DOTOMP_IS_LAST217]], i32* [[DOTOMP_LB214]], i32* [[DOTOMP_UB215]], i32* [[DOTOMP_STRIDE216]], i32 1, i32 1) -// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[DOTOMP_UB215]], align 4 -// CHECK-NEXT: [[CMP220:%.*]] = icmp sgt i32 [[TMP0]], 99 -// CHECK-NEXT: br i1 [[CMP220]], label [[COND_TRUE221:%.*]], label [[COND_FALSE222:%.*]] -// CHECK: cond.true221: -// CHECK-NEXT: br label [[COND_END223:%.*]] -// CHECK: cond.false222: -// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[DOTOMP_UB215]], align 4 -// CHECK-NEXT: br label [[COND_END223]] -// CHECK: cond.end223: -// CHECK-NEXT: [[COND224:%.*]] = phi i32 [ 99, [[COND_TRUE221]] ], [ [[TMP1]], [[COND_FALSE222]] ] -// CHECK-NEXT: store i32 [[COND224]], i32* [[DOTOMP_UB215]], align 4 -// CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[DOTOMP_LB214]], align 4 -// CHECK-NEXT: store i32 [[TMP2]], i32* [[DOTOMP_IV212]], align 4 -// CHECK-NEXT: br label [[OMP_INNER_FOR_COND225:%.*]] -// CHECK: omp.inner.for.cond225: -// CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[DOTOMP_IV212]], align 4 -// CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[DOTOMP_UB215]], align 4 -// CHECK-NEXT: [[CMP226:%.*]] = icmp sle i32 [[TMP3]], [[TMP4]] -// CHECK-NEXT: br i1 [[CMP226]], label [[OMP_INNER_FOR_BODY227:%.*]], label [[OMP_INNER_FOR_END236:%.*]] -// CHECK: omp.inner.for.body227: -// CHECK-NEXT: [[TMP5:%.*]] = load i32, i32* [[DOTOMP_IV212]], align 4 -// CHECK-NEXT: [[MUL228:%.*]] = mul nsw i32 [[TMP5]], 1 -// CHECK-NEXT: [[ADD229:%.*]] = add nsw i32 0, [[MUL228]] -// CHECK-NEXT: store i32 [[ADD229]], i32* [[I218]], align 4 -// CHECK-NEXT: [[TMP6:%.*]] = load i32, i32* [[A_ADDR]], align 4 -// CHECK-NEXT: [[CONV230:%.*]] = sitofp i32 [[TMP6]] to double -// CHECK-NEXT: [[TMP7:%.*]] = load double, double* [[B_ADDR]], align 8 -// CHECK-NEXT: [[ADD231:%.*]] = fadd double [[CONV230]], [[TMP7]] -// CHECK-NEXT: [[CONV232:%.*]] = fptrunc double [[ADD231]] to float -// CHECK-NEXT: [[TMP8:%.*]] = load float*, float** [[R_ADDR]], align 8 -// CHECK-NEXT: store float [[CONV232]], float* [[TMP8]], align 4 -// CHECK-NEXT: br label [[OMP_BODY_CONTINUE233:%.*]] -// CHECK: omp.body.continue233: -// CHECK-NEXT: br label [[OMP_INNER_FOR_INC234:%.*]] -// CHECK: omp.inner.for.inc234: -// CHECK-NEXT: [[TMP9:%.*]] = load i32, i32* [[DOTOMP_IV212]], align 4 -// CHECK-NEXT: [[ADD235:%.*]] = add nsw i32 [[TMP9]], 1 -// CHECK-NEXT: store i32 [[ADD235]], i32* [[DOTOMP_IV212]], align 4 -// CHECK-NEXT: br label [[OMP_INNER_FOR_COND225]] -// CHECK: omp.inner.for.end236: -// CHECK-NEXT: br label [[OMP_LOOP_EXIT237:%.*]] -// CHECK: omp.loop.exit237: -// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM238:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB43:@.*]]) -// CHECK-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* [[GLOB2]], i32 [[OMP_GLOBAL_THREAD_NUM238]]) -// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM239:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) -// CHECK-NEXT: call void @__kmpc_barrier(%struct.ident_t* [[GLOB7:@.*]], i32 [[OMP_GLOBAL_THREAD_NUM239]]) +// CHECK-NEXT: store i32 0, i32* [[I185]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ANON_17]], %struct.anon.17* [[AGG_CAPTURED186]], i32 0, i32 0 +// CHECK-NEXT: store i32* [[I185]], i32** [[TMP0]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ANON_18]], %struct.anon.18* [[AGG_CAPTURED187]], i32 0, i32 0 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[I185]], align 4 +// CHECK-NEXT: store i32 [[TMP2]], i32* [[TMP1]], align 4 +// CHECK-NEXT: call void @__captured_stmt.19(i32* [[DOTCOUNT_ADDR188]], %struct.anon.17* [[AGG_CAPTURED186]]) +// CHECK-NEXT: [[DOTCOUNT189:%.*]] = load i32, i32* [[DOTCOUNT_ADDR188]], align 4 +// CHECK-NEXT: br label [[OMP_LOOP_PREHEADER190:%.*]] +// CHECK: omp_loop.preheader190: +// CHECK-NEXT: store i32 0, i32* [[P_LOWERBOUND204]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = sub i32 [[DOTCOUNT189]], 1 +// CHECK-NEXT: store i32 [[TMP3]], i32* [[P_UPPERBOUND205]], align 4 +// CHECK-NEXT: store i32 1, i32* [[P_STRIDE206]], align 4 +// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM207:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) +// CHECK-NEXT: call void @__kmpc_for_static_init_4u(%struct.ident_t* [[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM207]], i32 34, i32* [[P_LASTITER203]], i32* [[P_LOWERBOUND204]], i32* [[P_UPPERBOUND205]], i32* [[P_STRIDE206]], i32 1, i32 1) +// CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[P_LOWERBOUND204]], align 4 +// CHECK-NEXT: [[TMP5:%.*]] = load i32, i32* [[P_UPPERBOUND205]], align 4 +// CHECK-NEXT: [[TMP6:%.*]] = sub i32 [[TMP5]], [[TMP4]] +// CHECK-NEXT: [[TMP7:%.*]] = add i32 [[TMP6]], 1 +// CHECK-NEXT: br label [[OMP_LOOP_HEADER191:%.*]] +// CHECK: omp_loop.header191: +// CHECK-NEXT: [[OMP_LOOP_IV197:%.*]] = phi i32 [ 0, [[OMP_LOOP_PREHEADER190]] ], [ [[OMP_LOOP_NEXT199:%.*]], [[OMP_LOOP_INC194:%.*]] ] +// CHECK-NEXT: br label [[OMP_LOOP_COND192:%.*]] +// CHECK: omp_loop.cond192: +// CHECK-NEXT: [[OMP_LOOP_CMP198:%.*]] = icmp ult i32 [[OMP_LOOP_IV197]], [[TMP7]] +// CHECK-NEXT: br i1 [[OMP_LOOP_CMP198]], label [[OMP_LOOP_BODY193:%.*]], label [[OMP_LOOP_EXIT195:%.*]] +// CHECK: omp_loop.body193: +// CHECK-NEXT: [[TMP8:%.*]] = add i32 [[OMP_LOOP_IV197]], [[TMP4]] +// CHECK-NEXT: call void @__captured_stmt.20(i32* [[I185]], i32 [[TMP8]], %struct.anon.18* [[AGG_CAPTURED187]]) +// CHECK-NEXT: [[TMP9:%.*]] = load i32, i32* [[A_ADDR]], align 4 +// CHECK-NEXT: [[CONV200:%.*]] = sitofp i32 [[TMP9]] to double +// CHECK-NEXT: [[TMP10:%.*]] = load double, double* [[B_ADDR]], align 8 +// CHECK-NEXT: [[ADD201:%.*]] = fadd double [[CONV200]], [[TMP10]] +// CHECK-NEXT: [[CONV202:%.*]] = fptrunc double [[ADD201]] to float +// CHECK-NEXT: [[TMP11:%.*]] = load float*, float** [[R_ADDR]], align 8 +// CHECK-NEXT: store float [[CONV202]], float* [[TMP11]], align 4 +// CHECK-NEXT: br label [[OMP_LOOP_INC194]] +// CHECK: omp_loop.inc194: +// CHECK-NEXT: [[OMP_LOOP_NEXT199]] = add nuw i32 [[OMP_LOOP_IV197]], 1 +// CHECK-NEXT: br label [[OMP_LOOP_HEADER191]] +// CHECK: omp_loop.exit195: +// CHECK-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* [[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM207]]) +// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM208:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) +// CHECK-NEXT: call void @__kmpc_barrier(%struct.ident_t* [[GLOB2:@.*]], i32 [[OMP_GLOBAL_THREAD_NUM208]]) +// CHECK-NEXT: br label [[OMP_LOOP_AFTER196:%.*]] +// CHECK: omp_loop.after196: // CHECK-NEXT: ret void // // CHECK-DEBUG-LABEL: @_Z14parallel_for_2Pfid( @@ -176,86 +172,77 @@ // CHECK-DEBUG-NEXT: [[R_ADDR:%.*]] = alloca float*, align 8 // CHECK-DEBUG-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 // CHECK-DEBUG-NEXT: [[B_ADDR:%.*]] = alloca double, align 8 -// CHECK-DEBUG-NEXT: [[DOTOMP_IV212:%.*]] = alloca i32, align 4 -// CHECK-DEBUG-NEXT: [[TMP213:%.*]] = alloca i32, align 4 -// CHECK-DEBUG-NEXT: [[DOTOMP_LB214:%.*]] = alloca i32, align 4 -// CHECK-DEBUG-NEXT: [[DOTOMP_UB215:%.*]] = alloca i32, align 4 -// CHECK-DEBUG-NEXT: [[DOTOMP_STRIDE216:%.*]] = alloca i32, align 4 -// CHECK-DEBUG-NEXT: [[DOTOMP_IS_LAST217:%.*]] = alloca i32, align 4 -// CHECK-DEBUG-NEXT: [[I218:%.*]] = alloca i32, align 4 +// CHECK-DEBUG-NEXT: [[I185:%.*]] = alloca i32, align 4 +// CHECK-DEBUG-NEXT: [[AGG_CAPTURED186:%.*]] = alloca [[STRUCT_ANON_17:%.*]], align 8 +// CHECK-DEBUG-NEXT: [[AGG_CAPTURED187:%.*]] = alloca [[STRUCT_ANON_18:%.*]], align 4 +// CHECK-DEBUG-NEXT: [[DOTCOUNT_ADDR188:%.*]] = alloca i32, align 4 +// CHECK-DEBUG-NEXT: [[P_LASTITER203:%.*]] = alloca i32, align 4 +// CHECK-DEBUG-NEXT: [[P_LOWERBOUND204:%.*]] = alloca i32, align 4 +// CHECK-DEBUG-NEXT: [[P_UPPERBOUND205:%.*]] = alloca i32, align 4 +// CHECK-DEBUG-NEXT: [[P_STRIDE206:%.*]] = alloca i32, align 4 // CHECK-DEBUG-NEXT: store float* [[R:%.*]], float** [[R_ADDR]], align 8 -// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata float** [[R_ADDR]], [[META77:metadata !.*]], metadata !DIExpression()), [[DBG78:!dbg !.*]] +// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata float** [[R_ADDR]], [[META133:metadata !.*]], metadata !DIExpression()), [[DBG134:!dbg !.*]] // CHECK-DEBUG-NEXT: store i32 [[A:%.*]], i32* [[A_ADDR]], align 4 -// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata i32* [[A_ADDR]], [[META79:metadata !.*]], metadata !DIExpression()), [[DBG80:!dbg !.*]] +// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata i32* [[A_ADDR]], [[META135:metadata !.*]], metadata !DIExpression()), [[DBG136:!dbg !.*]] // CHECK-DEBUG-NEXT: store double [[B:%.*]], double* [[B_ADDR]], align 8 -// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata double* [[B_ADDR]], [[META81:metadata !.*]], metadata !DIExpression()), [[DBG82:!dbg !.*]] -// CHECK-DEBUG-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB21:@.*]]), [[DBG83:!dbg !.*]] +// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata double* [[B_ADDR]], [[META137:metadata !.*]], metadata !DIExpression()), [[DBG138:!dbg !.*]] +// CHECK-DEBUG-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB13:@.*]]), [[DBG139:!dbg !.*]] // CHECK-DEBUG-NEXT: br label [[OMP_PARALLEL:%.*]] // CHECK-DEBUG: omp_parallel: -// CHECK-DEBUG-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* [[GLOB21]], i32 3, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, double*, float**)* @_Z14parallel_for_2Pfid..omp_par.4 to void (i32*, i32*, ...)*), i32* [[A_ADDR]], double* [[B_ADDR]], float** [[R_ADDR]]), [[DBG84:!dbg !.*]] -// CHECK-DEBUG-NEXT: br label [[OMP_PAR_OUTLINED_EXIT211:%.*]] -// CHECK-DEBUG: omp.par.outlined.exit211: +// CHECK-DEBUG-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* [[GLOB13]], i32 3, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, double*, float**)* @_Z14parallel_for_2Pfid..omp_par.23 to void (i32*, i32*, ...)*), i32* [[A_ADDR]], double* [[B_ADDR]], float** [[R_ADDR]]), [[DBG140:!dbg !.*]] +// CHECK-DEBUG-NEXT: br label [[OMP_PAR_OUTLINED_EXIT184:%.*]] +// CHECK-DEBUG: omp.par.outlined.exit184: // CHECK-DEBUG-NEXT: br label [[OMP_PAR_EXIT_SPLIT:%.*]] // CHECK-DEBUG: omp.par.exit.split: -// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata i32* [[DOTOMP_IV212]], [[META87:metadata !.*]], metadata !DIExpression()), [[DBG89:!dbg !.*]] -// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata i32* [[DOTOMP_LB214]], [[META90:metadata !.*]], metadata !DIExpression()), [[DBG89]] -// CHECK-DEBUG-NEXT: store i32 0, i32* [[DOTOMP_LB214]], align 4, [[DBG91:!dbg !.*]] -// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata i32* [[DOTOMP_UB215]], [[META92:metadata !.*]], metadata !DIExpression()), [[DBG89]] -// CHECK-DEBUG-NEXT: store i32 99, i32* [[DOTOMP_UB215]], align 4, [[DBG91]] -// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata i32* [[DOTOMP_STRIDE216]], [[META93:metadata !.*]], metadata !DIExpression()), [[DBG89]] -// CHECK-DEBUG-NEXT: store i32 1, i32* [[DOTOMP_STRIDE216]], align 4, [[DBG91]] -// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata i32* [[DOTOMP_IS_LAST217]], [[META94:metadata !.*]], metadata !DIExpression()), [[DBG89]] -// CHECK-DEBUG-NEXT: store i32 0, i32* [[DOTOMP_IS_LAST217]], align 4, [[DBG91]] -// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata i32* [[I218]], [[META95:metadata !.*]], metadata !DIExpression()), [[DBG89]] -// CHECK-DEBUG-NEXT: [[OMP_GLOBAL_THREAD_NUM219:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB79:@.*]]) -// CHECK-DEBUG-NEXT: call void @__kmpc_for_static_init_4(%struct.ident_t* [[GLOB78:@.*]], i32 [[OMP_GLOBAL_THREAD_NUM219]], i32 34, i32* [[DOTOMP_IS_LAST217]], i32* [[DOTOMP_LB214]], i32* [[DOTOMP_UB215]], i32* [[DOTOMP_STRIDE216]], i32 1, i32 1), [[DBG96:!dbg !.*]] -// CHECK-DEBUG-NEXT: [[TMP0:%.*]] = load i32, i32* [[DOTOMP_UB215]], align 4, [[DBG91]] -// CHECK-DEBUG-NEXT: [[CMP220:%.*]] = icmp sgt i32 [[TMP0]], 99, [[DBG91]] -// CHECK-DEBUG-NEXT: br i1 [[CMP220]], label [[COND_TRUE221:%.*]], label [[COND_FALSE222:%.*]], [[DBG91]] -// CHECK-DEBUG: cond.true221: -// CHECK-DEBUG-NEXT: br label [[COND_END223:%.*]], [[DBG91]] -// CHECK-DEBUG: cond.false222: -// CHECK-DEBUG-NEXT: [[TMP1:%.*]] = load i32, i32* [[DOTOMP_UB215]], align 4, [[DBG91]] -// CHECK-DEBUG-NEXT: br label [[COND_END223]], [[DBG91]] -// CHECK-DEBUG: cond.end223: -// CHECK-DEBUG-NEXT: [[COND224:%.*]] = phi i32 [ 99, [[COND_TRUE221]] ], [ [[TMP1]], [[COND_FALSE222]] ], [[DBG91]] -// CHECK-DEBUG-NEXT: store i32 [[COND224]], i32* [[DOTOMP_UB215]], align 4, [[DBG91]] -// CHECK-DEBUG-NEXT: [[TMP2:%.*]] = load i32, i32* [[DOTOMP_LB214]], align 4, [[DBG91]] -// CHECK-DEBUG-NEXT: store i32 [[TMP2]], i32* [[DOTOMP_IV212]], align 4, [[DBG91]] -// CHECK-DEBUG-NEXT: br label [[OMP_INNER_FOR_COND225:%.*]], [[DBG97:!dbg !.*]] -// CHECK-DEBUG: omp.inner.for.cond225: -// CHECK-DEBUG-NEXT: [[TMP3:%.*]] = load i32, i32* [[DOTOMP_IV212]], align 4, [[DBG91]] -// CHECK-DEBUG-NEXT: [[TMP4:%.*]] = load i32, i32* [[DOTOMP_UB215]], align 4, [[DBG91]] -// CHECK-DEBUG-NEXT: [[CMP226:%.*]] = icmp sle i32 [[TMP3]], [[TMP4]], [[DBG98:!dbg !.*]] -// CHECK-DEBUG-NEXT: br i1 [[CMP226]], label [[OMP_INNER_FOR_BODY227:%.*]], label [[OMP_INNER_FOR_END236:%.*]], [[DBG97]] -// CHECK-DEBUG: omp.inner.for.body227: -// CHECK-DEBUG-NEXT: [[TMP5:%.*]] = load i32, i32* [[DOTOMP_IV212]], align 4, [[DBG91]] -// CHECK-DEBUG-NEXT: [[MUL228:%.*]] = mul nsw i32 [[TMP5]], 1, [[DBG99:!dbg !.*]] -// CHECK-DEBUG-NEXT: [[ADD229:%.*]] = add nsw i32 0, [[MUL228]], [[DBG99]] -// CHECK-DEBUG-NEXT: store i32 [[ADD229]], i32* [[I218]], align 4, [[DBG99]] -// CHECK-DEBUG-NEXT: [[TMP6:%.*]] = load i32, i32* [[A_ADDR]], align 4, [[DBG100:!dbg !.*]] -// CHECK-DEBUG-NEXT: [[CONV230:%.*]] = sitofp i32 [[TMP6]] to double, [[DBG100]] -// CHECK-DEBUG-NEXT: [[TMP7:%.*]] = load double, double* [[B_ADDR]], align 8, [[DBG101:!dbg !.*]] -// CHECK-DEBUG-NEXT: [[ADD231:%.*]] = fadd double [[CONV230]], [[TMP7]], [[DBG102:!dbg !.*]] -// CHECK-DEBUG-NEXT: [[CONV232:%.*]] = fptrunc double [[ADD231]] to float, [[DBG100]] -// CHECK-DEBUG-NEXT: [[TMP8:%.*]] = load float*, float** [[R_ADDR]], align 8, [[DBG103:!dbg !.*]] -// CHECK-DEBUG-NEXT: store float [[CONV232]], float* [[TMP8]], align 4, [[DBG104:!dbg !.*]] -// CHECK-DEBUG-NEXT: br label [[OMP_BODY_CONTINUE233:%.*]], [[DBG105:!dbg !.*]] -// CHECK-DEBUG: omp.body.continue233: -// CHECK-DEBUG-NEXT: br label [[OMP_INNER_FOR_INC234:%.*]], [[DBG96]] -// CHECK-DEBUG: omp.inner.for.inc234: -// CHECK-DEBUG-NEXT: [[TMP9:%.*]] = load i32, i32* [[DOTOMP_IV212]], align 4, [[DBG91]] -// CHECK-DEBUG-NEXT: [[ADD235:%.*]] = add nsw i32 [[TMP9]], 1, [[DBG98]] -// CHECK-DEBUG-NEXT: store i32 [[ADD235]], i32* [[DOTOMP_IV212]], align 4, [[DBG98]] -// CHECK-DEBUG-NEXT: br label [[OMP_INNER_FOR_COND225]], [[DBG96]], [[LOOP106:!llvm.loop !.*]] -// CHECK-DEBUG: omp.inner.for.end236: -// CHECK-DEBUG-NEXT: br label [[OMP_LOOP_EXIT237:%.*]], [[DBG96]] -// CHECK-DEBUG: omp.loop.exit237: -// CHECK-DEBUG-NEXT: [[OMP_GLOBAL_THREAD_NUM238:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB82:@.*]]) -// CHECK-DEBUG-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* [[GLOB81:@.*]], i32 [[OMP_GLOBAL_THREAD_NUM238]]), [[DBG107:!dbg !.*]] -// CHECK-DEBUG-NEXT: [[OMP_GLOBAL_THREAD_NUM239:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB82]]), [[DBG107]] -// CHECK-DEBUG-NEXT: call void @__kmpc_barrier(%struct.ident_t* [[GLOB83:@.*]], i32 [[OMP_GLOBAL_THREAD_NUM239]]), [[DBG107]] -// CHECK-DEBUG-NEXT: ret void, [[DBG108:!dbg !.*]] +// CHECK-DEBUG-NEXT: call void @llvm.dbg.declare(metadata i32* [[I185]], [[META144:metadata !.*]], metadata !DIExpression()), [[DBG147:!dbg !.*]] +// CHECK-DEBUG-NEXT: store i32 0, i32* [[I185]], align 4, [[DBG147]] +// CHECK-DEBUG-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ANON_17]], %struct.anon.17* [[AGG_CAPTURED186]], i32 0, i32 0, [[DBG148:!dbg !.*]] +// CHECK-DEBUG-NEXT: store i32* [[I185]], i32** [[TMP0]], align 8, [[DBG148]] +// CHECK-DEBUG-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ANON_18]], %struct.anon.18* [[AGG_CAPTURED187]], i32 0, i32 0, [[DBG148]] +// CHECK-DEBUG-NEXT: [[TMP2:%.*]] = load i32, i32* [[I185]], align 4, [[DBG149:!dbg !.*]] +// CHECK-DEBUG-NEXT: store i32 [[TMP2]], i32* [[TMP1]], align 4, [[DBG148]] +// CHECK-DEBUG-NEXT: call void @__captured_stmt.19(i32* [[DOTCOUNT_ADDR188]], %struct.anon.17* [[AGG_CAPTURED186]]), [[DBG148]] +// CHECK-DEBUG-NEXT: [[DOTCOUNT189:%.*]] = load i32, i32* [[DOTCOUNT_ADDR188]], align 4, [[DBG148]] +// CHECK-DEBUG-NEXT: br label [[OMP_LOOP_PREHEADER190:%.*]], [[DBG148]] +// CHECK-DEBUG: omp_loop.preheader190: +// CHECK-DEBUG-NEXT: store i32 0, i32* [[P_LOWERBOUND204]], align 4, [[DBG148]] +// CHECK-DEBUG-NEXT: [[TMP3:%.*]] = sub i32 [[DOTCOUNT189]], 1, [[DBG148]] +// CHECK-DEBUG-NEXT: store i32 [[TMP3]], i32* [[P_UPPERBOUND205]], align 4, [[DBG148]] +// CHECK-DEBUG-NEXT: store i32 1, i32* [[P_STRIDE206]], align 4, [[DBG148]] +// CHECK-DEBUG-NEXT: [[OMP_GLOBAL_THREAD_NUM207:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB42:@.*]]), [[DBG148]] +// CHECK-DEBUG-NEXT: call void @__kmpc_for_static_init_4u(%struct.ident_t* [[GLOB42]], i32 [[OMP_GLOBAL_THREAD_NUM207]], i32 34, i32* [[P_LASTITER203]], i32* [[P_LOWERBOUND204]], i32* [[P_UPPERBOUND205]], i32* [[P_STRIDE206]], i32 1, i32 1), [[DBG148]] +// CHECK-DEBUG-NEXT: [[TMP4:%.*]] = load i32, i32* [[P_LOWERBOUND204]], align 4, [[DBG148]] +// CHECK-DEBUG-NEXT: [[TMP5:%.*]] = load i32, i32* [[P_UPPERBOUND205]], align 4, [[DBG148]] +// CHECK-DEBUG-NEXT: [[TMP6:%.*]] = sub i32 [[TMP5]], [[TMP4]], [[DBG148]] +// CHECK-DEBUG-NEXT: [[TMP7:%.*]] = add i32 [[TMP6]], 1, [[DBG148]] +// CHECK-DEBUG-NEXT: br label [[OMP_LOOP_HEADER191:%.*]], [[DBG148]] +// CHECK-DEBUG: omp_loop.header191: +// CHECK-DEBUG-NEXT: [[OMP_LOOP_IV197:%.*]] = phi i32 [ 0, [[OMP_LOOP_PREHEADER190]] ], [ [[OMP_LOOP_NEXT199:%.*]], [[OMP_LOOP_INC194:%.*]] ], [[DBG148]] +// CHECK-DEBUG-NEXT: br label [[OMP_LOOP_COND192:%.*]], [[DBG148]] +// CHECK-DEBUG: omp_loop.cond192: +// CHECK-DEBUG-NEXT: [[OMP_LOOP_CMP198:%.*]] = icmp ult i32 [[OMP_LOOP_IV197]], [[TMP7]], [[DBG148]] +// CHECK-DEBUG-NEXT: br i1 [[OMP_LOOP_CMP198]], label [[OMP_LOOP_BODY193:%.*]], label [[OMP_LOOP_EXIT195:%.*]], [[DBG148]] +// CHECK-DEBUG: omp_loop.body193: +// CHECK-DEBUG-NEXT: [[TMP8:%.*]] = add i32 [[OMP_LOOP_IV197]], [[TMP4]], [[DBG148]] +// CHECK-DEBUG-NEXT: call void @__captured_stmt.20(i32* [[I185]], i32 [[TMP8]], %struct.anon.18* [[AGG_CAPTURED187]]), [[DBG148]] +// CHECK-DEBUG-NEXT: [[TMP9:%.*]] = load i32, i32* [[A_ADDR]], align 4, [[DBG150:!dbg !.*]] +// CHECK-DEBUG-NEXT: [[CONV200:%.*]] = sitofp i32 [[TMP9]] to double, [[DBG150]] +// CHECK-DEBUG-NEXT: [[TMP10:%.*]] = load double, double* [[B_ADDR]], align 8, [[DBG151:!dbg !.*]] +// CHECK-DEBUG-NEXT: [[ADD201:%.*]] = fadd double [[CONV200]], [[TMP10]], [[DBG152:!dbg !.*]] +// CHECK-DEBUG-NEXT: [[CONV202:%.*]] = fptrunc double [[ADD201]] to float, [[DBG150]] +// CHECK-DEBUG-NEXT: [[TMP11:%.*]] = load float*, float** [[R_ADDR]], align 8, [[DBG153:!dbg !.*]] +// CHECK-DEBUG-NEXT: store float [[CONV202]], float* [[TMP11]], align 4, [[DBG154:!dbg !.*]] +// CHECK-DEBUG-NEXT: br label [[OMP_LOOP_INC194]], [[DBG148]] +// CHECK-DEBUG: omp_loop.inc194: +// CHECK-DEBUG-NEXT: [[OMP_LOOP_NEXT199]] = add nuw i32 [[OMP_LOOP_IV197]], 1, [[DBG148]] +// CHECK-DEBUG-NEXT: br label [[OMP_LOOP_HEADER191]], [[DBG148]] +// CHECK-DEBUG: omp_loop.exit195: +// CHECK-DEBUG-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* [[GLOB42]], i32 [[OMP_GLOBAL_THREAD_NUM207]]), [[DBG148]] +// CHECK-DEBUG-NEXT: [[OMP_GLOBAL_THREAD_NUM208:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB42]]), [[DBG151]] +// CHECK-DEBUG-NEXT: call void @__kmpc_barrier(%struct.ident_t* [[GLOB43:@.*]], i32 [[OMP_GLOBAL_THREAD_NUM208]]), [[DBG151]] +// CHECK-DEBUG-NEXT: br label [[OMP_LOOP_AFTER196:%.*]], [[DBG148]] +// CHECK-DEBUG: omp_loop.after196: +// CHECK-DEBUG-NEXT: ret void, [[DBG155:!dbg !.*]] // void parallel_for_2(float *r, int a, double b) { #pragma omp parallel diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -5542,6 +5542,8 @@ return cxstring::createRef("CXXAccessSpecifier"); case CXCursor_ModuleImportDecl: return cxstring::createRef("ModuleImport"); + case CXCursor_OMPCanonicalLoop: + return cxstring::createRef("OMPCanonicalLoop"); case CXCursor_OMPParallelDirective: return cxstring::createRef("OMPParallelDirective"); case CXCursor_OMPSimdDirective: diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -639,6 +639,9 @@ case Stmt::MSDependentExistsStmtClass: K = CXCursor_UnexposedStmt; break; + case Stmt::OMPCanonicalLoopClass: + K = CXCursor_OMPCanonicalLoop; + break; case Stmt::OMPParallelDirectiveClass: K = CXCursor_OMPParallelDirective; break; diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h --- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h @@ -31,6 +31,7 @@ /// Create a new OpenMPIRBuilder operating on the given module \p M. This will /// not have an effect on \p M (see initialize). OpenMPIRBuilder(Module &M) : M(M), Builder(M.getContext()) {} + ~OpenMPIRBuilder(); /// Initialize the internal state, this will put structures types and /// potentially other helpers into the underlying module. Must be called @@ -38,10 +39,12 @@ void initialize(); /// Finalize the underlying module, e.g., by outlining regions. + /// \param Fn The function to be finalized. If not used, + /// all functions are finalized. /// \param AllowExtractorSinking Flag to include sinking instructions, /// emitted by CodeExtractor, in the /// outlined region. Default is false. - void finalize(bool AllowExtractorSinking = false); + void finalize(Function *Fn = nullptr, bool AllowExtractorSinking = false); /// Add attributes known for \p FnID to \p Fn. void addAttributes(omp::RuntimeFunction FnID, Function &Fn); @@ -364,6 +367,31 @@ bool NeedsBarrier, Value *Chunk = nullptr); + /// Modifies the canonical loop to be a workshare loop. + /// + /// This takes a \p LoopInfo representing a canonical loop, such as the one + /// created by \p createCanonicalLoop and emits additional instructions to + /// turn it into a workshare loop. In particular, it calls to an OpenMP + /// runtime function in the preheader to obtain the loop bounds to be used in + /// the current thread, updates the relevant instructions in the canonical + /// loop and calls to an OpenMP runtime finalization function after the loop. + /// + /// \param Loc The source location description, the insertion location + /// is not used. + /// \param CLI A descriptor of the canonical loop to workshare. + /// \param AllocaIP An insertion point for Alloca instructions usable in the + /// preheader of the loop. + /// \param NeedsBarrier Indicates whether a barrier must be insterted after + /// the loop. + /// \param Chunk The size of loop chunk considered as a unit when + /// scheduling. If \p nullptr, defaults to 1. + /// + /// \returns Updated CanonicalLoopInfo. + CanonicalLoopInfo *createWorkshareLoop(const LocationDescription &Loc, + CanonicalLoopInfo *CLI, + InsertPointTy AllocaIP, + bool NeedsBarrier); + /// Tile a loop nest. /// /// Tiles the loops of \p Loops by the tile sizes in \p TileSizes. Loops in @@ -543,6 +571,9 @@ /// vector and set. void collectBlocks(SmallPtrSetImpl &BlockSet, SmallVectorImpl &BlockVector); + + /// Return the function that contains the region to be outlined. + Function *getFunction() const { return EntryBB->getParent(); } }; /// Collection of regions that need to be outlined during finalization. @@ -916,6 +947,8 @@ return {After, After->begin()}; }; + Function *getFunction() const { return Header->getParent(); } + /// Consistency self-check. void assertOK() const; }; diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp --- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -126,15 +126,23 @@ void OpenMPIRBuilder::initialize() { initializeTypes(M); } -void OpenMPIRBuilder::finalize(bool AllowExtractorSinking) { +void OpenMPIRBuilder::finalize(Function *Fn, bool AllowExtractorSinking) { SmallPtrSet ParallelRegionBlockSet; SmallVector Blocks; + SmallVector DeferredOutlines; for (OutlineInfo &OI : OutlineInfos) { + // Skip functions that have not finalized yet; may happen with nested + // function generation. + if (Fn && OI.getFunction() != Fn) { + DeferredOutlines.push_back(OI); + continue; + } + ParallelRegionBlockSet.clear(); Blocks.clear(); OI.collectBlocks(ParallelRegionBlockSet, Blocks); - Function *OuterFn = OI.EntryBB->getParent(); + Function *OuterFn = OI.getFunction(); CodeExtractorAnalysisCache CEAC(*OuterFn); CodeExtractor Extractor(Blocks, /* DominatorTree */ nullptr, /* AggregateArgs */ false, @@ -199,8 +207,12 @@ OI.PostOutlineCB(*OutlinedFn); } - // Allow finalize to be called multiple times. - OutlineInfos.clear(); + // Remove work items that have been completed. + OutlineInfos = std::move(DeferredOutlines); +} + +OpenMPIRBuilder::~OpenMPIRBuilder() { + assert(OutlineInfos.empty() && "There must be no outstanding outlinings"); } Value *OpenMPIRBuilder::getOrCreateIdent(Constant *SrcLocStr, @@ -1164,6 +1176,13 @@ return CLI; } +CanonicalLoopInfo *OpenMPIRBuilder::createWorkshareLoop( + const LocationDescription &Loc, CanonicalLoopInfo *CLI, + InsertPointTy AllocaIP, bool NeedsBarrier) { + // Currently only supports static schedules. + return createStaticWorkshareLoop(Loc, CLI, AllocaIP, NeedsBarrier); +} + /// Make \p Source branch to \p Target. /// /// Handles two situations: diff --git a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp --- a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp +++ b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp @@ -794,7 +794,8 @@ BranchInst::Create(AfterBB, AfterIP.getBlock()); // Perform the actual outlining. - OMPInfoCache.OMPBuilder.finalize(/* AllowExtractorSinking */ true); + OMPInfoCache.OMPBuilder.finalize(OriginalFn, + /* AllowExtractorSinking */ true); Function *OutlinedFn = MergableCIs.front()->getCaller();