update comments
Created using spr 1.3.6
This commit is contained in:
commit
fd9ca0bab8
@ -6,7 +6,7 @@ add_subdirectory(support)
|
||||
|
||||
# Configure the Features.inc file.
|
||||
if (NOT DEFINED CLANGD_BUILD_XPC)
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
|
||||
set(CLANGD_BUILD_XPC_DEFAULT ON)
|
||||
else ()
|
||||
set(CLANGD_BUILD_XPC_DEFAULT OFF)
|
||||
@ -193,7 +193,7 @@ if(CLANGD_TIDY_CHECKS)
|
||||
endif()
|
||||
|
||||
add_subdirectory(refactor/tweaks)
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
|
||||
# FIXME: Make fuzzer not use linux-specific APIs, build it everywhere.
|
||||
add_subdirectory(fuzzer)
|
||||
endif()
|
||||
|
@ -731,6 +731,12 @@ TEST_F(TargetDeclTest, BuiltinTemplates) {
|
||||
using type_pack_element = [[__type_pack_element]]<N, Pack...>;
|
||||
)cpp";
|
||||
EXPECT_DECLS("TemplateSpecializationTypeLoc", );
|
||||
|
||||
Code = R"cpp(
|
||||
template <template <class...> class Templ, class... Types>
|
||||
using dedup_types = Templ<[[__builtin_dedup_pack]]<Types...>...>;
|
||||
)cpp";
|
||||
EXPECT_DECLS("TemplateSpecializationTypeLoc", );
|
||||
}
|
||||
|
||||
TEST_F(TargetDeclTest, MemberOfTemplate) {
|
||||
|
@ -35,7 +35,7 @@ if(WIN32)
|
||||
endif()
|
||||
|
||||
# The Python FFI interface is broken on AIX: https://bugs.python.org/issue38628.
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
set(RUN_PYTHON_TESTS FALSE)
|
||||
endif()
|
||||
|
||||
|
@ -1810,6 +1810,37 @@ __make_integer_seq
|
||||
|
||||
This alias returns ``IntSeq`` instantiated with ``IntSeqT = T``and ``Ints`` being the pack ``0, ..., N - 1``.
|
||||
|
||||
__builtin_dedup_pack
|
||||
--------------------
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
template <class... Ts>
|
||||
using __builtin_dedup_pack = ...;
|
||||
|
||||
This alias takes a template parameter pack ``Ts`` and produces a new unexpanded pack containing the unique types
|
||||
from ``Ts``, with the order of the first occurrence of each type preserved.
|
||||
It is useful in template metaprogramming to normalize type lists.
|
||||
|
||||
The resulting pack can be expanded in contexts like template argument lists or base specifiers.
|
||||
|
||||
**Example of Use**:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
template <typename...> struct TypeList;
|
||||
|
||||
// The resulting type is TypeList<int, double, char>
|
||||
template <typename ...ExtraTypes>
|
||||
using MyTypeList = TypeList<__builtin_dedup_pack<int, double, int, char, double, ExtraTypes...>...>;
|
||||
|
||||
**Limitations**:
|
||||
|
||||
* This builtin can only be used inside a template.
|
||||
* The resulting pack is currently only supported for expansion in template argument lists and base specifiers.
|
||||
* This builtin cannot be assigned to a template template parameter.
|
||||
|
||||
|
||||
Type Trait Primitives
|
||||
=====================
|
||||
|
||||
|
@ -145,6 +145,22 @@ Non-comprehensive list of changes in this release
|
||||
correct method to check for these features is to test for the ``__PTRAUTH__``
|
||||
macro.
|
||||
|
||||
- Added a new builtin, ``__builtin_dedup_pack``, to remove duplicate types from a parameter pack.
|
||||
This feature is particularly useful in template metaprogramming for normalizing type lists.
|
||||
The builtin produces a new, unexpanded parameter pack that can be used in contexts like template
|
||||
argument lists or base specifiers.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
template <typename...> struct TypeList;
|
||||
|
||||
// The resulting type is TypeList<int, double, char>
|
||||
using MyTypeList = TypeList<__builtin_dedup_pack<int, double, int, char, double>...>;
|
||||
|
||||
Currently, the use of ``__builtin_dedup_pack`` is limited to template arguments and base
|
||||
specifiers, it also must be used within a template context.
|
||||
|
||||
|
||||
New Compiler Flags
|
||||
------------------
|
||||
- New option ``-fno-sanitize-annotate-debug-info-traps`` added to disable emitting trap reasons into the debug info when compiling with trapping UBSan (e.g. ``-fsanitize-trap=undefined``).
|
||||
@ -329,6 +345,9 @@ AST Matchers
|
||||
- Add a boolean member ``IgnoreSystemHeaders`` to ``MatchFinderOptions``. This
|
||||
allows it to ignore nodes in system headers when traversing the AST.
|
||||
|
||||
- ``hasConditionVariableStatement`` now supports ``for`` loop, ``while`` loop
|
||||
and ``switch`` statements.
|
||||
|
||||
clang-format
|
||||
------------
|
||||
- Add ``SpaceInEmptyBraces`` option and set it to ``Always`` for WebKit style.
|
||||
|
@ -230,6 +230,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
SubstTemplateTypeParmTypes;
|
||||
mutable llvm::FoldingSet<SubstTemplateTypeParmPackType>
|
||||
SubstTemplateTypeParmPackTypes;
|
||||
mutable llvm::FoldingSet<SubstBuiltinTemplatePackType>
|
||||
SubstBuiltinTemplatePackTypes;
|
||||
mutable llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&>
|
||||
TemplateSpecializationTypes;
|
||||
mutable llvm::FoldingSet<ParenType> ParenTypes{GeneralTypesLog2InitSize};
|
||||
@ -1895,6 +1897,7 @@ public:
|
||||
QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
|
||||
unsigned Index, bool Final,
|
||||
const TemplateArgument &ArgPack);
|
||||
QualType getSubstBuiltinTemplatePack(const TemplateArgument &ArgPack);
|
||||
|
||||
QualType
|
||||
getTemplateTypeParmType(unsigned Depth, unsigned Index,
|
||||
|
@ -1796,7 +1796,10 @@ public:
|
||||
}
|
||||
|
||||
BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; }
|
||||
|
||||
bool isPackProducingBuiltinTemplate() const;
|
||||
};
|
||||
bool isPackProducingBuiltinTemplateName(TemplateName N);
|
||||
|
||||
/// Provides information about an explicit instantiation of a variable or class
|
||||
/// template.
|
||||
|
@ -492,6 +492,8 @@ private:
|
||||
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
|
||||
unsigned Count);
|
||||
bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
|
||||
bool TraverseSubstPackTypeHelper(SubstPackType *T);
|
||||
bool TraverseSubstPackTypeLocHelper(SubstPackTypeLoc TL);
|
||||
bool TraverseRecordHelper(RecordDecl *D);
|
||||
bool TraverseCXXRecordHelper(CXXRecordDecl *D);
|
||||
bool TraverseDeclaratorHelper(DeclaratorDecl *D);
|
||||
@ -1138,9 +1140,10 @@ DEF_TRAVERSE_TYPE(TemplateTypeParmType, {})
|
||||
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {
|
||||
TRY_TO(TraverseType(T->getReplacementType()));
|
||||
})
|
||||
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {
|
||||
TRY_TO(TraverseTemplateArgument(T->getArgumentPack()));
|
||||
})
|
||||
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType,
|
||||
{ TRY_TO(TraverseSubstPackTypeHelper(T)); })
|
||||
DEF_TRAVERSE_TYPE(SubstBuiltinTemplatePackType,
|
||||
{ TRY_TO(TraverseSubstPackTypeHelper(T)); })
|
||||
|
||||
DEF_TRAVERSE_TYPE(AttributedType,
|
||||
{ TRY_TO(TraverseType(T->getModifiedType())); })
|
||||
@ -1481,9 +1484,26 @@ DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {})
|
||||
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {
|
||||
TRY_TO(TraverseType(TL.getTypePtr()->getReplacementType()));
|
||||
})
|
||||
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseSubstPackTypeLocHelper(
|
||||
SubstPackTypeLoc TL) {
|
||||
TRY_TO(TraverseTemplateArgument(TL.getTypePtr()->getArgumentPack()));
|
||||
})
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseSubstPackTypeHelper(
|
||||
SubstPackType *T) {
|
||||
TRY_TO(TraverseTemplateArgument(T->getArgumentPack()));
|
||||
return true;
|
||||
}
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType,
|
||||
{ TRY_TO(TraverseSubstPackTypeLocHelper(TL)); })
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(SubstBuiltinTemplatePackType,
|
||||
{ TRY_TO(TraverseSubstPackTypeLocHelper(TL)); })
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(ParenType, { TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); })
|
||||
|
||||
|
@ -2210,20 +2210,24 @@ protected:
|
||||
unsigned PackIndex : 15;
|
||||
};
|
||||
|
||||
class SubstTemplateTypeParmPackTypeBitfields {
|
||||
class SubstPackTypeBitfields {
|
||||
friend class SubstPackType;
|
||||
friend class SubstTemplateTypeParmPackType;
|
||||
|
||||
LLVM_PREFERRED_TYPE(TypeBitfields)
|
||||
unsigned : NumTypeBits;
|
||||
|
||||
// The index of the template parameter this substitution represents.
|
||||
unsigned Index : 16;
|
||||
|
||||
/// The number of template arguments in \c Arguments, which is
|
||||
/// expected to be able to hold at least 1024 according to [implimits].
|
||||
/// However as this limit is somewhat easy to hit with template
|
||||
/// metaprogramming we'd prefer to keep it as large as possible.
|
||||
unsigned NumArgs : 16;
|
||||
|
||||
// The index of the template parameter this substitution represents.
|
||||
// Only used by SubstTemplateTypeParmPackType. We keep it in the same
|
||||
// class to avoid dealing with complexities of bitfields that go over
|
||||
// the size of `unsigned`.
|
||||
unsigned SubstTemplTypeParmPackIndex : 16;
|
||||
};
|
||||
|
||||
class TemplateSpecializationTypeBitfields {
|
||||
@ -2340,7 +2344,7 @@ protected:
|
||||
VectorTypeBitfields VectorTypeBits;
|
||||
TemplateTypeParmTypeBitfields TemplateTypeParmTypeBits;
|
||||
SubstTemplateTypeParmTypeBitfields SubstTemplateTypeParmTypeBits;
|
||||
SubstTemplateTypeParmPackTypeBitfields SubstTemplateTypeParmPackTypeBits;
|
||||
SubstPackTypeBitfields SubstPackTypeBits;
|
||||
TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits;
|
||||
DependentTemplateSpecializationTypeBitfields
|
||||
DependentTemplateSpecializationTypeBits;
|
||||
@ -6992,6 +6996,56 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents the result of substituting a set of types as a template argument
|
||||
/// that needs to be expanded later.
|
||||
///
|
||||
/// These types are always dependent and produced depending on the situations:
|
||||
/// - SubstTemplateTypeParmPack is an expansion that had to be delayed,
|
||||
/// - SubstBuiltinTemplatePackType is an expansion from a builtin.
|
||||
class SubstPackType : public Type, public llvm::FoldingSetNode {
|
||||
friend class ASTContext;
|
||||
|
||||
/// A pointer to the set of template arguments that this
|
||||
/// parameter pack is instantiated with.
|
||||
const TemplateArgument *Arguments;
|
||||
|
||||
protected:
|
||||
SubstPackType(TypeClass Derived, QualType Canon,
|
||||
const TemplateArgument &ArgPack);
|
||||
|
||||
public:
|
||||
unsigned getNumArgs() const { return SubstPackTypeBits.NumArgs; }
|
||||
|
||||
TemplateArgument getArgumentPack() const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
const TemplateArgument &ArgPack);
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == SubstTemplateTypeParmPack ||
|
||||
T->getTypeClass() == SubstBuiltinTemplatePack;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents the result of substituting a builtin template as a pack.
|
||||
class SubstBuiltinTemplatePackType : public SubstPackType {
|
||||
friend class ASTContext;
|
||||
|
||||
SubstBuiltinTemplatePackType(QualType Canon, const TemplateArgument &ArgPack);
|
||||
|
||||
public:
|
||||
bool isSugared() const { return false; }
|
||||
QualType desugar() const { return QualType(this, 0); }
|
||||
|
||||
/// Mark that we reuse the Profile. We do not introduce new fields.
|
||||
using SubstPackType::Profile;
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == SubstBuiltinTemplatePack;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents the result of substituting a set of types for a template
|
||||
/// type parameter pack.
|
||||
///
|
||||
@ -7004,7 +7058,7 @@ public:
|
||||
/// that pack expansion (e.g., when all template parameters have corresponding
|
||||
/// arguments), this type will be replaced with the \c SubstTemplateTypeParmType
|
||||
/// at the current pack substitution index.
|
||||
class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
|
||||
class SubstTemplateTypeParmPackType : public SubstPackType {
|
||||
friend class ASTContext;
|
||||
|
||||
/// A pointer to the set of template arguments that this
|
||||
@ -7030,21 +7084,17 @@ public:
|
||||
|
||||
/// Returns the index of the replaced parameter in the associated declaration.
|
||||
/// This should match the result of `getReplacedParameter()->getIndex()`.
|
||||
unsigned getIndex() const { return SubstTemplateTypeParmPackTypeBits.Index; }
|
||||
unsigned getIndex() const {
|
||||
return SubstPackTypeBits.SubstTemplTypeParmPackIndex;
|
||||
}
|
||||
|
||||
// This substitution will be Final, which means the substitution will be fully
|
||||
// sugared: it doesn't need to be resugared later.
|
||||
bool getFinal() const;
|
||||
|
||||
unsigned getNumArgs() const {
|
||||
return SubstTemplateTypeParmPackTypeBits.NumArgs;
|
||||
}
|
||||
|
||||
bool isSugared() const { return false; }
|
||||
QualType desugar() const { return QualType(this, 0); }
|
||||
|
||||
TemplateArgument getArgumentPack() const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, const Decl *AssociatedDecl,
|
||||
unsigned Index, bool Final,
|
||||
@ -7279,9 +7329,7 @@ public:
|
||||
TemplateSpecializationTypeBits.NumArgs};
|
||||
}
|
||||
|
||||
bool isSugared() const {
|
||||
return !isDependentType() || isCurrentInstantiation() || isTypeAlias();
|
||||
}
|
||||
bool isSugared() const;
|
||||
|
||||
QualType desugar() const {
|
||||
return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal();
|
||||
|
@ -989,12 +989,22 @@ class SubstTemplateTypeParmTypeLoc :
|
||||
SubstTemplateTypeParmType> {
|
||||
};
|
||||
|
||||
/// Wrapper for substituted template type parameters.
|
||||
class SubstTemplateTypeParmPackTypeLoc :
|
||||
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
SubstTemplateTypeParmPackTypeLoc,
|
||||
SubstTemplateTypeParmPackType> {
|
||||
};
|
||||
/// Abstract type representing delayed type pack expansions.
|
||||
class SubstPackTypeLoc
|
||||
: public InheritingConcreteTypeLoc<TypeSpecTypeLoc, SubstPackTypeLoc,
|
||||
SubstPackType> {};
|
||||
|
||||
/// Wrapper for substituted template type parameters.
|
||||
class SubstTemplateTypeParmPackTypeLoc
|
||||
: public InheritingConcreteTypeLoc<SubstPackTypeLoc,
|
||||
SubstTemplateTypeParmPackTypeLoc,
|
||||
SubstTemplateTypeParmPackType> {};
|
||||
|
||||
/// Wrapper for substituted template type parameters.
|
||||
class SubstBuiltinTemplatePackTypeLoc
|
||||
: public InheritingConcreteTypeLoc<SubstPackTypeLoc,
|
||||
SubstBuiltinTemplatePackTypeLoc,
|
||||
SubstBuiltinTemplatePackType> {};
|
||||
|
||||
struct AttributedLocInfo {
|
||||
const Attr *TypeAttr;
|
||||
|
@ -820,6 +820,12 @@ let Class = PackExpansionType in {
|
||||
}]>;
|
||||
}
|
||||
|
||||
let Class = SubstPackType in {
|
||||
def : Property<"replacementPack", TemplateArgument> {
|
||||
let Read = [{ node->getArgumentPack() }];
|
||||
}
|
||||
}
|
||||
|
||||
let Class = SubstTemplateTypeParmPackType in {
|
||||
def : Property<"associatedDecl", DeclRef> {
|
||||
let Read = [{ node->getAssociatedDecl() }];
|
||||
@ -827,12 +833,7 @@ let Class = SubstTemplateTypeParmPackType in {
|
||||
def : Property<"Index", UInt32> {
|
||||
let Read = [{ node->getIndex() }];
|
||||
}
|
||||
def : Property<"Final", Bool> {
|
||||
let Read = [{ node->getFinal() }];
|
||||
}
|
||||
def : Property<"replacementPack", TemplateArgument> {
|
||||
let Read = [{ node->getArgumentPack() }];
|
||||
}
|
||||
def : Property<"Final", Bool> { let Read = [{ node->getFinal() }]; }
|
||||
|
||||
def : Creator<[{
|
||||
return ctx.getSubstTemplateTypeParmPackType(
|
||||
@ -840,6 +841,12 @@ let Class = SubstTemplateTypeParmPackType in {
|
||||
}]>;
|
||||
}
|
||||
|
||||
let Class = SubstBuiltinTemplatePackType in {
|
||||
def : Creator<[{
|
||||
return ctx.getSubstBuiltinTemplatePack(replacementPack);
|
||||
}]>;
|
||||
}
|
||||
|
||||
let Class = BuiltinType in {
|
||||
def : Property<"kind", BuiltinTypeKind> {
|
||||
let Read = [{ node->getKind() }];
|
||||
|
@ -5661,8 +5661,8 @@ AST_POLYMORPHIC_MATCHER_P(hasInitStatement,
|
||||
return Init != nullptr && InnerMatcher.matches(*Init, Finder, Builder);
|
||||
}
|
||||
|
||||
/// Matches the condition expression of an if statement, for loop,
|
||||
/// switch statement or conditional operator.
|
||||
/// Matches the condition expression of an if statement, for loop, while loop,
|
||||
/// do-while loop, switch statement or conditional operator.
|
||||
///
|
||||
/// Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
|
||||
/// \code
|
||||
@ -5747,16 +5747,21 @@ AST_MATCHER_P(Decl, declaresSameEntityAsBoundNode, std::string, ID) {
|
||||
});
|
||||
}
|
||||
|
||||
/// Matches the condition variable statement in an if statement.
|
||||
/// Matches the condition variable statement in an if statement, for loop,
|
||||
/// while loop or switch statement.
|
||||
///
|
||||
/// Given
|
||||
/// \code
|
||||
/// if (A* a = GetAPointer()) {}
|
||||
/// for (; A* a = GetAPointer(); ) {}
|
||||
/// \endcode
|
||||
/// hasConditionVariableStatement(...)
|
||||
/// matches 'A* a = GetAPointer()'.
|
||||
AST_MATCHER_P(IfStmt, hasConditionVariableStatement,
|
||||
internal::Matcher<DeclStmt>, InnerMatcher) {
|
||||
/// matches both 'A* a = GetAPointer()'.
|
||||
AST_POLYMORPHIC_MATCHER_P(hasConditionVariableStatement,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(IfStmt, ForStmt,
|
||||
WhileStmt,
|
||||
SwitchStmt),
|
||||
internal::Matcher<DeclStmt>, InnerMatcher) {
|
||||
const DeclStmt* const DeclarationStatement =
|
||||
Node.getConditionVariableDeclStmt();
|
||||
return DeclarationStatement != nullptr &&
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include <cassert>
|
||||
|
||||
@ -152,6 +153,11 @@ public:
|
||||
return {SyntheticFields.begin(), SyntheticFields.end()};
|
||||
}
|
||||
|
||||
/// Add a synthetic field, if none by that name is already present.
|
||||
void addSyntheticField(llvm::StringRef Name, StorageLocation &Loc) {
|
||||
SyntheticFields.insert({Name, &Loc});
|
||||
}
|
||||
|
||||
/// Changes the child storage location for a field `D` of reference type.
|
||||
/// All other fields cannot change their storage location and always retain
|
||||
/// the storage location passed to the `RecordStorageLocation` constructor.
|
||||
@ -164,6 +170,11 @@ public:
|
||||
Children[&D] = Loc;
|
||||
}
|
||||
|
||||
/// Add a child storage location for a field `D`, if not already present.
|
||||
void addChild(const ValueDecl &D, StorageLocation *Loc) {
|
||||
Children.insert({&D, Loc});
|
||||
}
|
||||
|
||||
llvm::iterator_range<FieldToLoc::const_iterator> children() const {
|
||||
return {Children.begin(), Children.end()};
|
||||
}
|
||||
|
@ -1632,6 +1632,13 @@ def DeviceKernel : DeclOrTypeAttr {
|
||||
}];
|
||||
}
|
||||
|
||||
def SYCLExternal : InheritableAttr {
|
||||
let Spellings = [CXX11<"clang", "sycl_external">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let LangOpts = [SYCLHost, SYCLDevice];
|
||||
let Documentation = [SYCLExternalDocs];
|
||||
}
|
||||
|
||||
def SYCLKernelEntryPoint : InheritableAttr {
|
||||
let Spellings = [CXX11<"clang", "sycl_kernel_entry_point">];
|
||||
let Args = [
|
||||
|
@ -476,6 +476,47 @@ The SYCL kernel in the previous code sample meets these expectations.
|
||||
}];
|
||||
}
|
||||
|
||||
def SYCLExternalDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Heading = "sycl_external";
|
||||
let Content = [{
|
||||
The ``sycl_external`` attribute indicates that a function defined in another
|
||||
translation unit may be called by a device function defined in the current
|
||||
translation unit or, if defined in the current translation unit, the function
|
||||
may be called by device functions defined in other translation units.
|
||||
The attribute is intended for use in the implementation of the ``SYCL_EXTERNAL``
|
||||
macro as specified in section 5.10.1, "SYCL functions and member functions
|
||||
linkage", of the SYCL 2020 specification.
|
||||
|
||||
The attribute only appertains to functions and only those that meet the
|
||||
following requirements:
|
||||
|
||||
* Has external linkage
|
||||
* Is not explicitly defined as deleted (the function may be an explicitly
|
||||
defaulted function that is defined as deleted)
|
||||
|
||||
The attribute shall be present on the first declaration of a function and
|
||||
may optionally be present on subsequent declarations.
|
||||
|
||||
When compiling for a SYCL device target that does not support the generic
|
||||
address space, the function shall not specify a raw pointer or reference type
|
||||
as the return type or as a parameter type.
|
||||
See section 5.10, "SYCL offline linking", of the SYCL 2020 specification.
|
||||
The following examples demonstrate the use of this attribute:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
[[clang::sycl_external]] void Foo(); // Ok.
|
||||
|
||||
[[clang::sycl_external]] void Bar() { /* ... */ } // Ok.
|
||||
|
||||
[[clang::sycl_external]] extern void Baz(); // Ok.
|
||||
|
||||
[[clang::sycl_external]] static void Quux() { /* ... */ } // error: Quux() has internal linkage.
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
def SYCLKernelEntryPointDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
|
@ -62,3 +62,7 @@ def __builtin_common_type : CPlusPlusBuiltinTemplate<
|
||||
// typename ...Operands>
|
||||
def __hlsl_spirv_type : HLSLBuiltinTemplate<
|
||||
[Uint32T, Uint32T, Uint32T, Class<"Operands", /*is_variadic=*/1>]>;
|
||||
|
||||
// template <class ...Args>
|
||||
def __builtin_dedup_pack
|
||||
: CPlusPlusBuiltinTemplate<[Class<"Args", /*is_variadic=*/1>]>;
|
||||
|
@ -652,6 +652,7 @@ def NonNull : DiagGroup<"nonnull">;
|
||||
def NonPODVarargs : DiagGroup<"non-pod-varargs">;
|
||||
def ClassVarargs : DiagGroup<"class-varargs", [NonPODVarargs]>;
|
||||
def : DiagGroup<"nonportable-cfstrings">;
|
||||
def NonPortableSYCL : DiagGroup<"nonportable-sycl">;
|
||||
def NonVirtualDtor : DiagGroup<"non-virtual-dtor">;
|
||||
def GNUNullPointerArithmetic : DiagGroup<"gnu-null-pointer-arithmetic">;
|
||||
def NullPointerArithmetic
|
||||
|
@ -6074,6 +6074,13 @@ def warn_cxx23_pack_indexing : Warning<
|
||||
def err_pack_outside_template : Error<
|
||||
"pack declaration outside of template">;
|
||||
|
||||
def err_builtin_pack_outside_template
|
||||
: Error<"%0 cannot be used outside of template">;
|
||||
|
||||
def err_unsupported_builtin_template_pack_expansion
|
||||
: Error<"expansions of %0 are not supported here. Only expansions in "
|
||||
"template arguments and class bases are supported">;
|
||||
|
||||
def err_fold_expression_packs_both_sides : Error<
|
||||
"binary fold expression has unexpanded parameter packs in both operands">;
|
||||
def err_fold_expression_empty : Error<
|
||||
@ -12951,6 +12958,17 @@ def err_sycl_special_type_num_init_method : Error<
|
||||
"types with 'sycl_special_class' attribute must have one and only one '__init' "
|
||||
"method defined">;
|
||||
|
||||
// SYCL external attribute diagnostics
|
||||
def err_sycl_external_invalid_linkage : Error<
|
||||
"%0 can only be applied to functions with external linkage">;
|
||||
def err_sycl_external_invalid_main : Error<
|
||||
"%0 cannot be applied to the 'main' function">;
|
||||
def err_sycl_external_invalid_deleted_function : Error<
|
||||
"%0 cannot be applied to an explicitly deleted function">;
|
||||
def warn_sycl_external_missing_on_first_decl : Warning<
|
||||
"%0 attribute does not appear on the first declaration">,
|
||||
InGroup<NonPortableSYCL>;
|
||||
|
||||
// SYCL kernel entry point diagnostics
|
||||
def err_sycl_entry_point_invalid : Error<
|
||||
"the %0 attribute cannot be applied to a"
|
||||
@ -12965,7 +12983,7 @@ def err_sycl_kernel_name_conflict : Error<
|
||||
"the %0 kernel name argument conflicts with a previous declaration">;
|
||||
def warn_sycl_kernel_name_not_a_class_type : Warning<
|
||||
"%0 is not a valid SYCL kernel name type; a non-union class type is required">,
|
||||
InGroup<DiagGroup<"nonportable-sycl">>, DefaultError;
|
||||
InGroup<NonPortableSYCL>, DefaultError;
|
||||
def warn_sycl_entry_point_redundant_declaration : Warning<
|
||||
"redundant %0 attribute">, InGroup<RedundantAttribute>;
|
||||
def err_sycl_entry_point_after_definition : Error<
|
||||
|
@ -97,7 +97,9 @@ def HLSLAttributedResourceType : TypeNode<Type>;
|
||||
def HLSLInlineSpirvType : TypeNode<Type>;
|
||||
def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent, LeafType;
|
||||
def SubstTemplateTypeParmType : TypeNode<Type>, NeverCanonical;
|
||||
def SubstTemplateTypeParmPackType : TypeNode<Type>, AlwaysDependent;
|
||||
def SubstPackType : TypeNode<Type, 1>;
|
||||
def SubstTemplateTypeParmPackType : TypeNode<SubstPackType>, AlwaysDependent;
|
||||
def SubstBuiltinTemplatePackType : TypeNode<SubstPackType>, AlwaysDependent;
|
||||
def TemplateSpecializationType : TypeNode<Type>, NeverCanonicalUnlessDependent;
|
||||
def DeducedType : TypeNode<Type, 1>;
|
||||
def AutoType : TypeNode<DeducedType>;
|
||||
|
@ -228,7 +228,9 @@ void threadSafetyCleanup(BeforeSet *Cache);
|
||||
|
||||
// FIXME: No way to easily map from TemplateTypeParmTypes to
|
||||
// TemplateTypeParmDecls, so we have this horrible PointerUnion.
|
||||
typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *>,
|
||||
typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *,
|
||||
const TemplateSpecializationType *,
|
||||
const SubstBuiltinTemplatePackType *>,
|
||||
SourceLocation>
|
||||
UnexpandedParameterPack;
|
||||
|
||||
@ -13497,8 +13499,6 @@ public:
|
||||
~ArgPackSubstIndexRAII() { Self.ArgPackSubstIndex = OldSubstIndex; }
|
||||
};
|
||||
|
||||
friend class ArgumentPackSubstitutionRAII;
|
||||
|
||||
void pushCodeSynthesisContext(CodeSynthesisContext Ctx);
|
||||
void popCodeSynthesisContext();
|
||||
|
||||
@ -14428,6 +14428,15 @@ public:
|
||||
static void collectUnexpandedParameterPacks(
|
||||
Expr *E, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
|
||||
|
||||
/// Invoked when parsing a template argument.
|
||||
///
|
||||
/// \param Arg the template argument, which may already be invalid.
|
||||
///
|
||||
/// If it is followed by ellipsis, this function is called before
|
||||
/// `ActOnPackExpansion`.
|
||||
ParsedTemplateArgument
|
||||
ActOnTemplateTemplateArgument(const ParsedTemplateArgument &Arg);
|
||||
|
||||
/// Invoked when parsing a template argument followed by an
|
||||
/// ellipsis, which creates a pack expansion.
|
||||
///
|
||||
@ -14515,7 +14524,8 @@ public:
|
||||
bool CheckParameterPacksForExpansion(
|
||||
SourceLocation EllipsisLoc, SourceRange PatternRange,
|
||||
ArrayRef<UnexpandedParameterPack> Unexpanded,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
bool FailOnPackProducingTemplates, bool &ShouldExpand,
|
||||
bool &RetainExpansion, UnsignedOrNone &NumExpansions);
|
||||
|
||||
/// Determine the number of arguments in the given pack expansion
|
||||
|
@ -71,12 +71,17 @@ inline std::pair<unsigned, unsigned> getDepthAndIndex(const NamedDecl *ND) {
|
||||
}
|
||||
|
||||
/// Retrieve the depth and index of an unexpanded parameter pack.
|
||||
inline std::pair<unsigned, unsigned>
|
||||
/// Returns nullopt when the unexpanded packs do not correspond to template
|
||||
/// parameters, e.g. __builtin_dedup_types.
|
||||
inline std::optional<std::pair<unsigned, unsigned>>
|
||||
getDepthAndIndex(UnexpandedParameterPack UPP) {
|
||||
if (const auto *TTP = dyn_cast<const TemplateTypeParmType *>(UPP.first))
|
||||
return std::make_pair(TTP->getDepth(), TTP->getIndex());
|
||||
|
||||
return getDepthAndIndex(cast<NamedDecl *>(UPP.first));
|
||||
if (isa<NamedDecl *>(UPP.first))
|
||||
return getDepthAndIndex(cast<NamedDecl *>(UPP.first));
|
||||
assert((isa<const TemplateSpecializationType *,
|
||||
const SubstBuiltinTemplatePackType *>(UPP.first)));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
class TypoCorrectionConsumer : public VisibleDeclConsumer {
|
||||
|
@ -64,6 +64,7 @@ public:
|
||||
void handleKernelAttr(Decl *D, const ParsedAttr &AL);
|
||||
void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL);
|
||||
|
||||
void CheckSYCLExternalFunctionDecl(FunctionDecl *FD);
|
||||
void CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD);
|
||||
StmtResult BuildSYCLKernelCallStmt(FunctionDecl *FD, CompoundStmt *Body);
|
||||
};
|
||||
|
@ -69,5 +69,6 @@ TYPE_BIT_CODE(ArrayParameter, ARRAY_PARAMETER, 58)
|
||||
TYPE_BIT_CODE(HLSLAttributedResource, HLSLRESOURCE_ATTRIBUTED, 59)
|
||||
TYPE_BIT_CODE(HLSLInlineSpirv, HLSL_INLINE_SPIRV, 60)
|
||||
TYPE_BIT_CODE(PredefinedSugar, PREDEFINED_SUGAR, 61)
|
||||
TYPE_BIT_CODE(SubstBuiltinTemplatePack, SUBST_BUILTIN_TEMPLATE_PACK, 62)
|
||||
|
||||
#undef TYPE_BIT_CODE
|
||||
|
@ -4306,6 +4306,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
|
||||
case Type::DependentTemplateSpecialization:
|
||||
case Type::TemplateTypeParm:
|
||||
case Type::SubstTemplateTypeParmPack:
|
||||
case Type::SubstBuiltinTemplatePack:
|
||||
case Type::Auto:
|
||||
case Type::DeducedTemplateSpecialization:
|
||||
case Type::PackExpansion:
|
||||
@ -5848,7 +5849,6 @@ QualType ASTContext::getSubstTemplateTypeParmType(QualType Replacement,
|
||||
return QualType(SubstParm, 0);
|
||||
}
|
||||
|
||||
/// Retrieve a
|
||||
QualType
|
||||
ASTContext::getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
|
||||
unsigned Index, bool Final,
|
||||
@ -5887,6 +5887,34 @@ ASTContext::getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
|
||||
return QualType(SubstParm, 0);
|
||||
}
|
||||
|
||||
QualType
|
||||
ASTContext::getSubstBuiltinTemplatePack(const TemplateArgument &ArgPack) {
|
||||
assert(llvm::all_of(ArgPack.pack_elements(),
|
||||
[](const auto &P) {
|
||||
return P.getKind() == TemplateArgument::Type;
|
||||
}) &&
|
||||
"Pack contains a non-type");
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
SubstBuiltinTemplatePackType::Profile(ID, ArgPack);
|
||||
|
||||
void *InsertPos = nullptr;
|
||||
if (auto *T =
|
||||
SubstBuiltinTemplatePackTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(T, 0);
|
||||
|
||||
QualType Canon;
|
||||
TemplateArgument CanonArgPack = getCanonicalTemplateArgument(ArgPack);
|
||||
if (!CanonArgPack.structurallyEquals(ArgPack))
|
||||
Canon = getSubstBuiltinTemplatePack(CanonArgPack);
|
||||
|
||||
auto *PackType = new (*this, alignof(SubstBuiltinTemplatePackType))
|
||||
SubstBuiltinTemplatePackType(Canon, ArgPack);
|
||||
Types.push_back(PackType);
|
||||
SubstBuiltinTemplatePackTypes.InsertNode(PackType, InsertPos);
|
||||
return QualType(PackType, 0);
|
||||
}
|
||||
|
||||
/// Retrieve the template type parameter type for a template
|
||||
/// parameter or parameter pack with the given depth, index, and (optionally)
|
||||
/// name.
|
||||
@ -13099,6 +13127,14 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
|
||||
if (D->hasAttr<WeakRefAttr>())
|
||||
return false;
|
||||
|
||||
// SYCL device compilation requires that functions defined with the
|
||||
// sycl_kernel_entry_point or sycl_external attributes be emitted. All
|
||||
// other entities are emitted only if they are used by a function
|
||||
// defined with one of those attributes.
|
||||
if (LangOpts.SYCLIsDevice)
|
||||
return isa<FunctionDecl>(D) && (D->hasAttr<SYCLKernelEntryPointAttr>() ||
|
||||
D->hasAttr<SYCLExternalAttr>());
|
||||
|
||||
// Aliases and used decls are required.
|
||||
if (D->hasAttr<AliasAttr>() || D->hasAttr<UsedAttr>())
|
||||
return true;
|
||||
@ -13108,15 +13144,6 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
|
||||
if (!FD->doesThisDeclarationHaveABody())
|
||||
return FD->doesDeclarationForceExternallyVisibleDefinition();
|
||||
|
||||
// Function definitions with the sycl_kernel_entry_point attribute are
|
||||
// required during device compilation so that SYCL kernel caller offload
|
||||
// entry points are emitted.
|
||||
if (LangOpts.SYCLIsDevice && FD->hasAttr<SYCLKernelEntryPointAttr>())
|
||||
return true;
|
||||
|
||||
// FIXME: Functions declared with SYCL_EXTERNAL are required during
|
||||
// device compilation.
|
||||
|
||||
// Constructors and destructors are required.
|
||||
if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
|
||||
return true;
|
||||
@ -14045,6 +14072,7 @@ static QualType getCommonNonSugarTypeNode(const ASTContext &Ctx, const Type *X,
|
||||
SUGAR_FREE_TYPE(BitInt)
|
||||
SUGAR_FREE_TYPE(ObjCInterface)
|
||||
SUGAR_FREE_TYPE(SubstTemplateTypeParmPack)
|
||||
SUGAR_FREE_TYPE(SubstBuiltinTemplatePack)
|
||||
SUGAR_FREE_TYPE(UnresolvedUsing)
|
||||
SUGAR_FREE_TYPE(HLSLAttributedResource)
|
||||
SUGAR_FREE_TYPE(HLSLInlineSpirv)
|
||||
|
@ -1842,6 +1842,14 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType(
|
||||
*ReplacedOrErr, T->getIndex(), T->getFinal(), *ToArgumentPack);
|
||||
}
|
||||
|
||||
ExpectedType ASTNodeImporter::VisitSubstBuiltinTemplatePackType(
|
||||
const SubstBuiltinTemplatePackType *T) {
|
||||
Expected<TemplateArgument> ToArgumentPack = import(T->getArgumentPack());
|
||||
if (!ToArgumentPack)
|
||||
return ToArgumentPack.takeError();
|
||||
return Importer.getToContext().getSubstBuiltinTemplatePack(*ToArgumentPack);
|
||||
}
|
||||
|
||||
ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
|
||||
const TemplateSpecializationType *T) {
|
||||
auto ToTemplateOrErr = import(T->getTemplateName());
|
||||
|
@ -1337,6 +1337,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::SubstBuiltinTemplatePack: {
|
||||
const auto *Subst1 = cast<SubstBuiltinTemplatePackType>(T1);
|
||||
const auto *Subst2 = cast<SubstBuiltinTemplatePackType>(T2);
|
||||
if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(),
|
||||
Subst2->getArgumentPack()))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case Type::SubstTemplateTypeParmPack: {
|
||||
const auto *Subst1 = cast<SubstTemplateTypeParmPackType>(T1);
|
||||
const auto *Subst2 = cast<SubstTemplateTypeParmPackType>(T2);
|
||||
|
@ -1830,6 +1830,7 @@ static bool interp__builtin_elementwise_countzeroes(InterpState &S,
|
||||
assert(Call->getArg(1)->getType()->isVectorType() &&
|
||||
ASTCtx.hasSameUnqualifiedType(Call->getArg(0)->getType(),
|
||||
Call->getArg(1)->getType()));
|
||||
(void)ASTCtx;
|
||||
ZeroArg = S.Stk.pop<Pointer>();
|
||||
assert(ZeroArg.getFieldDesc()->isPrimitiveArray());
|
||||
}
|
||||
@ -2728,6 +2729,8 @@ static bool interp__builtin_elementwise_fma(InterpState &S, CodePtr OpPC,
|
||||
if (!Arg1Type->isVectorType()) {
|
||||
assert(!Arg2Type->isVectorType());
|
||||
assert(!Arg3Type->isVectorType());
|
||||
(void)Arg2Type;
|
||||
(void)Arg3Type;
|
||||
|
||||
const Floating &Z = S.Stk.pop<Floating>();
|
||||
const Floating &Y = S.Stk.pop<Floating>();
|
||||
@ -2753,6 +2756,7 @@ static bool interp__builtin_elementwise_fma(InterpState &S, CodePtr OpPC,
|
||||
assert(NumElems == Arg2Type->castAs<VectorType>()->getNumElements() &&
|
||||
NumElems == Arg3Type->castAs<VectorType>()->getNumElements());
|
||||
assert(ElemT->isRealFloatingType());
|
||||
(void)ElemT;
|
||||
|
||||
const Pointer &VZ = S.Stk.pop<Pointer>();
|
||||
const Pointer &VY = S.Stk.pop<Pointer>();
|
||||
|
@ -307,8 +307,9 @@ bool TemplateDecl::hasAssociatedConstraints() const {
|
||||
bool TemplateDecl::isTypeAlias() const {
|
||||
switch (getKind()) {
|
||||
case TemplateDecl::TypeAliasTemplate:
|
||||
case TemplateDecl::BuiltinTemplate:
|
||||
return true;
|
||||
case TemplateDecl::BuiltinTemplate:
|
||||
return !cast<BuiltinTemplateDecl>(this)->isPackProducingBuiltinTemplate();
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
@ -1598,6 +1599,16 @@ BuiltinTemplateDecl::BuiltinTemplateDecl(const ASTContext &C, DeclContext *DC,
|
||||
createBuiltinTemplateParameterList(C, DC, BTK)),
|
||||
BTK(BTK) {}
|
||||
|
||||
bool BuiltinTemplateDecl::isPackProducingBuiltinTemplate() const {
|
||||
return getBuiltinTemplateKind() == clang::BTK__builtin_dedup_pack;
|
||||
}
|
||||
|
||||
bool clang::isPackProducingBuiltinTemplateName(TemplateName N) {
|
||||
auto *T = dyn_cast_or_null<BuiltinTemplateDecl>(
|
||||
N.getAsTemplateDecl(/*IgnoreDeduced=*/true));
|
||||
return T && T->isPackProducingBuiltinTemplate();
|
||||
}
|
||||
|
||||
TemplateParamObjectDecl *TemplateParamObjectDecl::Create(const ASTContext &C,
|
||||
QualType T,
|
||||
const APValue &V) {
|
||||
|
@ -2444,6 +2444,13 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
|
||||
case Type::CountAttributed:
|
||||
llvm_unreachable("type is illegal as a nested name specifier");
|
||||
|
||||
case Type::SubstBuiltinTemplatePack:
|
||||
// FIXME: not clear how to mangle this!
|
||||
// template <class T...> class A {
|
||||
// template <class U...> void foo(__builtin_dedup_pack<T...>(*)(U) x...);
|
||||
// };
|
||||
Out << "_SUBSTBUILTINPACK_";
|
||||
break;
|
||||
case Type::SubstTemplateTypeParmPack:
|
||||
// FIXME: not clear how to mangle this!
|
||||
// template <class T...> class A {
|
||||
@ -3891,6 +3898,14 @@ void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) {
|
||||
Out << "_SUBSTPACK_";
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleType(const SubstBuiltinTemplatePackType *T) {
|
||||
// FIXME: not clear how to mangle this!
|
||||
// template <class T...> class A {
|
||||
// template <class U...> void foo(__builtin_dedup_pack<T...>(*)(U) x...);
|
||||
// };
|
||||
Out << "_SUBSTBUILTINPACK_";
|
||||
}
|
||||
|
||||
// <type> ::= P <type> # pointer-to
|
||||
void CXXNameMangler::mangleType(const PointerType *T) {
|
||||
Out << 'P';
|
||||
|
@ -3383,6 +3383,11 @@ void MicrosoftCXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T,
|
||||
Error(Range.getBegin(), "substituted parameter pack") << Range;
|
||||
}
|
||||
|
||||
void MicrosoftCXXNameMangler::mangleType(const SubstBuiltinTemplatePackType *T,
|
||||
Qualifiers, SourceRange Range) {
|
||||
Error(Range.getBegin(), "substituted builtin template pack") << Range;
|
||||
}
|
||||
|
||||
// <type> ::= <pointer-type>
|
||||
// <pointer-type> ::= E? <pointer-cvr-qualifiers> <cvr-qualifiers> <type>
|
||||
// # the E is required for 64-bit non-static pointers
|
||||
|
@ -4558,17 +4558,45 @@ void SubstTemplateTypeParmType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
ID.AddBoolean(Final);
|
||||
}
|
||||
|
||||
SubstPackType::SubstPackType(TypeClass Derived, QualType Canon,
|
||||
const TemplateArgument &ArgPack)
|
||||
: Type(Derived, Canon,
|
||||
TypeDependence::DependentInstantiation |
|
||||
TypeDependence::UnexpandedPack),
|
||||
Arguments(ArgPack.pack_begin()) {
|
||||
assert(llvm::all_of(
|
||||
ArgPack.pack_elements(),
|
||||
[](auto &P) { return P.getKind() == TemplateArgument::Type; }) &&
|
||||
"non-type argument to SubstPackType?");
|
||||
SubstPackTypeBits.NumArgs = ArgPack.pack_size();
|
||||
}
|
||||
|
||||
TemplateArgument SubstPackType::getArgumentPack() const {
|
||||
return TemplateArgument(llvm::ArrayRef(Arguments, getNumArgs()));
|
||||
}
|
||||
|
||||
void SubstPackType::Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getArgumentPack());
|
||||
}
|
||||
|
||||
void SubstPackType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
const TemplateArgument &ArgPack) {
|
||||
ID.AddInteger(ArgPack.pack_size());
|
||||
for (const auto &P : ArgPack.pack_elements())
|
||||
ID.AddPointer(P.getAsType().getAsOpaquePtr());
|
||||
}
|
||||
|
||||
SubstTemplateTypeParmPackType::SubstTemplateTypeParmPackType(
|
||||
QualType Canon, Decl *AssociatedDecl, unsigned Index, bool Final,
|
||||
const TemplateArgument &ArgPack)
|
||||
: Type(SubstTemplateTypeParmPack, Canon,
|
||||
TypeDependence::DependentInstantiation |
|
||||
TypeDependence::UnexpandedPack),
|
||||
Arguments(ArgPack.pack_begin()),
|
||||
: SubstPackType(SubstTemplateTypeParmPack, Canon, ArgPack),
|
||||
AssociatedDeclAndFinal(AssociatedDecl, Final) {
|
||||
SubstTemplateTypeParmPackTypeBits.Index = Index;
|
||||
SubstTemplateTypeParmPackTypeBits.NumArgs = ArgPack.pack_size();
|
||||
assert(AssociatedDecl != nullptr);
|
||||
|
||||
SubstPackTypeBits.SubstTemplTypeParmPackIndex = Index;
|
||||
assert(getNumArgs() == ArgPack.pack_size() &&
|
||||
"Parent bitfields in SubstPackType were overwritten."
|
||||
"Check NumSubstPackTypeBits.");
|
||||
}
|
||||
|
||||
Decl *SubstTemplateTypeParmPackType::getAssociatedDecl() const {
|
||||
@ -4588,10 +4616,6 @@ IdentifierInfo *SubstTemplateTypeParmPackType::getIdentifier() const {
|
||||
return getReplacedParameter()->getIdentifier();
|
||||
}
|
||||
|
||||
TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const {
|
||||
return TemplateArgument(llvm::ArrayRef(Arguments, getNumArgs()));
|
||||
}
|
||||
|
||||
void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getAssociatedDecl(), getIndex(), getFinal(), getArgumentPack());
|
||||
}
|
||||
@ -4603,11 +4627,13 @@ void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
ID.AddPointer(AssociatedDecl);
|
||||
ID.AddInteger(Index);
|
||||
ID.AddBoolean(Final);
|
||||
ID.AddInteger(ArgPack.pack_size());
|
||||
for (const auto &P : ArgPack.pack_elements())
|
||||
ID.AddPointer(P.getAsType().getAsOpaquePtr());
|
||||
SubstPackType::Profile(ID, ArgPack);
|
||||
}
|
||||
|
||||
SubstBuiltinTemplatePackType::SubstBuiltinTemplatePackType(
|
||||
QualType Canon, const TemplateArgument &ArgPack)
|
||||
: SubstPackType(SubstBuiltinTemplatePack, Canon, ArgPack) {}
|
||||
|
||||
bool TemplateSpecializationType::anyDependentTemplateArguments(
|
||||
const TemplateArgumentListInfo &Args,
|
||||
ArrayRef<TemplateArgument> Converted) {
|
||||
@ -4631,18 +4657,28 @@ bool TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
|
||||
return false;
|
||||
}
|
||||
|
||||
static TypeDependence
|
||||
getTemplateSpecializationTypeDependence(QualType Underlying, TemplateName T) {
|
||||
TypeDependence D = Underlying.isNull()
|
||||
? TypeDependence::DependentInstantiation
|
||||
: toSemanticDependence(Underlying->getDependence());
|
||||
D |= toTypeDependence(T.getDependence()) & TypeDependence::UnexpandedPack;
|
||||
if (isPackProducingBuiltinTemplateName(T)) {
|
||||
if (Underlying.isNull()) // Dependent, will produce a pack on substitution.
|
||||
D |= TypeDependence::UnexpandedPack;
|
||||
else
|
||||
D |= (Underlying->getDependence() & TypeDependence::UnexpandedPack);
|
||||
}
|
||||
return D;
|
||||
}
|
||||
|
||||
TemplateSpecializationType::TemplateSpecializationType(
|
||||
ElaboratedTypeKeyword Keyword, TemplateName T, bool IsAlias,
|
||||
ArrayRef<TemplateArgument> Args, QualType Underlying)
|
||||
: TypeWithKeyword(
|
||||
Keyword, TemplateSpecialization,
|
||||
Underlying.isNull() ? QualType(this, 0)
|
||||
: Underlying.getCanonicalType(),
|
||||
(Underlying.isNull()
|
||||
? TypeDependence::DependentInstantiation
|
||||
: toSemanticDependence(Underlying->getDependence())) |
|
||||
(toTypeDependence(T.getDependence()) &
|
||||
TypeDependence::UnexpandedPack)),
|
||||
: TypeWithKeyword(Keyword, TemplateSpecialization,
|
||||
Underlying.isNull() ? QualType(this, 0)
|
||||
: Underlying.getCanonicalType(),
|
||||
getTemplateSpecializationTypeDependence(Underlying, T)),
|
||||
Template(T) {
|
||||
TemplateSpecializationTypeBits.NumArgs = Args.size();
|
||||
TemplateSpecializationTypeBits.TypeAlias = IsAlias;
|
||||
@ -4688,6 +4724,12 @@ QualType TemplateSpecializationType::getAliasedType() const {
|
||||
return *reinterpret_cast<const QualType *>(template_arguments().end());
|
||||
}
|
||||
|
||||
bool clang::TemplateSpecializationType::isSugared() const {
|
||||
return !isDependentType() || isCurrentInstantiation() || isTypeAlias() ||
|
||||
(isPackProducingBuiltinTemplateName(Template) &&
|
||||
isa<SubstBuiltinTemplatePackType>(*getCanonicalTypeInternal()));
|
||||
}
|
||||
|
||||
void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
const ASTContext &Ctx) {
|
||||
Profile(ID, Template, template_arguments(),
|
||||
@ -5103,6 +5145,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
|
||||
case Type::UnaryTransform:
|
||||
case Type::TemplateTypeParm:
|
||||
case Type::SubstTemplateTypeParmPack:
|
||||
case Type::SubstBuiltinTemplatePack:
|
||||
case Type::DependentName:
|
||||
case Type::DependentTemplateSpecialization:
|
||||
case Type::Auto:
|
||||
|
@ -232,6 +232,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
|
||||
case Type::Enum:
|
||||
case Type::TemplateTypeParm:
|
||||
case Type::SubstTemplateTypeParmPack:
|
||||
case Type::SubstBuiltinTemplatePack:
|
||||
case Type::DeducedTemplateSpecialization:
|
||||
case Type::TemplateSpecialization:
|
||||
case Type::InjectedClassName:
|
||||
@ -1731,6 +1732,15 @@ void TypePrinter::printSubstTemplateTypeParmAfter(
|
||||
printAfter(T->getReplacementType(), OS);
|
||||
}
|
||||
|
||||
void TypePrinter::printSubstBuiltinTemplatePackBefore(
|
||||
const SubstBuiltinTemplatePackType *T, raw_ostream &OS) {
|
||||
IncludeStrongLifetimeRAII Strong(Policy);
|
||||
OS << "type-pack";
|
||||
}
|
||||
|
||||
void TypePrinter::printSubstBuiltinTemplatePackAfter(
|
||||
const SubstBuiltinTemplatePackType *T, raw_ostream &OS) {}
|
||||
|
||||
void TypePrinter::printSubstTemplateTypeParmPackBefore(
|
||||
const SubstTemplateTypeParmPackType *T,
|
||||
raw_ostream &OS) {
|
||||
|
@ -20,14 +20,17 @@
|
||||
#include "clang/AST/OperationKinds.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Analysis/FlowSensitive/ASTOps.h"
|
||||
#include "clang/Analysis/FlowSensitive/AdornedCFG.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
|
||||
#include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
|
||||
#include "clang/Analysis/FlowSensitive/RecordOps.h"
|
||||
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
|
||||
#include "clang/Analysis/FlowSensitive/Value.h"
|
||||
#include "clang/Basic/Builtins.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include <assert.h>
|
||||
@ -287,7 +290,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
|
||||
void VisitCastExpr(const CastExpr *S) {
|
||||
const Expr *SubExpr = S->getSubExpr();
|
||||
assert(SubExpr != nullptr);
|
||||
|
||||
@ -317,6 +320,60 @@ public:
|
||||
break;
|
||||
}
|
||||
|
||||
case CK_BaseToDerived: {
|
||||
// This is a cast of (single-layer) pointer or reference to a record type.
|
||||
// We should now model the fields for the derived type.
|
||||
|
||||
// Get the RecordStorageLocation for the record object underneath.
|
||||
RecordStorageLocation *Loc = nullptr;
|
||||
if (S->getType()->isPointerType()) {
|
||||
auto *PV = Env.get<PointerValue>(*SubExpr);
|
||||
assert(PV != nullptr);
|
||||
if (PV == nullptr)
|
||||
break;
|
||||
Loc = cast<RecordStorageLocation>(&PV->getPointeeLoc());
|
||||
} else {
|
||||
assert(S->getType()->isRecordType());
|
||||
if (SubExpr->isGLValue()) {
|
||||
Loc = Env.get<RecordStorageLocation>(*SubExpr);
|
||||
} else {
|
||||
Loc = &Env.getResultObjectLocation(*SubExpr);
|
||||
}
|
||||
}
|
||||
if (!Loc) {
|
||||
// Nowhere to add children or propagate from, so we're done.
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the derived record type underneath the reference or pointer.
|
||||
QualType Derived = S->getType().getNonReferenceType();
|
||||
if (Derived->isPointerType()) {
|
||||
Derived = Derived->getPointeeType();
|
||||
}
|
||||
|
||||
// Add children to the storage location for fields (including synthetic
|
||||
// fields) of the derived type and initialize their values.
|
||||
for (const FieldDecl *Field :
|
||||
Env.getDataflowAnalysisContext().getModeledFields(Derived)) {
|
||||
assert(Field != nullptr);
|
||||
QualType FieldType = Field->getType();
|
||||
if (FieldType->isReferenceType()) {
|
||||
Loc->addChild(*Field, nullptr);
|
||||
} else {
|
||||
Loc->addChild(*Field, &Env.createStorageLocation(FieldType));
|
||||
}
|
||||
|
||||
for (const auto &Entry :
|
||||
Env.getDataflowAnalysisContext().getSyntheticFields(Derived)) {
|
||||
Loc->addSyntheticField(Entry.getKey(),
|
||||
Env.createStorageLocation(Entry.getValue()));
|
||||
}
|
||||
}
|
||||
Env.initializeFieldsWithValues(*Loc, Derived);
|
||||
|
||||
// Fall through to propagate SubExpr's StorageLocation to the CastExpr.
|
||||
[[fallthrough]];
|
||||
}
|
||||
case CK_IntegralCast:
|
||||
// FIXME: This cast creates a new integral value from the
|
||||
// subexpression. But, because we don't model integers, we don't
|
||||
@ -324,10 +381,9 @@ public:
|
||||
// modeling is added, then update this code to create a fresh location and
|
||||
// value.
|
||||
case CK_UncheckedDerivedToBase:
|
||||
case CK_DerivedToBase:
|
||||
case CK_ConstructorConversion:
|
||||
case CK_UserDefinedConversion:
|
||||
// FIXME: Add tests that excercise CK_UncheckedDerivedToBase,
|
||||
// CK_ConstructorConversion, and CK_UserDefinedConversion.
|
||||
case CK_NoOp: {
|
||||
// FIXME: Consider making `Environment::getStorageLocation` skip noop
|
||||
// expressions (this and other similar expressions in the file) instead
|
||||
@ -684,15 +740,6 @@ public:
|
||||
propagateValue(*SubExpr, *S, Env);
|
||||
}
|
||||
|
||||
void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
|
||||
if (S->getCastKind() == CK_NoOp) {
|
||||
const Expr *SubExpr = S->getSubExpr();
|
||||
assert(SubExpr != nullptr);
|
||||
|
||||
propagateValueOrStorageLocation(*SubExpr, *S, Env);
|
||||
}
|
||||
}
|
||||
|
||||
void VisitConditionalOperator(const ConditionalOperator *S) {
|
||||
const Environment *TrueEnv = StmtToEnv.getEnvironment(*S->getTrueExpr());
|
||||
const Environment *FalseEnv = StmtToEnv.getEnvironment(*S->getFalseExpr());
|
||||
|
@ -1310,6 +1310,8 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
|
||||
}
|
||||
}
|
||||
|
||||
Result = Actions.ActOnTemplateTemplateArgument(Result);
|
||||
|
||||
// If this is a pack expansion, build it as such.
|
||||
if (EllipsisLoc.isValid() && !Result.isInvalid())
|
||||
Result = Actions.ActOnPackExpansion(Result, EllipsisLoc);
|
||||
|
@ -307,7 +307,8 @@ static UnsignedOrNone EvaluateFoldExpandedConstraintSize(
|
||||
UnsignedOrNone NumExpansions = FE->getNumExpansions();
|
||||
if (S.CheckParameterPacksForExpansion(
|
||||
FE->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded, MLTAL,
|
||||
Expand, RetainExpansion, NumExpansions) ||
|
||||
/*FailOnPackProducingTemplates=*/true, Expand, RetainExpansion,
|
||||
NumExpansions) ||
|
||||
!Expand || RetainExpansion)
|
||||
return std::nullopt;
|
||||
|
||||
@ -1696,11 +1697,13 @@ bool FoldExpandedConstraint::AreCompatibleForSubsumption(
|
||||
Sema::collectUnexpandedParameterPacks(const_cast<Expr *>(B.Pattern), BPacks);
|
||||
|
||||
for (const UnexpandedParameterPack &APack : APacks) {
|
||||
std::pair<unsigned, unsigned> DepthAndIndex = getDepthAndIndex(APack);
|
||||
auto it = llvm::find_if(BPacks, [&](const UnexpandedParameterPack &BPack) {
|
||||
return getDepthAndIndex(BPack) == DepthAndIndex;
|
||||
auto ADI = getDepthAndIndex(APack);
|
||||
if (!ADI)
|
||||
continue;
|
||||
auto It = llvm::find_if(BPacks, [&](const UnexpandedParameterPack &BPack) {
|
||||
return getDepthAndIndex(BPack) == ADI;
|
||||
});
|
||||
if (it != BPacks.end())
|
||||
if (It != BPacks.end())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -3115,6 +3115,10 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
|
||||
cast<SYCLKernelEntryPointAttr>(NewAttribute)->setInvalidAttr();
|
||||
++I;
|
||||
continue;
|
||||
} else if (isa<SYCLExternalAttr>(NewAttribute)) {
|
||||
// SYCLExternalAttr may be added after a definition.
|
||||
++I;
|
||||
continue;
|
||||
}
|
||||
|
||||
S.Diag(NewAttribute->getLocation(),
|
||||
@ -4140,6 +4144,18 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S,
|
||||
diag::note_carries_dependency_missing_first_decl) << 0/*Function*/;
|
||||
}
|
||||
|
||||
// SYCL 2020 section 5.10.1, "SYCL functions and member functions linkage":
|
||||
// When a function is declared with SYCL_EXTERNAL, that macro must be
|
||||
// used on the first declaration of that function in the translation unit.
|
||||
// Redeclarations of the function in the same translation unit may
|
||||
// optionally use SYCL_EXTERNAL, but this is not required.
|
||||
const SYCLExternalAttr *SEA = New->getAttr<SYCLExternalAttr>();
|
||||
if (SEA && !Old->hasAttr<SYCLExternalAttr>()) {
|
||||
Diag(SEA->getLocation(), diag::warn_sycl_external_missing_on_first_decl)
|
||||
<< SEA;
|
||||
Diag(Old->getLocation(), diag::note_previous_declaration);
|
||||
}
|
||||
|
||||
// (C++98 8.3.5p3):
|
||||
// All declarations for a function shall agree exactly in both the
|
||||
// return type and the parameter-type-list.
|
||||
@ -12325,6 +12341,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
|
||||
if (NewFD->hasAttr<SYCLKernelEntryPointAttr>())
|
||||
SYCL().CheckSYCLEntryPointFunctionDecl(NewFD);
|
||||
|
||||
if (NewFD->hasAttr<SYCLExternalAttr>())
|
||||
SYCL().CheckSYCLExternalFunctionDecl(NewFD);
|
||||
|
||||
// Semantic checking for this function declaration (in isolation).
|
||||
|
||||
if (getLangOpts().CPlusPlus) {
|
||||
@ -12513,6 +12532,13 @@ void Sema::CheckMain(FunctionDecl *FD, const DeclSpec &DS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (FD->hasAttr<SYCLExternalAttr>()) {
|
||||
Diag(FD->getLocation(), diag::err_sycl_external_invalid_main)
|
||||
<< FD->getAttr<SYCLExternalAttr>();
|
||||
FD->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
||||
// Functions named main in hlsl are default entries, but don't have specific
|
||||
// signatures they are required to conform to.
|
||||
if (getLangOpts().HLSL)
|
||||
@ -16351,6 +16377,14 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation,
|
||||
}
|
||||
}
|
||||
|
||||
if (FD && !FD->isInvalidDecl() && FD->hasAttr<SYCLExternalAttr>()) {
|
||||
SYCLExternalAttr *SEAttr = FD->getAttr<SYCLExternalAttr>();
|
||||
if (FD->isDeletedAsWritten())
|
||||
Diag(SEAttr->getLocation(),
|
||||
diag::err_sycl_external_invalid_deleted_function)
|
||||
<< SEAttr;
|
||||
}
|
||||
|
||||
{
|
||||
// Do not call PopExpressionEvaluationContext() if it is a lambda because
|
||||
// one is already popped when finishing the lambda in BuildLambdaExpr().
|
||||
|
@ -7061,6 +7061,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
|
||||
case ParsedAttr::AT_EnumExtensibility:
|
||||
handleEnumExtensibilityAttr(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_SYCLExternal:
|
||||
handleSimpleAttribute<SYCLExternalAttr>(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_SYCLKernelEntryPoint:
|
||||
S.SYCL().handleKernelEntryPointAttr(D, AL);
|
||||
break;
|
||||
|
@ -18005,7 +18005,8 @@ DeclResult Sema::ActOnTemplatedFriendTag(
|
||||
collectUnexpandedParameterPacks(QualifierLoc, Unexpanded);
|
||||
unsigned FriendDeclDepth = TempParamLists.front()->getDepth();
|
||||
for (UnexpandedParameterPack &U : Unexpanded) {
|
||||
if (getDepthAndIndex(U).first >= FriendDeclDepth) {
|
||||
if (std::optional<std::pair<unsigned, unsigned>> DI = getDepthAndIndex(U);
|
||||
DI && DI->first >= FriendDeclDepth) {
|
||||
auto *ND = dyn_cast<NamedDecl *>(U.first);
|
||||
if (!ND)
|
||||
ND = cast<const TemplateTypeParmType *>(U.first)->getDecl();
|
||||
|
@ -250,6 +250,23 @@ static bool CheckSYCLKernelName(Sema &S, SourceLocation Loc,
|
||||
return false;
|
||||
}
|
||||
|
||||
void SemaSYCL::CheckSYCLExternalFunctionDecl(FunctionDecl *FD) {
|
||||
const auto *SEAttr = FD->getAttr<SYCLExternalAttr>();
|
||||
assert(SEAttr && "Missing sycl_external attribute");
|
||||
if (!FD->isInvalidDecl() && !FD->isTemplated()) {
|
||||
if (!FD->isExternallyVisible())
|
||||
if (!FD->isFunctionTemplateSpecialization() ||
|
||||
FD->getTemplateSpecializationInfo()->isExplicitSpecialization())
|
||||
Diag(SEAttr->getLocation(), diag::err_sycl_external_invalid_linkage)
|
||||
<< SEAttr;
|
||||
}
|
||||
if (FD->isDeletedAsWritten()) {
|
||||
Diag(SEAttr->getLocation(),
|
||||
diag::err_sycl_external_invalid_deleted_function)
|
||||
<< SEAttr;
|
||||
}
|
||||
}
|
||||
|
||||
void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) {
|
||||
// Ensure that all attributes present on the declaration are consistent
|
||||
// and warn about any redundant ones.
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/TemplateName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/TypeOrdering.h"
|
||||
#include "clang/AST/TypeVisitor.h"
|
||||
#include "clang/Basic/Builtins.h"
|
||||
#include "clang/Basic/DiagnosticSema.h"
|
||||
@ -316,6 +317,12 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
|
||||
}
|
||||
}
|
||||
|
||||
if (isPackProducingBuiltinTemplateName(Template) &&
|
||||
S->getTemplateParamParent() == nullptr)
|
||||
Diag(Name.getBeginLoc(), diag::err_builtin_pack_outside_template) << TName;
|
||||
// Recover by returning the template, even though we would never be able to
|
||||
// substitute it.
|
||||
|
||||
TemplateResult = TemplateTy::make(Template);
|
||||
return TemplateKind;
|
||||
}
|
||||
@ -3477,6 +3484,28 @@ static QualType checkBuiltinTemplateIdType(
|
||||
|
||||
return Context.getHLSLInlineSpirvType(Opcode, Size, Alignment, Operands);
|
||||
}
|
||||
case BTK__builtin_dedup_pack: {
|
||||
assert(Converted.size() == 1 && "__builtin_dedup_pack should be given "
|
||||
"a parameter pack");
|
||||
TemplateArgument Ts = Converted[0];
|
||||
// Delay the computation until we can compute the final result. We choose
|
||||
// not to remove the duplicates upfront before substitution to keep the code
|
||||
// simple.
|
||||
if (Ts.isDependent())
|
||||
return QualType();
|
||||
assert(Ts.getKind() == clang::TemplateArgument::Pack);
|
||||
llvm::SmallVector<TemplateArgument> OutArgs;
|
||||
llvm::SmallDenseSet<QualType> Seen;
|
||||
// Synthesize a new template argument list, removing duplicates.
|
||||
for (auto T : Ts.getPackAsArray()) {
|
||||
assert(T.getKind() == clang::TemplateArgument::Type);
|
||||
if (!Seen.insert(T.getAsType().getCanonicalType()).second)
|
||||
continue;
|
||||
OutArgs.push_back(T);
|
||||
}
|
||||
return Context.getSubstBuiltinTemplatePack(
|
||||
TemplateArgument::CreatePackCopy(Context, OutArgs));
|
||||
}
|
||||
}
|
||||
llvm_unreachable("unexpected BuiltinTemplateDecl!");
|
||||
}
|
||||
@ -5839,6 +5868,29 @@ bool Sema::CheckTemplateArgumentList(
|
||||
}
|
||||
}
|
||||
|
||||
// Check for builtins producing template packs in this context, we do not
|
||||
// support them yet.
|
||||
if (const NonTypeTemplateParmDecl *NTTP =
|
||||
dyn_cast<NonTypeTemplateParmDecl>(*Param);
|
||||
NTTP && NTTP->isPackExpansion()) {
|
||||
auto TL = NTTP->getTypeSourceInfo()
|
||||
->getTypeLoc()
|
||||
.castAs<PackExpansionTypeLoc>();
|
||||
llvm::SmallVector<UnexpandedParameterPack> Unexpanded;
|
||||
collectUnexpandedParameterPacks(TL.getPatternLoc(), Unexpanded);
|
||||
for (const auto &UPP : Unexpanded) {
|
||||
auto *TST = UPP.first.dyn_cast<const TemplateSpecializationType *>();
|
||||
if (!TST)
|
||||
continue;
|
||||
assert(isPackProducingBuiltinTemplateName(TST->getTemplateName()));
|
||||
// Expanding a built-in pack in this context is not yet supported.
|
||||
Diag(TL.getEllipsisLoc(),
|
||||
diag::err_unsupported_builtin_template_pack_expansion)
|
||||
<< TST->getTemplateName();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ArgIdx < NumArgs) {
|
||||
TemplateArgumentLoc &ArgLoc = NewArgs[ArgIdx];
|
||||
bool NonPackParameter =
|
||||
@ -6296,6 +6348,11 @@ bool UnnamedLocalNoLinkageFinder::VisitSubstTemplateTypeParmPackType(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UnnamedLocalNoLinkageFinder::VisitSubstBuiltinTemplatePackType(
|
||||
const SubstBuiltinTemplatePackType *) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UnnamedLocalNoLinkageFinder::VisitTemplateSpecializationType(
|
||||
const TemplateSpecializationType*) {
|
||||
return false;
|
||||
|
@ -710,6 +710,9 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
|
||||
// If the parameter is an alias template, there is nothing to deduce.
|
||||
if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias())
|
||||
return TemplateDeductionResult::Success;
|
||||
// Pack-producing templates can only be matched after substitution.
|
||||
if (isPackProducingBuiltinTemplateName(TNP))
|
||||
return TemplateDeductionResult::Success;
|
||||
|
||||
// Check whether the template argument is a dependent template-id.
|
||||
if (isa<TemplateSpecializationType>(A.getCanonicalType())) {
|
||||
@ -928,7 +931,11 @@ private:
|
||||
S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
|
||||
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
|
||||
unsigned Depth, Index;
|
||||
std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
|
||||
if (auto DI = getDepthAndIndex(Unexpanded[I]))
|
||||
std::tie(Depth, Index) = *DI;
|
||||
else
|
||||
continue;
|
||||
|
||||
if (Depth == Info.getDeducedDepth())
|
||||
AddPack(Index);
|
||||
}
|
||||
@ -936,7 +943,6 @@ private:
|
||||
|
||||
// Look for unexpanded packs in the pattern.
|
||||
Collect(Pattern);
|
||||
assert(!Packs.empty() && "Pack expansion without unexpanded packs?");
|
||||
|
||||
unsigned NumNamedPacks = Packs.size();
|
||||
|
||||
@ -1858,6 +1864,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
|
||||
|
||||
case Type::TemplateTypeParm:
|
||||
case Type::SubstTemplateTypeParmPack:
|
||||
case Type::SubstBuiltinTemplatePack:
|
||||
llvm_unreachable("Type nodes handled above");
|
||||
|
||||
case Type::Auto:
|
||||
@ -6967,7 +6974,12 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
|
||||
= cast<SubstTemplateTypeParmPackType>(T);
|
||||
if (Subst->getReplacedParameter()->getDepth() == Depth)
|
||||
Used[Subst->getIndex()] = true;
|
||||
MarkUsedTemplateParameters(Ctx, Subst->getArgumentPack(),
|
||||
MarkUsedTemplateParameters(Ctx, Subst->getArgumentPack(), OnlyDeduced,
|
||||
Depth, Used);
|
||||
break;
|
||||
}
|
||||
case Type::SubstBuiltinTemplatePack: {
|
||||
MarkUsedTemplateParameters(Ctx, cast<SubstPackType>(T)->getArgumentPack(),
|
||||
OnlyDeduced, Depth, Used);
|
||||
break;
|
||||
}
|
||||
|
@ -1459,6 +1459,7 @@ namespace {
|
||||
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
|
||||
SourceRange PatternRange,
|
||||
ArrayRef<UnexpandedParameterPack> Unexpanded,
|
||||
bool FailOnPackProducingTemplates,
|
||||
bool &ShouldExpand, bool &RetainExpansion,
|
||||
UnsignedOrNone &NumExpansions) {
|
||||
if (SemaRef.CurrentInstantiationScope &&
|
||||
@ -1472,8 +1473,9 @@ namespace {
|
||||
}
|
||||
|
||||
return getSema().CheckParameterPacksForExpansion(
|
||||
EllipsisLoc, PatternRange, Unexpanded, TemplateArgs, ShouldExpand,
|
||||
RetainExpansion, NumExpansions);
|
||||
EllipsisLoc, PatternRange, Unexpanded, TemplateArgs,
|
||||
FailOnPackProducingTemplates, ShouldExpand, RetainExpansion,
|
||||
NumExpansions);
|
||||
}
|
||||
|
||||
void ExpandingFunctionParameterPack(ParmVarDecl *Pack) {
|
||||
@ -1515,6 +1517,21 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
MultiLevelTemplateArgumentList ForgetSubstitution() {
|
||||
MultiLevelTemplateArgumentList New;
|
||||
New.addOuterRetainedLevels(this->TemplateArgs.getNumLevels());
|
||||
|
||||
MultiLevelTemplateArgumentList Old =
|
||||
const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
|
||||
const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) =
|
||||
std::move(New);
|
||||
return Old;
|
||||
}
|
||||
void RememberSubstitution(MultiLevelTemplateArgumentList Old) {
|
||||
const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) =
|
||||
std::move(Old);
|
||||
}
|
||||
|
||||
TemplateArgument
|
||||
getTemplateArgumentPackPatternForRewrite(const TemplateArgument &TA) {
|
||||
if (TA.getKind() != TemplateArgument::Pack)
|
||||
@ -1697,6 +1714,26 @@ namespace {
|
||||
return inherited::TransformTemplateArgument(Input, Output, Uneval);
|
||||
}
|
||||
|
||||
using TreeTransform::TransformTemplateSpecializationType;
|
||||
QualType
|
||||
TransformTemplateSpecializationType(TypeLocBuilder &TLB,
|
||||
TemplateSpecializationTypeLoc TL) {
|
||||
auto *T = TL.getTypePtr();
|
||||
if (!getSema().ArgPackSubstIndex || !T->isSugared() ||
|
||||
!isPackProducingBuiltinTemplateName(T->getTemplateName()))
|
||||
return TreeTransform::TransformTemplateSpecializationType(TLB, TL);
|
||||
// Look through sugar to get to the SubstBuiltinTemplatePackType that we
|
||||
// need to substitute into.
|
||||
|
||||
// `TransformType` code below will handle picking the element from a pack
|
||||
// with the index `ArgPackSubstIndex`.
|
||||
// FIXME: add ability to represent sugarred type for N-th element of a
|
||||
// builtin pack and produce the sugar here.
|
||||
QualType R = TransformType(T->desugar());
|
||||
TLB.pushTrivial(getSema().getASTContext(), R, TL.getBeginLoc());
|
||||
return R;
|
||||
}
|
||||
|
||||
UnsignedOrNone ComputeSizeOfPackExprWithoutSubstitution(
|
||||
ArrayRef<TemplateArgument> PackArgs) {
|
||||
// Don't do this when rewriting template parameters for CTAD:
|
||||
@ -1746,6 +1783,9 @@ namespace {
|
||||
TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB,
|
||||
SubstTemplateTypeParmPackTypeLoc TL,
|
||||
bool SuppressObjCLifetime);
|
||||
QualType
|
||||
TransformSubstBuiltinTemplatePackType(TypeLocBuilder &TLB,
|
||||
SubstBuiltinTemplatePackTypeLoc TL);
|
||||
|
||||
CXXRecordDecl::LambdaDependencyKind
|
||||
ComputeLambdaDependency(LambdaScopeInfo *LSI) {
|
||||
@ -1983,6 +2023,7 @@ bool TemplateInstantiator::maybeInstantiateFunctionParameterToScope(
|
||||
UnsignedOrNone NumExpansions = OrigNumExpansions;
|
||||
if (TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
|
||||
Pattern.getSourceRange(), Unexpanded,
|
||||
/*FailOnPackProducingTemplates=*/true,
|
||||
ShouldExpand, RetainExpansion, NumExpansions))
|
||||
return true;
|
||||
|
||||
@ -2719,6 +2760,17 @@ QualType TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
|
||||
getPackIndex(Pack), Arg, TL.getNameLoc());
|
||||
}
|
||||
|
||||
QualType TemplateInstantiator::TransformSubstBuiltinTemplatePackType(
|
||||
TypeLocBuilder &TLB, SubstBuiltinTemplatePackTypeLoc TL) {
|
||||
if (!getSema().ArgPackSubstIndex)
|
||||
return TreeTransform::TransformSubstBuiltinTemplatePackType(TLB, TL);
|
||||
auto &Sema = getSema();
|
||||
TemplateArgument Result = getPackSubstitutedTemplateArgument(
|
||||
Sema, TL.getTypePtr()->getArgumentPack());
|
||||
TLB.pushTrivial(Sema.getASTContext(), Result.getAsType(), TL.getBeginLoc());
|
||||
return Result.getAsType();
|
||||
}
|
||||
|
||||
static concepts::Requirement::SubstitutionDiagnostic *
|
||||
createSubstDiag(Sema &S, TemplateDeductionInfo &Info,
|
||||
Sema::EntityPrinter Printer) {
|
||||
@ -3446,6 +3498,72 @@ bool Sema::SubstDefaultArgument(
|
||||
return false;
|
||||
}
|
||||
|
||||
// See TreeTransform::PreparePackForExpansion for the relevant comment.
|
||||
// This function implements the same concept for base specifiers.
|
||||
static bool
|
||||
PreparePackForExpansion(Sema &S, const CXXBaseSpecifier &Base,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
TypeSourceInfo *&Out, UnexpandedInfo &Info) {
|
||||
SourceRange BaseSourceRange = Base.getSourceRange();
|
||||
SourceLocation BaseEllipsisLoc = Base.getEllipsisLoc();
|
||||
Info.Ellipsis = Base.getEllipsisLoc();
|
||||
auto ComputeInfo = [&S, &TemplateArgs, BaseSourceRange, BaseEllipsisLoc](
|
||||
TypeSourceInfo *BaseTypeInfo,
|
||||
bool IsLateExpansionAttempt, UnexpandedInfo &Info) {
|
||||
// This is a pack expansion. See whether we should expand it now, or
|
||||
// wait until later.
|
||||
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||
S.collectUnexpandedParameterPacks(BaseTypeInfo->getTypeLoc(), Unexpanded);
|
||||
if (IsLateExpansionAttempt) {
|
||||
// Request expansion only when there is an opportunity to expand a pack
|
||||
// that required a substituion first.
|
||||
bool SawPackTypes =
|
||||
llvm::any_of(Unexpanded, [](UnexpandedParameterPack P) {
|
||||
return P.first.dyn_cast<const SubstBuiltinTemplatePackType *>();
|
||||
});
|
||||
if (!SawPackTypes) {
|
||||
Info.Expand = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine whether the set of unexpanded parameter packs can and should be
|
||||
// expanded.
|
||||
Info.Expand = false;
|
||||
Info.RetainExpansion = false;
|
||||
Info.NumExpansions = std::nullopt;
|
||||
return S.CheckParameterPacksForExpansion(
|
||||
BaseEllipsisLoc, BaseSourceRange, Unexpanded, TemplateArgs,
|
||||
/*FailOnPackProducingTemplates=*/false, Info.Expand,
|
||||
Info.RetainExpansion, Info.NumExpansions);
|
||||
};
|
||||
|
||||
if (ComputeInfo(Base.getTypeSourceInfo(), false, Info))
|
||||
return true;
|
||||
|
||||
if (Info.Expand) {
|
||||
Out = Base.getTypeSourceInfo();
|
||||
return false;
|
||||
}
|
||||
|
||||
// The resulting base specifier will (still) be a pack expansion.
|
||||
{
|
||||
Sema::ArgPackSubstIndexRAII SubstIndex(S, std::nullopt);
|
||||
Out = S.SubstType(Base.getTypeSourceInfo(), TemplateArgs,
|
||||
BaseSourceRange.getBegin(), DeclarationName());
|
||||
}
|
||||
if (!Out->getType()->containsUnexpandedParameterPack())
|
||||
return false;
|
||||
|
||||
// Some packs will learn their length after substitution.
|
||||
// We may need to request their expansion.
|
||||
if (ComputeInfo(Out, /*IsLateExpansionAttempt=*/true, Info))
|
||||
return true;
|
||||
if (Info.Expand)
|
||||
Info.ExpandUnderForgetSubstitions = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
|
||||
CXXRecordDecl *Pattern,
|
||||
@ -3463,47 +3581,37 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
|
||||
}
|
||||
|
||||
SourceLocation EllipsisLoc;
|
||||
TypeSourceInfo *BaseTypeLoc;
|
||||
TypeSourceInfo *BaseTypeLoc = nullptr;
|
||||
if (Base.isPackExpansion()) {
|
||||
// This is a pack expansion. See whether we should expand it now, or
|
||||
// wait until later.
|
||||
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||
collectUnexpandedParameterPacks(Base.getTypeSourceInfo()->getTypeLoc(),
|
||||
Unexpanded);
|
||||
bool ShouldExpand = false;
|
||||
bool RetainExpansion = false;
|
||||
UnsignedOrNone NumExpansions = std::nullopt;
|
||||
if (CheckParameterPacksForExpansion(Base.getEllipsisLoc(),
|
||||
Base.getSourceRange(),
|
||||
Unexpanded,
|
||||
TemplateArgs, ShouldExpand,
|
||||
RetainExpansion,
|
||||
NumExpansions)) {
|
||||
UnexpandedInfo Info;
|
||||
if (PreparePackForExpansion(*this, Base, TemplateArgs, BaseTypeLoc,
|
||||
Info)) {
|
||||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we should expand this pack expansion now, do so.
|
||||
if (ShouldExpand) {
|
||||
for (unsigned I = 0; I != *NumExpansions; ++I) {
|
||||
MultiLevelTemplateArgumentList EmptyList;
|
||||
const MultiLevelTemplateArgumentList *ArgsForSubst = &TemplateArgs;
|
||||
if (Info.ExpandUnderForgetSubstitions)
|
||||
ArgsForSubst = &EmptyList;
|
||||
|
||||
if (Info.Expand) {
|
||||
for (unsigned I = 0; I != *Info.NumExpansions; ++I) {
|
||||
Sema::ArgPackSubstIndexRAII SubstIndex(*this, I);
|
||||
|
||||
TypeSourceInfo *BaseTypeLoc = SubstType(Base.getTypeSourceInfo(),
|
||||
TemplateArgs,
|
||||
Base.getSourceRange().getBegin(),
|
||||
DeclarationName());
|
||||
if (!BaseTypeLoc) {
|
||||
TypeSourceInfo *Expanded =
|
||||
SubstType(BaseTypeLoc, *ArgsForSubst,
|
||||
Base.getSourceRange().getBegin(), DeclarationName());
|
||||
if (!Expanded) {
|
||||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CXXBaseSpecifier *InstantiatedBase
|
||||
= CheckBaseSpecifier(Instantiation,
|
||||
Base.getSourceRange(),
|
||||
Base.isVirtual(),
|
||||
Base.getAccessSpecifierAsWritten(),
|
||||
BaseTypeLoc,
|
||||
SourceLocation()))
|
||||
if (CXXBaseSpecifier *InstantiatedBase = CheckBaseSpecifier(
|
||||
Instantiation, Base.getSourceRange(), Base.isVirtual(),
|
||||
Base.getAccessSpecifierAsWritten(), Expanded,
|
||||
SourceLocation()))
|
||||
InstantiatedBases.push_back(InstantiatedBase);
|
||||
else
|
||||
Invalid = true;
|
||||
@ -3515,10 +3623,9 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
|
||||
// The resulting base specifier will (still) be a pack expansion.
|
||||
EllipsisLoc = Base.getEllipsisLoc();
|
||||
Sema::ArgPackSubstIndexRAII SubstIndex(*this, std::nullopt);
|
||||
BaseTypeLoc = SubstType(Base.getTypeSourceInfo(),
|
||||
TemplateArgs,
|
||||
Base.getSourceRange().getBegin(),
|
||||
DeclarationName());
|
||||
BaseTypeLoc =
|
||||
SubstType(BaseTypeLoc, *ArgsForSubst,
|
||||
Base.getSourceRange().getBegin(), DeclarationName());
|
||||
} else {
|
||||
BaseTypeLoc = SubstType(Base.getTypeSourceInfo(),
|
||||
TemplateArgs,
|
||||
|
@ -133,8 +133,9 @@ static void instantiateDependentAlignedAttr(
|
||||
// FIXME: Use the actual location of the ellipsis.
|
||||
SourceLocation EllipsisLoc = Aligned->getLocation();
|
||||
if (S.CheckParameterPacksForExpansion(EllipsisLoc, Aligned->getRange(),
|
||||
Unexpanded, TemplateArgs, Expand,
|
||||
RetainExpansion, NumExpansions))
|
||||
Unexpanded, TemplateArgs,
|
||||
/*FailOnPackProducingTemplates=*/true,
|
||||
Expand, RetainExpansion, NumExpansions))
|
||||
return;
|
||||
|
||||
if (!Expand) {
|
||||
@ -1914,7 +1915,8 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
|
||||
UnsignedOrNone NumExpansions = std::nullopt;
|
||||
if (SemaRef.CheckParameterPacksForExpansion(
|
||||
D->getEllipsisLoc(), D->getSourceRange(), Unexpanded,
|
||||
TemplateArgs, ShouldExpand, RetainExpansion, NumExpansions))
|
||||
TemplateArgs, /*FailOnPackProducingTemplates=*/true,
|
||||
ShouldExpand, RetainExpansion, NumExpansions))
|
||||
return nullptr;
|
||||
|
||||
assert(!RetainExpansion &&
|
||||
@ -3464,10 +3466,11 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
|
||||
cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
|
||||
->getEllipsisLoc(),
|
||||
SourceRange(TC->getConceptNameLoc(),
|
||||
TC->hasExplicitTemplateArgs() ?
|
||||
TC->getTemplateArgsAsWritten()->getRAngleLoc() :
|
||||
TC->getConceptNameInfo().getEndLoc()),
|
||||
Unexpanded, TemplateArgs, Expand, RetainExpansion, NumExpanded))
|
||||
TC->hasExplicitTemplateArgs()
|
||||
? TC->getTemplateArgsAsWritten()->getRAngleLoc()
|
||||
: TC->getConceptNameInfo().getEndLoc()),
|
||||
Unexpanded, TemplateArgs, /*FailOnPackProducingTemplates=*/true,
|
||||
Expand, RetainExpansion, NumExpanded))
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@ -3555,12 +3558,10 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
|
||||
UnsignedOrNone OrigNumExpansions =
|
||||
Expansion.getTypePtr()->getNumExpansions();
|
||||
UnsignedOrNone NumExpansions = OrigNumExpansions;
|
||||
if (SemaRef.CheckParameterPacksForExpansion(Expansion.getEllipsisLoc(),
|
||||
Pattern.getSourceRange(),
|
||||
Unexpanded,
|
||||
TemplateArgs,
|
||||
Expand, RetainExpansion,
|
||||
NumExpansions))
|
||||
if (SemaRef.CheckParameterPacksForExpansion(
|
||||
Expansion.getEllipsisLoc(), Pattern.getSourceRange(), Unexpanded,
|
||||
TemplateArgs, /*FailOnPackProducingTemplates=*/true, Expand,
|
||||
RetainExpansion, NumExpansions))
|
||||
return nullptr;
|
||||
|
||||
if (Expand) {
|
||||
@ -3726,12 +3727,10 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
|
||||
bool Expand = true;
|
||||
bool RetainExpansion = false;
|
||||
UnsignedOrNone NumExpansions = std::nullopt;
|
||||
if (SemaRef.CheckParameterPacksForExpansion(D->getLocation(),
|
||||
TempParams->getSourceRange(),
|
||||
Unexpanded,
|
||||
TemplateArgs,
|
||||
Expand, RetainExpansion,
|
||||
NumExpansions))
|
||||
if (SemaRef.CheckParameterPacksForExpansion(
|
||||
D->getLocation(), TempParams->getSourceRange(), Unexpanded,
|
||||
TemplateArgs, /*FailOnPackProducingTemplates=*/true, Expand,
|
||||
RetainExpansion, NumExpansions))
|
||||
return nullptr;
|
||||
|
||||
if (Expand) {
|
||||
@ -4003,8 +4002,9 @@ Decl *TemplateDeclInstantiator::instantiateUnresolvedUsingDecl(
|
||||
bool RetainExpansion = false;
|
||||
UnsignedOrNone NumExpansions = std::nullopt;
|
||||
if (SemaRef.CheckParameterPacksForExpansion(
|
||||
D->getEllipsisLoc(), D->getSourceRange(), Unexpanded, TemplateArgs,
|
||||
Expand, RetainExpansion, NumExpansions))
|
||||
D->getEllipsisLoc(), D->getSourceRange(), Unexpanded, TemplateArgs,
|
||||
/*FailOnPackProducingTemplates=*/true, Expand, RetainExpansion,
|
||||
NumExpansions))
|
||||
return nullptr;
|
||||
|
||||
// This declaration cannot appear within a function template signature,
|
||||
@ -6401,12 +6401,10 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
|
||||
bool ShouldExpand = false;
|
||||
bool RetainExpansion = false;
|
||||
UnsignedOrNone NumExpansions = std::nullopt;
|
||||
if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(),
|
||||
BaseTL.getSourceRange(),
|
||||
Unexpanded,
|
||||
TemplateArgs, ShouldExpand,
|
||||
RetainExpansion,
|
||||
NumExpansions)) {
|
||||
if (CheckParameterPacksForExpansion(
|
||||
Init->getEllipsisLoc(), BaseTL.getSourceRange(), Unexpanded,
|
||||
TemplateArgs, /*FailOnPackProducingTemplates=*/true, ShouldExpand,
|
||||
RetainExpansion, NumExpansions)) {
|
||||
AnyErrors = true;
|
||||
New->setInvalidDecl();
|
||||
continue;
|
||||
|
@ -65,6 +65,41 @@ class CollectUnexpandedParameterPacksVisitor
|
||||
Unexpanded.push_back({T, Loc});
|
||||
}
|
||||
|
||||
bool addUnexpanded(const SubstBuiltinTemplatePackType *T,
|
||||
SourceLocation Loc = SourceLocation()) {
|
||||
Unexpanded.push_back({T, Loc});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addUnexpanded(const TemplateSpecializationType *T,
|
||||
SourceLocation Loc = SourceLocation()) {
|
||||
assert(T->isCanonicalUnqualified() &&
|
||||
isPackProducingBuiltinTemplateName(T->getTemplateName()));
|
||||
Unexpanded.push_back({T, Loc});
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns true iff it handled the traversal. On false, the callers must
|
||||
/// traverse themselves.
|
||||
bool
|
||||
TryTraverseSpecializationProducingPacks(const TemplateSpecializationType *T,
|
||||
SourceLocation Loc) {
|
||||
if (!isPackProducingBuiltinTemplateName(T->getTemplateName()))
|
||||
return false;
|
||||
// Canonical types are inputs to the initial substitution. Report them and
|
||||
// do not recurse any further.
|
||||
if (T->isCanonicalUnqualified()) {
|
||||
addUnexpanded(T, Loc);
|
||||
return true;
|
||||
}
|
||||
// For sugared types, do not use the default traversal as it would be
|
||||
// looking at (now irrelevant) template arguments. Instead, look at the
|
||||
// result of substitution, it usually contains SubstPackType that needs to
|
||||
// be expanded further.
|
||||
DynamicRecursiveASTVisitor::TraverseType(T->desugar());
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit CollectUnexpandedParameterPacksVisitor(
|
||||
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
|
||||
@ -123,6 +158,23 @@ class CollectUnexpandedParameterPacksVisitor
|
||||
return DynamicRecursiveASTVisitor::TraverseTemplateName(Template);
|
||||
}
|
||||
|
||||
bool
|
||||
TraverseTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc T,
|
||||
bool TraverseQualifier) override {
|
||||
if (TryTraverseSpecializationProducingPacks(T.getTypePtr(),
|
||||
T.getBeginLoc()))
|
||||
return true;
|
||||
return DynamicRecursiveASTVisitor::TraverseTemplateSpecializationTypeLoc(
|
||||
T, TraverseQualifier);
|
||||
}
|
||||
|
||||
bool TraverseTemplateSpecializationType(TemplateSpecializationType *T,
|
||||
bool TraverseQualfier) override {
|
||||
if (TryTraverseSpecializationProducingPacks(T, SourceLocation()))
|
||||
return true;
|
||||
return DynamicRecursiveASTVisitor::TraverseTemplateSpecializationType(T);
|
||||
}
|
||||
|
||||
/// Suppress traversal into Objective-C container literal
|
||||
/// elements that are pack expansions.
|
||||
bool TraverseObjCDictionaryLiteral(ObjCDictionaryLiteral *E) override {
|
||||
@ -325,6 +377,14 @@ class CollectUnexpandedParameterPacksVisitor
|
||||
return DynamicRecursiveASTVisitor::TraverseUnresolvedLookupExpr(E);
|
||||
}
|
||||
|
||||
bool TraverseSubstBuiltinTemplatePackType(SubstBuiltinTemplatePackType *T,
|
||||
bool TraverseQualifier) override {
|
||||
addUnexpanded(T);
|
||||
// Do not call into base implementation to supress traversal of the
|
||||
// substituted types.
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool TraverseFunctionParmPackExpr(FunctionParmPackExpr *) override {
|
||||
ContainsIntermediatePacks = true;
|
||||
@ -645,6 +705,23 @@ void Sema::collectUnexpandedParameterPacks(
|
||||
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E);
|
||||
}
|
||||
|
||||
ParsedTemplateArgument
|
||||
Sema::ActOnTemplateTemplateArgument(const ParsedTemplateArgument &Arg) {
|
||||
if (Arg.isInvalid())
|
||||
return Arg;
|
||||
|
||||
// We do not allow to reference builtin templates that produce multiple
|
||||
// values, they would not have a well-defined semantics outside template
|
||||
// arguments.
|
||||
auto *T = dyn_cast_or_null<BuiltinTemplateDecl>(
|
||||
Arg.getAsTemplate().get().getAsTemplateDecl());
|
||||
if (T && T->isPackProducingBuiltinTemplate())
|
||||
diagnoseMissingTemplateArguments(Arg.getAsTemplate().get(),
|
||||
Arg.getNameLoc());
|
||||
|
||||
return Arg;
|
||||
}
|
||||
|
||||
ParsedTemplateArgument
|
||||
Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg,
|
||||
SourceLocation EllipsisLoc) {
|
||||
@ -731,7 +808,7 @@ QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange,
|
||||
if (!Pattern->containsUnexpandedParameterPack() &&
|
||||
!Pattern->getContainedDeducedType()) {
|
||||
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
|
||||
<< PatternRange;
|
||||
<< PatternRange;
|
||||
return QualType();
|
||||
}
|
||||
|
||||
@ -765,7 +842,8 @@ ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
|
||||
bool Sema::CheckParameterPacksForExpansion(
|
||||
SourceLocation EllipsisLoc, SourceRange PatternRange,
|
||||
ArrayRef<UnexpandedParameterPack> Unexpanded,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
bool FailOnPackProducingTemplates, bool &ShouldExpand,
|
||||
bool &RetainExpansion, UnsignedOrNone &NumExpansions) {
|
||||
ShouldExpand = true;
|
||||
RetainExpansion = false;
|
||||
@ -781,12 +859,31 @@ bool Sema::CheckParameterPacksForExpansion(
|
||||
IdentifierInfo *Name;
|
||||
bool IsVarDeclPack = false;
|
||||
FunctionParmPackExpr *BindingPack = nullptr;
|
||||
std::optional<unsigned> NumPrecomputedArguments;
|
||||
|
||||
if (const TemplateTypeParmType *TTP =
|
||||
ParmPack.first.dyn_cast<const TemplateTypeParmType *>()) {
|
||||
if (auto *TTP = ParmPack.first.dyn_cast<const TemplateTypeParmType *>()) {
|
||||
Depth = TTP->getDepth();
|
||||
Index = TTP->getIndex();
|
||||
Name = TTP->getIdentifier();
|
||||
} else if (auto *TST =
|
||||
ParmPack.first
|
||||
.dyn_cast<const TemplateSpecializationType *>()) {
|
||||
assert(isPackProducingBuiltinTemplateName(TST->getTemplateName()));
|
||||
// Delay expansion, substitution is required to know the size.
|
||||
ShouldExpand = false;
|
||||
if (!FailOnPackProducingTemplates)
|
||||
continue;
|
||||
|
||||
// It is not yet supported in certain contexts.
|
||||
return Diag(PatternRange.getBegin().isValid() ? PatternRange.getBegin()
|
||||
: EllipsisLoc,
|
||||
diag::err_unsupported_builtin_template_pack_expansion)
|
||||
<< TST->getTemplateName();
|
||||
} else if (auto *S =
|
||||
ParmPack.first
|
||||
.dyn_cast<const SubstBuiltinTemplatePackType *>()) {
|
||||
Name = nullptr;
|
||||
NumPrecomputedArguments = S->getNumArgs();
|
||||
} else {
|
||||
NamedDecl *ND = cast<NamedDecl *>(ParmPack.first);
|
||||
if (isa<VarDecl>(ND))
|
||||
@ -826,6 +923,8 @@ bool Sema::CheckParameterPacksForExpansion(
|
||||
}
|
||||
} else if (BindingPack) {
|
||||
NewPackSize = BindingPack->getNumExpansions();
|
||||
} else if (NumPrecomputedArguments) {
|
||||
NewPackSize = *NumPrecomputedArguments;
|
||||
} else {
|
||||
// If we don't have a template argument at this depth/index, then we
|
||||
// cannot expand the pack expansion. Make a note of this, but we still
|
||||
@ -967,6 +1066,21 @@ UnsignedOrNone Sema::getNumArgumentsInExpansionFromUnexpanded(
|
||||
Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) {
|
||||
Depth = TTP->getDepth();
|
||||
Index = TTP->getIndex();
|
||||
} else if (auto *TST =
|
||||
Unexpanded[I]
|
||||
.first.dyn_cast<const TemplateSpecializationType *>()) {
|
||||
// This is a dependent pack, we are not ready to expand it yet.
|
||||
assert(isPackProducingBuiltinTemplateName(TST->getTemplateName()));
|
||||
(void)TST;
|
||||
return std::nullopt;
|
||||
} else if (auto *PST =
|
||||
Unexpanded[I]
|
||||
.first
|
||||
.dyn_cast<const SubstBuiltinTemplatePackType *>()) {
|
||||
assert((!Result || *Result == PST->getNumArgs()) &&
|
||||
"inconsistent pack sizes");
|
||||
Result = PST->getNumArgs();
|
||||
continue;
|
||||
} else {
|
||||
NamedDecl *ND = cast<NamedDecl *>(Unexpanded[I].first);
|
||||
if (isa<VarDecl>(ND)) {
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "clang/Sema/SemaOpenMP.h"
|
||||
#include "clang/Sema/SemaPseudoObject.h"
|
||||
#include "clang/Sema/SemaSYCL.h"
|
||||
#include "clang/Sema/Template.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <algorithm>
|
||||
@ -55,6 +56,17 @@ using namespace llvm::omp;
|
||||
namespace clang {
|
||||
using namespace sema;
|
||||
|
||||
// This helper class is used to facilitate pack expansion during tree transform.
|
||||
struct UnexpandedInfo {
|
||||
SourceLocation Ellipsis;
|
||||
UnsignedOrNone OrigNumExpansions = std::nullopt;
|
||||
|
||||
bool Expand = false;
|
||||
bool RetainExpansion = false;
|
||||
UnsignedOrNone NumExpansions = std::nullopt;
|
||||
bool ExpandUnderForgetSubstitions = false;
|
||||
};
|
||||
|
||||
/// A semantic tree transformation that allows one to transform one
|
||||
/// abstract syntax tree into another.
|
||||
///
|
||||
@ -292,6 +304,7 @@ public:
|
||||
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
|
||||
SourceRange PatternRange,
|
||||
ArrayRef<UnexpandedParameterPack> Unexpanded,
|
||||
bool FailOnPackProducingTemplates,
|
||||
bool &ShouldExpand, bool &RetainExpansion,
|
||||
UnsignedOrNone &NumExpansions) {
|
||||
ShouldExpand = false;
|
||||
@ -314,6 +327,27 @@ public:
|
||||
/// This routine is meant to be overridden by the template instantiator.
|
||||
void RememberPartiallySubstitutedPack(TemplateArgument Arg) { }
|
||||
|
||||
/// "Forget" the template substitution to allow transforming the AST without
|
||||
/// any template instantiations. This is used to expand template packs when
|
||||
/// their size is not known in advance (e.g. for builtins that produce type
|
||||
/// packs).
|
||||
MultiLevelTemplateArgumentList ForgetSubstitution() { return {}; }
|
||||
void RememberSubstitution(MultiLevelTemplateArgumentList) {}
|
||||
|
||||
private:
|
||||
struct ForgetSubstitutionRAII {
|
||||
Derived &Self;
|
||||
MultiLevelTemplateArgumentList Old;
|
||||
|
||||
public:
|
||||
ForgetSubstitutionRAII(Derived &Self) : Self(Self) {
|
||||
Old = Self.ForgetSubstitution();
|
||||
}
|
||||
|
||||
~ForgetSubstitutionRAII() { Self.RememberSubstitution(std::move(Old)); }
|
||||
};
|
||||
|
||||
public:
|
||||
/// Note to the derived class when a function parameter pack is
|
||||
/// being expanded.
|
||||
void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { }
|
||||
@ -660,6 +694,19 @@ public:
|
||||
TemplateArgumentListInfo &Outputs,
|
||||
bool Uneval = false);
|
||||
|
||||
/// Checks if the argument pack from \p In will need to be expanded and does
|
||||
/// the necessary prework.
|
||||
/// Whether the expansion is needed is captured in Info.Expand.
|
||||
///
|
||||
/// - When the expansion is required, \p Out will be a template pattern that
|
||||
/// would need to be expanded.
|
||||
/// - When the expansion must not happen, \p Out will be a pack that must be
|
||||
/// returned to the outputs directly.
|
||||
///
|
||||
/// \return true iff the error occurred
|
||||
bool PreparePackForExpansion(TemplateArgumentLoc In, bool Uneval,
|
||||
TemplateArgumentLoc &Out, UnexpandedInfo &Info);
|
||||
|
||||
/// Fakes up a TemplateArgumentLoc for a given TemplateArgument.
|
||||
void InventTemplateArgumentLoc(const TemplateArgument &Arg,
|
||||
TemplateArgumentLoc &ArgLoc);
|
||||
@ -4461,11 +4508,10 @@ bool TreeTransform<Derived>::TransformExprs(Expr *const *Inputs,
|
||||
bool RetainExpansion = false;
|
||||
UnsignedOrNone OrigNumExpansions = Expansion->getNumExpansions();
|
||||
UnsignedOrNone NumExpansions = OrigNumExpansions;
|
||||
if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(),
|
||||
Pattern->getSourceRange(),
|
||||
Unexpanded,
|
||||
Expand, RetainExpansion,
|
||||
NumExpansions))
|
||||
if (getDerived().TryExpandParameterPacks(
|
||||
Expansion->getEllipsisLoc(), Pattern->getSourceRange(),
|
||||
Unexpanded, /*FailOnPackProducingTemplates=*/true, Expand,
|
||||
RetainExpansion, NumExpansions))
|
||||
return true;
|
||||
|
||||
if (!Expand) {
|
||||
@ -5081,60 +5127,30 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
|
||||
}
|
||||
|
||||
if (In.getArgument().isPackExpansion()) {
|
||||
// We have a pack expansion, for which we will be substituting into
|
||||
// the pattern.
|
||||
SourceLocation Ellipsis;
|
||||
UnsignedOrNone OrigNumExpansions = std::nullopt;
|
||||
TemplateArgumentLoc Pattern
|
||||
= getSema().getTemplateArgumentPackExpansionPattern(
|
||||
In, Ellipsis, OrigNumExpansions);
|
||||
|
||||
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||
getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
|
||||
assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
|
||||
|
||||
// Determine whether the set of unexpanded parameter packs can and should
|
||||
// be expanded.
|
||||
bool Expand = true;
|
||||
bool RetainExpansion = false;
|
||||
UnsignedOrNone NumExpansions = OrigNumExpansions;
|
||||
if (getDerived().TryExpandParameterPacks(Ellipsis,
|
||||
Pattern.getSourceRange(),
|
||||
Unexpanded,
|
||||
Expand,
|
||||
RetainExpansion,
|
||||
NumExpansions))
|
||||
UnexpandedInfo Info;
|
||||
TemplateArgumentLoc Prepared;
|
||||
if (PreparePackForExpansion(In, Uneval, Prepared, Info))
|
||||
return true;
|
||||
|
||||
if (!Expand) {
|
||||
// The transform has determined that we should perform a simple
|
||||
// transformation on the pack expansion, producing another pack
|
||||
// expansion.
|
||||
TemplateArgumentLoc OutPattern;
|
||||
Sema::ArgPackSubstIndexRAII SubstIndex(getSema(), std::nullopt);
|
||||
if (getDerived().TransformTemplateArgument(Pattern, OutPattern, Uneval))
|
||||
return true;
|
||||
|
||||
Out = getDerived().RebuildPackExpansion(OutPattern, Ellipsis,
|
||||
NumExpansions);
|
||||
if (Out.getArgument().isNull())
|
||||
return true;
|
||||
|
||||
Outputs.addArgument(Out);
|
||||
if (!Info.Expand) {
|
||||
Outputs.addArgument(Prepared);
|
||||
continue;
|
||||
}
|
||||
|
||||
// The transform has determined that we should perform an elementwise
|
||||
// expansion of the pattern. Do so.
|
||||
for (unsigned I = 0; I != *NumExpansions; ++I) {
|
||||
std::optional<ForgetSubstitutionRAII> ForgetSubst;
|
||||
if (Info.ExpandUnderForgetSubstitions)
|
||||
ForgetSubst.emplace(getDerived());
|
||||
for (unsigned I = 0; I != *Info.NumExpansions; ++I) {
|
||||
Sema::ArgPackSubstIndexRAII SubstIndex(getSema(), I);
|
||||
|
||||
if (getDerived().TransformTemplateArgument(Pattern, Out, Uneval))
|
||||
TemplateArgumentLoc Out;
|
||||
if (getDerived().TransformTemplateArgument(Prepared, Out, Uneval))
|
||||
return true;
|
||||
|
||||
if (Out.getArgument().containsUnexpandedParameterPack()) {
|
||||
Out = getDerived().RebuildPackExpansion(Out, Ellipsis,
|
||||
OrigNumExpansions);
|
||||
Out = getDerived().RebuildPackExpansion(Out, Info.Ellipsis,
|
||||
Info.OrigNumExpansions);
|
||||
if (Out.getArgument().isNull())
|
||||
return true;
|
||||
}
|
||||
@ -5144,14 +5160,15 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
|
||||
|
||||
// If we're supposed to retain a pack expansion, do so by temporarily
|
||||
// forgetting the partially-substituted parameter pack.
|
||||
if (RetainExpansion) {
|
||||
if (Info.RetainExpansion) {
|
||||
ForgetPartiallySubstitutedPackRAII Forget(getDerived());
|
||||
|
||||
if (getDerived().TransformTemplateArgument(Pattern, Out, Uneval))
|
||||
TemplateArgumentLoc Out;
|
||||
if (getDerived().TransformTemplateArgument(Prepared, Out, Uneval))
|
||||
return true;
|
||||
|
||||
Out = getDerived().RebuildPackExpansion(Out, Ellipsis,
|
||||
OrigNumExpansions);
|
||||
Out = getDerived().RebuildPackExpansion(Out, Info.Ellipsis,
|
||||
Info.OrigNumExpansions);
|
||||
if (Out.getArgument().isNull())
|
||||
return true;
|
||||
|
||||
@ -5172,6 +5189,114 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
|
||||
|
||||
}
|
||||
|
||||
// FIXME: Find ways to reduce code duplication for pack expansions.
|
||||
template <typename Derived>
|
||||
bool TreeTransform<Derived>::PreparePackForExpansion(TemplateArgumentLoc In,
|
||||
bool Uneval,
|
||||
TemplateArgumentLoc &Out,
|
||||
UnexpandedInfo &Info) {
|
||||
auto ComputeInfo = [this](TemplateArgumentLoc Arg,
|
||||
bool IsLateExpansionAttempt, UnexpandedInfo &Info,
|
||||
TemplateArgumentLoc &Pattern) {
|
||||
assert(Arg.getArgument().isPackExpansion());
|
||||
// We have a pack expansion, for which we will be substituting into the
|
||||
// pattern.
|
||||
Pattern = getSema().getTemplateArgumentPackExpansionPattern(
|
||||
Arg, Info.Ellipsis, Info.OrigNumExpansions);
|
||||
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||
getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
|
||||
if (IsLateExpansionAttempt) {
|
||||
// Request expansion only when there is an opportunity to expand a pack
|
||||
// that required a substituion first.
|
||||
bool SawPackTypes =
|
||||
llvm::any_of(Unexpanded, [](UnexpandedParameterPack P) {
|
||||
return P.first.dyn_cast<const SubstBuiltinTemplatePackType *>();
|
||||
});
|
||||
if (!SawPackTypes) {
|
||||
Info.Expand = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
|
||||
|
||||
// Determine whether the set of unexpanded parameter packs can and
|
||||
// should be expanded.
|
||||
Info.Expand = true;
|
||||
Info.RetainExpansion = false;
|
||||
Info.NumExpansions = Info.OrigNumExpansions;
|
||||
return getDerived().TryExpandParameterPacks(
|
||||
Info.Ellipsis, Pattern.getSourceRange(), Unexpanded,
|
||||
/*FailOnPackProducingTemplates=*/false, Info.Expand,
|
||||
Info.RetainExpansion, Info.NumExpansions);
|
||||
};
|
||||
|
||||
TemplateArgumentLoc Pattern;
|
||||
if (ComputeInfo(In, false, Info, Pattern))
|
||||
return true;
|
||||
|
||||
if (Info.Expand) {
|
||||
Out = Pattern;
|
||||
return false;
|
||||
}
|
||||
|
||||
// The transform has determined that we should perform a simple
|
||||
// transformation on the pack expansion, producing another pack
|
||||
// expansion.
|
||||
TemplateArgumentLoc OutPattern;
|
||||
std::optional<Sema::ArgPackSubstIndexRAII> SubstIndex(
|
||||
std::in_place, getSema(), std::nullopt);
|
||||
if (getDerived().TransformTemplateArgument(Pattern, OutPattern, Uneval))
|
||||
return true;
|
||||
|
||||
Out = getDerived().RebuildPackExpansion(OutPattern, Info.Ellipsis,
|
||||
Info.NumExpansions);
|
||||
if (Out.getArgument().isNull())
|
||||
return true;
|
||||
SubstIndex.reset();
|
||||
|
||||
if (!OutPattern.getArgument().containsUnexpandedParameterPack())
|
||||
return false;
|
||||
|
||||
// Some packs will learn their length after substitution, e.g.
|
||||
// __builtin_dedup_pack<T,int> has size 1 or 2, depending on the substitution
|
||||
// value of `T`.
|
||||
//
|
||||
// We only expand after we know sizes of all packs, check if this is the case
|
||||
// or not. However, we avoid a full template substitution and only do
|
||||
// expanstions after this point.
|
||||
|
||||
// E.g. when substituting template arguments of tuple with {T -> int} in the
|
||||
// following example:
|
||||
// template <class T>
|
||||
// struct TupleWithInt {
|
||||
// using type = std::tuple<__builtin_dedup_pack<T, int>...>;
|
||||
// };
|
||||
// TupleWithInt<int>::type y;
|
||||
// At this point we will see the `__builtin_dedup_pack<int, int>` with a known
|
||||
// lenght and run `ComputeInfo()` to provide the necessary information to our
|
||||
// caller.
|
||||
//
|
||||
// Note that we may still have situations where builtin is not going to be
|
||||
// expanded. For example:
|
||||
// template <class T>
|
||||
// struct Foo {
|
||||
// template <class U> using tuple_with_t =
|
||||
// std::tuple<__builtin_dedup_pack<T, U, int>...>; using type =
|
||||
// tuple_with_t<short>;
|
||||
// }
|
||||
// Because the substitution into `type` happens in dependent context, `type`
|
||||
// will be `tuple<builtin_dedup_pack<T, short, int>...>` after substitution
|
||||
// and the caller will not be able to expand it.
|
||||
ForgetSubstitutionRAII ForgetSubst(getDerived());
|
||||
if (ComputeInfo(Out, true, Info, OutPattern))
|
||||
return true;
|
||||
if (!Info.Expand)
|
||||
return false;
|
||||
Out = OutPattern;
|
||||
Info.ExpandUnderForgetSubstitions = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Type transformation
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -6182,12 +6307,10 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
|
||||
if (Unexpanded.size() > 0) {
|
||||
OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions();
|
||||
NumExpansions = OrigNumExpansions;
|
||||
if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
|
||||
Pattern.getSourceRange(),
|
||||
Unexpanded,
|
||||
ShouldExpand,
|
||||
RetainExpansion,
|
||||
NumExpansions)) {
|
||||
if (getDerived().TryExpandParameterPacks(
|
||||
ExpansionTL.getEllipsisLoc(), Pattern.getSourceRange(),
|
||||
Unexpanded, /*FailOnPackProducingTemplates=*/true,
|
||||
ShouldExpand, RetainExpansion, NumExpansions)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
@ -6293,11 +6416,10 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
|
||||
// Determine whether we should expand the parameter packs.
|
||||
bool ShouldExpand = false;
|
||||
bool RetainExpansion = false;
|
||||
if (getDerived().TryExpandParameterPacks(Loc, SourceRange(),
|
||||
Unexpanded,
|
||||
ShouldExpand,
|
||||
RetainExpansion,
|
||||
NumExpansions)) {
|
||||
if (getDerived().TryExpandParameterPacks(
|
||||
Loc, SourceRange(), Unexpanded,
|
||||
/*FailOnPackProducingTemplates=*/true, ShouldExpand,
|
||||
RetainExpansion, NumExpansions)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -6594,8 +6716,9 @@ bool TreeTransform<Derived>::TransformExceptionSpec(
|
||||
// FIXME: Track the location of the ellipsis (and track source location
|
||||
// information for the types in the exception specification in general).
|
||||
if (getDerived().TryExpandParameterPacks(
|
||||
Loc, SourceRange(), Unexpanded, Expand,
|
||||
RetainExpansion, NumExpansions))
|
||||
Loc, SourceRange(), Unexpanded,
|
||||
/*FailOnPackProducingTemplates=*/true, Expand, RetainExpansion,
|
||||
NumExpansions))
|
||||
return true;
|
||||
|
||||
if (!Expand) {
|
||||
@ -6907,9 +7030,10 @@ TreeTransform<Derived>::TransformPackIndexingType(TypeLocBuilder &TLB,
|
||||
bool ShouldExpand = true;
|
||||
bool RetainExpansion = false;
|
||||
UnsignedOrNone NumExpansions = std::nullopt;
|
||||
if (getDerived().TryExpandParameterPacks(TL.getEllipsisLoc(), SourceRange(),
|
||||
Unexpanded, ShouldExpand,
|
||||
RetainExpansion, NumExpansions))
|
||||
if (getDerived().TryExpandParameterPacks(
|
||||
TL.getEllipsisLoc(), SourceRange(), Unexpanded,
|
||||
/*FailOnPackProducingTemplates=*/true, ShouldExpand,
|
||||
RetainExpansion, NumExpansions))
|
||||
return QualType();
|
||||
if (!ShouldExpand) {
|
||||
Sema::ArgPackSubstIndexRAII SubstIndex(getSema(), std::nullopt);
|
||||
@ -7131,6 +7255,11 @@ QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType(
|
||||
return Result;
|
||||
|
||||
}
|
||||
template <typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformSubstBuiltinTemplatePackType(
|
||||
TypeLocBuilder &TLB, SubstBuiltinTemplatePackTypeLoc TL) {
|
||||
return TransformTypeSpecType(TLB, TL);
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmPackType(
|
||||
@ -7857,8 +7986,9 @@ TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB,
|
||||
bool RetainExpansion = false;
|
||||
UnsignedOrNone NumExpansions = PackExpansion->getNumExpansions();
|
||||
if (getDerived().TryExpandParameterPacks(
|
||||
PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(),
|
||||
Unexpanded, Expand, RetainExpansion, NumExpansions))
|
||||
PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(),
|
||||
Unexpanded, /*FailOnPackProducingTemplates=*/true, Expand,
|
||||
RetainExpansion, NumExpansions))
|
||||
return QualType();
|
||||
|
||||
if (!Expand) {
|
||||
@ -14841,11 +14971,10 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
|
||||
UnsignedOrNone OrigNumExpansions =
|
||||
ExpansionTL.getTypePtr()->getNumExpansions();
|
||||
UnsignedOrNone NumExpansions = OrigNumExpansions;
|
||||
if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
|
||||
PatternTL.getSourceRange(),
|
||||
Unexpanded,
|
||||
Expand, RetainExpansion,
|
||||
NumExpansions))
|
||||
if (getDerived().TryExpandParameterPacks(
|
||||
ExpansionTL.getEllipsisLoc(), PatternTL.getSourceRange(),
|
||||
Unexpanded, /*FailOnPackProducingTemplates=*/true, Expand,
|
||||
RetainExpansion, NumExpansions))
|
||||
return ExprError();
|
||||
|
||||
if (!Expand) {
|
||||
@ -15419,8 +15548,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
||||
ExpansionTL.getTypePtr()->getNumExpansions();
|
||||
UnsignedOrNone NumExpansions = OrigNumExpansions;
|
||||
if (getDerived().TryExpandParameterPacks(
|
||||
ExpansionTL.getEllipsisLoc(),
|
||||
OldVD->getInit()->getSourceRange(), Unexpanded, Expand,
|
||||
ExpansionTL.getEllipsisLoc(), OldVD->getInit()->getSourceRange(),
|
||||
Unexpanded, /*FailOnPackProducingTemplates=*/true, Expand,
|
||||
RetainExpansion, NumExpansions))
|
||||
return ExprError();
|
||||
assert(!RetainExpansion && "Should not need to retain expansion after a "
|
||||
@ -15580,11 +15709,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
||||
bool ShouldExpand = false;
|
||||
bool RetainExpansion = false;
|
||||
UnsignedOrNone NumExpansions = std::nullopt;
|
||||
if (getDerived().TryExpandParameterPacks(C->getEllipsisLoc(),
|
||||
C->getLocation(),
|
||||
Unexpanded,
|
||||
ShouldExpand, RetainExpansion,
|
||||
NumExpansions)) {
|
||||
if (getDerived().TryExpandParameterPacks(
|
||||
C->getEllipsisLoc(), C->getLocation(), Unexpanded,
|
||||
/*FailOnPackProducingTemplates=*/true, ShouldExpand,
|
||||
RetainExpansion, NumExpansions)) {
|
||||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
@ -16098,10 +16226,10 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
|
||||
bool ShouldExpand = false;
|
||||
bool RetainExpansion = false;
|
||||
UnsignedOrNone NumExpansions = std::nullopt;
|
||||
if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(),
|
||||
Unexpanded,
|
||||
ShouldExpand, RetainExpansion,
|
||||
NumExpansions))
|
||||
if (getDerived().TryExpandParameterPacks(
|
||||
E->getOperatorLoc(), E->getPackLoc(), Unexpanded,
|
||||
/*FailOnPackProducingTemplates=*/true, ShouldExpand,
|
||||
RetainExpansion, NumExpansions))
|
||||
return ExprError();
|
||||
|
||||
// If we need to expand the pack, build a template argument from it and
|
||||
@ -16218,7 +16346,8 @@ TreeTransform<Derived>::TransformPackIndexingExpr(PackIndexingExpr *E) {
|
||||
NumExpansions = std::nullopt;
|
||||
if (getDerived().TryExpandParameterPacks(
|
||||
E->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded,
|
||||
ShouldExpand, RetainExpansion, NumExpansions))
|
||||
/*FailOnPackProducingTemplates=*/true, ShouldExpand,
|
||||
RetainExpansion, NumExpansions))
|
||||
return true;
|
||||
if (!ShouldExpand) {
|
||||
Sema::ArgPackSubstIndexRAII SubstIndex(getSema(), std::nullopt);
|
||||
@ -16324,11 +16453,10 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
|
||||
bool RetainExpansion = false;
|
||||
UnsignedOrNone OrigNumExpansions = E->getNumExpansions(),
|
||||
NumExpansions = OrigNumExpansions;
|
||||
if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(),
|
||||
Pattern->getSourceRange(),
|
||||
Unexpanded,
|
||||
Expand, RetainExpansion,
|
||||
NumExpansions))
|
||||
if (getDerived().TryExpandParameterPacks(
|
||||
E->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded,
|
||||
/*FailOnPackProducingTemplates=*/true, Expand, RetainExpansion,
|
||||
NumExpansions))
|
||||
return true;
|
||||
|
||||
if (!Expand) {
|
||||
@ -16562,9 +16690,10 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
|
||||
UnsignedOrNone NumExpansions = OrigNumExpansions;
|
||||
SourceRange PatternRange(OrigElement.Key->getBeginLoc(),
|
||||
OrigElement.Value->getEndLoc());
|
||||
if (getDerived().TryExpandParameterPacks(OrigElement.EllipsisLoc,
|
||||
PatternRange, Unexpanded, Expand,
|
||||
RetainExpansion, NumExpansions))
|
||||
if (getDerived().TryExpandParameterPacks(
|
||||
OrigElement.EllipsisLoc, PatternRange, Unexpanded,
|
||||
/*FailOnPackProducingTemplates=*/true, Expand, RetainExpansion,
|
||||
NumExpansions))
|
||||
return ExprError();
|
||||
|
||||
if (!Expand) {
|
||||
|
@ -7500,6 +7500,11 @@ void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc(
|
||||
TL.setNameLoc(readSourceLocation());
|
||||
}
|
||||
|
||||
void TypeLocReader::VisitSubstBuiltinTemplatePackTypeLoc(
|
||||
SubstBuiltinTemplatePackTypeLoc TL) {
|
||||
TL.setNameLoc(readSourceLocation());
|
||||
}
|
||||
|
||||
void TypeLocReader::VisitTemplateSpecializationTypeLoc(
|
||||
TemplateSpecializationTypeLoc TL) {
|
||||
SourceLocation ElaboratedKeywordLoc = readSourceLocation();
|
||||
|
@ -627,6 +627,11 @@ void TypeLocWriter::VisitSubstTemplateTypeParmPackTypeLoc(
|
||||
addSourceLocation(TL.getNameLoc());
|
||||
}
|
||||
|
||||
void TypeLocWriter::VisitSubstBuiltinTemplatePackTypeLoc(
|
||||
SubstBuiltinTemplatePackTypeLoc TL) {
|
||||
addSourceLocation(TL.getNameLoc());
|
||||
}
|
||||
|
||||
void TypeLocWriter::VisitTemplateSpecializationTypeLoc(
|
||||
TemplateSpecializationTypeLoc TL) {
|
||||
addSourceLocation(TL.getElaboratedKeywordLoc());
|
||||
@ -1060,6 +1065,7 @@ void ASTWriter::WriteBlockInfoBlock() {
|
||||
RECORD(TYPE_PACK_EXPANSION);
|
||||
RECORD(TYPE_ATTRIBUTED);
|
||||
RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK);
|
||||
RECORD(TYPE_SUBST_BUILTIN_TEMPLATE_PACK);
|
||||
RECORD(TYPE_AUTO);
|
||||
RECORD(TYPE_UNARY_TRANSFORM);
|
||||
RECORD(TYPE_ATOMIC);
|
||||
|
@ -1,33 +1,36 @@
|
||||
// RUN: %clang_cc1 -O1 -triple spirv64 -fsycl-is-device %s -emit-llvm -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -O1 -triple spirv64 -fsycl-is-device -x c++ %s -emit-llvm -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -O1 -triple spirv64 -cl-std=CL3.0 -x cl %s -emit-llvm -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -O1 -triple spirv32 -cl-std=CL3.0 -x cl %s -emit-llvm -o - | FileCheck %s
|
||||
|
||||
// CHECK: spir_func noundef ptr @test_cast_to_private(
|
||||
// CHECK-SAME: ptr addrspace(4) noundef readnone [[P:%.*]]
|
||||
#ifdef __SYCL_DEVICE_ONLY__
|
||||
#define SYCL_EXTERNAL [[clang::sycl_external]]
|
||||
#else
|
||||
#define SYCL_EXTERNAL
|
||||
#endif
|
||||
|
||||
// CHECK: spir_func noundef ptr @{{.*}}test_cast_to_private{{.*}}(ptr addrspace(4) noundef readnone [[P:%.*]]
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[SPV_CAST:%.*]] = tail call noundef ptr @llvm.spv.generic.cast.to.ptr.explicit.p0(ptr addrspace(4) %p)
|
||||
// CHECK-NEXT: ret ptr [[SPV_CAST]]
|
||||
//
|
||||
__attribute__((opencl_private)) int* test_cast_to_private(int* p) {
|
||||
SYCL_EXTERNAL __attribute__((opencl_private)) int* test_cast_to_private(int* p) {
|
||||
return __builtin_spirv_generic_cast_to_ptr_explicit(p, 7);
|
||||
}
|
||||
|
||||
// CHECK: spir_func noundef ptr addrspace(1) @test_cast_to_global(
|
||||
// CHECK-SAME: ptr addrspace(4) noundef readnone [[P:%.*]]
|
||||
// CHECK: spir_func noundef ptr addrspace(1) @{{.*}}test_cast_to_global{{.*}}(ptr addrspace(4) noundef readnone [[P:%.*]]
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[SPV_CAST:%.*]] = tail call noundef ptr addrspace(1) @llvm.spv.generic.cast.to.ptr.explicit.p1(ptr addrspace(4) %p)
|
||||
// CHECK-NEXT: ret ptr addrspace(1) [[SPV_CAST]]
|
||||
//
|
||||
__attribute__((opencl_global)) int* test_cast_to_global(int* p) {
|
||||
SYCL_EXTERNAL __attribute__((opencl_global)) int* test_cast_to_global(int* p) {
|
||||
return __builtin_spirv_generic_cast_to_ptr_explicit(p, 5);
|
||||
}
|
||||
|
||||
// CHECK: spir_func noundef ptr addrspace(3) @test_cast_to_local(
|
||||
// CHECK-SAME: ptr addrspace(4) noundef readnone [[P:%.*]]
|
||||
// CHECK: spir_func noundef ptr addrspace(3) @{{.*}}test_cast_to_local{{.*}}(ptr addrspace(4) noundef readnone [[P:%.*]]
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[SPV_CAST:%.*]] = tail call noundef ptr addrspace(3) @llvm.spv.generic.cast.to.ptr.explicit.p3(ptr addrspace(4) %p)
|
||||
// CHECK-NEXT: ret ptr addrspace(3) [[SPV_CAST]]
|
||||
//
|
||||
__attribute__((opencl_local)) int* test_cast_to_local(int* p) {
|
||||
SYCL_EXTERNAL __attribute__((opencl_local)) int* test_cast_to_local(int* p) {
|
||||
return __builtin_spirv_generic_cast_to_ptr_explicit(p, 4);
|
||||
}
|
||||
|
@ -1,106 +1,106 @@
|
||||
// RUN: %clang_cc1 -O1 -triple spirv64 -fsycl-is-device %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK64
|
||||
// RUN: %clang_cc1 -O1 -triple spirv64 -fsycl-is-device -x c++ %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK64
|
||||
// RUN: %clang_cc1 -O1 -triple spirv64 -cl-std=CL3.0 -x cl %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK64
|
||||
// RUN: %clang_cc1 -O1 -triple spirv32 -cl-std=CL3.0 -x cl %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK32
|
||||
|
||||
// CHECK: @test_num_workgroups(
|
||||
// CHECK: @{{.*}}test_num_workgroups{{.*}}(
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK64-NEXT: tail call i64 @llvm.spv.num.workgroups.i64(i32 0)
|
||||
// CHECK32-NEXT: tail call i32 @llvm.spv.num.workgroups.i32(i32 0)
|
||||
//
|
||||
unsigned int test_num_workgroups() {
|
||||
[[clang::sycl_external]] unsigned int test_num_workgroups() {
|
||||
return __builtin_spirv_num_workgroups(0);
|
||||
}
|
||||
|
||||
// CHECK: @test_workgroup_size(
|
||||
// CHECK: @{{.*}}test_workgroup_size{{.*}}(
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK64-NEXT: tail call i64 @llvm.spv.workgroup.size.i64(i32 0)
|
||||
// CHECK32-NEXT: tail call i32 @llvm.spv.workgroup.size.i32(i32 0)
|
||||
//
|
||||
unsigned int test_workgroup_size() {
|
||||
[[clang::sycl_external]] unsigned int test_workgroup_size() {
|
||||
return __builtin_spirv_workgroup_size(0);
|
||||
}
|
||||
|
||||
// CHECK: @test_workgroup_id(
|
||||
// CHECK: @{{.*}}test_workgroup_id{{.*}}(
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK64-NEXT: tail call i64 @llvm.spv.group.id.i64(i32 0)
|
||||
// CHECK32-NEXT: tail call i32 @llvm.spv.group.id.i32(i32 0)
|
||||
//
|
||||
unsigned int test_workgroup_id() {
|
||||
[[clang::sycl_external]] unsigned int test_workgroup_id() {
|
||||
return __builtin_spirv_workgroup_id(0);
|
||||
}
|
||||
|
||||
// CHECK: @test_local_invocation_id(
|
||||
// CHECK: @{{.*}}test_local_invocation_id{{.*}}(
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK64-NEXT: tail call i64 @llvm.spv.thread.id.in.group.i64(i32 0)
|
||||
// CHECK32-NEXT: tail call i32 @llvm.spv.thread.id.in.group.i32(i32 0)
|
||||
//
|
||||
unsigned int test_local_invocation_id() {
|
||||
[[clang::sycl_external]] unsigned int test_local_invocation_id() {
|
||||
return __builtin_spirv_local_invocation_id(0);
|
||||
}
|
||||
|
||||
// CHECK: @test_global_invocation_id(
|
||||
// CHECK: @{{.*}}test_global_invocation_id{{.*}}(
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK64-NEXT: tail call i64 @llvm.spv.thread.id.i64(i32 0)
|
||||
// CHECK32-NEXT: tail call i32 @llvm.spv.thread.id.i32(i32 0)
|
||||
//
|
||||
unsigned int test_global_invocation_id() {
|
||||
[[clang::sycl_external]] unsigned int test_global_invocation_id() {
|
||||
return __builtin_spirv_global_invocation_id(0);
|
||||
}
|
||||
|
||||
// CHECK: @test_global_size(
|
||||
// CHECK: @{{.*}}test_global_size{{.*}}(
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK64-NEXT: tail call i64 @llvm.spv.global.size.i64(i32 0)
|
||||
// CHECK32-NEXT: tail call i32 @llvm.spv.global.size.i32(i32 0)
|
||||
//
|
||||
unsigned int test_global_size() {
|
||||
[[clang::sycl_external]] unsigned int test_global_size() {
|
||||
return __builtin_spirv_global_size(0);
|
||||
}
|
||||
|
||||
// CHECK: @test_global_offset(
|
||||
// CHECK: @{{.*}}test_global_offset{{.*}}(
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK64-NEXT: tail call i64 @llvm.spv.global.offset.i64(i32 0)
|
||||
// CHECK32-NEXT: tail call i32 @llvm.spv.global.offset.i32(i32 0)
|
||||
//
|
||||
unsigned int test_global_offset() {
|
||||
[[clang::sycl_external]] unsigned int test_global_offset() {
|
||||
return __builtin_spirv_global_offset(0);
|
||||
}
|
||||
|
||||
// CHECK: @test_subgroup_size(
|
||||
// CHECK: @{{.*}}test_subgroup_size{{.*}}(
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: tail call i32 @llvm.spv.subgroup.size()
|
||||
//
|
||||
unsigned int test_subgroup_size() {
|
||||
[[clang::sycl_external]] unsigned int test_subgroup_size() {
|
||||
return __builtin_spirv_subgroup_size();
|
||||
}
|
||||
|
||||
// CHECK: @test_subgroup_max_size(
|
||||
// CHECK: @{{.*}}test_subgroup_max_size{{.*}}(
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: tail call i32 @llvm.spv.subgroup.max.size()
|
||||
//
|
||||
unsigned int test_subgroup_max_size() {
|
||||
[[clang::sycl_external]] unsigned int test_subgroup_max_size() {
|
||||
return __builtin_spirv_subgroup_max_size();
|
||||
}
|
||||
|
||||
// CHECK: @test_num_subgroups(
|
||||
// CHECK: @{{.*}}test_num_subgroups{{.*}}(
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: tail call i32 @llvm.spv.num.subgroups()
|
||||
//
|
||||
unsigned int test_num_subgroups() {
|
||||
[[clang::sycl_external]] unsigned int test_num_subgroups() {
|
||||
return __builtin_spirv_num_subgroups();
|
||||
}
|
||||
|
||||
// CHECK: @test_subgroup_id(
|
||||
// CHECK: @{{.*}}test_subgroup_id{{.*}}(
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: tail call i32 @llvm.spv.subgroup.id()
|
||||
//
|
||||
unsigned int test_subgroup_id() {
|
||||
[[clang::sycl_external]] unsigned int test_subgroup_id() {
|
||||
return __builtin_spirv_subgroup_id();
|
||||
}
|
||||
|
||||
// CHECK: @test_subgroup_local_invocation_id(
|
||||
// CHECK: @{{.*}}test_subgroup_local_invocation_id{{.*}}(
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: tail call i32 @llvm.spv.subgroup.local.invocation.id()
|
||||
//
|
||||
unsigned int test_subgroup_local_invocation_id() {
|
||||
[[clang::sycl_external]] unsigned int test_subgroup_local_invocation_id() {
|
||||
return __builtin_spirv_subgroup_local_invocation_id();
|
||||
}
|
||||
|
@ -1,143 +1,143 @@
|
||||
// RUN: %clang_cc1 -triple spir64 -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s
|
||||
void bar(int &Data) {}
|
||||
// CHECK: define{{.*}} spir_func void @[[RAW_REF:[a-zA-Z0-9_]+]](ptr addrspace(4) noundef align 4 dereferenceable(4) %
|
||||
// CHECK-DAG: define{{.*}} spir_func void @[[RAW_REF:[a-zA-Z0-9_]+]](ptr addrspace(4) noundef align 4 dereferenceable(4) %
|
||||
void bar2(int &Data) {}
|
||||
// CHECK: define{{.*}} spir_func void @[[RAW_REF2:[a-zA-Z0-9_]+]](ptr addrspace(4) noundef align 4 dereferenceable(4) %
|
||||
// CHECK-DAG: define{{.*}} spir_func void @[[RAW_REF2:[a-zA-Z0-9_]+]](ptr addrspace(4) noundef align 4 dereferenceable(4) %
|
||||
void bar(__attribute__((opencl_local)) int &Data) {}
|
||||
// CHECK: define{{.*}} spir_func void [[LOC_REF:@[a-zA-Z0-9_]+]](ptr addrspace(3) noundef align 4 dereferenceable(4) %
|
||||
// CHECK-DAG: define{{.*}} spir_func void [[LOC_REF:@[a-zA-Z0-9_]+]](ptr addrspace(3) noundef align 4 dereferenceable(4) %
|
||||
void foo(int *Data) {}
|
||||
// CHECK: define{{.*}} spir_func void @[[RAW_PTR:[a-zA-Z0-9_]+]](ptr addrspace(4) noundef %
|
||||
// CHECK-DAG: define{{.*}} spir_func void @[[RAW_PTR:[a-zA-Z0-9_]+]](ptr addrspace(4) noundef %
|
||||
void foo2(int *Data) {}
|
||||
// CHECK: define{{.*}} spir_func void @[[RAW_PTR2:[a-zA-Z0-9_]+]](ptr addrspace(4) noundef %
|
||||
// CHECK-DAG: define{{.*}} spir_func void @[[RAW_PTR2:[a-zA-Z0-9_]+]](ptr addrspace(4) noundef %
|
||||
void foo(__attribute__((opencl_local)) int *Data) {}
|
||||
// CHECK: define{{.*}} spir_func void [[LOC_PTR:@[a-zA-Z0-9_]+]](ptr addrspace(3) noundef %
|
||||
// CHECK-DAG: define{{.*}} spir_func void [[LOC_PTR:@[a-zA-Z0-9_]+]](ptr addrspace(3) noundef %
|
||||
|
||||
template <typename T>
|
||||
void tmpl(T t) {}
|
||||
// See Check Lines below.
|
||||
|
||||
void usages() {
|
||||
[[clang::sycl_external]] void usages() {
|
||||
int *NoAS;
|
||||
// CHECK: [[NoAS:%[a-zA-Z0-9]+]] = alloca ptr addrspace(4)
|
||||
// CHECK-DAG: [[NoAS:%[a-zA-Z0-9]+]] = alloca ptr addrspace(4)
|
||||
__attribute__((opencl_global)) int *GLOB;
|
||||
// CHECK: [[GLOB:%[a-zA-Z0-9]+]] = alloca ptr addrspace(1)
|
||||
// CHECK-DAG: [[GLOB:%[a-zA-Z0-9]+]] = alloca ptr addrspace(1)
|
||||
__attribute__((opencl_local)) int *LOC;
|
||||
// CHECK: [[LOC:%[a-zA-Z0-9]+]] = alloca ptr addrspace(3)
|
||||
// CHECK-DAG: [[LOC:%[a-zA-Z0-9]+]] = alloca ptr addrspace(3)
|
||||
__attribute__((opencl_private)) int *PRIV;
|
||||
// CHECK: [[PRIV:%[a-zA-Z0-9]+]] = alloca ptr
|
||||
// CHECK-DAG: [[PRIV:%[a-zA-Z0-9]+]] = alloca ptr
|
||||
__attribute__((opencl_global_device)) int *GLOBDEVICE;
|
||||
// CHECK: [[GLOB_DEVICE:%[a-zA-Z0-9]+]] = alloca ptr addrspace(5)
|
||||
// CHECK-DAG: [[GLOB_DEVICE:%[a-zA-Z0-9]+]] = alloca ptr addrspace(5)
|
||||
__attribute__((opencl_global_host)) int *GLOBHOST;
|
||||
// CHECK: [[GLOB_HOST:%[a-zA-Z0-9]+]] = alloca ptr addrspace(6)
|
||||
// CHECK-DAG: [[GLOB_HOST:%[a-zA-Z0-9]+]] = alloca ptr addrspace(6)
|
||||
|
||||
// CHECK: [[NoAS]].ascast = addrspacecast ptr [[NoAS]] to ptr addrspace(4)
|
||||
// CHECK: [[GLOB]].ascast = addrspacecast ptr [[GLOB]] to ptr addrspace(4)
|
||||
// CHECK: [[LOC]].ascast = addrspacecast ptr [[LOC]] to ptr addrspace(4)
|
||||
// CHECK: [[PRIV]].ascast = addrspacecast ptr [[PRIV]] to ptr addrspace(4)
|
||||
// CHECK-DAG: [[NoAS]].ascast = addrspacecast ptr [[NoAS]] to ptr addrspace(4)
|
||||
// CHECK-DAG: [[GLOB]].ascast = addrspacecast ptr [[GLOB]] to ptr addrspace(4)
|
||||
// CHECK-DAG: [[LOC]].ascast = addrspacecast ptr [[LOC]] to ptr addrspace(4)
|
||||
// CHECK-DAG: [[PRIV]].ascast = addrspacecast ptr [[PRIV]] to ptr addrspace(4)
|
||||
LOC = nullptr;
|
||||
// CHECK: store ptr addrspace(3) null, ptr addrspace(4) [[LOC]].ascast, align 8
|
||||
// CHECK-DAG: store ptr addrspace(3) null, ptr addrspace(4) [[LOC]].ascast, align 8
|
||||
GLOB = nullptr;
|
||||
// CHECK: store ptr addrspace(1) null, ptr addrspace(4) [[GLOB]].ascast, align 8
|
||||
// CHECK-DAG: store ptr addrspace(1) null, ptr addrspace(4) [[GLOB]].ascast, align 8
|
||||
|
||||
// Explicit conversions
|
||||
// From named address spaces to default address space
|
||||
// CHECK: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr addrspace(4)
|
||||
// CHECK: store ptr addrspace(4) [[GLOB_CAST]], ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK-DAG: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK-DAG: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr addrspace(4)
|
||||
// CHECK-DAG: store ptr addrspace(4) [[GLOB_CAST]], ptr addrspace(4) [[NoAS]].ascast
|
||||
NoAS = (int *)GLOB;
|
||||
// CHECK: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr addrspace(4) [[LOC]].ascast
|
||||
// CHECK: [[LOC_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD]] to ptr addrspace(4)
|
||||
// CHECK: store ptr addrspace(4) [[LOC_CAST]], ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK-DAG: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr addrspace(4) [[LOC]].ascast
|
||||
// CHECK-DAG: [[LOC_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD]] to ptr addrspace(4)
|
||||
// CHECK-DAG: store ptr addrspace(4) [[LOC_CAST]], ptr addrspace(4) [[NoAS]].ascast
|
||||
NoAS = (int *)LOC;
|
||||
// CHECK: [[PRIV_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr addrspace(4) [[PRIV]].ascast
|
||||
// CHECK: [[PRIV_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr [[PRIV_LOAD]] to ptr addrspace(4)
|
||||
// CHECK: store ptr addrspace(4) [[PRIV_CAST]], ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK-DAG: [[PRIV_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr addrspace(4) [[PRIV]].ascast
|
||||
// CHECK-DAG: [[PRIV_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr [[PRIV_LOAD]] to ptr addrspace(4)
|
||||
// CHECK-DAG: store ptr addrspace(4) [[PRIV_CAST]], ptr addrspace(4) [[NoAS]].ascast
|
||||
NoAS = (int *)PRIV;
|
||||
// From default address space to named address space
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(4) [[NoAS_LOAD]] to ptr addrspace(1)
|
||||
// CHECK: store ptr addrspace(1) [[NoAS_CAST]], ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK-DAG: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(4) [[NoAS_LOAD]] to ptr addrspace(1)
|
||||
// CHECK-DAG: store ptr addrspace(1) [[NoAS_CAST]], ptr addrspace(4) [[GLOB]].ascast
|
||||
GLOB = (__attribute__((opencl_global)) int *)NoAS;
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(4) [[NoAS_LOAD]] to ptr addrspace(3)
|
||||
// CHECK: store ptr addrspace(3) [[NoAS_CAST]], ptr addrspace(4) [[LOC]].ascast
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK-DAG: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(4) [[NoAS_LOAD]] to ptr addrspace(3)
|
||||
// CHECK-DAG: store ptr addrspace(3) [[NoAS_CAST]], ptr addrspace(4) [[LOC]].ascast
|
||||
LOC = (__attribute__((opencl_local)) int *)NoAS;
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(4) [[NoAS_LOAD]] to ptr
|
||||
// CHECK: store ptr [[NoAS_CAST]], ptr addrspace(4) [[PRIV]].ascast
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK-DAG: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(4) [[NoAS_LOAD]] to ptr
|
||||
// CHECK-DAG: store ptr [[NoAS_CAST]], ptr addrspace(4) [[PRIV]].ascast
|
||||
PRIV = (__attribute__((opencl_private)) int *)NoAS;
|
||||
// From opencl_global_[host/device] address spaces to opencl_global
|
||||
// CHECK: [[GLOBDEVICE_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(5), ptr addrspace(4) [[GLOB_DEVICE]].ascast
|
||||
// CHECK: [[GLOBDEVICE_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(5) [[GLOBDEVICE_LOAD]] to ptr addrspace(1)
|
||||
// CHECK: store ptr addrspace(1) [[GLOBDEVICE_CAST]], ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK-DAG: [[GLOBDEVICE_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(5), ptr addrspace(4) [[GLOB_DEVICE]].ascast
|
||||
// CHECK-DAG: [[GLOBDEVICE_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(5) [[GLOBDEVICE_LOAD]] to ptr addrspace(1)
|
||||
// CHECK-DAG: store ptr addrspace(1) [[GLOBDEVICE_CAST]], ptr addrspace(4) [[GLOB]].ascast
|
||||
GLOB = (__attribute__((opencl_global)) int *)GLOBDEVICE;
|
||||
// CHECK: [[GLOBHOST_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(6), ptr addrspace(4) [[GLOB_HOST]].ascast
|
||||
// CHECK: [[GLOBHOST_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(6) [[GLOBHOST_LOAD]] to ptr addrspace(1)
|
||||
// CHECK: store ptr addrspace(1) [[GLOBHOST_CAST]], ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK-DAG: [[GLOBHOST_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(6), ptr addrspace(4) [[GLOB_HOST]].ascast
|
||||
// CHECK-DAG: [[GLOBHOST_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(6) [[GLOBHOST_LOAD]] to ptr addrspace(1)
|
||||
// CHECK-DAG: store ptr addrspace(1) [[GLOBHOST_CAST]], ptr addrspace(4) [[GLOB]].ascast
|
||||
GLOB = (__attribute__((opencl_global)) int *)GLOBHOST;
|
||||
|
||||
bar(*GLOB);
|
||||
// CHECK: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr addrspace(4)
|
||||
// CHECK: call spir_func void @[[RAW_REF]](ptr addrspace(4) noundef align 4 dereferenceable(4) [[GLOB_CAST]])
|
||||
// CHECK-DAG: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK-DAG: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr addrspace(4)
|
||||
// CHECK-DAG: call spir_func void @[[RAW_REF]](ptr addrspace(4) noundef align 4 dereferenceable(4) [[GLOB_CAST]])
|
||||
bar2(*GLOB);
|
||||
// CHECK: [[GLOB_LOAD2:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK: [[GLOB_CAST2:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD2]] to ptr addrspace(4)
|
||||
// CHECK: call spir_func void @[[RAW_REF2]](ptr addrspace(4) noundef align 4 dereferenceable(4) [[GLOB_CAST2]])
|
||||
// CHECK-DAG: [[GLOB_LOAD2:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK-DAG: [[GLOB_CAST2:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD2]] to ptr addrspace(4)
|
||||
// CHECK-DAG: call spir_func void @[[RAW_REF2]](ptr addrspace(4) noundef align 4 dereferenceable(4) [[GLOB_CAST2]])
|
||||
|
||||
bar(*LOC);
|
||||
// CHECK: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr addrspace(4) [[LOC]].ascast
|
||||
// CHECK: call spir_func void [[LOC_REF]](ptr addrspace(3) noundef align 4 dereferenceable(4) [[LOC_LOAD]])
|
||||
// CHECK-DAG: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr addrspace(4) [[LOC]].ascast
|
||||
// CHECK-DAG: call spir_func void [[LOC_REF]](ptr addrspace(3) noundef align 4 dereferenceable(4) [[LOC_LOAD]])
|
||||
bar2(*LOC);
|
||||
// CHECK: [[LOC_LOAD2:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr addrspace(4) [[LOC]].ascast
|
||||
// CHECK: [[LOC_CAST2:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD2]] to ptr addrspace(4)
|
||||
// CHECK: call spir_func void @[[RAW_REF2]](ptr addrspace(4) noundef align 4 dereferenceable(4) [[LOC_CAST2]])
|
||||
// CHECK-DAG: [[LOC_LOAD2:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr addrspace(4) [[LOC]].ascast
|
||||
// CHECK-DAG: [[LOC_CAST2:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD2]] to ptr addrspace(4)
|
||||
// CHECK-DAG: call spir_func void @[[RAW_REF2]](ptr addrspace(4) noundef align 4 dereferenceable(4) [[LOC_CAST2]])
|
||||
|
||||
bar(*NoAS);
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK: call spir_func void @[[RAW_REF]](ptr addrspace(4) noundef align 4 dereferenceable(4) [[NoAS_LOAD]])
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK-DAG: call spir_func void @[[RAW_REF]](ptr addrspace(4) noundef align 4 dereferenceable(4) [[NoAS_LOAD]])
|
||||
bar2(*NoAS);
|
||||
// CHECK: [[NoAS_LOAD2:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK: call spir_func void @[[RAW_REF2]](ptr addrspace(4) noundef align 4 dereferenceable(4) [[NoAS_LOAD2]])
|
||||
// CHECK-DAG: [[NoAS_LOAD2:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK-DAG: call spir_func void @[[RAW_REF2]](ptr addrspace(4) noundef align 4 dereferenceable(4) [[NoAS_LOAD2]])
|
||||
|
||||
foo(GLOB);
|
||||
// CHECK: [[GLOB_LOAD3:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK: [[GLOB_CAST3:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD3]] to ptr addrspace(4)
|
||||
// CHECK: call spir_func void @[[RAW_PTR]](ptr addrspace(4) noundef [[GLOB_CAST3]])
|
||||
// CHECK-DAG: [[GLOB_LOAD3:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK-DAG: [[GLOB_CAST3:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD3]] to ptr addrspace(4)
|
||||
// CHECK-DAG: call spir_func void @[[RAW_PTR]](ptr addrspace(4) noundef [[GLOB_CAST3]])
|
||||
foo2(GLOB);
|
||||
// CHECK: [[GLOB_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK: [[GLOB_CAST4:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD4]] to ptr addrspace(4)
|
||||
// CHECK: call spir_func void @[[RAW_PTR2]](ptr addrspace(4) noundef [[GLOB_CAST4]])
|
||||
// CHECK-DAG: [[GLOB_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK-DAG: [[GLOB_CAST4:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD4]] to ptr addrspace(4)
|
||||
// CHECK-DAG: call spir_func void @[[RAW_PTR2]](ptr addrspace(4) noundef [[GLOB_CAST4]])
|
||||
foo(LOC);
|
||||
// CHECK: [[LOC_LOAD3:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr addrspace(4) [[LOC]].ascast
|
||||
// CHECK: call spir_func void [[LOC_PTR]](ptr addrspace(3) noundef [[LOC_LOAD3]])
|
||||
// CHECK-DAG: [[LOC_LOAD3:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr addrspace(4) [[LOC]].ascast
|
||||
// CHECK-DAG: call spir_func void [[LOC_PTR]](ptr addrspace(3) noundef [[LOC_LOAD3]])
|
||||
foo2(LOC);
|
||||
// CHECK: [[LOC_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr addrspace(4) [[LOC]].ascast
|
||||
// CHECK: [[LOC_CAST4:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD4]] to ptr addrspace(4)
|
||||
// CHECK: call spir_func void @[[RAW_PTR2]](ptr addrspace(4) noundef [[LOC_CAST4]])
|
||||
// CHECK-DAG: [[LOC_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr addrspace(4) [[LOC]].ascast
|
||||
// CHECK-DAG: [[LOC_CAST4:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD4]] to ptr addrspace(4)
|
||||
// CHECK-DAG: call spir_func void @[[RAW_PTR2]](ptr addrspace(4) noundef [[LOC_CAST4]])
|
||||
foo(NoAS);
|
||||
// CHECK: [[NoAS_LOAD3:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK: call spir_func void @[[RAW_PTR]](ptr addrspace(4) noundef [[NoAS_LOAD3]])
|
||||
// CHECK-DAG: [[NoAS_LOAD3:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK-DAG: call spir_func void @[[RAW_PTR]](ptr addrspace(4) noundef [[NoAS_LOAD3]])
|
||||
foo2(NoAS);
|
||||
// CHECK: [[NoAS_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK: call spir_func void @[[RAW_PTR2]](ptr addrspace(4) noundef [[NoAS_LOAD4]])
|
||||
// CHECK-DAG: [[NoAS_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK-DAG: call spir_func void @[[RAW_PTR2]](ptr addrspace(4) noundef [[NoAS_LOAD4]])
|
||||
|
||||
// Ensure that we still get 3 different template instantiations.
|
||||
tmpl(GLOB);
|
||||
// CHECK: [[GLOB_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK: call spir_func void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) noundef [[GLOB_LOAD4]])
|
||||
// CHECK-DAG: [[GLOB_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr addrspace(4) [[GLOB]].ascast
|
||||
// CHECK-DAG: call spir_func void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) noundef [[GLOB_LOAD4]])
|
||||
tmpl(LOC);
|
||||
// CHECK: [[LOC_LOAD5:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr addrspace(4) [[LOC]].ascast
|
||||
// CHECK: call spir_func void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) noundef [[LOC_LOAD5]])
|
||||
// CHECK-DAG: [[LOC_LOAD5:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr addrspace(4) [[LOC]].ascast
|
||||
// CHECK-DAG: call spir_func void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) noundef [[LOC_LOAD5]])
|
||||
tmpl(PRIV);
|
||||
// CHECK: [[PRIV_LOAD5:%[a-zA-Z0-9]+]] = load ptr, ptr addrspace(4) [[PRIV]].ascast
|
||||
// CHECK: call spir_func void @_Z4tmplIPU3AS0iEvT_(ptr noundef [[PRIV_LOAD5]])
|
||||
// CHECK-DAG: [[PRIV_LOAD5:%[a-zA-Z0-9]+]] = load ptr, ptr addrspace(4) [[PRIV]].ascast
|
||||
// CHECK-DAG: call spir_func void @_Z4tmplIPU3AS0iEvT_(ptr noundef [[PRIV_LOAD5]])
|
||||
tmpl(NoAS);
|
||||
// CHECK: [[NoAS_LOAD5:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK: call spir_func void @_Z4tmplIPiEvT_(ptr addrspace(4) noundef [[NoAS_LOAD5]])
|
||||
// CHECK-DAG: [[NoAS_LOAD5:%[a-zA-Z0-9]+]] = load ptr addrspace(4), ptr addrspace(4) [[NoAS]].ascast
|
||||
// CHECK-DAG: call spir_func void @_Z4tmplIPiEvT_(ptr addrspace(4) noundef [[NoAS_LOAD5]])
|
||||
}
|
||||
|
||||
// CHECK: define linkonce_odr spir_func void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) noundef %
|
||||
// CHECK: define linkonce_odr spir_func void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) noundef %
|
||||
// CHECK: define linkonce_odr spir_func void @_Z4tmplIPU3AS0iEvT_(ptr noundef %
|
||||
// CHECK: define linkonce_odr spir_func void @_Z4tmplIPiEvT_(ptr addrspace(4) noundef %
|
||||
// CHECK-DAG: define linkonce_odr spir_func void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) noundef %
|
||||
// CHECK-DAG: define linkonce_odr spir_func void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) noundef %
|
||||
// CHECK-DAG: define linkonce_odr spir_func void @_Z4tmplIPU3AS0iEvT_(ptr noundef %
|
||||
// CHECK-DAG: define linkonce_odr spir_func void @_Z4tmplIPiEvT_(ptr addrspace(4) noundef %
|
||||
|
@ -85,7 +85,7 @@
|
||||
// CHECK-NEXT: store ptr addrspace(4) addrspacecast (ptr addrspace(1) @.str.1 to ptr addrspace(4)), ptr addrspace(4) [[SELECT_STR_TRIVIAL2_ASCAST]], align 8
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
void test() {
|
||||
[[clang::sycl_external]] void test() {
|
||||
static const int foo = 0x42;
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ void foo(int *);
|
||||
// X86: declare void @_Z3fooPU9SYprivatei(ptr noundef) #1
|
||||
// X86: declare void @_Z3fooPi(ptr noundef) #1
|
||||
|
||||
void test() {
|
||||
[[clang::sycl_external]] void test() {
|
||||
__attribute__((opencl_global)) int *glob;
|
||||
__attribute__((opencl_local)) int *loc;
|
||||
__attribute__((opencl_private)) int *priv;
|
||||
|
@ -1,128 +1,128 @@
|
||||
// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s
|
||||
void bar(int &Data) {}
|
||||
// CHECK: define dso_local void @[[RAW_REF:[a-zA-Z0-9_]+]](ptr noundef nonnull align 4 dereferenceable(4) %
|
||||
// CHECK-DAG: define {{.*}} void @[[RAW_REF:[a-zA-Z0-9_]+]](ptr noundef nonnull align 4 dereferenceable(4) %
|
||||
void bar2(int &Data) {}
|
||||
// CHECK: define dso_local void @[[RAW_REF2:[a-zA-Z0-9_]+]](ptr noundef nonnull align 4 dereferenceable(4) %
|
||||
// CHECK-DAG: define {{.*}} void @[[RAW_REF2:[a-zA-Z0-9_]+]](ptr noundef nonnull align 4 dereferenceable(4) %
|
||||
void bar(__attribute__((opencl_local)) int &Data) {}
|
||||
// CHECK: define dso_local void @[[LOCAL_REF:[a-zA-Z0-9_]+]](ptr addrspace(3) noundef align 4 dereferenceable(4) %
|
||||
// CHECK-DAG: define {{.*}} void @[[LOCAL_REF:[a-zA-Z0-9_]+]](ptr addrspace(3) noundef align 4 dereferenceable(4) %
|
||||
void foo(int *Data) {}
|
||||
// CHECK: define dso_local void @[[RAW_PTR:[a-zA-Z0-9_]+]](ptr noundef %
|
||||
// CHECK-DAG: define {{.*}} void @[[RAW_PTR:[a-zA-Z0-9_]+]](ptr noundef %
|
||||
void foo2(int *Data) {}
|
||||
// CHECK: define dso_local void @[[RAW_PTR2:[a-zA-Z0-9_]+]](ptr noundef %
|
||||
// CHECK-DAG: define {{.*}} void @[[RAW_PTR2:[a-zA-Z0-9_]+]](ptr noundef %
|
||||
void foo(__attribute__((opencl_local)) int *Data) {}
|
||||
// CHECK: define dso_local void @[[LOC_PTR:[a-zA-Z0-9_]+]](ptr addrspace(3) noundef %
|
||||
// CHECK-DAG: define {{.*}} void @[[LOC_PTR:[a-zA-Z0-9_]+]](ptr addrspace(3) noundef %
|
||||
|
||||
template <typename T>
|
||||
void tmpl(T t);
|
||||
void tmpl(T t) {}
|
||||
// See Check Lines below.
|
||||
|
||||
void usages() {
|
||||
[[clang::sycl_external]] void usages() {
|
||||
int *NoAS;
|
||||
// CHECK: [[NoAS:%[a-zA-Z0-9]+]] = alloca ptr, align 8, addrspace(5)
|
||||
// CHECK-DAG: [[NoAS:%[a-zA-Z0-9]+]] = alloca ptr, align 8, addrspace(5)
|
||||
__attribute__((opencl_global)) int *GLOB;
|
||||
// CHECK: [[GLOB:%[a-zA-Z0-9]+]] = alloca ptr addrspace(1), align 8, addrspace(5)
|
||||
// CHECK-DAG: [[GLOB:%[a-zA-Z0-9]+]] = alloca ptr addrspace(1), align 8, addrspace(5)
|
||||
__attribute__((opencl_local)) int *LOC;
|
||||
// CHECK: [[LOC:%[a-zA-Z0-9]+]] = alloca ptr addrspace(3), align 4, addrspace(5)
|
||||
// CHECK-DAG: [[LOC:%[a-zA-Z0-9]+]] = alloca ptr addrspace(3), align 4, addrspace(5)
|
||||
__attribute__((opencl_private)) int *PRIV;
|
||||
// CHECK: [[PRIV:%[a-zA-Z0-9]+]] = alloca ptr addrspace(5), align 4, addrspace(5)
|
||||
// CHECK-DAG: [[PRIV:%[a-zA-Z0-9]+]] = alloca ptr addrspace(5), align 4, addrspace(5)
|
||||
__attribute__((opencl_global_device)) int *GLOBDEVICE;
|
||||
// CHECK: [[GLOB_DEVICE:%[a-zA-Z0-9]+]] = alloca ptr addrspace(1), align 8, addrspace(5)
|
||||
// CHECK-DAG: [[GLOB_DEVICE:%[a-zA-Z0-9]+]] = alloca ptr addrspace(1), align 8, addrspace(5)
|
||||
__attribute__((opencl_global_host)) int *GLOBHOST;
|
||||
// CHECK: [[GLOB_HOST:%[a-zA-Z0-9]+]] = alloca ptr addrspace(1), align 8, addrspace(5)
|
||||
// CHECK-DAG: [[GLOB_HOST:%[a-zA-Z0-9]+]] = alloca ptr addrspace(1), align 8, addrspace(5)
|
||||
LOC = nullptr;
|
||||
// CHECK: store ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr [[LOC]].ascast, align 4
|
||||
// CHECK-DAG: store ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr [[LOC]].ascast, align 4
|
||||
GLOB = nullptr;
|
||||
// CHECK: store ptr addrspace(1) null, ptr [[GLOB]].ascast, align 8
|
||||
// CHECK-DAG: store ptr addrspace(1) null, ptr [[GLOB]].ascast, align 8
|
||||
NoAS = (int *)GLOB;
|
||||
// CHECK: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]].ascast, align 8
|
||||
// CHECK: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr
|
||||
// CHECK: store ptr [[GLOB_CAST]], ptr [[NoAS]].ascast, align 8
|
||||
// CHECK-DAG: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]].ascast, align 8
|
||||
// CHECK-DAG: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr
|
||||
// CHECK-DAG: store ptr [[GLOB_CAST]], ptr [[NoAS]].ascast, align 8
|
||||
NoAS = (int *)LOC;
|
||||
// CHECK: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]].ascast, align 4
|
||||
// CHECK: [[LOC_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD]] to ptr
|
||||
// CHECK: store ptr [[LOC_CAST]], ptr [[NoAS]].ascast, align 8
|
||||
// CHECK-DAG: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]].ascast, align 4
|
||||
// CHECK-DAG: [[LOC_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD]] to ptr
|
||||
// CHECK-DAG: store ptr [[LOC_CAST]], ptr [[NoAS]].ascast, align 8
|
||||
NoAS = (int *)PRIV;
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(5), ptr [[PRIV]].ascast, align 4
|
||||
// CHECK: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(5) [[NoAS_LOAD]] to ptr
|
||||
// CHECK: store ptr %5, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(5), ptr [[PRIV]].ascast, align 4
|
||||
// CHECK-DAG: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(5) [[NoAS_LOAD]] to ptr
|
||||
// CHECK-DAG: store ptr %5, ptr [[NoAS]].ascast, align 8
|
||||
GLOB = (__attribute__((opencl_global)) int *)NoAS;
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr %6 to ptr addrspace(1)
|
||||
// CHECK: store ptr addrspace(1) %7, ptr [[GLOB]].ascast, align 8
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK-DAG: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr %6 to ptr addrspace(1)
|
||||
// CHECK-DAG: store ptr addrspace(1) %7, ptr [[GLOB]].ascast, align 8
|
||||
LOC = (__attribute__((opencl_local)) int *)NoAS;
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr [[NoAS_LOAD]] to ptr addrspace(3)
|
||||
// CHECK: store ptr addrspace(3) %9, ptr [[LOC]].ascast, align 4
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK-DAG: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr [[NoAS_LOAD]] to ptr addrspace(3)
|
||||
// CHECK-DAG: store ptr addrspace(3) %9, ptr [[LOC]].ascast, align 4
|
||||
PRIV = (__attribute__((opencl_private)) int *)NoAS;
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr [[NoAS_LOAD]] to ptr addrspace(5)
|
||||
// CHECK: store ptr addrspace(5) [[NoAS_CAST]], ptr [[PRIV]].ascast, align 4
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK-DAG: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr [[NoAS_LOAD]] to ptr addrspace(5)
|
||||
// CHECK-DAG: store ptr addrspace(5) [[NoAS_CAST]], ptr [[PRIV]].ascast, align 4
|
||||
GLOB = (__attribute__((opencl_global)) int *)GLOBDEVICE;
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]]DEVICE.ascast, align 8
|
||||
// CHECK: store ptr addrspace(1) [[NoAS_LOAD]], ptr [[GLOB]].ascast, align 8
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]]DEVICE.ascast, align 8
|
||||
// CHECK-DAG: store ptr addrspace(1) [[NoAS_LOAD]], ptr [[GLOB]].ascast, align 8
|
||||
GLOB = (__attribute__((opencl_global)) int *)GLOBHOST;
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]]HOST.ascast, align 8
|
||||
// CHECK: tore ptr addrspace(1) [[NoAS_LOAD]], ptr [[GLOB]].ascast, align 8
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]]HOST.ascast, align 8
|
||||
// CHECK-DAG: tore ptr addrspace(1) [[NoAS_LOAD]], ptr [[GLOB]].ascast, align 8
|
||||
bar(*GLOB);
|
||||
// CHECK: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]].ascast, align 8
|
||||
// CHECK: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr
|
||||
// CHECK: call void @[[RAW_REF]](ptr noundef nonnull align 4 dereferenceable(4) [[GLOB_CAST]])
|
||||
// CHECK-DAG: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]].ascast, align 8
|
||||
// CHECK-DAG: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr
|
||||
// CHECK-DAG: call void @[[RAW_REF]](ptr noundef nonnull align 4 dereferenceable(4) [[GLOB_CAST]])
|
||||
bar2(*GLOB);
|
||||
// CHECK: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]].ascast, align 8
|
||||
// CHECK: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr
|
||||
// CHECK: call void @[[RAW_REF2]](ptr noundef nonnull align 4 dereferenceable(4) [[GLOB_CAST]])
|
||||
// CHECK-DAG: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]].ascast, align 8
|
||||
// CHECK-DAG: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr
|
||||
// CHECK-DAG: call void @[[RAW_REF2]](ptr noundef nonnull align 4 dereferenceable(4) [[GLOB_CAST]])
|
||||
bar(*LOC);
|
||||
// CHECK: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]].ascast, align 4
|
||||
// CHECK: call void @_Z3barRU3AS3i(ptr addrspace(3) noundef align 4 dereferenceable(4) [[LOC_LOAD]])
|
||||
// CHECK-DAG: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]].ascast, align 4
|
||||
// CHECK-DAG: call void @_Z3barRU3AS3i(ptr addrspace(3) noundef align 4 dereferenceable(4) [[LOC_LOAD]])
|
||||
bar2(*LOC);
|
||||
// CHECK: [[LOC_LOAD2:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]].ascast, align 4
|
||||
// CHECK: [[LOC_CAST2:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD2]] to ptr
|
||||
// CHECK: call void @_Z4bar2Ri(ptr noundef nonnull align 4 dereferenceable(4) [[LOC_CAST2]])
|
||||
// CHECK-DAG: [[LOC_LOAD2:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]].ascast, align 4
|
||||
// CHECK-DAG: [[LOC_CAST2:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD2]] to ptr
|
||||
// CHECK-DAG: call void @_Z4bar2Ri(ptr noundef nonnull align 4 dereferenceable(4) [[LOC_CAST2]])
|
||||
bar(*NoAS);
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK: call void @_Z3barRi(ptr noundef nonnull align 4 dereferenceable(4) [[NoAS_LOAD]])
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK-DAG: call void @_Z3barRi(ptr noundef nonnull align 4 dereferenceable(4) [[NoAS_LOAD]])
|
||||
bar2(*NoAS);
|
||||
// CHECK: [[NoAS_LOAD2:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK: call void @_Z4bar2Ri(ptr noundef nonnull align 4 dereferenceable(4) [[NoAS_LOAD2]])
|
||||
// CHECK-DAG: [[NoAS_LOAD2:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK-DAG: call void @_Z4bar2Ri(ptr noundef nonnull align 4 dereferenceable(4) [[NoAS_LOAD2]])
|
||||
foo(GLOB);
|
||||
// CHECK: [[GLOB_LOAD3:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]].ascast, align 8
|
||||
// CHECK: [[GLOB_CAST3:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD3]] to ptr
|
||||
// CHECK: call void @[[RAW_PTR]](ptr noundef [[GLOB_CAST3]])
|
||||
// CHECK-DAG: [[GLOB_LOAD3:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]].ascast, align 8
|
||||
// CHECK-DAG: [[GLOB_CAST3:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD3]] to ptr
|
||||
// CHECK-DAG: call void @[[RAW_PTR]](ptr noundef [[GLOB_CAST3]])
|
||||
foo2(GLOB);
|
||||
// CHECK: [[GLOB_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]].ascast, align 8
|
||||
// CHECK: [[GLOB_CAST4:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD4]] to ptr
|
||||
// CHECK: call void @[[RAW_PTR2]](ptr noundef [[GLOB_CAST4]])
|
||||
// CHECK-DAG: [[GLOB_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]].ascast, align 8
|
||||
// CHECK-DAG: [[GLOB_CAST4:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD4]] to ptr
|
||||
// CHECK-DAG: call void @[[RAW_PTR2]](ptr noundef [[GLOB_CAST4]])
|
||||
foo(LOC);
|
||||
// CHECK: [[LOC_LOAD3:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]].ascast, align 4
|
||||
// CHECK: call void @[[LOC_PTR]](ptr addrspace(3) noundef [[LOC_LOAD3]])
|
||||
// CHECK-DAG: [[LOC_LOAD3:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]].ascast, align 4
|
||||
// CHECK-DAG: call void @[[LOC_PTR]](ptr addrspace(3) noundef [[LOC_LOAD3]])
|
||||
foo2(LOC);
|
||||
// CHECK: [[LOC_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]].ascast, align 4
|
||||
// CHECK: [[LOC_CAST4:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD4]] to ptr
|
||||
// CHECK: call void @[[RAW_PTR2]](ptr noundef [[LOC_CAST4]])
|
||||
// CHECK-DAG: [[LOC_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]].ascast, align 4
|
||||
// CHECK-DAG: [[LOC_CAST4:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD4]] to ptr
|
||||
// CHECK-DAG: call void @[[RAW_PTR2]](ptr noundef [[LOC_CAST4]])
|
||||
foo(NoAS);
|
||||
// CHECK: [[NoAS_LOAD3:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK: call void @[[RAW_PTR]](ptr noundef [[NoAS_LOAD3]])
|
||||
// CHECK-DAG: [[NoAS_LOAD3:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK-DAG: call void @[[RAW_PTR]](ptr noundef [[NoAS_LOAD3]])
|
||||
foo2(NoAS);
|
||||
// CHECK: [[NoAS_LOAD4:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK: call void @[[RAW_PTR2]](ptr noundef [[NoAS_LOAD4]])
|
||||
// CHECK-DAG: [[NoAS_LOAD4:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK-DAG: call void @[[RAW_PTR2]](ptr noundef [[NoAS_LOAD4]])
|
||||
|
||||
// Ensure that we still get 3 different template instantiations.
|
||||
tmpl(GLOB);
|
||||
// CHECK: [[GLOB_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]].ascast, align 8
|
||||
// CHECK: call void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) noundef [[GLOB_LOAD4]])
|
||||
// CHECK-DAG: [[GLOB_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]].ascast, align 8
|
||||
// CHECK-DAG: call void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) noundef [[GLOB_LOAD4]])
|
||||
tmpl(LOC);
|
||||
// CHECK: [[LOC_LOAD5:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]].ascast, align 4
|
||||
// CHECK: call void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) noundef [[LOC_LOAD5]])
|
||||
// CHECK-DAG: [[LOC_LOAD5:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]].ascast, align 4
|
||||
// CHECK-DAG: call void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) noundef [[LOC_LOAD5]])
|
||||
tmpl(PRIV);
|
||||
// CHECK: [[PRIV_LOAD5:%[a-zA-Z0-9]+]] = load ptr addrspace(5), ptr [[PRIV]].ascast, align 4
|
||||
// CHECK: call void @_Z4tmplIPU3AS5iEvT_(ptr addrspace(5) noundef [[PRIV_LOAD5]])
|
||||
// CHECK-DAG: [[PRIV_LOAD5:%[a-zA-Z0-9]+]] = load ptr addrspace(5), ptr [[PRIV]].ascast, align 4
|
||||
// CHECK-DAG: call void @_Z4tmplIPU3AS5iEvT_(ptr addrspace(5) noundef [[PRIV_LOAD5]])
|
||||
tmpl(NoAS);
|
||||
// CHECK: [[NoAS_LOAD5:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK: call void @_Z4tmplIPiEvT_(ptr noundef [[NoAS_LOAD5]])
|
||||
// CHECK-DAG: [[NoAS_LOAD5:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]].ascast, align 8
|
||||
// CHECK-DAG: call void @_Z4tmplIPiEvT_(ptr noundef [[NoAS_LOAD5]])
|
||||
}
|
||||
|
||||
// CHECK: declare void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) noundef)
|
||||
// CHECK: declare void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) noundef)
|
||||
// CHECK: declare void @_Z4tmplIPU3AS5iEvT_(ptr addrspace(5) noundef)
|
||||
// CHECK: declare void @_Z4tmplIPiEvT_(ptr noundef)
|
||||
// CHECK-DAG: define linkonce_odr void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) noundef %
|
||||
// CHECK-DAG: define linkonce_odr void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) noundef %
|
||||
// CHECK-DAG: define linkonce_odr void @_Z4tmplIPU3AS5iEvT_(ptr addrspace(5) noundef %
|
||||
// CHECK-DAG: define linkonce_odr void @_Z4tmplIPiEvT_(ptr noundef %
|
||||
|
||||
|
@ -1,122 +1,122 @@
|
||||
// RUN: %clang_cc1 -triple nvptx64-nvidia-cuda -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s
|
||||
void bar(int &Data) {}
|
||||
// CHECK: define dso_local void @[[RAW_REF:[a-zA-Z0-9_]+]](ptr noundef nonnull align 4 dereferenceable(4) %
|
||||
// CHECK-DAG: define {{.*}} void @[[RAW_REF:[a-zA-Z0-9_]+]](ptr noundef nonnull align 4 dereferenceable(4) %
|
||||
void bar2(int &Data) {}
|
||||
// CHECK: define dso_local void @[[RAW_REF2:[a-zA-Z0-9_]+]](ptr noundef nonnull align 4 dereferenceable(4) %
|
||||
// CHECK-DAG: define {{.*}} void @[[RAW_REF2:[a-zA-Z0-9_]+]](ptr noundef nonnull align 4 dereferenceable(4) %
|
||||
void bar(__attribute__((opencl_local)) int &Data) {}
|
||||
// CHECK: define dso_local void @[[LOCAL_REF:[a-zA-Z0-9_]+]](ptr addrspace(3) noundef align 4 dereferenceable(4) %
|
||||
// CHECK-DAG: define {{.*}} void @[[LOCAL_REF:[a-zA-Z0-9_]+]](ptr addrspace(3) noundef align 4 dereferenceable(4) %
|
||||
void foo(int *Data) {}
|
||||
// CHECK: define dso_local void @[[RAW_PTR:[a-zA-Z0-9_]+]](ptr noundef %
|
||||
// CHECK-DAG: define {{.*}} void @[[RAW_PTR:[a-zA-Z0-9_]+]](ptr noundef %
|
||||
void foo2(int *Data) {}
|
||||
// CHECK: define dso_local void @[[RAW_PTR2:[a-zA-Z0-9_]+]](ptr noundef %
|
||||
// CHECK-DAG: define {{.*}} void @[[RAW_PTR2:[a-zA-Z0-9_]+]](ptr noundef %
|
||||
void foo(__attribute__((opencl_local)) int *Data) {}
|
||||
// CHECK: define dso_local void @[[LOC_PTR:[a-zA-Z0-9_]+]](ptr addrspace(3) noundef %
|
||||
// CHECK-DAG: define {{.*}} void @[[LOC_PTR:[a-zA-Z0-9_]+]](ptr addrspace(3) noundef %
|
||||
|
||||
template <typename T>
|
||||
void tmpl(T t);
|
||||
// See Check Lines below.
|
||||
|
||||
void usages() {
|
||||
[[clang::sycl_external]] void usages() {
|
||||
int *NoAS;
|
||||
// CHECK: [[NoAS:%[a-zA-Z0-9]+]] = alloca ptr, align 8
|
||||
// CHECK-DAG: [[NoAS:%[a-zA-Z0-9]+]] = alloca ptr, align 8
|
||||
__attribute__((opencl_global)) int *GLOB;
|
||||
// CHECK: [[GLOB:%[a-zA-Z0-9]+]] = alloca ptr addrspace(1), align 8
|
||||
// CHECK-DAG: [[GLOB:%[a-zA-Z0-9]+]] = alloca ptr addrspace(1), align 8
|
||||
__attribute__((opencl_local)) int *LOC;
|
||||
// CHECK: [[LOC:%[a-zA-Z0-9]+]] = alloca ptr addrspace(3), align 8
|
||||
// CHECK-DAG: [[LOC:%[a-zA-Z0-9]+]] = alloca ptr addrspace(3), align 8
|
||||
__attribute__((opencl_private)) int *PRIV;
|
||||
// CHECK: [[PRIV:%[a-zA-Z0-9]+]] = alloca ptr, align 8
|
||||
// CHECK-DAG: [[PRIV:%[a-zA-Z0-9]+]] = alloca ptr, align 8
|
||||
__attribute__((opencl_global_device)) int *GLOBDEVICE;
|
||||
// CHECK: [[GLOB_DEVICE:%[a-zA-Z0-9]+]] = alloca ptr addrspace(1), align 8
|
||||
// CHECK-DAG: [[GLOB_DEVICE:%[a-zA-Z0-9]+]] = alloca ptr addrspace(1), align 8
|
||||
__attribute__((opencl_global_host)) int *GLOBHOST;
|
||||
// CHECK: [[GLOB_HOST:%[a-zA-Z0-9]+]] = alloca ptr addrspace(1), align 8
|
||||
// CHECK-DAG: [[GLOB_HOST:%[a-zA-Z0-9]+]] = alloca ptr addrspace(1), align 8
|
||||
LOC = nullptr;
|
||||
// CHECK: store ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr [[LOC]], align 8
|
||||
// CHECK-DAG: store ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr [[LOC]], align 8
|
||||
GLOB = nullptr;
|
||||
// CHECK: store ptr addrspace(1) null, ptr [[GLOB]], align 8
|
||||
// CHECK-DAG: store ptr addrspace(1) null, ptr [[GLOB]], align 8
|
||||
NoAS = (int *)GLOB;
|
||||
// CHECK: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]], align 8
|
||||
// CHECK: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr
|
||||
// CHECK: store ptr [[GLOB_CAST]], ptr [[NoAS]], align 8
|
||||
// CHECK-DAG: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]], align 8
|
||||
// CHECK-DAG: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr
|
||||
// CHECK-DAG: store ptr [[GLOB_CAST]], ptr [[NoAS]], align 8
|
||||
NoAS = (int *)LOC;
|
||||
// CHECK: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]], align 8
|
||||
// CHECK: [[LOC_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD]] to ptr
|
||||
// CHECK: store ptr [[LOC_CAST]], ptr [[NoAS]], align 8
|
||||
// CHECK-DAG: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]], align 8
|
||||
// CHECK-DAG: [[LOC_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD]] to ptr
|
||||
// CHECK-DAG: store ptr [[LOC_CAST]], ptr [[NoAS]], align 8
|
||||
NoAS = (int *)PRIV;
|
||||
// CHECK: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[PRIV]], align 8
|
||||
// CHECK: store ptr [[LOC_LOAD]], ptr [[NoAS]], align 8
|
||||
// CHECK-DAG: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[PRIV]], align 8
|
||||
// CHECK-DAG: store ptr [[LOC_LOAD]], ptr [[NoAS]], align 8
|
||||
GLOB = (__attribute__((opencl_global)) int *)NoAS;
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]], align 8
|
||||
// CHECK: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr [[NoAS_LOAD]] to ptr addrspace(1)
|
||||
// CHECK: store ptr addrspace(1) [[NoAS_CAST]], ptr [[GLOB]], align 8
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]], align 8
|
||||
// CHECK-DAG: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr [[NoAS_LOAD]] to ptr addrspace(1)
|
||||
// CHECK-DAG: store ptr addrspace(1) [[NoAS_CAST]], ptr [[GLOB]], align 8
|
||||
LOC = (__attribute__((opencl_local)) int *)NoAS;
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]], align 8
|
||||
// CHECK: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr [[NoAS_LOAD]] to ptr addrspace(3)
|
||||
// CHECK: store ptr addrspace(3) [[NoAS_CAST]], ptr [[LOC]], align 8
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]], align 8
|
||||
// CHECK-DAG: [[NoAS_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr [[NoAS_LOAD]] to ptr addrspace(3)
|
||||
// CHECK-DAG: store ptr addrspace(3) [[NoAS_CAST]], ptr [[LOC]], align 8
|
||||
PRIV = (__attribute__((opencl_private)) int *)NoAS;
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]], align 8
|
||||
// CHECK: store ptr [[NoAS_LOAD]], ptr [[PRIV]], align 8
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]], align 8
|
||||
// CHECK-DAG: store ptr [[NoAS_LOAD]], ptr [[PRIV]], align 8
|
||||
GLOB = (__attribute__((opencl_global)) int *)GLOBDEVICE;
|
||||
// CHECK: [[GLOBDEVICE_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB_DEVICE]], align 8
|
||||
// CHECK: store ptr addrspace(1) [[GLOBDEVICE_LOAD]], ptr %GLOB, align 8
|
||||
// CHECK-DAG: [[GLOBDEVICE_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB_DEVICE]], align 8
|
||||
// CHECK-DAG: store ptr addrspace(1) [[GLOBDEVICE_LOAD]], ptr %GLOB, align 8
|
||||
GLOB = (__attribute__((opencl_global)) int *)GLOBHOST;
|
||||
// CHECK: [[GLOB_HOST_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB_HOST]], align 8
|
||||
// CHECK: store ptr addrspace(1) [[GLOB_HOST_LOAD]], ptr [[GLOB]], align 8
|
||||
// CHECK-DAG: [[GLOB_HOST_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB_HOST]], align 8
|
||||
// CHECK-DAG: store ptr addrspace(1) [[GLOB_HOST_LOAD]], ptr [[GLOB]], align 8
|
||||
bar(*GLOB);
|
||||
// CHECK: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]], align 8
|
||||
// CHECK: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr
|
||||
// CHECK: call void @[[RAW_REF]](ptr noundef nonnull align 4 dereferenceable(4) [[GLOB_CAST]])
|
||||
// CHECK-DAG: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]], align 8
|
||||
// CHECK-DAG: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr
|
||||
// CHECK-DAG: call void @[[RAW_REF]](ptr noundef nonnull align 4 dereferenceable(4) [[GLOB_CAST]])
|
||||
bar2(*GLOB);
|
||||
// CHECK: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]], align 8
|
||||
// CHECK: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr
|
||||
// CHECK: call void @[[RAW_REF2]](ptr noundef nonnull align 4 dereferenceable(4) [[GLOB_CAST]])
|
||||
// CHECK-DAG: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]], align 8
|
||||
// CHECK-DAG: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD]] to ptr
|
||||
// CHECK-DAG: call void @[[RAW_REF2]](ptr noundef nonnull align 4 dereferenceable(4) [[GLOB_CAST]])
|
||||
bar(*LOC);
|
||||
// CHECK: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]], align 8
|
||||
// CHECK: call void @[[LOCAL_REF]](ptr addrspace(3) noundef align 4 dereferenceable(4) [[LOC_LOAD]])
|
||||
// CHECK-DAG: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]], align 8
|
||||
// CHECK-DAG: call void @[[LOCAL_REF]](ptr addrspace(3) noundef align 4 dereferenceable(4) [[LOC_LOAD]])
|
||||
bar2(*LOC);
|
||||
// CHECK: [[LOC_LOAD2:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]], align 8
|
||||
// CHECK: [[LOC_CAST2:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD2]] to ptr
|
||||
// CHECK: call void @[[RAW_REF2]](ptr noundef nonnull align 4 dereferenceable(4) [[LOC_CAST2]])
|
||||
// CHECK-DAG: [[LOC_LOAD2:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]], align 8
|
||||
// CHECK-DAG: [[LOC_CAST2:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD2]] to ptr
|
||||
// CHECK-DAG: call void @[[RAW_REF2]](ptr noundef nonnull align 4 dereferenceable(4) [[LOC_CAST2]])
|
||||
bar(*NoAS);
|
||||
// CHECK: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]], align 8
|
||||
// CHECK: call void @[[RAW_REF]](ptr noundef nonnull align 4 dereferenceable(4) [[NoAS_LOAD]])
|
||||
// CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]], align 8
|
||||
// CHECK-DAG: call void @[[RAW_REF]](ptr noundef nonnull align 4 dereferenceable(4) [[NoAS_LOAD]])
|
||||
bar2(*NoAS);
|
||||
// CHECK: [[NoAS_LOAD2:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]], align 8
|
||||
// CHECK: call void @[[RAW_REF2]](ptr noundef nonnull align 4 dereferenceable(4) [[NoAS_LOAD2]])
|
||||
// CHECK-DAG: [[NoAS_LOAD2:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]], align 8
|
||||
// CHECK-DAG: call void @[[RAW_REF2]](ptr noundef nonnull align 4 dereferenceable(4) [[NoAS_LOAD2]])
|
||||
foo(GLOB);
|
||||
// CHECK: [[GLOB_LOAD3:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]], align 8
|
||||
// CHECK: [[GLOB_CAST3:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD3]] to ptr
|
||||
// CHECK: call void @[[RAW_PTR]](ptr noundef [[GLOB_CAST3]])
|
||||
// CHECK-DAG: [[GLOB_LOAD3:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]], align 8
|
||||
// CHECK-DAG: [[GLOB_CAST3:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD3]] to ptr
|
||||
// CHECK-DAG: call void @[[RAW_PTR]](ptr noundef [[GLOB_CAST3]])
|
||||
foo2(GLOB);
|
||||
// CHECK: [[GLOB_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]], align 8
|
||||
// CHECK: [[GLOB_CAST4:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD4]] to ptr
|
||||
// CHECK: call void @[[RAW_PTR2]](ptr noundef [[GLOB_CAST4]])
|
||||
// CHECK-DAG: [[GLOB_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]], align 8
|
||||
// CHECK-DAG: [[GLOB_CAST4:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(1) [[GLOB_LOAD4]] to ptr
|
||||
// CHECK-DAG: call void @[[RAW_PTR2]](ptr noundef [[GLOB_CAST4]])
|
||||
foo(LOC);
|
||||
// CHECK: [[LOC_LOAD3:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]], align 8
|
||||
// CHECK: call void @[[LOC_PTR]](ptr addrspace(3) noundef [[LOC_LOAD3]])
|
||||
// CHECK-DAG: [[LOC_LOAD3:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]], align 8
|
||||
// CHECK-DAG: call void @[[LOC_PTR]](ptr addrspace(3) noundef [[LOC_LOAD3]])
|
||||
foo2(LOC);
|
||||
// CHECK: [[LOC_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]], align 8
|
||||
// CHECK: [[LOC_CAST4:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD4]] to ptr
|
||||
// CHECK: call void @[[RAW_PTR2]](ptr noundef [[LOC_CAST4]])
|
||||
// CHECK-DAG: [[LOC_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]], align 8
|
||||
// CHECK-DAG: [[LOC_CAST4:%[a-zA-Z0-9]+]] = addrspacecast ptr addrspace(3) [[LOC_LOAD4]] to ptr
|
||||
// CHECK-DAG: call void @[[RAW_PTR2]](ptr noundef [[LOC_CAST4]])
|
||||
foo(NoAS);
|
||||
// CHECK: [[NoAS_LOAD3:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]], align 8
|
||||
// CHECK: call void @[[RAW_PTR]](ptr noundef [[NoAS_LOAD3]])
|
||||
// CHECK-DAG: [[NoAS_LOAD3:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]], align 8
|
||||
// CHECK-DAG: call void @[[RAW_PTR]](ptr noundef [[NoAS_LOAD3]])
|
||||
foo2(NoAS);
|
||||
// CHECK: [[NoAS_LOAD4:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]], align 8
|
||||
// CHECK: call void @[[RAW_PTR2]](ptr noundef [[NoAS_LOAD4]])
|
||||
// CHECK-DAG: [[NoAS_LOAD4:%[a-zA-Z0-9]+]] = load ptr, ptr [[NoAS]], align 8
|
||||
// CHECK-DAG: call void @[[RAW_PTR2]](ptr noundef [[NoAS_LOAD4]])
|
||||
tmpl(GLOB);
|
||||
// CHECK: [[GLOB_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]], align 8
|
||||
// CHECK: call void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) noundef [[GLOB_LOAD4]])
|
||||
// CHECK-DAG: [[GLOB_LOAD4:%[a-zA-Z0-9]+]] = load ptr addrspace(1), ptr [[GLOB]], align 8
|
||||
// CHECK-DAG: call void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) noundef [[GLOB_LOAD4]])
|
||||
tmpl(LOC);
|
||||
// CHECK: [[LOC_LOAD5:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]], align 8
|
||||
// CHECK: call void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) noundef [[LOC_LOAD5]])
|
||||
// CHECK-DAG: [[LOC_LOAD5:%[a-zA-Z0-9]+]] = load ptr addrspace(3), ptr [[LOC]], align 8
|
||||
// CHECK-DAG: call void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) noundef [[LOC_LOAD5]])
|
||||
tmpl(PRIV);
|
||||
// CHECK: [[PRIV_LOAD5:%[a-zA-Z0-9]+]] = load ptr, ptr [[PRIV]], align 8
|
||||
// CHECK: call void @_Z4tmplIPiEvT_(ptr noundef [[PRIV_LOAD5]])
|
||||
// CHECK-DAG: [[PRIV_LOAD5:%[a-zA-Z0-9]+]] = load ptr, ptr [[PRIV]], align 8
|
||||
// CHECK-DAG: call void @_Z4tmplIPiEvT_(ptr noundef [[PRIV_LOAD5]])
|
||||
tmpl(NoAS);
|
||||
// CHECK: %33 = load ptr, ptr %NoAS, align 8
|
||||
// CHECK: call void @_Z4tmplIPiEvT_(ptr noundef %33)
|
||||
// CHECK-DAG: %33 = load ptr, ptr %NoAS, align 8
|
||||
// CHECK-DAG: call void @_Z4tmplIPiEvT_(ptr noundef %33)
|
||||
}
|
||||
|
||||
// CHECK: declare void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) noundef)
|
||||
// CHECK: declare void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) noundef)
|
||||
// CHECK: declare void @_Z4tmplIPiEvT_(ptr noundef)
|
||||
// CHECK-DAG: void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) noundef
|
||||
// CHECK-DAG: void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) noundef
|
||||
// CHECK-DAG: void @_Z4tmplIPiEvT_(ptr noundef
|
||||
|
@ -18,7 +18,7 @@ KERNEL void parallel_for(const KernelType &KernelFunc) {
|
||||
KernelFunc();
|
||||
}
|
||||
|
||||
void my_kernel(int my_param) {
|
||||
[[clang::sycl_external]] void my_kernel(int my_param) {
|
||||
int my_local = 0;
|
||||
my_local = my_param;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ struct HasField {
|
||||
int *a;
|
||||
};
|
||||
|
||||
void foo(int *b) {
|
||||
[[clang::sycl_external]] void foo(int *b) {
|
||||
struct HasField f;
|
||||
// CHECK: %[[A:.+]] = getelementptr inbounds nuw %struct.HasField, ptr addrspace(4) %{{.+}}
|
||||
// CHECK: %[[CALL:.+]] = call ptr addrspace(4) @llvm.ptr.annotation.p4.p1(ptr addrspace(4) %[[A]], ptr addrspace(1) [[ANNOT]]
|
||||
|
@ -5,11 +5,11 @@
|
||||
int foo();
|
||||
|
||||
// CHECK-LABEL: define dso_local spir_func void @_Z3barv(
|
||||
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
|
||||
// CHECK-SAME: ) #[[ATTR2:[0-9]+]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: [[A_ASCAST:%.*]] = addrspacecast ptr [[A]] to ptr addrspace(4)
|
||||
// CHECK-NEXT: [[CALL:%.*]] = call spir_func noundef i32 @_Z3foov() #[[ATTR1:[0-9]+]]
|
||||
// CHECK-NEXT: [[CALL:%.*]] = call spir_func noundef i32 @_Z3foov() #[[ATTR3:[0-9]+]]
|
||||
// CHECK-NEXT: store i32 [[CALL]], ptr addrspace(4) [[A_ASCAST]], align 4
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
@ -18,7 +18,7 @@ void bar() {
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define dso_local spir_func noundef i32 @_Z3foov(
|
||||
// CHECK-SAME: ) #[[ATTR0]] {
|
||||
// CHECK-SAME: ) #[[ATTR2]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr [[RETVAL]] to ptr addrspace(4)
|
||||
@ -29,21 +29,10 @@ int foo() {
|
||||
}
|
||||
|
||||
template <typename Name, typename Func>
|
||||
__attribute__((sycl_kernel)) void kernel_single_task(const Func &kernelFunc) {
|
||||
[[clang::sycl_kernel_entry_point(Name)]] void kernel_single_task(const Func &kernelFunc) {
|
||||
kernelFunc();
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define dso_local noundef i32 @main(
|
||||
// CHECK-SAME: ) #[[ATTR0]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_ANON:%.*]], align 1
|
||||
// CHECK-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr [[RETVAL]] to ptr addrspace(4)
|
||||
// CHECK-NEXT: [[REF_TMP_ASCAST:%.*]] = addrspacecast ptr [[REF_TMP]] to ptr addrspace(4)
|
||||
// CHECK-NEXT: store i32 0, ptr addrspace(4) [[RETVAL_ASCAST]], align 4
|
||||
// CHECK-NEXT: call spir_func void @_Z18kernel_single_taskIZ4mainE11fake_kernelZ4mainEUlvE_EvRKT0_(ptr addrspace(4) noundef align 1 dereferenceable(1) [[REF_TMP_ASCAST]]) #[[ATTR1]]
|
||||
// CHECK-NEXT: ret i32 0
|
||||
//
|
||||
int main() {
|
||||
kernel_single_task<class fake_kernel>([] { bar(); });
|
||||
return 0;
|
||||
@ -52,5 +41,5 @@ int main() {
|
||||
// CHECK: attributes #0 = { convergent mustprogress noinline norecurse nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
|
||||
// CHECK: attributes #1 = { convergent nounwind }
|
||||
//.
|
||||
// CHECK: !0 = !{i32 1, !"wchar_size", i32 4}
|
||||
// CHECK: !{{[0-9]+}} = !{i32 1, !"wchar_size", i32 4}
|
||||
//.
|
||||
|
@ -8,7 +8,7 @@ __attribute__((sycl_kernel)) void kernel_single_task(const Func &kernelFunc) {
|
||||
}
|
||||
|
||||
// CHECK: define dso_local spir_func{{.*}}invoke_function{{.*}}(ptr noundef %fptr, ptr addrspace(4) noundef %ptr)
|
||||
void invoke_function(int (*fptr)(), int *ptr) {}
|
||||
[[clang::sycl_external]] void invoke_function(int (*fptr)(), int *ptr) {}
|
||||
|
||||
int f() { return 0; }
|
||||
|
||||
|
@ -100,11 +100,8 @@ int main() {
|
||||
|
||||
// Verify that SYCL kernel caller functions are emitted for each device target.
|
||||
//
|
||||
// FIXME: The following set of matches are used to skip over the declaration of
|
||||
// main(). main() shouldn't be emitted in device code, but that pruning isn't
|
||||
// performed yet.
|
||||
// CHECK-DEVICE: Function Attrs: convergent mustprogress noinline norecurse nounwind optnone
|
||||
// CHECK-DEVICE-NEXT: define {{[a-z_ ]*}}noundef i32 @main() #0
|
||||
// main() shouldn't be emitted in device code.
|
||||
// CHECK-NOT: @main()
|
||||
|
||||
// IR for the SYCL kernel caller function generated for
|
||||
// single_purpose_kernel_task with single_purpose_kernel_name as the SYCL kernel
|
||||
|
85
clang/test/CodeGenSYCL/sycl-external-attr.cpp
Normal file
85
clang/test/CodeGenSYCL/sycl-external-attr.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s
|
||||
|
||||
// This test code generation when sycl_external attribute is used
|
||||
|
||||
// Function defined and not used - symbols emitted
|
||||
[[clang::sycl_external]] int square(int x) { return x*x; }
|
||||
// CHECK: define dso_local spir_func noundef i32 @_Z6squarei
|
||||
|
||||
// Function defined and used - symbols emitted
|
||||
[[clang::sycl_external]] int squareUsed(int x) { return x*x; }
|
||||
// CHECK: define dso_local spir_func noundef i32 @_Z10squareUsedi
|
||||
|
||||
// FIXME: Constexpr function defined and not used - symbols emitted
|
||||
[[clang::sycl_external]] constexpr int squareInlined(int x) { return x*x; }
|
||||
// CHECK: define linkonce_odr spir_func noundef i32 @_Z13squareInlinedi
|
||||
|
||||
// Function declared but not defined or used - no symbols emitted
|
||||
[[clang::sycl_external]] int declOnly();
|
||||
// CHECK-NOT: define {{.*}} i32 @_Z8declOnlyv
|
||||
// CHECK-NOT: declare {{.*}} i32 @_Z8declOnlyv
|
||||
|
||||
// Function declared and used in host but not defined - no symbols emitted
|
||||
[[clang::sycl_external]] void declUsedInHost(int y);
|
||||
|
||||
// Function declared and used in device but not defined - emit external reference
|
||||
[[clang::sycl_external]] void declUsedInDevice(int y);
|
||||
// CHECK: define dso_local spir_func void @_Z9deviceUsev
|
||||
[[clang::sycl_external]] void deviceUse() { declUsedInDevice(3); }
|
||||
// CHECK: declare spir_func void @_Z16declUsedInDevicei
|
||||
|
||||
// Function declared with the attribute and later defined - definition emitted
|
||||
[[clang::sycl_external]] int func1(int arg);
|
||||
int func1(int arg) { return arg; }
|
||||
// CHECK: define dso_local spir_func noundef i32 @_Z5func1i
|
||||
|
||||
class A {
|
||||
// Unused defaulted special member functions - no symbols emitted
|
||||
[[clang::sycl_external]] A& operator=(A& a) = default;
|
||||
};
|
||||
|
||||
class B {
|
||||
[[clang::sycl_external]] virtual void BFunc1WithAttr() { int i = 1; }
|
||||
// CHECK: define linkonce_odr spir_func void @_ZN1B14BFunc1WithAttrEv
|
||||
virtual void BFunc2NoAttr() { int i = 2; }
|
||||
};
|
||||
|
||||
class C {
|
||||
// Special member function defined - definition emitted
|
||||
[[clang::sycl_external]] ~C() {}
|
||||
// CHECK: define linkonce_odr spir_func void @_ZN1CD1Ev
|
||||
};
|
||||
|
||||
// Function reachable from an unused function - definition emitted
|
||||
int ret1() { return 1; }
|
||||
[[clang::sycl_external]] int withAttr() { return ret1(); }
|
||||
// CHECK: define dso_local spir_func noundef i32 @_Z8withAttrv
|
||||
// CHECK: define dso_local spir_func noundef i32 @_Z4ret1v
|
||||
|
||||
template <typename T>
|
||||
[[clang::sycl_external]] void tFunc1(T arg) {}
|
||||
// Explicit specialization defined - symbols emitted
|
||||
template<>
|
||||
[[clang::sycl_external]] void tFunc1<int>(int arg) {}
|
||||
// CHECK: define dso_local spir_func void @_Z6tFunc1IiEvT_
|
||||
|
||||
template <typename T>
|
||||
[[clang::sycl_external]] void tFunc2(T arg) {}
|
||||
template void tFunc2<int>(int arg);
|
||||
// CHECK: define weak_odr spir_func void @_Z6tFunc2IiEvT_
|
||||
template<> void tFunc2<char>(char arg) {}
|
||||
// CHECK: define dso_local spir_func void @_Z6tFunc2IcEvT_
|
||||
template<> [[clang::sycl_external]] void tFunc2<long>(long arg) {}
|
||||
// CHECK: define dso_local spir_func void @_Z6tFunc2IlEvT_
|
||||
|
||||
// Functions defined without the sycl_external attribute that are used
|
||||
// in host code, but not in device code are not emitted.
|
||||
int squareNoAttr(int x) { return x*x; }
|
||||
// CHECK-NOT: define {{.*}} i32 @_Z12squareNoAttri
|
||||
|
||||
int main() {
|
||||
declUsedInHost(4);
|
||||
int i = squareUsed(5);
|
||||
int j = squareNoAttr(6);
|
||||
return 0;
|
||||
}
|
@ -1,22 +1,22 @@
|
||||
// RUN: %clang_cc1 -triple spir64-unknown-unknown-sycldevice -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s
|
||||
// CHECK: @[[LAMBDA_KERNEL3:[^\w]+]] = private unnamed_addr addrspace(1) constant [[LAMBDA_K3_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ4mainEUlPZ4mainEUlvE_E_\00"
|
||||
// CHECK: @[[INT1:[^\w]+]] = private unnamed_addr addrspace(1) constant [[INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSi\00"
|
||||
// CHECK: @[[STRING:[^\w]+]] = private unnamed_addr addrspace(1) constant [[STRING_SIZE:\[[0-9]+ x i8\]]] c"_ZTSAppL_ZZ4mainE1jE_i\00",
|
||||
// CHECK: @[[INT2:[^\w]+]] = private unnamed_addr addrspace(1) constant [[INT_SIZE]] c"_ZTSi\00"
|
||||
// CHECK: @[[LAMBDA_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[LAMBDA_X_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE_\00"
|
||||
// CHECK: @[[MACRO_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE0_\00"
|
||||
// CHECK: @[[MACRO_Y:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE1_\00"
|
||||
// CHECK: @{{.*}} = private unnamed_addr addrspace(1) constant [32 x i8] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE2_\00", align 1
|
||||
// CHECK: @{{.*}} = private unnamed_addr addrspace(1) constant [32 x i8] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE3_\00", align 1
|
||||
// CHECK: @[[MACRO_MACRO_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE4_\00"
|
||||
// CHECK: @[[MACRO_MACRO_Y:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE5_\00"
|
||||
// CHECK: @[[INT3:[^\w]+]] = private unnamed_addr addrspace(1) constant [[INT_SIZE]] c"_ZTSi\00"
|
||||
// CHECK: @[[LAMBDA:[^\w]+]] = private unnamed_addr addrspace(1) constant [[LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE_\00"
|
||||
// CHECK: @[[LAMBDA_IN_DEP_INT:[^\w]+]] = private unnamed_addr addrspace(1) constant [[DEP_INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIiEvvEUlvE_\00",
|
||||
// CHECK: @[[LAMBDA_IN_DEP_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_EvvEUlvE_\00",
|
||||
// CHECK: @[[LAMBDA_NO_DEP:[^\w]+]] = private unnamed_addr addrspace(1) constant [[NO_DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ13lambda_no_depIidEvT_T0_EUlidE_\00",
|
||||
// CHECK: @[[LAMBDA_TWO_DEP:[^\w]+]] = private unnamed_addr addrspace(1) constant [[DEP_LAMBDA1_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_EvvEUlvE_\00",
|
||||
// CHECK: @[[LAMBDA_TWO_DEP2:[^\w]+]] = private unnamed_addr addrspace(1) constant [[DEP_LAMBDA2_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_EvvEUlvE_\00",
|
||||
// RUN: %clang_cc1 -triple x86_64-linux-pc -fsycl-is-host -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s
|
||||
// CHECK: @[[LAMBDA_KERNEL3:[^\w]+]] = private unnamed_addr constant [[LAMBDA_K3_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ4mainEUlPZ4mainEUlvE_E_\00"
|
||||
// CHECK: @[[INT1:[^\w]+]] = private unnamed_addr constant [[INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSi\00"
|
||||
// CHECK: @[[STRING:[^\w]+]] = private unnamed_addr constant [[STRING_SIZE:\[[0-9]+ x i8\]]] c"_ZTSAppL_ZZ4mainE1jE_i\00",
|
||||
// CHECK: @[[INT2:[^\w]+]] = private unnamed_addr constant [[INT_SIZE]] c"_ZTSi\00"
|
||||
// CHECK: @[[LAMBDA_X:[^\w]+]] = private unnamed_addr constant [[LAMBDA_X_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE_\00"
|
||||
// CHECK: @[[MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE0_\00"
|
||||
// CHECK: @[[MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE1_\00"
|
||||
// CHECK: @{{.*}} = private unnamed_addr constant [32 x i8] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE2_\00", align 1
|
||||
// CHECK: @{{.*}} = private unnamed_addr constant [32 x i8] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE3_\00", align 1
|
||||
// CHECK: @[[MACRO_MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE4_\00"
|
||||
// CHECK: @[[MACRO_MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE5_\00"
|
||||
// CHECK: @[[INT3:[^\w]+]] = private unnamed_addr constant [[INT_SIZE]] c"_ZTSi\00"
|
||||
// CHECK: @[[LAMBDA:[^\w]+]] = private unnamed_addr constant [[LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE_\00"
|
||||
// CHECK: @[[LAMBDA_IN_DEP_INT:[^\w]+]] = private unnamed_addr constant [[DEP_INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIiEvvEUlvE_\00",
|
||||
// CHECK: @[[LAMBDA_IN_DEP_X:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_EvvEUlvE_\00",
|
||||
// CHECK: @[[LAMBDA_NO_DEP:[^\w]+]] = private unnamed_addr constant [[NO_DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ13lambda_no_depIidEvT_T0_EUlidE_\00",
|
||||
// CHECK: @[[LAMBDA_TWO_DEP:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA1_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_EvvEUlvE_\00",
|
||||
// CHECK: @[[LAMBDA_TWO_DEP2:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA2_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_EvvEUlvE_\00",
|
||||
|
||||
extern "C" void puts(const char *) {}
|
||||
|
||||
@ -65,95 +65,105 @@ template <typename KernelName, typename KernelType>
|
||||
kernelFunc();
|
||||
}
|
||||
|
||||
template<typename KernelType>
|
||||
void unnamed_kernel_single_task(KernelType kernelFunc) {
|
||||
kernel_single_task<KernelType>(kernelFunc);
|
||||
}
|
||||
|
||||
template <typename KernelName, typename KernelType>
|
||||
void not_kernel_single_task(KernelType kernelFunc) {
|
||||
kernelFunc();
|
||||
}
|
||||
|
||||
int main() {
|
||||
kernel_single_task<class kernel2>(func<Derp>);
|
||||
// CHECK: call spir_func void @_Z18kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_(ptr noundef @_Z4funcI4DerpEDTu33__builtin_sycl_unique_stable_nameDtsrT_3strEEEv)
|
||||
not_kernel_single_task<class kernel2>(func<Derp>);
|
||||
// CHECK: call void @_Z22not_kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_(ptr noundef @_Z4funcI4DerpEDTu33__builtin_sycl_unique_stable_nameDtsrT_3strEEEv)
|
||||
|
||||
auto l1 = []() { return 1; };
|
||||
auto l2 = [](decltype(l1) *l = nullptr) { return 2; };
|
||||
kernel_single_task<class kernel3>(l2);
|
||||
kernel_single_task<decltype(l2)>(l2);
|
||||
puts(__builtin_sycl_unique_stable_name(decltype(l2)));
|
||||
// CHECK: call spir_func void @_Z18kernel_single_taskIZ4mainE7kernel3Z4mainEUlPZ4mainEUlvE_E_EvT0_
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_KERNEL3]] to ptr addrspace(4)))
|
||||
// CHECK: call void @_Z18kernel_single_taskIZ4mainEUlPZ4mainEUlvE_E_S2_EvT0_
|
||||
// CHECK: call void @puts(ptr noundef @[[LAMBDA_KERNEL3]])
|
||||
|
||||
constexpr const char str[] = "lalala";
|
||||
static_assert(__builtin_strcmp(__builtin_sycl_unique_stable_name(decltype(str)), "_ZTSA7_Kc\0") == 0, "unexpected mangling");
|
||||
|
||||
int i = 0;
|
||||
puts(__builtin_sycl_unique_stable_name(decltype(i++)));
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[INT1]] to ptr addrspace(4)))
|
||||
// CHECK: call void @puts(ptr noundef @[[INT1]])
|
||||
|
||||
// FIXME: Ensure that j is incremented because VLAs are terrible.
|
||||
int j = 55;
|
||||
puts(__builtin_sycl_unique_stable_name(int[++j]));
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[STRING]] to ptr addrspace(4)))
|
||||
// CHECK: call void @puts(ptr noundef @[[STRING]])
|
||||
|
||||
// CHECK: define internal spir_func void @_Z18kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_
|
||||
// CHECK: declare spir_func noundef ptr addrspace(4) @_Z4funcI4DerpEDTu33__builtin_sycl_unique_stable_nameDtsrT_3strEEEv
|
||||
// CHECK: define internal spir_func void @_Z18kernel_single_taskIZ4mainE7kernel3Z4mainEUlPZ4mainEUlvE_E_EvT0_
|
||||
// CHECK: define internal spir_func void @_Z18kernel_single_taskIZ4mainE6kernelZ4mainEUlvE0_EvT0_
|
||||
// CHECK: define internal void @_Z22not_kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_
|
||||
// CHECK: declare noundef ptr @_Z4funcI4DerpEDTu33__builtin_sycl_unique_stable_nameDtsrT_3strEEEv
|
||||
// CHECK: define internal void @_Z18kernel_single_taskIZ4mainEUlPZ4mainEUlvE_E_S2_EvT0_
|
||||
// CHECK: define internal void @_Z18kernel_single_taskIZ4mainEUlvE0_S0_EvT0_
|
||||
|
||||
kernel_single_task<class kernel>(
|
||||
unnamed_kernel_single_task(
|
||||
[]() {
|
||||
puts(__builtin_sycl_unique_stable_name(int));
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[INT2]] to ptr addrspace(4)))
|
||||
// CHECK: call void @puts(ptr noundef @[[INT2]])
|
||||
|
||||
auto x = []() {};
|
||||
puts(__builtin_sycl_unique_stable_name(decltype(x)));
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_X]] to ptr addrspace(4)))
|
||||
// CHECK: call void @puts(ptr noundef @[[LAMBDA_X]])
|
||||
|
||||
DEF_IN_MACRO();
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[MACRO_X]] to ptr addrspace(4)))
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[MACRO_Y]] to ptr addrspace(4)))
|
||||
// CHECK: call void @puts(ptr noundef @[[MACRO_X]])
|
||||
// CHECK: call void @puts(ptr noundef @[[MACRO_Y]])
|
||||
|
||||
MACRO_CALLS_MACRO();
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[MACRO_MACRO_X]] to ptr addrspace(4)))
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[MACRO_MACRO_Y]] to ptr addrspace(4)))
|
||||
// CHECK: call void @puts(ptr noundef @[[MACRO_MACRO_X]])
|
||||
// CHECK: call void @puts(ptr noundef @[[MACRO_MACRO_Y]])
|
||||
|
||||
template_param<int>();
|
||||
// CHECK: call spir_func void @_Z14template_paramIiEvv
|
||||
// CHECK: call void @_Z14template_paramIiEvv
|
||||
|
||||
template_param<decltype(x)>();
|
||||
// CHECK: call spir_func void @_Z14template_paramIZZ4mainENKUlvE0_clEvEUlvE_Evv
|
||||
// CHECK: call void @_Z14template_paramIZZ4mainENKUlvE0_clEvEUlvE_Evv
|
||||
|
||||
lambda_in_dependent_function<int>();
|
||||
// CHECK: call spir_func void @_Z28lambda_in_dependent_functionIiEvv
|
||||
// CHECK: call void @_Z28lambda_in_dependent_functionIiEvv
|
||||
|
||||
lambda_in_dependent_function<decltype(x)>();
|
||||
// CHECK: call spir_func void @_Z28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_Evv
|
||||
// CHECK: call void @_Z28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_Evv
|
||||
|
||||
lambda_no_dep<int, double>(3, 5.5);
|
||||
// CHECK: call spir_func void @_Z13lambda_no_depIidEvT_T0_(i32 noundef 3, double noundef 5.500000e+00)
|
||||
// CHECK: call void @_Z13lambda_no_depIidEvT_T0_(i32 noundef 3, double noundef 5.500000e+00)
|
||||
|
||||
int a = 5;
|
||||
double b = 10.7;
|
||||
auto y = [](int a) { return a; };
|
||||
auto z = [](double b) { return b; };
|
||||
lambda_two_dep<decltype(y), decltype(z)>();
|
||||
// CHECK: call spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_Evv
|
||||
// CHECK: call void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_Evv
|
||||
|
||||
lambda_two_dep<decltype(z), decltype(y)>();
|
||||
// CHECK: call spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_Evv
|
||||
// CHECK: call void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_Evv
|
||||
});
|
||||
}
|
||||
|
||||
// CHECK: define linkonce_odr spir_func void @_Z14template_paramIiEvv
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[INT3]] to ptr addrspace(4)))
|
||||
// CHECK: define linkonce_odr void @_Z14template_paramIiEvv
|
||||
// CHECK: call void @puts(ptr noundef @[[INT3]])
|
||||
|
||||
// CHECK: define internal spir_func void @_Z14template_paramIZZ4mainENKUlvE0_clEvEUlvE_Evv
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA]] to ptr addrspace(4)))
|
||||
// CHECK: define internal void @_Z14template_paramIZZ4mainENKUlvE0_clEvEUlvE_Evv
|
||||
// CHECK: call void @puts(ptr noundef @[[LAMBDA]])
|
||||
|
||||
// CHECK: define linkonce_odr spir_func void @_Z28lambda_in_dependent_functionIiEvv
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_IN_DEP_INT]] to ptr addrspace(4)))
|
||||
// CHECK: define linkonce_odr void @_Z28lambda_in_dependent_functionIiEvv
|
||||
// CHECK: call void @puts(ptr noundef @[[LAMBDA_IN_DEP_INT]])
|
||||
|
||||
// CHECK: define internal spir_func void @_Z28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_Evv
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_IN_DEP_X]] to ptr addrspace(4)))
|
||||
// CHECK: define internal void @_Z28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_Evv
|
||||
// CHECK: call void @puts(ptr noundef @[[LAMBDA_IN_DEP_X]])
|
||||
|
||||
// CHECK: define linkonce_odr spir_func void @_Z13lambda_no_depIidEvT_T0_(i32 noundef %a, double noundef %b)
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_NO_DEP]] to ptr addrspace(4)))
|
||||
// CHECK: define linkonce_odr void @_Z13lambda_no_depIidEvT_T0_(i32 noundef %a, double noundef %b)
|
||||
// CHECK: call void @puts(ptr noundef @[[LAMBDA_NO_DEP]])
|
||||
|
||||
// CHECK: define internal spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_Evv
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_TWO_DEP]] to ptr addrspace(4)))
|
||||
// CHECK: define internal void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_Evv
|
||||
// CHECK: call void @puts(ptr noundef @[[LAMBDA_TWO_DEP]])
|
||||
|
||||
// CHECK: define internal spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_Evv
|
||||
// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_TWO_DEP2]] to ptr addrspace(4)))
|
||||
// CHECK: define internal void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_Evv
|
||||
// CHECK: call void @puts(ptr noundef @[[LAMBDA_TWO_DEP2]])
|
||||
|
@ -15,7 +15,7 @@
|
||||
// NV: call noundef ptr @_Z42__spirv_GenericCastToPtrExplicit_ToPrivatePvi
|
||||
// NV: addrspacecast ptr %{{.*}} to ptr addrspace(1)
|
||||
// NV: addrspacecast ptr %{{.*}} to ptr addrspace(3)
|
||||
void test_cast(int* p) {
|
||||
[[clang::sycl_external]] void test_cast(int* p) {
|
||||
__spirv_GenericCastToPtrExplicit_ToGlobal(p, 5);
|
||||
__spirv_GenericCastToPtrExplicit_ToLocal(p, 4);
|
||||
__spirv_GenericCastToPtrExplicit_ToPrivate(p, 7);
|
||||
|
@ -80,7 +80,7 @@
|
||||
// NV: call noundef i32 @_Z25__spirv_BuiltInSubgroupIdv() #2
|
||||
// NV: call noundef i32 @_Z40__spirv_BuiltInSubgroupLocalInvocationIdv() #2
|
||||
|
||||
void test_id_and_range() {
|
||||
[[clang::sycl_external]] void test_id_and_range() {
|
||||
__spirv_BuiltInNumWorkgroups(0);
|
||||
__spirv_BuiltInNumWorkgroups(1);
|
||||
__spirv_BuiltInNumWorkgroups(2);
|
||||
|
@ -14,3 +14,13 @@ using TypePackElement = __type_pack_element<i, T...>;
|
||||
|
||||
template <int i>
|
||||
struct X;
|
||||
|
||||
using X0 = X<0>;
|
||||
template <int I>
|
||||
using SameAsX = X<I>;
|
||||
|
||||
template <template <class...> class Templ, class...Types>
|
||||
using TypePackDedup = Templ<__builtin_dedup_pack<Types...>...>;
|
||||
|
||||
template <class ...Ts>
|
||||
struct TypeList {};
|
||||
|
@ -1,9 +1,11 @@
|
||||
// RUN: clang-import-test -dump-ast -import %S/Inputs/S.cpp -expression %s -Xcc -DSEQ | FileCheck --check-prefix=CHECK-SEQ %s
|
||||
// RUN: clang-import-test -dump-ast -import %S/Inputs/S.cpp -expression %s -Xcc -DPACK | FileCheck --check-prefix=CHECK-PACK %s
|
||||
// RUN: clang-import-test -dump-ast -import %S/Inputs/S.cpp -expression %s -Xcc -DPACK -Xcc -DSEQ | FileCheck --check-prefixes=CHECK-SEQ,CHECK-PACK %s
|
||||
// RUN: clang-import-test -dump-ast -import %S/Inputs/S.cpp -expression %s -Xcc -DDEDUP | FileCheck --check-prefix=CHECK-DEDUP %s
|
||||
// RUN: clang-import-test -dump-ast -import %S/Inputs/S.cpp -expression %s -Xcc -DPACK -Xcc -DSEQ -Xcc -DDEDUP | FileCheck --check-prefixes=CHECK-SEQ,CHECK-PACK,CHECK-DEDUP %s
|
||||
|
||||
// CHECK-SEQ: BuiltinTemplateDecl {{.+}} <<invalid sloc>> <invalid sloc> implicit __make_integer_seq{{$}}
|
||||
// CHECK-PACK: BuiltinTemplateDecl {{.+}} <<invalid sloc>> <invalid sloc> implicit __type_pack_element{{$}}
|
||||
// CHECK-DEDUP: BuiltinTemplateDecl {{.+}} <<invalid sloc>> <invalid sloc> implicit __builtin_dedup_pack{{$}}
|
||||
|
||||
void expr() {
|
||||
#ifdef SEQ
|
||||
@ -20,4 +22,12 @@ void expr() {
|
||||
static_assert(__is_same(TypePackElement<0, X<0>, X<1>>, X<0>), "");
|
||||
static_assert(__is_same(TypePackElement<1, X<0>, X<1>>, X<1>), "");
|
||||
#endif
|
||||
|
||||
#ifdef DEDUP
|
||||
static_assert(__is_same(TypePackDedup<TypeList>, TypeList<>), "");
|
||||
static_assert(__is_same(TypePackDedup<TypeList, int, double, int>, TypeList<int, double>), "");
|
||||
static_assert(!__is_same(TypePackDedup<TypeList, int, double, int>, TypeList<double, int>), "");
|
||||
static_assert(__is_same(TypePackDedup<TypeList, X<0>, X<1>, X<1>, X<2>, X<0>>, TypeList<X<0>, X<1>, X<2>>), "");
|
||||
static_assert(__is_same(TypePackDedup<TypeList, X0, SameAsX<1>, X<1>, X<0>>, TypeList<X<0>,X<1>>), "");
|
||||
#endif
|
||||
}
|
||||
|
@ -182,6 +182,7 @@
|
||||
// CHECK-NEXT: ReturnTypestate (SubjectMatchRule_function, SubjectMatchRule_variable_is_parameter)
|
||||
// CHECK-NEXT: ReturnsNonNull (SubjectMatchRule_objc_method, SubjectMatchRule_function)
|
||||
// CHECK-NEXT: ReturnsTwice (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: SYCLExternal (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: SYCLKernelEntryPoint (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: SYCLSpecialClass (SubjectMatchRule_record)
|
||||
// CHECK-NEXT: ScopedLockable (SubjectMatchRule_record)
|
||||
|
20
clang/test/PCH/dedup_types.cpp
Normal file
20
clang/test/PCH/dedup_types.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
// RUN: %clang_cc1 -std=c++14 -x c++-header %s -emit-pch -o %t.pch
|
||||
// RUN: %clang_cc1 -std=c++14 -x c++ /dev/null -include-pch %t.pch
|
||||
|
||||
// RUN: %clang_cc1 -std=c++14 -x c++-header %s -emit-pch -fpch-instantiate-templates -o %t.pch
|
||||
// RUN: %clang_cc1 -std=c++14 -x c++ /dev/null -include-pch %t.pch
|
||||
|
||||
template <template <class...> class Templ, class...Types>
|
||||
using TypePackDedup = Templ<__builtin_dedup_pack<Types...>...>;
|
||||
|
||||
template <class ...Ts>
|
||||
struct TypeList {};
|
||||
|
||||
template <int i>
|
||||
struct X {};
|
||||
|
||||
void fn1() {
|
||||
TypeList<int, double> l1 = TypePackDedup<TypeList, int, double, int>{};
|
||||
TypeList<> l2 = TypePackDedup<TypeList>{};
|
||||
TypeList<X<0>, X<1>> x1 = TypePackDedup<TypeList, X<0>, X<1>, X<0>, X<1>>{};
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s
|
||||
// XFAIL: asserts
|
||||
|
||||
template <class> struct Pair;
|
||||
template <class...> struct Tuple {
|
||||
|
36
clang/test/SemaSYCL/sycl-external-attr-appertainment.cpp
Normal file
36
clang/test/SemaSYCL/sycl-external-attr-appertainment.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
// RUN: %clang_cc1 -fsycl-is-host -fsyntax-only -std=c++17 -verify %s
|
||||
// RUN: %clang_cc1 -fsycl-is-device -fsyntax-only -std=c++17 -verify %s
|
||||
// RUN: %clang_cc1 -fsycl-is-host -fsyntax-only -std=c++20 -verify %s
|
||||
// RUN: %clang_cc1 -fsycl-is-device -fsyntax-only -std=c++20 -verify %s
|
||||
// RUN: %clang_cc1 -fsycl-is-host -fsyntax-only -std=c++23 -verify %s
|
||||
// RUN: %clang_cc1 -fsycl-is-device -fsyntax-only -std=c++23 -verify %s
|
||||
|
||||
// expected-error@+1{{'clang::sycl_external' attribute only applies to functions}}
|
||||
[[clang::sycl_external]] int bad1;
|
||||
|
||||
|
||||
// expected-error@+2{{'clang::sycl_external' attribute only applies to functions}}
|
||||
struct s {
|
||||
[[clang::sycl_external]] int bad2;
|
||||
};
|
||||
|
||||
// expected-error@+1{{'clang::sycl_external' attribute only applies to functions}}
|
||||
namespace [[clang::sycl_external]] bad3 {}
|
||||
|
||||
// expected-error@+1{{'clang::sycl_external' attribute only applies to functions}}
|
||||
struct [[clang::sycl_external]] bad4;
|
||||
|
||||
// expected-error@+1{{'clang::sycl_external' attribute only applies to functions}}
|
||||
enum [[clang::sycl_external]] bad5 {};
|
||||
|
||||
// expected-error@+1{{'clang::sycl_external' attribute only applies to functions}}
|
||||
int bad6(void (fp [[clang::sycl_external]])());
|
||||
|
||||
// expected-error@+1{{'clang::sycl_external' attribute only applies to functions}}
|
||||
[[clang::sycl_external]];
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
// expected-error@+2{{'clang::sycl_external' attribute only applies to functions}}
|
||||
template<typename>
|
||||
concept bad8 [[clang::sycl_external]] = true;
|
||||
#endif
|
14
clang/test/SemaSYCL/sycl-external-attr-grammar.cpp
Normal file
14
clang/test/SemaSYCL/sycl-external-attr-grammar.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
// RUN: %clang_cc1 -fsycl-is-host -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -fsycl-is-device -fsyntax-only -verify %s
|
||||
|
||||
// FIXME-expected-error@+1{{'clang::sycl_external' attribute takes no arguments}}
|
||||
[[clang::sycl_external()]] void bad1();
|
||||
|
||||
// expected-error@+1{{expected expression}}
|
||||
[[clang::sycl_external(,)]] void bad2();
|
||||
|
||||
// expected-error@+1{{'clang::sycl_external' attribute takes no arguments}}
|
||||
[[clang::sycl_external(3)]] void bad3();
|
||||
|
||||
// expected-error@+1{{expected expression}}
|
||||
[[clang::sycl_external(4,)]] void bad4();
|
15
clang/test/SemaSYCL/sycl-external-attr-ignored.cpp
Normal file
15
clang/test/SemaSYCL/sycl-external-attr-ignored.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
// These tests validate that the sycl_external attribute is ignored when SYCL
|
||||
// support is not enabled.
|
||||
|
||||
// expected-warning@+1{{'clang::sycl_external' attribute ignored}}
|
||||
[[clang::sycl_external]] void bar() {}
|
||||
|
||||
// expected-warning@+1{{'clang::sycl_external' attribute ignored}}
|
||||
[[clang::sycl_external]] int a;
|
||||
|
||||
// expected-warning@+2{{'clang::sycl_external' attribute ignored}}
|
||||
template<typename T>
|
||||
[[clang::sycl_external]] void ft(T) {}
|
||||
template void ft(int);
|
154
clang/test/SemaSYCL/sycl-external-attr.cpp
Normal file
154
clang/test/SemaSYCL/sycl-external-attr.cpp
Normal file
@ -0,0 +1,154 @@
|
||||
// RUN: %clang_cc1 -fsycl-is-host -std=c++17 -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -fsycl-is-device -std=c++17 -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -fsycl-is-host -std=c++20 -fsyntax-only -verify -DCPP20 %s
|
||||
// RUN: %clang_cc1 -fsycl-is-device -std=c++20 -fsyntax-only -verify -DCPP20 %s
|
||||
|
||||
// Semantic tests for the sycl_external attribute.
|
||||
|
||||
// expected-error@+1{{'clang::sycl_external' can only be applied to functions with external linkage}}
|
||||
[[clang::sycl_external]]
|
||||
static void func1() {}
|
||||
|
||||
// expected-error@+2{{'clang::sycl_external' can only be applied to functions with external linkage}}
|
||||
namespace {
|
||||
[[clang::sycl_external]]
|
||||
void func2() {}
|
||||
}
|
||||
|
||||
// expected-error@+2{{'clang::sycl_external' can only be applied to functions with external linkage}}
|
||||
namespace { struct S4 {}; }
|
||||
[[clang::sycl_external]] void func4(S4) {}
|
||||
|
||||
// expected-error@+3{{'clang::sycl_external' can only be applied to functions with external linkage}}
|
||||
namespace { struct S5 {}; }
|
||||
template<typename> [[clang::sycl_external]] void func5();
|
||||
template<> [[clang::sycl_external]] void func5<S5>() {}
|
||||
|
||||
namespace { struct S6 {}; }
|
||||
template<typename>
|
||||
[[clang::sycl_external]] void func6() {}
|
||||
template void func6<S6>();
|
||||
|
||||
// FIXME: C++23 [temp.expl.spec]p12 states:
|
||||
// ... Similarly, attributes appearing in the declaration of a template
|
||||
// have no effect on an explicit specialization of that template.
|
||||
// Clang currently instantiates and propagates attributes from a function
|
||||
// template to its explicit specializations resulting in the following
|
||||
// spurious error.
|
||||
// expected-error@+3{{'clang::sycl_external' can only be applied to functions with external linkage}}
|
||||
namespace { struct S7 {}; }
|
||||
template<typename>
|
||||
[[clang::sycl_external]] void func7();
|
||||
template<> void func7<S7>() {}
|
||||
|
||||
// FIXME: The explicit function template specialization appears to trigger
|
||||
// instantiation of a declaration from the primary template without the
|
||||
// attribute leading to a spurious diagnostic that the sycl_external
|
||||
// attribute is not present on the first declaration.
|
||||
namespace { struct S8 {}; }
|
||||
template<typename>
|
||||
void func8();
|
||||
template<> [[clang::sycl_external]] void func8<S8>() {}
|
||||
// expected-warning@-1{{'clang::sycl_external' attribute does not appear on the first declaration}}
|
||||
// expected-error@-2{{'clang::sycl_external' can only be applied to functions with external linkage}}
|
||||
// expected-note@-3{{previous declaration is here}}
|
||||
|
||||
namespace { struct S9 {}; }
|
||||
struct T9 {
|
||||
using type = S9;
|
||||
};
|
||||
template<typename>
|
||||
[[clang::sycl_external]] void func9() {}
|
||||
template<typename T>
|
||||
[[clang::sycl_external]] void test_func9() {
|
||||
func9<typename T::type>();
|
||||
}
|
||||
template void test_func9<T9>();
|
||||
|
||||
// The first declaration of a SYCL external function is required to have this attribute.
|
||||
// expected-note@+1{{previous declaration is here}}
|
||||
int foo();
|
||||
// expected-warning@+1{{'clang::sycl_external' attribute does not appear on the first declaration}}
|
||||
[[clang::sycl_external]] int foo();
|
||||
|
||||
// expected-note@+1{{previous declaration is here}}
|
||||
void goo();
|
||||
// expected-warning@+1{{'clang::sycl_external' attribute does not appear on the first declaration}}
|
||||
[[clang::sycl_external]] void goo();
|
||||
void goo() {}
|
||||
|
||||
// expected-note@+1{{previous declaration is here}}
|
||||
void hoo() {}
|
||||
// expected-warning@+1{{'clang::sycl_external' attribute does not appear on the first declaration}}
|
||||
[[clang::sycl_external]] void hoo();
|
||||
|
||||
// expected-note@+1{{previous declaration is here}}
|
||||
void joo();
|
||||
void use_joo() {
|
||||
joo();
|
||||
}
|
||||
// expected-warning@+1{{'clang::sycl_external' attribute does not appear on the first declaration}}
|
||||
[[clang::sycl_external]] void joo();
|
||||
|
||||
// Subsequent declarations of a SYCL external function may optionally specify this attribute.
|
||||
[[clang::sycl_external]] int boo();
|
||||
[[clang::sycl_external]] int boo(); // OK
|
||||
int boo(); // OK
|
||||
|
||||
class C {
|
||||
[[clang::sycl_external]] void member();
|
||||
};
|
||||
|
||||
// expected-error@+1{{'clang::sycl_external' cannot be applied to the 'main' function}}
|
||||
[[clang::sycl_external]] int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// expected-error@+2{{'clang::sycl_external' cannot be applied to an explicitly deleted function}}
|
||||
class D {
|
||||
[[clang::sycl_external]] void mdel() = delete;
|
||||
};
|
||||
|
||||
// expected-error@+1{{'clang::sycl_external' cannot be applied to an explicitly deleted function}}
|
||||
[[clang::sycl_external]] void del() = delete;
|
||||
|
||||
struct NonCopyable {
|
||||
~NonCopyable() = delete;
|
||||
[[clang::sycl_external]] NonCopyable(const NonCopyable&) = default;
|
||||
};
|
||||
|
||||
class A {
|
||||
[[clang::sycl_external]]
|
||||
A() {}
|
||||
|
||||
[[clang::sycl_external]] void mf() {}
|
||||
[[clang::sycl_external]] static void smf();
|
||||
};
|
||||
|
||||
class B {
|
||||
public:
|
||||
[[clang::sycl_external]] virtual void foo() {}
|
||||
|
||||
[[clang::sycl_external]] virtual void bar() = 0;
|
||||
};
|
||||
[[clang::sycl_external]] void B::bar() {}
|
||||
|
||||
[[clang::sycl_external]] constexpr int square(int x);
|
||||
|
||||
// Devices that do not support the generic address space shall not specify
|
||||
// a raw pointer or reference type as the return type or as a parameter type.
|
||||
[[clang::sycl_external]] int *fun0();
|
||||
[[clang::sycl_external]] int &fun1();
|
||||
[[clang::sycl_external]] int &&fun2();
|
||||
[[clang::sycl_external]] void fun3(int *);
|
||||
[[clang::sycl_external]] void fun4(int &);
|
||||
[[clang::sycl_external]] void fun5(int &&);
|
||||
template<typename T>
|
||||
[[clang::sycl_external]] void fun6(T) {}
|
||||
template void fun6(int *);
|
||||
template<> [[clang::sycl_external]] void fun6<long*>(long *) {}
|
||||
|
||||
#if CPP20
|
||||
[[clang::sycl_external]] consteval int func();
|
||||
#endif
|
226
clang/test/SemaTemplate/dedup-types-builtin.cpp
Normal file
226
clang/test/SemaTemplate/dedup-types-builtin.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
// RUN: %clang_cc1 %s -verify
|
||||
template <typename...> struct TypeList;
|
||||
|
||||
// === Check results of the builtin.
|
||||
template <class>
|
||||
struct TemplateWrapper {
|
||||
static_assert(__is_same( // expected-error {{static assertion contains an unexpanded parameter pack}}
|
||||
TypeList<__builtin_dedup_pack<int, int*, int, double, float>>,
|
||||
TypeList<int, int*, double, float>));
|
||||
};
|
||||
|
||||
template <template<typename ...> typename Templ, typename ...Types>
|
||||
struct Dependent {
|
||||
using empty_list = Templ<__builtin_dedup_pack<>...>;
|
||||
using same = Templ<__builtin_dedup_pack<Types...>...>;
|
||||
using twice = Templ<__builtin_dedup_pack<Types..., Types...>...>;
|
||||
using dep_only_types = TypeList<__builtin_dedup_pack<Types...>...>;
|
||||
using dep_only_template = Templ<__builtin_dedup_pack<int, double, int>...>;
|
||||
};
|
||||
|
||||
// Check the reverse condition to make sure we see an error and not accidentally produced dependent expression.
|
||||
static_assert(!__is_same(Dependent<TypeList>::empty_list, TypeList<>)); // expected-error {{static assertion failed}}
|
||||
static_assert(!__is_same(Dependent<TypeList>::same, TypeList<>)); // expected-error {{static assertion failed}}
|
||||
static_assert(!__is_same(Dependent<TypeList>::twice, TypeList<>)); // expected-error {{static assertion failed}}
|
||||
static_assert(!__is_same(Dependent<TypeList>::dep_only_types, TypeList<>)); // expected-error {{static assertion failed}}
|
||||
static_assert(!__is_same(Dependent<TypeList>::dep_only_template, TypeList<int, double>)); // expected-error {{static assertion failed}}
|
||||
static_assert(!__is_same(Dependent<TypeList, int*, double*, int*>::empty_list, TypeList<>)); // expected-error {{static assertion failed}}
|
||||
static_assert(!__is_same(Dependent<TypeList, int*, double*, int*>::same, TypeList<int*, double*>)); // expected-error {{static assertion failed}}
|
||||
static_assert(!__is_same(Dependent<TypeList, int*, double*, int*>::twice, TypeList<int*, double*>)); // expected-error {{static assertion failed}}
|
||||
static_assert(!__is_same(Dependent<TypeList, int*, double*, int*>::dep_only_types, TypeList<int*, double*>)); // expected-error {{static assertion failed}}
|
||||
static_assert(!__is_same(Dependent<TypeList, int*, double*, int*>::dep_only_template, TypeList<int, double>)); // expected-error {{static assertion failed}}
|
||||
|
||||
|
||||
template <class ...T>
|
||||
using Twice = TypeList<T..., T...>;
|
||||
|
||||
template <class>
|
||||
struct TwiceTemplateWrapper {
|
||||
static_assert(!__is_same(Twice<__builtin_dedup_pack<int, double, int>...>, TypeList<int, double, int, double>)); // expected-error {{static assertion failed}}
|
||||
|
||||
};
|
||||
template struct TwiceTemplateWrapper<int>; // expected-note {{in instantiation of template class 'TwiceTemplateWrapper<int>' requested here}}
|
||||
|
||||
template <int...> struct IntList;
|
||||
// Wrong kinds of template arguments.
|
||||
template <class> struct IntListTemplateWrapper {
|
||||
IntList<__builtin_dedup_pack<int>...>* wrong_template; // expected-error {{template argument for non-type template parameter must be an expression}}
|
||||
// expected-note@-4 {{template parameter is declared here}}
|
||||
TypeList<__builtin_dedup_pack<1, 2, 3>...>* wrong_template_args; // expected-error {{template argument for template type parameter must be a type}}
|
||||
// expected-note@* {{template parameter from hidden source}}
|
||||
__builtin_dedup_pack<> not_enough_args; // expected-error {{data member type contains an unexpanded parameter pack}}
|
||||
// expected-note@* {{template declaration from hidden source}}
|
||||
__builtin_dedup_pack missing_template_args; // expected-error {{use of template '__builtin_dedup_pack' requires template arguments}}
|
||||
};
|
||||
|
||||
// Make sure various canonical / non-canonical type representations do not affect results
|
||||
// of the deduplication and the qualifiers do end up creating different types when C++ requires it.
|
||||
using Int = int;
|
||||
using CInt = const Int;
|
||||
using IntArray = Int[10];
|
||||
using CIntArray = Int[10];
|
||||
using IntPtr = int*;
|
||||
using CIntPtr = const int*;
|
||||
|
||||
template <class>
|
||||
struct Foo {
|
||||
static_assert(
|
||||
!__is_same( // expected-error {{static assertion failed}}
|
||||
// expected-note@* {{in instantiation of template class 'Foo<int>'}}
|
||||
TypeList<__builtin_dedup_pack<
|
||||
Int, int,
|
||||
const int, const Int, CInt, const CInt,
|
||||
IntArray, Int[10], int[10],
|
||||
const IntArray, const int[10], CIntArray, const CIntArray,
|
||||
IntPtr, int*,
|
||||
const IntPtr, int* const,
|
||||
CIntPtr, const int*,
|
||||
const IntPtr*, int*const*,
|
||||
CIntPtr*, const int**,
|
||||
const CIntPtr*, const int* const*
|
||||
>...>,
|
||||
TypeList<int, const int, int[10], const int [10], int*, int* const, const int*, int*const *, const int**, const int*const*>),
|
||||
"");
|
||||
};
|
||||
|
||||
template struct Foo<int>;
|
||||
|
||||
// === Show an error when packs are used in non-template contexts.
|
||||
static_assert(!__is_same(TypeList<__builtin_dedup_pack<int>...>, TypeList<int>)); // expected-error {{outside}}
|
||||
// Non-dependent uses in template are fine, though.
|
||||
template <class T>
|
||||
struct NonDepInTemplate {
|
||||
static_assert(!__is_same(TypeList<__builtin_dedup_pack<int>...>, TypeList<int>)); // expected-error {{static assertion failed}}
|
||||
};
|
||||
template struct NonDepInTemplate<int>; // expected-note {{requested here}}
|
||||
|
||||
template <template<class...> class T = __builtin_dedup_pack> // expected-error {{use of template '__builtin_dedup_pack' requires template arguments}}
|
||||
// expected-note@* {{template declaration from hidden source}}
|
||||
struct UseAsTemplate;
|
||||
template <template<class...> class>
|
||||
struct AcceptsTemplateArg;
|
||||
template <class>
|
||||
struct UseAsTemplateWrapper {
|
||||
AcceptsTemplateArg<__builtin_dedup_pack>* a; // expected-error {{use of template '__builtin_dedup_pack' requires template arguments}}
|
||||
// expected-note@* {{template declaration from hidden source}}
|
||||
};
|
||||
|
||||
// === Check how expansions in various contexts behave.
|
||||
// The following cases are not supported yet, should produce an error.
|
||||
template <class... T>
|
||||
struct DedupBases : __builtin_dedup_pack<T...>... {};
|
||||
struct Base1 {
|
||||
int a1;
|
||||
};
|
||||
struct Base2 {
|
||||
int a2;
|
||||
};
|
||||
static_assert(DedupBases<Base1, Base1, Base2, Base1, Base2, Base2>{1, 2}.a1 != 1); // expected-error {{static assertion failed}} \
|
||||
// expected-note {{}}
|
||||
static_assert(DedupBases<Base1, Base1, Base2, Base1, Base2, Base2>{1, 2}.a2 != 2); // expected-error {{static assertion failed}} \
|
||||
// expected-note {{}}
|
||||
|
||||
template <class ...T>
|
||||
constexpr int dedup_params(__builtin_dedup_pack<T...>... as) {
|
||||
return (as + ...);
|
||||
}
|
||||
static_assert(dedup_params<int, int, short, int, short, short>(1, 2)); // expected-error {{no matching function}} \
|
||||
// expected-note@-3 {{expansions of '__builtin_dedup_pack' are not supported here}}
|
||||
|
||||
template <class ...T>
|
||||
constexpr int dedup_params_into_type_list(TypeList<__builtin_dedup_pack<T...>...> *, T... as) {
|
||||
return (as + ...);
|
||||
}
|
||||
static_assert(dedup_params_into_type_list(static_cast<TypeList<int,short,long>*>(nullptr), 1, short(1), 1, 1l, 1l) != 5); // expected-error {{static assertion failed}} \
|
||||
// expected-note {{expression evaluates}}
|
||||
|
||||
template <class T, __builtin_dedup_pack<T, int>...> // expected-error 2{{expansions of '__builtin_dedup_pack' are not supported here}}
|
||||
struct InTemplateParams {};
|
||||
InTemplateParams<int> itp1;
|
||||
InTemplateParams<int, 1, 2, 3, 4, 5> itp2;
|
||||
|
||||
template <class T>
|
||||
struct DeepTemplateParams {
|
||||
template <__builtin_dedup_pack<T, int>...> // expected-error {{expansions of '__builtin_dedup_pack' are not supported here}}
|
||||
struct Templ {};
|
||||
};
|
||||
DeepTemplateParams<int>::Templ<> dtp1; // expected-note {{requested here}} \
|
||||
// expected-error {{no template named 'Templ'}}
|
||||
|
||||
|
||||
template <class ...T>
|
||||
struct MemInitializers : T... {
|
||||
MemInitializers() : __builtin_dedup_pack<T...>()... {} // expected-error 2{{expansions of '__builtin_dedup_pack' are not supported here.}}
|
||||
};
|
||||
MemInitializers<> mi1; // expected-note {{in instantiation of member function}}
|
||||
MemInitializers<Base1, Base2> mi2; // expected-note {{in instantiation of member function}}
|
||||
|
||||
template <class ...T>
|
||||
constexpr int dedup_in_expressions() {
|
||||
// counts the number of unique Ts.
|
||||
return ((1 + __builtin_dedup_pack<T...>()) + ...); // expected-error {{expansions of '__builtin_dedup_pack' are not supported here.}} \
|
||||
// expected-note@+3 {{in instantiation of function template specialization}}
|
||||
}
|
||||
static_assert(dedup_in_expressions<int, int, short, double, int, short, double, int>() == 3); // expected-error {{not an integral constant expression}}
|
||||
|
||||
template <class ...T>
|
||||
void in_exception_spec() throw(__builtin_dedup_pack<T...>...); // expected-error{{C++17 does not allow dynamic exception specifications}} \
|
||||
// expected-note {{use 'noexcept}} \
|
||||
// expected-error{{expansions of '__builtin_dedup_pack' are not supported here.}}
|
||||
|
||||
void test_in_exception_spec() {
|
||||
in_exception_spec<int, double, int>(); // expected-note {{instantiation of exception specification}}
|
||||
}
|
||||
|
||||
template <class ...T>
|
||||
constexpr bool in_type_trait = __is_trivially_constructible(int, __builtin_dedup_pack<T...>...); // expected-error{{expansions of '__builtin_dedup_pack' are not supported here.}}
|
||||
|
||||
static_assert(in_type_trait<int, int, int>); // expected-note{{in instantiation of variable template specialization}}
|
||||
|
||||
template <class ...T>
|
||||
struct InFriends {
|
||||
friend __builtin_dedup_pack<T>...; // expected-warning {{variadic 'friend' declarations are a C++2c extension}} \
|
||||
// expected-error 2 {{expansions of '__builtin_dedup_pack' are not supported here.}} \
|
||||
// expected-note@* 2 {{in instantiation of template class}}
|
||||
|
||||
};
|
||||
struct Friend1 {};
|
||||
struct Friend2 {};
|
||||
InFriends<> if1;
|
||||
InFriends<Friend1, Friend2> if2;
|
||||
|
||||
template <class ...T>
|
||||
struct InUsingDecl {
|
||||
using __builtin_dedup_pack<T...>::func...; // expected-error 2 {{expansions of '__builtin_dedup_pack' are not supported here.}}
|
||||
};
|
||||
struct WithFunc1 { void func(); };
|
||||
struct WithFunc2 { void func(int); };
|
||||
InUsingDecl<> iu1; // expected-note {{in instantiation of template class}}
|
||||
InUsingDecl<WithFunc1, WithFunc2> iu2; // expected-note {{in instantiation of template class}}
|
||||
|
||||
// Note: produces parsing errors and does not construct pack indexing.
|
||||
// Keep this commented out until the parser supports this.
|
||||
//
|
||||
// template <class ...T>
|
||||
// struct InPackIndexing {
|
||||
//
|
||||
// using type = __builtin_dedup_pack<T...>...[0];
|
||||
// };
|
||||
// static_assert(__is_same(InPackIndexing<int, int>, int));
|
||||
|
||||
template <class ...T>
|
||||
struct LambdaInitCaptures {
|
||||
static constexpr int test() {
|
||||
[...foos=__builtin_dedup_pack<T...>()]{}; // expected-warning {{initialized lambda pack captures are a C++20 extension}} \
|
||||
// expected-error 2{{expansions of '__builtin_dedup_pack' are not supported here.}}
|
||||
return 3;
|
||||
}
|
||||
};
|
||||
static_assert(LambdaInitCaptures<>::test() == 3); // expected-note {{in instantiation of member function}}
|
||||
static_assert(LambdaInitCaptures<int, int, int>::test() == 3); // expected-note {{in instantiation of member function}}
|
||||
|
||||
template <class ...T>
|
||||
struct alignas(__builtin_dedup_pack<T...>...) AlignAs {}; // expected-error 2{{expansions of '__builtin_dedup_pack' are not supported here.}}
|
||||
AlignAs<> aa1; // expected-note {{in instantiation of template class}}
|
||||
AlignAs<int, double> aa2; // expected-note {{in instantiation of template class}}
|
||||
|
@ -1900,6 +1900,7 @@ DEFAULT_TYPELOC_IMPL(Record, TagType)
|
||||
DEFAULT_TYPELOC_IMPL(Enum, TagType)
|
||||
DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParm, Type)
|
||||
DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParmPack, Type)
|
||||
DEFAULT_TYPELOC_IMPL(SubstBuiltinTemplatePack, Type)
|
||||
DEFAULT_TYPELOC_IMPL(Auto, Type)
|
||||
DEFAULT_TYPELOC_IMPL(BitInt, Type)
|
||||
DEFAULT_TYPELOC_IMPL(DependentBitInt, Type)
|
||||
|
@ -93,7 +93,7 @@ if(MSVC)
|
||||
set(LLVM_EXPORTED_SYMBOL_FILE)
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "AIX" AND NOT CYGWIN)
|
||||
if (UNIX AND NOT APPLE AND NOT "${CMAKE_SYSTEM_NAME}" MATCHES "AIX" AND NOT CYGWIN)
|
||||
set(LLVM_EXPORTED_SYMBOL_FILE)
|
||||
set(USE_VERSION_SCRIPT ${LLVM_HAVE_LINK_VERSION_SCRIPT})
|
||||
endif()
|
||||
@ -125,7 +125,7 @@ else()
|
||||
set(output_name "clang")
|
||||
endif()
|
||||
|
||||
if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if (UNIX AND "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
set(CMAKE_AIX_EXPORT_ALL_SYMBOLS OFF)
|
||||
# libclang requires headers which need _ALL_SOURCE to build on AIX
|
||||
remove_definitions("-D_XOPEN_SOURCE=700")
|
||||
@ -186,7 +186,7 @@ if(ENABLE_SHARED)
|
||||
endif()
|
||||
endif()
|
||||
if (USE_VERSION_SCRIPT)
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS")
|
||||
include(CheckLinkerFlag)
|
||||
# The Solaris 11.4 linker supports a subset of GNU ld version scripts,
|
||||
# but requires a special option to enable it.
|
||||
|
@ -1183,6 +1183,39 @@ TEST_P(ASTMatchersTest, AsmStatement) {
|
||||
EXPECT_TRUE(matches("void foo() { __asm(\"mov al, 2\"); }", asmStmt()));
|
||||
}
|
||||
|
||||
TEST_P(ASTMatchersTest, HasConditionVariableStatement) {
|
||||
if (!GetParam().isCXX()) {
|
||||
// FIXME: Add a test for `hasConditionVariableStatement()` that does not
|
||||
// depend on C++.
|
||||
return;
|
||||
}
|
||||
|
||||
StatementMatcher IfCondition =
|
||||
ifStmt(hasConditionVariableStatement(declStmt()));
|
||||
|
||||
EXPECT_TRUE(matches("void x() { if (int* a = 0) {} }", IfCondition));
|
||||
EXPECT_TRUE(notMatches("void x() { if (true) {} }", IfCondition));
|
||||
EXPECT_TRUE(notMatches("void x() { int x; if ((x = 42)) {} }", IfCondition));
|
||||
|
||||
StatementMatcher SwitchCondition =
|
||||
switchStmt(hasConditionVariableStatement(declStmt()));
|
||||
|
||||
EXPECT_TRUE(matches("void x() { switch (int a = 0) {} }", SwitchCondition));
|
||||
if (GetParam().isCXX17OrLater()) {
|
||||
EXPECT_TRUE(
|
||||
notMatches("void x() { switch (int a = 0; a) {} }", SwitchCondition));
|
||||
}
|
||||
|
||||
StatementMatcher ForCondition =
|
||||
forStmt(hasConditionVariableStatement(declStmt()));
|
||||
|
||||
EXPECT_TRUE(matches("void x() { for (; int a = 0; ) {} }", ForCondition));
|
||||
EXPECT_TRUE(notMatches("void x() { for (int a = 0; ; ) {} }", ForCondition));
|
||||
|
||||
EXPECT_TRUE(matches("void x() { while (int a = 0) {} }",
|
||||
whileStmt(hasConditionVariableStatement(declStmt()))));
|
||||
}
|
||||
|
||||
TEST_P(ASTMatchersTest, HasCondition) {
|
||||
if (!GetParam().isCXX()) {
|
||||
// FIXME: Add a test for `hasCondition()` that does not depend on C++.
|
||||
|
@ -5142,21 +5142,6 @@ TEST(ForEachLambdaCapture, MatchExplicitCapturesOnly) {
|
||||
matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC", 1)));
|
||||
}
|
||||
|
||||
TEST(HasConditionVariableStatement, DoesNotMatchCondition) {
|
||||
EXPECT_TRUE(notMatches(
|
||||
"void x() { if(true) {} }",
|
||||
ifStmt(hasConditionVariableStatement(declStmt()))));
|
||||
EXPECT_TRUE(notMatches(
|
||||
"void x() { int x; if((x = 42)) {} }",
|
||||
ifStmt(hasConditionVariableStatement(declStmt()))));
|
||||
}
|
||||
|
||||
TEST(HasConditionVariableStatement, MatchesConditionVariables) {
|
||||
EXPECT_TRUE(matches(
|
||||
"void x() { if(int* a = 0) {} }",
|
||||
ifStmt(hasConditionVariableStatement(declStmt()))));
|
||||
}
|
||||
|
||||
TEST(ForEach, BindsOneNode) {
|
||||
EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; };",
|
||||
recordDecl(hasName("C"), forEach(fieldDecl(hasName("x")).bind("x"))),
|
||||
|
@ -9,17 +9,25 @@
|
||||
#include "TestingSupport.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/OperationKinds.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
|
||||
#include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
|
||||
#include "clang/Analysis/FlowSensitive/NoopLattice.h"
|
||||
#include "clang/Analysis/FlowSensitive/RecordOps.h"
|
||||
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
|
||||
#include "clang/Analysis/FlowSensitive/Value.h"
|
||||
#include "clang/Basic/LangStandard.h"
|
||||
#include "clang/Testing/TestAST.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Testing/Support/Error.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
@ -27,6 +35,7 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
@ -3541,7 +3550,7 @@ TEST(TransferTest, ResultObjectLocationDontVisitUnevaluatedContexts) {
|
||||
testFunction(Code, "noexceptTarget");
|
||||
}
|
||||
|
||||
TEST(TransferTest, StaticCast) {
|
||||
TEST(TransferTest, StaticCastNoOp) {
|
||||
std::string Code = R"(
|
||||
void target(int Foo) {
|
||||
int Bar = static_cast<int>(Foo);
|
||||
@ -3561,6 +3570,13 @@ TEST(TransferTest, StaticCast) {
|
||||
const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
|
||||
ASSERT_THAT(BarDecl, NotNull());
|
||||
|
||||
const auto *Cast = ast_matchers::selectFirst<CXXStaticCastExpr>(
|
||||
"cast",
|
||||
ast_matchers::match(ast_matchers::cxxStaticCastExpr().bind("cast"),
|
||||
ASTCtx));
|
||||
ASSERT_THAT(Cast, NotNull());
|
||||
ASSERT_EQ(Cast->getCastKind(), CK_NoOp);
|
||||
|
||||
const auto *FooVal = Env.getValue(*FooDecl);
|
||||
const auto *BarVal = Env.getValue(*BarDecl);
|
||||
EXPECT_TRUE(isa<IntegerValue>(FooVal));
|
||||
@ -3569,6 +3585,268 @@ TEST(TransferTest, StaticCast) {
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TransferTest, StaticCastBaseToDerived) {
|
||||
std::string Code = R"cc(
|
||||
struct Base {
|
||||
char C;
|
||||
};
|
||||
struct Intermediate : public Base {
|
||||
bool B;
|
||||
};
|
||||
struct Derived : public Intermediate {
|
||||
int I;
|
||||
};
|
||||
Base& getBaseRef();
|
||||
void target(Base* BPtr) {
|
||||
Derived* DPtr = static_cast<Derived*>(BPtr);
|
||||
DPtr->C;
|
||||
DPtr->B;
|
||||
DPtr->I;
|
||||
Derived& DRef = static_cast<Derived&>(*BPtr);
|
||||
DRef.C;
|
||||
DRef.B;
|
||||
DRef.I;
|
||||
Derived& DRefFromFunc = static_cast<Derived&>(getBaseRef());
|
||||
DRefFromFunc.C;
|
||||
DRefFromFunc.B;
|
||||
DRefFromFunc.I;
|
||||
// [[p]]
|
||||
}
|
||||
)cc";
|
||||
runDataflow(
|
||||
Code,
|
||||
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
|
||||
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
|
||||
|
||||
const ValueDecl *BPtrDecl = findValueDecl(ASTCtx, "BPtr");
|
||||
ASSERT_THAT(BPtrDecl, NotNull());
|
||||
|
||||
const ValueDecl *DPtrDecl = findValueDecl(ASTCtx, "DPtr");
|
||||
ASSERT_THAT(DPtrDecl, NotNull());
|
||||
|
||||
const ValueDecl *DRefDecl = findValueDecl(ASTCtx, "DRef");
|
||||
ASSERT_THAT(DRefDecl, NotNull());
|
||||
|
||||
const ValueDecl *DRefFromFuncDecl =
|
||||
findValueDecl(ASTCtx, "DRefFromFunc");
|
||||
ASSERT_THAT(DRefFromFuncDecl, NotNull());
|
||||
|
||||
const auto *Cast = ast_matchers::selectFirst<CXXStaticCastExpr>(
|
||||
"cast",
|
||||
ast_matchers::match(ast_matchers::cxxStaticCastExpr().bind("cast"),
|
||||
ASTCtx));
|
||||
ASSERT_THAT(Cast, NotNull());
|
||||
ASSERT_EQ(Cast->getCastKind(), CK_BaseToDerived);
|
||||
|
||||
EXPECT_EQ(Env.getValue(*BPtrDecl), Env.getValue(*DPtrDecl));
|
||||
EXPECT_EQ(&Env.get<PointerValue>(*BPtrDecl)->getPointeeLoc(),
|
||||
Env.getStorageLocation(*DRefDecl));
|
||||
// For DRefFromFunc, not crashing when analyzing the field accesses is
|
||||
// enough.
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TransferTest, ExplicitDerivedToBaseCast) {
|
||||
std::string Code = R"cc(
|
||||
struct Base {};
|
||||
struct Derived : public Base {};
|
||||
void target(Derived D) {
|
||||
(Base*)&D;
|
||||
// [[p]]
|
||||
}
|
||||
)cc";
|
||||
runDataflow(
|
||||
Code,
|
||||
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
|
||||
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
|
||||
|
||||
auto *Cast = ast_matchers::selectFirst<ImplicitCastExpr>(
|
||||
"cast", ast_matchers::match(
|
||||
ast_matchers::implicitCastExpr().bind("cast"), ASTCtx));
|
||||
ASSERT_THAT(Cast, NotNull());
|
||||
ASSERT_EQ(Cast->getCastKind(), CK_DerivedToBase);
|
||||
|
||||
auto *AddressOf = ast_matchers::selectFirst<UnaryOperator>(
|
||||
"addressof",
|
||||
ast_matchers::match(ast_matchers::unaryOperator().bind("addressof"),
|
||||
ASTCtx));
|
||||
ASSERT_THAT(AddressOf, NotNull());
|
||||
ASSERT_EQ(AddressOf->getOpcode(), UO_AddrOf);
|
||||
|
||||
EXPECT_EQ(Env.getValue(*Cast), Env.getValue(*AddressOf));
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TransferTest, ConstructorConversion) {
|
||||
std::string Code = R"cc(
|
||||
struct Base {};
|
||||
struct Derived : public Base {};
|
||||
void target(Derived D) {
|
||||
Base B = (Base)D;
|
||||
// [[p]]
|
||||
}
|
||||
)cc";
|
||||
runDataflow(
|
||||
Code,
|
||||
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
|
||||
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
|
||||
|
||||
auto *Cast = ast_matchers::selectFirst<CStyleCastExpr>(
|
||||
"cast", ast_matchers::match(
|
||||
ast_matchers::cStyleCastExpr().bind("cast"), ASTCtx));
|
||||
ASSERT_THAT(Cast, NotNull());
|
||||
ASSERT_EQ(Cast->getCastKind(), CK_ConstructorConversion);
|
||||
|
||||
auto &DLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "D");
|
||||
auto &BLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "B");
|
||||
EXPECT_NE(&BLoc, &DLoc);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TransferTest, UserDefinedConversion) {
|
||||
std::string Code = R"cc(
|
||||
struct To {};
|
||||
struct From {
|
||||
operator To();
|
||||
};
|
||||
void target(From F) {
|
||||
To T = (To)F;
|
||||
// [[p]]
|
||||
}
|
||||
)cc";
|
||||
runDataflow(
|
||||
Code,
|
||||
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
|
||||
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
|
||||
|
||||
auto *Cast = ast_matchers::selectFirst<ImplicitCastExpr>(
|
||||
"cast", ast_matchers::match(
|
||||
ast_matchers::implicitCastExpr().bind("cast"), ASTCtx));
|
||||
ASSERT_THAT(Cast, NotNull());
|
||||
ASSERT_EQ(Cast->getCastKind(), CK_UserDefinedConversion);
|
||||
|
||||
auto &FLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "F");
|
||||
auto &TLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "T");
|
||||
EXPECT_NE(&TLoc, &FLoc);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TransferTest, ImplicitUncheckedDerivedToBaseCast) {
|
||||
std::string Code = R"cc(
|
||||
struct Base {
|
||||
void method();
|
||||
};
|
||||
struct Derived : public Base {};
|
||||
void target(Derived D) {
|
||||
D.method();
|
||||
// [[p]]
|
||||
}
|
||||
)cc";
|
||||
runDataflow(
|
||||
Code,
|
||||
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
|
||||
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
|
||||
|
||||
auto *Cast = ast_matchers::selectFirst<ImplicitCastExpr>(
|
||||
"cast", ast_matchers::match(
|
||||
ast_matchers::implicitCastExpr().bind("cast"), ASTCtx));
|
||||
ASSERT_THAT(Cast, NotNull());
|
||||
ASSERT_EQ(Cast->getCastKind(), CK_UncheckedDerivedToBase);
|
||||
|
||||
auto &DLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "D");
|
||||
EXPECT_EQ(Env.getStorageLocation(*Cast), &DLoc);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TransferTest, ImplicitDerivedToBaseCast) {
|
||||
std::string Code = R"cc(
|
||||
struct Base {};
|
||||
struct Derived : public Base {};
|
||||
void target() {
|
||||
Base* B = new Derived();
|
||||
// [[p]]
|
||||
}
|
||||
)cc";
|
||||
runDataflow(
|
||||
Code,
|
||||
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
|
||||
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
|
||||
|
||||
auto *Cast = ast_matchers::selectFirst<ImplicitCastExpr>(
|
||||
"cast", ast_matchers::match(
|
||||
ast_matchers::implicitCastExpr().bind("cast"), ASTCtx));
|
||||
ASSERT_THAT(Cast, NotNull());
|
||||
ASSERT_EQ(Cast->getCastKind(), CK_DerivedToBase);
|
||||
|
||||
auto *New = ast_matchers::selectFirst<CXXNewExpr>(
|
||||
"new", ast_matchers::match(ast_matchers::cxxNewExpr().bind("new"),
|
||||
ASTCtx));
|
||||
ASSERT_THAT(New, NotNull());
|
||||
|
||||
EXPECT_EQ(Env.getValue(*Cast), Env.getValue(*New));
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TransferTest, ReinterpretCast) {
|
||||
std::string Code = R"cc(
|
||||
struct S {
|
||||
int I;
|
||||
};
|
||||
|
||||
void target(unsigned char* Bytes) {
|
||||
S& SRef = reinterpret_cast<S&>(Bytes);
|
||||
SRef.I;
|
||||
S* SPtr = reinterpret_cast<S*>(Bytes);
|
||||
SPtr->I;
|
||||
// [[p]]
|
||||
}
|
||||
)cc";
|
||||
runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>
|
||||
&Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
|
||||
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
|
||||
const ValueDecl *I = findValueDecl(ASTCtx, "I");
|
||||
ASSERT_THAT(I, NotNull());
|
||||
|
||||
// No particular knowledge of I's value is modeled, but for both casts,
|
||||
// the fields of S are modeled.
|
||||
|
||||
{
|
||||
auto &Loc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "SRef");
|
||||
std::vector<const ValueDecl *> Children;
|
||||
for (const auto &Entry : Loc.children()) {
|
||||
Children.push_back(Entry.getFirst());
|
||||
}
|
||||
|
||||
EXPECT_THAT(Children, UnorderedElementsAre(I));
|
||||
}
|
||||
|
||||
{
|
||||
auto &Loc = cast<RecordStorageLocation>(
|
||||
getValueForDecl<PointerValue>(ASTCtx, Env, "SPtr").getPointeeLoc());
|
||||
std::vector<const ValueDecl *> Children;
|
||||
for (const auto &Entry : Loc.children()) {
|
||||
Children.push_back(Entry.getFirst());
|
||||
}
|
||||
|
||||
EXPECT_THAT(Children, UnorderedElementsAre(I));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TransferTest, IntegralCast) {
|
||||
std::string Code = R"(
|
||||
void target(int Foo) {
|
||||
|
@ -204,7 +204,7 @@ check_library_exists(stdc++ __cxa_throw "" COMPILER_RT_HAS_LIBSTDCXX)
|
||||
llvm_check_compiler_linker_flag(C "-Wl,-z,text" COMPILER_RT_HAS_Z_TEXT)
|
||||
llvm_check_compiler_linker_flag(C "-fuse-ld=lld" COMPILER_RT_HAS_FUSE_LD_LLD_FLAG)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS" AND LLVM_LINKER_IS_SOLARISLD)
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS" AND LLVM_LINKER_IS_SOLARISLD)
|
||||
set(VERS_COMPAT_OPTION "-Wl,-z,gnu-version-script-compat")
|
||||
llvm_check_compiler_linker_flag(C "${VERS_COMPAT_OPTION}" COMPILER_RT_HAS_GNU_VERSION_SCRIPT_COMPAT)
|
||||
endif()
|
||||
|
@ -282,7 +282,7 @@ else()
|
||||
endif()
|
||||
|
||||
# On AIX, we only need the static libraries.
|
||||
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if (NOT "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
foreach(arch ${ASAN_SUPPORTED_ARCH})
|
||||
if (COMPILER_RT_HAS_VERSION_SCRIPT)
|
||||
if(WIN32)
|
||||
@ -392,7 +392,7 @@ add_compiler_rt_resource_file(asan_ignorelist asan_ignorelist.txt asan)
|
||||
# On AIX, static sanitizer libraries are not added to the DSO, so we need to put
|
||||
# asan.link_with_main_exec.txt and asan_cxx.link_with_main_exec.txt to the build
|
||||
# and install dir for use in resolving undefined sanitizer symbols at runtime.
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
foreach(arch ${ASAN_SUPPORTED_ARCH})
|
||||
add_compiler_rt_cfg(asan_symbols_${arch} asan.link_with_main_exec.txt asan ${arch})
|
||||
add_compiler_rt_cfg(asan_cxx_symbols_${arch} asan_cxx.link_with_main_exec.txt asan ${arch})
|
||||
|
@ -113,7 +113,7 @@ option(LIBCXX_ENABLE_MONOTONIC_CLOCK
|
||||
#
|
||||
# TODO TZDB make the default always ON when most platforms ship with the IANA
|
||||
# database.
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
|
||||
set(ENABLE_TIME_ZONE_DATABASE_DEFAULT ON)
|
||||
else()
|
||||
set(ENABLE_TIME_ZONE_DATABASE_DEFAULT OFF)
|
||||
@ -159,7 +159,7 @@ set(LIBCXX_TEST_PARAMS "" CACHE STRING
|
||||
"A list of parameters to run the Lit test suite with.")
|
||||
|
||||
# TODO: Figure out how to build GoogleBenchmark on those platforms, and how to build when exceptions or RTTI is disabled
|
||||
if (WIN32 OR MINGW OR ANDROID OR ${CMAKE_SYSTEM_NAME} MATCHES "AIX"
|
||||
if (WIN32 OR MINGW OR ANDROID OR "${CMAKE_SYSTEM_NAME}" MATCHES "AIX"
|
||||
OR NOT LIBCXX_ENABLE_LOCALIZATION
|
||||
OR NOT LIBCXX_ENABLE_THREADS
|
||||
OR NOT LIBCXX_ENABLE_FILESYSTEM
|
||||
@ -466,7 +466,7 @@ include(HandleLibcxxFlags)
|
||||
# 'config-ix' use them during feature checks. It also adds them to both
|
||||
# 'LIBCXX_COMPILE_FLAGS' and 'LIBCXX_LINK_FLAGS'
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
add_flags_if_supported("-mdefault-visibility-export-mapping=explicit")
|
||||
set(CMAKE_AIX_EXPORT_ALL_SYMBOLS OFF)
|
||||
endif()
|
||||
|
@ -244,7 +244,7 @@ include(HandleLibcxxabiFlags)
|
||||
#===============================================================================
|
||||
|
||||
# Configure target flags
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
add_flags_if_supported("-mdefault-visibility-export-mapping=explicit")
|
||||
set(CMAKE_AIX_EXPORT_ALL_SYMBOLS OFF)
|
||||
endif()
|
||||
@ -458,7 +458,7 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBCXXABI_C_FLAGS}")
|
||||
|
||||
# On AIX, avoid picking up VMX extensions(i.e. vec_malloc) which would change
|
||||
# the default alignment of the allocators here.
|
||||
if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if (UNIX AND "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
add_definitions("-D_XOPEN_SOURCE=700")
|
||||
endif()
|
||||
|
||||
|
@ -37,7 +37,7 @@ else()
|
||||
endif()
|
||||
|
||||
if (LIBCXXABI_ENABLE_THREADS AND (UNIX OR FUCHSIA) AND NOT (APPLE OR CYGWIN)
|
||||
AND NOT (${CMAKE_SYSTEM_NAME} MATCHES "AIX"))
|
||||
AND NOT ("${CMAKE_SYSTEM_NAME}" MATCHES "AIX"))
|
||||
list(APPEND LIBCXXABI_SOURCES
|
||||
cxa_thread_atexit.cpp
|
||||
)
|
||||
|
@ -6,7 +6,7 @@ set(LIBUNWIND_CXX_SOURCES
|
||||
Unwind-seh.cpp
|
||||
)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
list(APPEND LIBUNWIND_CXX_SOURCES
|
||||
Unwind_AIXExtras.cpp
|
||||
)
|
||||
|
@ -7,7 +7,7 @@ if (APPLE AND LLVM_ENABLE_LOCAL_SUBMODULE_VISIBILITY)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if (UNIX AND "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
add_definitions("-D_ALL_SOURCE")
|
||||
endif()
|
||||
|
||||
|
@ -2,7 +2,7 @@ set(FBSDKERNEL_LIBS)
|
||||
if(FBSDVMCore_FOUND)
|
||||
list(APPEND FBSDKERNEL_LIBS fbsdvmcore)
|
||||
endif()
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
|
||||
list(APPEND FBSDKERNEL_LIBS kvm)
|
||||
endif()
|
||||
|
||||
|
@ -11,7 +11,7 @@ if(APPLE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_BINARY_DIR}/lldb-Info.plist")
|
||||
endif()
|
||||
|
||||
if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if (UNIX AND "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
remove_definitions("-D_XOPEN_SOURCE=700")
|
||||
add_definitions("-D_ALL_SOURCE")
|
||||
endif()
|
||||
|
@ -110,7 +110,7 @@ endif()
|
||||
# one for llvm+clang+... using the same sources.
|
||||
# These projects will be included when "all" is included in LLVM_ENABLE_PROJECTS.
|
||||
set(LLVM_ALL_PROJECTS "bolt;clang;clang-tools-extra;compiler-rt;cross-project-tests;libclc;lld;lldb;mlir;openmp;polly")
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
# Disallow 'openmp' as a LLVM PROJECT on AIX as the supported way is to use
|
||||
# LLVM_ENABLE_RUNTIMES.
|
||||
list(REMOVE_ITEM LLVM_ALL_PROJECTS openmp)
|
||||
@ -682,7 +682,7 @@ if (NOT CMAKE_SYSTEM_NAME MATCHES "OS390")
|
||||
option(LLVM_ENABLE_PIC "Build Position-Independent Code" ON)
|
||||
endif()
|
||||
option(LLVM_ENABLE_MODULES "Compile with C++ modules enabled." OFF)
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
|
||||
option(LLVM_ENABLE_MODULE_DEBUGGING "Compile with -gmodules." ON)
|
||||
else()
|
||||
option(LLVM_ENABLE_MODULE_DEBUGGING "Compile with -gmodules." OFF)
|
||||
@ -786,7 +786,7 @@ option(LLVM_USE_SPLIT_DWARF
|
||||
|
||||
# Define an option controlling whether we should build for 32-bit on 64-bit
|
||||
# platforms, where supported.
|
||||
if( CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT (WIN32 OR ${CMAKE_SYSTEM_NAME} MATCHES "AIX"))
|
||||
if( CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT (WIN32 OR "${CMAKE_SYSTEM_NAME}" MATCHES "AIX"))
|
||||
# TODO: support other platforms and toolchains.
|
||||
option(LLVM_BUILD_32_BITS "Build 32 bits executables and libraries." OFF)
|
||||
endif()
|
||||
@ -1257,7 +1257,7 @@ endif()
|
||||
|
||||
# Build with _XOPEN_SOURCE on AIX, as stray macros in _ALL_SOURCE mode tend to
|
||||
# break things. In this case we need to enable the large-file API as well.
|
||||
if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if (UNIX AND "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
add_compile_definitions(_XOPEN_SOURCE=700)
|
||||
add_compile_definitions(_LARGE_FILE_API)
|
||||
add_compile_options(-pthread)
|
||||
@ -1285,7 +1285,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "OS390")
|
||||
endif()
|
||||
|
||||
# Build with _FILE_OFFSET_BITS=64 on Solaris to match g++ >= 9.
|
||||
if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||
if (UNIX AND "${CMAKE_SYSTEM_NAME}" MATCHES "SunOS")
|
||||
add_compile_definitions(_FILE_OFFSET_BITS=64)
|
||||
endif()
|
||||
|
||||
@ -1303,10 +1303,10 @@ if(LLVM_TARGET_IS_CROSSCOMPILE_HOST)
|
||||
# (this is a variable that CrossCompile sets on recursive invocations)
|
||||
endif()
|
||||
|
||||
if( ${CMAKE_SYSTEM_NAME} MATCHES SunOS )
|
||||
if( "${CMAKE_SYSTEM_NAME}" MATCHES SunOS )
|
||||
# special hack for Solaris to handle crazy system sys/regset.h
|
||||
include_directories("${LLVM_MAIN_INCLUDE_DIR}/llvm/Support/Solaris")
|
||||
endif( ${CMAKE_SYSTEM_NAME} MATCHES SunOS )
|
||||
endif( "${CMAKE_SYSTEM_NAME}" MATCHES SunOS )
|
||||
|
||||
# Make sure we don't get -rdynamic in every binary. For those that need it,
|
||||
# use EXPORT_SYMBOLS argument.
|
||||
|
@ -69,14 +69,14 @@ endif()
|
||||
|
||||
# Do checks with _XOPEN_SOURCE and large-file API on AIX, because we will build
|
||||
# with those too.
|
||||
if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if (UNIX AND "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_XOPEN_SOURCE=700")
|
||||
list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_LARGE_FILE_API")
|
||||
endif()
|
||||
|
||||
# Do checks with _FILE_OFFSET_BITS=64 on Solaris, because we will build
|
||||
# with those too.
|
||||
if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||
if (UNIX AND "${CMAKE_SYSTEM_NAME}" MATCHES "SunOS")
|
||||
list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_FILE_OFFSET_BITS=64")
|
||||
endif()
|
||||
|
||||
@ -122,7 +122,7 @@ if(APPLE)
|
||||
HAVE_CRASHREPORTER_INFO)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
|
||||
check_include_file(linux/magic.h HAVE_LINUX_MAGIC_H)
|
||||
if(NOT HAVE_LINUX_MAGIC_H)
|
||||
# older kernels use split files
|
||||
@ -411,7 +411,7 @@ endif()
|
||||
|
||||
CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtimespec.tv_nsec
|
||||
"sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
|
||||
if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if (UNIX AND "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
# The st_mtim.tv_nsec member of a `stat` structure is not reliable on some AIX
|
||||
# environments.
|
||||
set(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 0)
|
||||
|
@ -99,7 +99,7 @@ function(llvm_update_compile_flags name)
|
||||
endfunction()
|
||||
|
||||
function(add_llvm_symbol_exports target_name export_file)
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
|
||||
set(native_export_file "${target_name}.exports")
|
||||
add_custom_command(OUTPUT ${native_export_file}
|
||||
COMMAND sed -e "s/^/_/" < ${export_file} > ${native_export_file}
|
||||
@ -108,7 +108,7 @@ function(add_llvm_symbol_exports target_name export_file)
|
||||
COMMENT "Creating export file for ${target_name}")
|
||||
set_property(TARGET ${target_name} APPEND_STRING PROPERTY
|
||||
LINK_FLAGS " -Wl,-exported_symbols_list,\"${CMAKE_CURRENT_BINARY_DIR}/${native_export_file}\"")
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
# FIXME: `-Wl,-bE:` bypasses whatever handling there is in the build
|
||||
# compiler driver to defer to the specified export list.
|
||||
set(native_export_file "${export_file}")
|
||||
@ -268,7 +268,7 @@ if (NOT DEFINED LLVM_LINKER_DETECTED AND NOT WIN32)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
|
||||
include(CheckLinkerFlag)
|
||||
# Linkers that support Darwin allow a setting to internalize all symbol exports,
|
||||
# aiding in reducing binary size and often is applicable for executables.
|
||||
@ -315,11 +315,11 @@ function(add_link_opts target_name)
|
||||
# linker in a context where the optimizations are not important.
|
||||
if (NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG")
|
||||
if(NOT LLVM_NO_DEAD_STRIP)
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
|
||||
# ld64's implementation of -dead_strip breaks tools that use plugins.
|
||||
set_property(TARGET ${target_name} APPEND_STRING PROPERTY
|
||||
LINK_FLAGS " -Wl,-dead_strip")
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "SunOS" AND LLVM_LINKER_IS_SOLARISLD)
|
||||
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS" AND LLVM_LINKER_IS_SOLARISLD)
|
||||
# Support for ld -z discard-unused=sections was only added in
|
||||
# Solaris 11.4. GNU ld ignores it, but warns every time.
|
||||
check_linker_flag(CXX "-Wl,-z,discard-unused=sections" LINKER_SUPPORTS_Z_DISCARD_UNUSED)
|
||||
@ -333,7 +333,7 @@ function(add_link_opts target_name)
|
||||
LINK_FLAGS " -Wl,--gc-sections")
|
||||
endif()
|
||||
else() #LLVM_NO_DEAD_STRIP
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
set_property(TARGET ${target_name} APPEND_STRING PROPERTY
|
||||
LINK_FLAGS " -Wl,-bnogc")
|
||||
endif()
|
||||
@ -345,7 +345,7 @@ function(add_link_opts target_name)
|
||||
LINK_FLAGS " -Wl,-no_warn_duplicate_libraries")
|
||||
endif()
|
||||
|
||||
if(ARG_SUPPORT_PLUGINS AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if(ARG_SUPPORT_PLUGINS AND "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
set_property(TARGET ${target_name} APPEND_STRING PROPERTY
|
||||
LINK_FLAGS " -Wl,-brtl")
|
||||
endif()
|
||||
@ -667,7 +667,7 @@ function(llvm_add_library name)
|
||||
# that are used across shared objects which we can't hide.
|
||||
if (LLVM_BUILD_LLVM_DYLIB_VIS AND NOT BUILD_SHARED_LIBS AND NOT APPLE AND
|
||||
(NOT (WIN32 OR CYGWIN) OR ((MINGW OR CYGWIN) AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")) AND
|
||||
NOT (${CMAKE_SYSTEM_NAME} MATCHES "AIX") AND
|
||||
NOT ("${CMAKE_SYSTEM_NAME}" MATCHES "AIX") AND
|
||||
NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET)
|
||||
|
||||
set_target_properties(${name} PROPERTIES
|
||||
@ -1094,7 +1094,7 @@ macro(add_llvm_executable name)
|
||||
llvm_update_compile_flags(${name})
|
||||
endif()
|
||||
|
||||
if (ARG_SUPPORT_PLUGINS AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if (ARG_SUPPORT_PLUGINS AND NOT "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
set(LLVM_NO_DEAD_STRIP On)
|
||||
endif()
|
||||
|
||||
@ -1417,7 +1417,7 @@ function(export_executable_symbols target)
|
||||
# CMake doesn't set CMAKE_EXE_EXPORTS_${lang}_FLAG on Solaris, so
|
||||
# ENABLE_EXPORTS has no effect. While Solaris ld defaults to -rdynamic
|
||||
# behaviour, GNU ld needs it.
|
||||
if (APPLE OR ${CMAKE_SYSTEM_NAME} STREQUAL "SunOS")
|
||||
if (APPLE OR "${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS")
|
||||
set_property(TARGET ${target} APPEND_STRING PROPERTY
|
||||
LINK_FLAGS " -rdynamic")
|
||||
endif()
|
||||
@ -2540,7 +2540,7 @@ function(llvm_setup_rpath name)
|
||||
if (APPLE)
|
||||
set(_install_name_dir INSTALL_NAME_DIR "@rpath")
|
||||
set(_install_rpath "@loader_path/../lib${LLVM_LIBDIR_SUFFIX}" ${extra_libdir})
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "AIX" AND BUILD_SHARED_LIBS)
|
||||
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "AIX" AND BUILD_SHARED_LIBS)
|
||||
# $ORIGIN is not interpreted at link time by aix ld.
|
||||
# Since BUILD_SHARED_LIBS is only recommended for use by developers,
|
||||
# hardcode the rpath to build/install lib dir first in this mode.
|
||||
@ -2549,7 +2549,7 @@ function(llvm_setup_rpath name)
|
||||
elseif(UNIX)
|
||||
set(_build_rpath "\$ORIGIN/../lib${LLVM_LIBDIR_SUFFIX}" ${extra_libdir})
|
||||
set(_install_rpath "\$ORIGIN/../lib${LLVM_LIBDIR_SUFFIX}")
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "(FreeBSD|DragonFly)")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "(FreeBSD|DragonFly)")
|
||||
set_property(TARGET ${name} APPEND_STRING PROPERTY
|
||||
LINK_FLAGS " -Wl,-z,origin ")
|
||||
endif()
|
||||
@ -2567,7 +2567,7 @@ function(llvm_setup_rpath name)
|
||||
# On AIX, the tool chain doesn't support modifying rpaths/libpaths for XCOFF
|
||||
# on install at the moment, so BUILD_WITH_INSTALL_RPATH is required.
|
||||
if("${CMAKE_BUILD_RPATH}" STREQUAL "")
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin|AIX")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin|AIX")
|
||||
set_property(TARGET ${name} PROPERTY BUILD_WITH_INSTALL_RPATH ON)
|
||||
else()
|
||||
set_property(TARGET ${name} APPEND PROPERTY BUILD_RPATH "${_build_rpath}")
|
||||
|
@ -228,7 +228,7 @@ if(WIN32 OR CYGWIN)
|
||||
elseif(FUCHSIA OR UNIX)
|
||||
set(LLVM_ON_WIN32 0)
|
||||
set(LLVM_ON_UNIX 1)
|
||||
if(APPLE OR ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if(APPLE OR "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
set(LLVM_HAVE_LINK_VERSION_SCRIPT 0)
|
||||
else()
|
||||
set(LLVM_HAVE_LINK_VERSION_SCRIPT 1)
|
||||
@ -249,7 +249,7 @@ set(EXEEXT ${CMAKE_EXECUTABLE_SUFFIX})
|
||||
set(LTDL_SHLIB_EXT ${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
|
||||
# We use *.dylib rather than *.so on darwin, but we stick with *.so on AIX.
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
set(LLVM_PLUGIN_EXT ${CMAKE_SHARED_MODULE_SUFFIX})
|
||||
else()
|
||||
set(LLVM_PLUGIN_EXT ${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
@ -260,7 +260,7 @@ if(APPLE)
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-flat_namespace -Wl,-undefined -Wl,dynamic_lookup")
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
|
||||
# RHEL7 has ar and ranlib being non-deterministic by default. The D flag forces determinism,
|
||||
# however only GNU version of ar and ranlib (2.27) have this option.
|
||||
# RHEL DTS7 is also affected by this, which uses GNU binutils 2.28
|
||||
@ -292,7 +292,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
# -fPIC does not enable the large code model for GCC on AIX but does for XL.
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
append("-mcmodel=large" CMAKE_CXX_FLAGS CMAKE_C_FLAGS)
|
||||
@ -328,7 +328,7 @@ endif()
|
||||
# by dlclose(). We need that since the CLI API relies on cross-references
|
||||
# between global objects which became horribly broken when one of the libraries
|
||||
# is unloaded.
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,nodelete")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-z,nodelete")
|
||||
endif()
|
||||
@ -454,13 +454,13 @@ if( LLVM_ENABLE_PIC )
|
||||
# to SEGV (GCC PR target/96607).
|
||||
# clang with -O3 -fPIC generates code that SEGVs.
|
||||
# Both can be worked around by compiling with -O instead.
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "SunOS" AND LLVM_NATIVE_ARCH STREQUAL "Sparc")
|
||||
if("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS" AND LLVM_NATIVE_ARCH STREQUAL "Sparc")
|
||||
llvm_replace_compiler_option(CMAKE_CXX_FLAGS_RELEASE "-O[23]" "-O")
|
||||
llvm_replace_compiler_option(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O[23]" "-O")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if((NOT (${CMAKE_SYSTEM_NAME} MATCHES "AIX")) AND
|
||||
if((NOT ("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")) AND
|
||||
(NOT (WIN32 OR CYGWIN) OR ((MINGW OR CYGWIN) AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")))
|
||||
# GCC for MinGW does nothing about -fvisibility-inlines-hidden, but warns
|
||||
# about use of the attributes. As long as we don't use the attributes (to
|
||||
@ -708,7 +708,7 @@ endif ()
|
||||
if ( LLVM_COMPILER_IS_GCC_COMPATIBLE AND LLVM_ENABLE_MODULES )
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
|
||||
set(module_flags "-fmodules -fmodules-cache-path=${PROJECT_BINARY_DIR}/module.cache")
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
|
||||
# On Darwin -fmodules does not imply -fcxx-modules.
|
||||
set(module_flags "${module_flags} -fcxx-modules")
|
||||
endif()
|
||||
@ -1123,7 +1123,7 @@ endif()
|
||||
# But MinSizeRel seems to add that automatically, so maybe disable these
|
||||
# flags instead if LLVM_NO_DEAD_STRIP is set.
|
||||
if(NOT CYGWIN AND NOT MSVC)
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND
|
||||
if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Darwin" AND
|
||||
NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG")
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "XL")
|
||||
append("-qfuncsect" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
@ -1315,9 +1315,14 @@ endif()
|
||||
# linking (due to incompatibility). With MSVC, note that the plugin has to
|
||||
# explicitly link against (exactly one) tool so we can't unilaterally turn on
|
||||
# LLVM_ENABLE_PLUGINS when it's enabled.
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES AIX)
|
||||
set(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_OPTION OFF)
|
||||
else()
|
||||
set(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_OPTION ON)
|
||||
endif()
|
||||
CMAKE_DEPENDENT_OPTION(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS
|
||||
"Export symbols from LLVM tools so that plugins can import them" OFF
|
||||
"NOT ${CMAKE_SYSTEM_NAME} MATCHES AIX" ${LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_AIX_default})
|
||||
"LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_OPTION" ${LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_AIX_default})
|
||||
if(BUILD_SHARED_LIBS AND LLVM_EXPORT_SYMBOLS_FOR_PLUGINS)
|
||||
message(FATAL_ERROR "BUILD_SHARED_LIBS not compatible with LLVM_EXPORT_SYMBOLS_FOR_PLUGINS")
|
||||
endif()
|
||||
|
@ -37,8 +37,6 @@ namespace llvm::cas {
|
||||
/// in the same process since file locks will misbehave. Clients should
|
||||
/// coordinate (somehow).
|
||||
///
|
||||
/// \note Currently we allocate the whole file without sparseness on Windows.
|
||||
///
|
||||
/// Provides 8-byte alignment for all allocations.
|
||||
class MappedFileRegionBumpPtr {
|
||||
public:
|
||||
@ -97,13 +95,6 @@ public:
|
||||
MappedFileRegionBumpPtr &operator=(const MappedFileRegionBumpPtr &) = delete;
|
||||
|
||||
private:
|
||||
// The file size increment to extend the storage size.
|
||||
// The minimum increment is a page, but allocate more to amortize the cost.
|
||||
static constexpr int64_t Increment = 4 * 1024 * 1024; // 4 MB
|
||||
|
||||
// Extend the AllocatedSize to be enough to hold NewEnd.
|
||||
Error extendSpaceImpl(int64_t NewEnd);
|
||||
|
||||
void destroyImpl();
|
||||
void moveImpl(MappedFileRegionBumpPtr &RHS) {
|
||||
std::swap(Region, RHS.Region);
|
||||
|
@ -1103,6 +1103,7 @@ def OMP_Target : Directive<[Spelling<"target">]> {
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_InReduction, 50>,
|
||||
@ -1115,7 +1116,6 @@ def OMP_Target : Directive<[Spelling<"target">]> {
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_If>,
|
||||
VersionedClause<OMPC_NoWait>,
|
||||
VersionedClause<OMPC_OMPX_Bare>,
|
||||
@ -1258,6 +1258,7 @@ def OMP_TaskYield : Directive<[Spelling<"taskyield">]> {
|
||||
def OMP_Teams : Directive<[Spelling<"teams">]> {
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_OMPX_Attribute>,
|
||||
VersionedClause<OMPC_Private>,
|
||||
@ -1266,7 +1267,6 @@ def OMP_Teams : Directive<[Spelling<"teams">]> {
|
||||
];
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_If, 52>,
|
||||
VersionedClause<OMPC_NumTeams>,
|
||||
VersionedClause<OMPC_ThreadLimit>,
|
||||
@ -1520,6 +1520,7 @@ def OMP_target_loop : Directive<[Spelling<"target loop">]> {
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_IsDevicePtr>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
@ -1535,7 +1536,6 @@ def OMP_target_loop : Directive<[Spelling<"target loop">]> {
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_Bind, 50>,
|
||||
VersionedClause<OMPC_Collapse>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_Order>,
|
||||
VersionedClause<OMPC_ThreadLimit>,
|
||||
VersionedClause<OMPC_OMPX_DynCGroupMem>,
|
||||
@ -1982,6 +1982,7 @@ def OMP_TargetParallel : Directive<[Spelling<"target parallel">]> {
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -1997,7 +1998,6 @@ def OMP_TargetParallel : Directive<[Spelling<"target parallel">]> {
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_NumThreads>,
|
||||
VersionedClause<OMPC_OMPX_DynCGroupMem>,
|
||||
VersionedClause<OMPC_ProcBind>,
|
||||
@ -2011,6 +2011,7 @@ def OMP_TargetParallelDo : Directive<[Spelling<"target parallel do">]> {
|
||||
VersionedClause<OMPC_Allocator>,
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -2027,7 +2028,6 @@ def OMP_TargetParallelDo : Directive<[Spelling<"target parallel do">]> {
|
||||
VersionedClause<OMPC_Collapse>,
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_NoWait>,
|
||||
VersionedClause<OMPC_NumThreads>,
|
||||
VersionedClause<OMPC_Order, 50>,
|
||||
@ -2049,6 +2049,7 @@ def OMP_TargetParallelDoSimd
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -2070,9 +2071,6 @@ def OMP_TargetParallelDoSimd
|
||||
VersionedClause<OMPC_SimdLen>,
|
||||
VersionedClause<OMPC_UsesAllocators>,
|
||||
];
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
];
|
||||
let leafConstructs = [OMP_Target, OMP_Parallel, OMP_Do, OMP_Simd];
|
||||
let category = CA_Executable;
|
||||
let languages = [L_Fortran];
|
||||
@ -2085,6 +2083,7 @@ def OMP_TargetParallelFor : Directive<[Spelling<"target parallel for">]> {
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -2105,7 +2104,6 @@ def OMP_TargetParallelFor : Directive<[Spelling<"target parallel for">]> {
|
||||
VersionedClause<OMPC_UsesAllocators, 50>,
|
||||
];
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_OMPX_DynCGroupMem>,
|
||||
VersionedClause<OMPC_ThreadLimit, 51>,
|
||||
];
|
||||
@ -2123,6 +2121,7 @@ def OMP_TargetParallelForSimd
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -2146,7 +2145,6 @@ def OMP_TargetParallelForSimd
|
||||
VersionedClause<OMPC_UsesAllocators, 50>,
|
||||
];
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_OMPX_DynCGroupMem>,
|
||||
VersionedClause<OMPC_ThreadLimit, 51>,
|
||||
];
|
||||
@ -2159,6 +2157,7 @@ def OMP_target_parallel_loop : Directive<[Spelling<"target parallel loop">]> {
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -2176,7 +2175,6 @@ def OMP_target_parallel_loop : Directive<[Spelling<"target parallel loop">]> {
|
||||
VersionedClause<OMPC_Collapse>,
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_NoWait>,
|
||||
VersionedClause<OMPC_NumThreads>,
|
||||
VersionedClause<OMPC_OMPX_DynCGroupMem>,
|
||||
@ -2192,6 +2190,7 @@ def OMP_TargetSimd : Directive<[Spelling<"target simd">]> {
|
||||
VersionedClause<OMPC_Aligned>,
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -2211,7 +2210,6 @@ def OMP_TargetSimd : Directive<[Spelling<"target simd">]> {
|
||||
VersionedClause<OMPC_Collapse>,
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_NumThreads>,
|
||||
VersionedClause<OMPC_OMPX_DynCGroupMem>,
|
||||
VersionedClause<OMPC_Order, 50>,
|
||||
@ -2228,6 +2226,7 @@ def OMP_TargetTeams : Directive<[Spelling<"target teams">]> {
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -2243,7 +2242,6 @@ def OMP_TargetTeams : Directive<[Spelling<"target teams">]> {
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_NoWait>,
|
||||
VersionedClause<OMPC_NumTeams>,
|
||||
VersionedClause<OMPC_OMPX_DynCGroupMem>,
|
||||
@ -2258,6 +2256,7 @@ def OMP_TargetTeamsDistribute
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -2276,7 +2275,6 @@ def OMP_TargetTeamsDistribute
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DistSchedule>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_NoWait>,
|
||||
VersionedClause<OMPC_NumTeams>,
|
||||
VersionedClause<OMPC_OMPX_DynCGroupMem>,
|
||||
@ -2291,6 +2289,7 @@ def OMP_TargetTeamsDistributeParallelDo
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -2309,7 +2308,6 @@ def OMP_TargetTeamsDistributeParallelDo
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DistSchedule>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_NoWait>,
|
||||
VersionedClause<OMPC_NumTeams>,
|
||||
VersionedClause<OMPC_NumThreads>,
|
||||
@ -2329,6 +2327,7 @@ def OMP_TargetTeamsDistributeParallelDoSimd
|
||||
VersionedClause<OMPC_Aligned>,
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -2348,7 +2347,6 @@ def OMP_TargetTeamsDistributeParallelDoSimd
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DistSchedule>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_NoWait>,
|
||||
VersionedClause<OMPC_NumTeams>,
|
||||
VersionedClause<OMPC_NumThreads>,
|
||||
@ -2374,6 +2372,7 @@ def OMP_TargetTeamsDistributeParallelFor
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DistSchedule>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -2394,7 +2393,6 @@ def OMP_TargetTeamsDistributeParallelFor
|
||||
VersionedClause<OMPC_UsesAllocators, 50>,
|
||||
];
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_OMPX_DynCGroupMem>,
|
||||
];
|
||||
let leafConstructs =
|
||||
@ -2413,6 +2411,7 @@ def OMP_TargetTeamsDistributeParallelForSimd
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DistSchedule>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -2437,7 +2436,6 @@ def OMP_TargetTeamsDistributeParallelForSimd
|
||||
VersionedClause<OMPC_UsesAllocators, 50>,
|
||||
];
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_OMPX_DynCGroupMem>,
|
||||
];
|
||||
let leafConstructs =
|
||||
@ -2451,6 +2449,7 @@ def OMP_TargetTeamsDistributeSimd
|
||||
VersionedClause<OMPC_Aligned>,
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -2470,7 +2469,6 @@ def OMP_TargetTeamsDistributeSimd
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DistSchedule>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_NoWait>,
|
||||
VersionedClause<OMPC_NumTeams>,
|
||||
VersionedClause<OMPC_OMPX_DynCGroupMem>,
|
||||
@ -2488,6 +2486,7 @@ def OMP_target_teams_loop : Directive<[Spelling<"target teams loop">]> {
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
@ -2504,7 +2503,6 @@ def OMP_target_teams_loop : Directive<[Spelling<"target teams loop">]> {
|
||||
VersionedClause<OMPC_Bind, 50>,
|
||||
VersionedClause<OMPC_Collapse>,
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_NoWait>,
|
||||
VersionedClause<OMPC_NumTeams>,
|
||||
VersionedClause<OMPC_OMPX_DynCGroupMem>,
|
||||
@ -2553,6 +2551,7 @@ def OMP_TeamsDistribute : Directive<[Spelling<"teams distribute">]> {
|
||||
VersionedClause<OMPC_Collapse>,
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_DistSchedule>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_LastPrivate>,
|
||||
VersionedClause<OMPC_NumTeams>,
|
||||
@ -2563,7 +2562,6 @@ def OMP_TeamsDistribute : Directive<[Spelling<"teams distribute">]> {
|
||||
VersionedClause<OMPC_ThreadLimit>,
|
||||
];
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_If>,
|
||||
VersionedClause<OMPC_Order, 50>,
|
||||
];
|
||||
@ -2575,6 +2573,7 @@ def OMP_TeamsDistributeParallelDo
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_Copyin>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_If>,
|
||||
VersionedClause<OMPC_LastPrivate>,
|
||||
@ -2587,7 +2586,6 @@ def OMP_TeamsDistributeParallelDo
|
||||
VersionedClause<OMPC_Collapse>,
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_DistSchedule>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_NumTeams>,
|
||||
VersionedClause<OMPC_NumThreads>,
|
||||
VersionedClause<OMPC_Order, 50>,
|
||||
@ -2604,6 +2602,7 @@ def OMP_TeamsDistributeParallelDoSimd
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Aligned>,
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_If>,
|
||||
VersionedClause<OMPC_LastPrivate>,
|
||||
@ -2617,7 +2616,6 @@ def OMP_TeamsDistributeParallelDoSimd
|
||||
VersionedClause<OMPC_Collapse>,
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_DistSchedule>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_NumTeams>,
|
||||
VersionedClause<OMPC_NumThreads>,
|
||||
VersionedClause<OMPC_Order, 50>,
|
||||
@ -2640,6 +2638,7 @@ def OMP_TeamsDistributeParallelFor
|
||||
VersionedClause<OMPC_Copyin>,
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_DistSchedule>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_If>,
|
||||
VersionedClause<OMPC_LastPrivate>,
|
||||
@ -2654,9 +2653,6 @@ def OMP_TeamsDistributeParallelFor
|
||||
VersionedClause<OMPC_Shared>,
|
||||
VersionedClause<OMPC_ThreadLimit>,
|
||||
];
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
];
|
||||
let leafConstructs = [OMP_Teams, OMP_Distribute, OMP_Parallel, OMP_For];
|
||||
let category = CA_Executable;
|
||||
let languages = [L_C];
|
||||
@ -2669,6 +2665,7 @@ def OMP_TeamsDistributeParallelForSimd
|
||||
VersionedClause<OMPC_Collapse>,
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_DistSchedule>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_If>,
|
||||
VersionedClause<OMPC_LastPrivate>,
|
||||
@ -2687,9 +2684,6 @@ def OMP_TeamsDistributeParallelForSimd
|
||||
VersionedClause<OMPC_SimdLen>,
|
||||
VersionedClause<OMPC_ThreadLimit>,
|
||||
];
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
];
|
||||
let leafConstructs =
|
||||
[OMP_Teams, OMP_Distribute, OMP_Parallel, OMP_For, OMP_Simd];
|
||||
let category = CA_Executable;
|
||||
@ -2699,6 +2693,7 @@ def OMP_TeamsDistributeSimd : Directive<[Spelling<"teams distribute simd">]> {
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Aligned>,
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_If, 50>,
|
||||
VersionedClause<OMPC_LastPrivate>,
|
||||
@ -2713,7 +2708,6 @@ def OMP_TeamsDistributeSimd : Directive<[Spelling<"teams distribute simd">]> {
|
||||
VersionedClause<OMPC_Collapse>,
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_DistSchedule>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_NumTeams>,
|
||||
VersionedClause<OMPC_Order, 50>,
|
||||
VersionedClause<OMPC_SafeLen>,
|
||||
@ -2726,6 +2720,7 @@ def OMP_TeamsDistributeSimd : Directive<[Spelling<"teams distribute simd">]> {
|
||||
def OMP_teams_loop : Directive<[Spelling<"teams loop">]> {
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_LastPrivate>,
|
||||
VersionedClause<OMPC_OMPX_Attribute>,
|
||||
@ -2737,7 +2732,6 @@ def OMP_teams_loop : Directive<[Spelling<"teams loop">]> {
|
||||
VersionedClause<OMPC_Bind, 50>,
|
||||
VersionedClause<OMPC_Collapse>,
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_DynGroupprivate, 61>,
|
||||
VersionedClause<OMPC_NumTeams>,
|
||||
VersionedClause<OMPC_Order>,
|
||||
VersionedClause<OMPC_ThreadLimit>,
|
||||
|
@ -20,12 +20,14 @@
|
||||
/// and across multiple processes without locking for every read. Our current
|
||||
/// implementation strategy is:
|
||||
///
|
||||
/// 1. Use \c ftruncate (\c sys::fs::resize_file) to grow the file to its max
|
||||
/// size (typically several GB). Many modern filesystems will create a sparse
|
||||
/// file, so that the trailing unused pages do not take space on disk.
|
||||
/// 2. Call \c mmap (\c sys::fs::mapped_file_region)
|
||||
/// 1. Use \c sys::fs::resize_file_sparse to grow the file to its max size
|
||||
/// (typically several GB). If the file system doesn't support sparse file,
|
||||
/// this may return a fully allocated file.
|
||||
/// 2. Call \c sys::fs::mapped_file_region to map the entire file.
|
||||
/// 3. [Automatic as part of 2.]
|
||||
/// 4. [Automatic as part of 2.]
|
||||
/// 4. If supported, use \c fallocate or similiar APIs to ensure the file system
|
||||
/// storage for the sparse file so we won't end up with partial file if the
|
||||
/// disk is out of space.
|
||||
///
|
||||
/// Additionally, we attempt to resize the file to its actual data size when
|
||||
/// closing the mapping, if this is the only concurrent instance. This is done
|
||||
@ -160,9 +162,7 @@ Expected<MappedFileRegionBumpPtr> MappedFileRegionBumpPtr::create(
|
||||
if (FileSize->Size < Capacity) {
|
||||
// We are initializing the file; it may be empty, or may have been shrunk
|
||||
// during a previous close.
|
||||
// FIXME: Detect a case where someone opened it with a smaller capacity.
|
||||
// FIXME: On Windows we should use FSCTL_SET_SPARSE and FSCTL_SET_ZERO_DATA
|
||||
// to make this a sparse region, if supported.
|
||||
// TODO: Detect a case where someone opened it with a smaller capacity.
|
||||
assert(InitLock.Locked == sys::fs::LockKind::Exclusive);
|
||||
if (std::error_code EC = sys::fs::resize_file_sparse(FD, Capacity))
|
||||
return createFileError(Result.Path, EC);
|
||||
|
@ -62,7 +62,7 @@ elseif( CMAKE_HOST_UNIX )
|
||||
if( UNIX AND NOT (BEOS OR HAIKU) )
|
||||
set(system_libs ${system_libs} m)
|
||||
endif()
|
||||
if( UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "SunOS" )
|
||||
if( UNIX AND "${CMAKE_SYSTEM_NAME}" MATCHES "SunOS" )
|
||||
set(system_libs ${system_libs} kstat socket)
|
||||
endif()
|
||||
if( FUCHSIA )
|
||||
@ -130,7 +130,7 @@ endif()
|
||||
# unistd.h and it is guarded by _ALL_SOURCE, so we remove the _XOPEN_SOURCE
|
||||
# guard here. We should remove the guards all together once AIX cleans up
|
||||
# the system headers.
|
||||
if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
if (UNIX AND "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
remove_definitions("-D_XOPEN_SOURCE=700")
|
||||
endif()
|
||||
|
||||
|
@ -24,7 +24,7 @@ add_llvm_component_library(LLVMTarget
|
||||
# that are used across shared objects which we can't hide.
|
||||
if (NOT BUILD_SHARED_LIBS AND NOT APPLE AND
|
||||
(NOT (WIN32 OR CYGWIN) OR ((MINGW OR CYGWIN) AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")) AND
|
||||
NOT (${CMAKE_SYSTEM_NAME} MATCHES "AIX") AND
|
||||
NOT ("${CMAKE_SYSTEM_NAME}" MATCHES "AIX") AND
|
||||
NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET)
|
||||
# Set default visibility to hidden, so we don't export all the Target classes
|
||||
# in libLLVM.so.
|
||||
|
@ -110,8 +110,6 @@ RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
|
||||
MachineBasicBlock::iterator NextI = next_nodbg(I, E);
|
||||
DestSourcePair FirstPair = TII->isCopyInstrImpl(*I).value();
|
||||
DestSourcePair PairedRegs = TII->isCopyInstrImpl(*Paired).value();
|
||||
Register ARegInFirstPair = MoveFromSToA ? FirstPair.Destination->getReg()
|
||||
: FirstPair.Source->getReg();
|
||||
|
||||
if (NextI == Paired)
|
||||
NextI = next_nodbg(NextI, E);
|
||||
@ -130,7 +128,6 @@ RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
|
||||
//
|
||||
// mv a0, s2
|
||||
// mv a1, s1 => cm.mva01s s2,s1
|
||||
bool StartWithX10 = ARegInFirstPair == RISCV::X10;
|
||||
unsigned Opcode;
|
||||
if (MoveFromSToA) {
|
||||
// We are moving one of the copies earlier so its kill flag may become
|
||||
@ -141,12 +138,16 @@ RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
|
||||
PairedSource.setIsKill(false);
|
||||
|
||||
Opcode = getMoveFromSToAOpcode(*ST);
|
||||
Sreg1 = StartWithX10 ? FirstPair.Source : &PairedSource;
|
||||
Sreg2 = StartWithX10 ? &PairedSource : FirstPair.Source;
|
||||
Sreg1 = FirstPair.Source;
|
||||
Sreg2 = &PairedSource;
|
||||
if (FirstPair.Destination->getReg() != RISCV::X10)
|
||||
std::swap(Sreg1, Sreg2);
|
||||
} else {
|
||||
Opcode = getMoveFromAToSOpcode(*ST);
|
||||
Sreg1 = StartWithX10 ? FirstPair.Destination : PairedRegs.Destination;
|
||||
Sreg2 = StartWithX10 ? PairedRegs.Destination : FirstPair.Destination;
|
||||
Sreg1 = FirstPair.Destination;
|
||||
Sreg2 = PairedRegs.Destination;
|
||||
if (FirstPair.Source->getReg() != RISCV::X10)
|
||||
std::swap(Sreg1, Sreg2);
|
||||
}
|
||||
|
||||
BuildMI(*I->getParent(), I, DL, TII->get(Opcode)).add(*Sreg1).add(*Sreg2);
|
||||
|
@ -23185,43 +23185,51 @@ static SDValue LowerVectorAllEqual(const SDLoc &DL, SDValue LHS, SDValue RHS,
|
||||
|
||||
// Check whether an AND/OR'd reduction tree is PTEST-able, or if we can fallback
|
||||
// to CMP(MOVMSK(PCMPEQB(X,Y))).
|
||||
static SDValue MatchVectorAllEqualTest(SDValue LHS, SDValue RHS,
|
||||
static SDValue MatchVectorAllEqualTest(SDValue OrigLHS, SDValue OrigRHS,
|
||||
ISD::CondCode CC, const SDLoc &DL,
|
||||
const X86Subtarget &Subtarget,
|
||||
SelectionDAG &DAG,
|
||||
X86::CondCode &X86CC) {
|
||||
assert((CC == ISD::SETEQ || CC == ISD::SETNE) && "Unsupported ISD::CondCode");
|
||||
SDValue Op = OrigLHS;
|
||||
|
||||
bool CmpNull = isNullConstant(RHS);
|
||||
bool CmpAllOnes = isAllOnesConstant(RHS);
|
||||
if (!CmpNull && !CmpAllOnes)
|
||||
return SDValue();
|
||||
bool CmpNull;
|
||||
APInt Mask;
|
||||
if (CC == ISD::SETEQ || CC == ISD::SETNE) {
|
||||
CmpNull = isNullConstant(OrigRHS);
|
||||
if (!CmpNull && !isAllOnesConstant(OrigRHS))
|
||||
return SDValue();
|
||||
|
||||
SDValue Op = LHS;
|
||||
if (!Subtarget.hasSSE2() || !Op->hasOneUse())
|
||||
return SDValue();
|
||||
if (!Subtarget.hasSSE2() || !Op->hasOneUse())
|
||||
return SDValue();
|
||||
|
||||
// Check whether we're masking/truncating an OR-reduction result, in which
|
||||
// case track the masked bits.
|
||||
// TODO: Add CmpAllOnes support.
|
||||
APInt Mask = APInt::getAllOnes(Op.getScalarValueSizeInBits());
|
||||
if (CmpNull) {
|
||||
switch (Op.getOpcode()) {
|
||||
case ISD::TRUNCATE: {
|
||||
SDValue Src = Op.getOperand(0);
|
||||
Mask = APInt::getLowBitsSet(Src.getScalarValueSizeInBits(),
|
||||
Op.getScalarValueSizeInBits());
|
||||
Op = Src;
|
||||
break;
|
||||
}
|
||||
case ISD::AND: {
|
||||
if (auto *Cst = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {
|
||||
Mask = Cst->getAPIntValue();
|
||||
Op = Op.getOperand(0);
|
||||
// Check whether we're masking/truncating an OR-reduction result, in which
|
||||
// case track the masked bits.
|
||||
// TODO: Add CmpAllOnes support.
|
||||
Mask = APInt::getAllOnes(Op.getScalarValueSizeInBits());
|
||||
if (CmpNull) {
|
||||
switch (Op.getOpcode()) {
|
||||
case ISD::TRUNCATE: {
|
||||
SDValue Src = Op.getOperand(0);
|
||||
Mask = APInt::getLowBitsSet(Src.getScalarValueSizeInBits(),
|
||||
Op.getScalarValueSizeInBits());
|
||||
Op = Src;
|
||||
break;
|
||||
}
|
||||
case ISD::AND: {
|
||||
if (auto *Cst = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {
|
||||
Mask = Cst->getAPIntValue();
|
||||
Op = Op.getOperand(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (CC == ISD::SETGT && isAllOnesConstant(OrigRHS)) {
|
||||
CC = ISD::SETEQ;
|
||||
CmpNull = true;
|
||||
Mask = APInt::getSignMask(Op.getScalarValueSizeInBits());
|
||||
} else {
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
ISD::NodeType LogicOp = CmpNull ? ISD::OR : ISD::AND;
|
||||
@ -56274,14 +56282,16 @@ static SDValue combineSetCC(SDNode *N, SelectionDAG &DAG,
|
||||
if (SDValue V = combineVectorSizedSetCCEquality(VT, LHS, RHS, CC, DL, DAG,
|
||||
Subtarget))
|
||||
return V;
|
||||
}
|
||||
|
||||
if (VT == MVT::i1) {
|
||||
X86::CondCode X86CC;
|
||||
if (SDValue V =
|
||||
MatchVectorAllEqualTest(LHS, RHS, CC, DL, Subtarget, DAG, X86CC))
|
||||
return DAG.getNode(ISD::TRUNCATE, DL, VT, getSETCC(X86CC, V, DL, DAG));
|
||||
}
|
||||
if (VT == MVT::i1) {
|
||||
X86::CondCode X86CC;
|
||||
if (SDValue V =
|
||||
MatchVectorAllEqualTest(LHS, RHS, CC, DL, Subtarget, DAG, X86CC))
|
||||
return DAG.getNode(ISD::TRUNCATE, DL, VT, getSETCC(X86CC, V, DL, DAG));
|
||||
}
|
||||
|
||||
if (CC == ISD::SETNE || CC == ISD::SETEQ) {
|
||||
if (OpVT.isScalarInteger()) {
|
||||
// cmpeq(or(X,Y),X) --> cmpeq(and(~X,Y),0)
|
||||
// cmpne(or(X,Y),X) --> cmpne(and(~X,Y),0)
|
||||
|
@ -9,7 +9,7 @@ if (HAS_WERROR_GLOBAL_CTORS AND NOT LLVM_HAS_NOGLOBAL_CTOR_MUTEX)
|
||||
endif()
|
||||
|
||||
# Solaris code uses kstat, so specify dependency explicitly for shared builds.
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS")
|
||||
set(system_libs kstat)
|
||||
endif()
|
||||
|
||||
|
@ -903,6 +903,95 @@ define i1 @mask_v8i32(<8 x i32> %a0) {
|
||||
ret i1 %3
|
||||
}
|
||||
|
||||
define i1 @mask_v8i32_2(<8 x i32> %a0) {
|
||||
; SSE2-LABEL: mask_v8i32_2:
|
||||
; SSE2: # %bb.0:
|
||||
; SSE2-NEXT: por %xmm1, %xmm0
|
||||
; SSE2-NEXT: pslld $1, %xmm0
|
||||
; SSE2-NEXT: movmskps %xmm0, %eax
|
||||
; SSE2-NEXT: testl %eax, %eax
|
||||
; SSE2-NEXT: sete %al
|
||||
; SSE2-NEXT: retq
|
||||
;
|
||||
; SSE41-LABEL: mask_v8i32_2:
|
||||
; SSE41: # %bb.0:
|
||||
; SSE41-NEXT: por %xmm1, %xmm0
|
||||
; SSE41-NEXT: ptest {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
|
||||
; SSE41-NEXT: sete %al
|
||||
; SSE41-NEXT: retq
|
||||
;
|
||||
; AVX1-LABEL: mask_v8i32_2:
|
||||
; AVX1: # %bb.0:
|
||||
; AVX1-NEXT: vptest {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm0
|
||||
; AVX1-NEXT: sete %al
|
||||
; AVX1-NEXT: vzeroupper
|
||||
; AVX1-NEXT: retq
|
||||
;
|
||||
; AVX2-LABEL: mask_v8i32_2:
|
||||
; AVX2: # %bb.0:
|
||||
; AVX2-NEXT: vpbroadcastq {{.*#+}} ymm1 = [4611686019501129728,4611686019501129728,4611686019501129728,4611686019501129728]
|
||||
; AVX2-NEXT: vptest %ymm1, %ymm0
|
||||
; AVX2-NEXT: sete %al
|
||||
; AVX2-NEXT: vzeroupper
|
||||
; AVX2-NEXT: retq
|
||||
;
|
||||
; AVX512-LABEL: mask_v8i32_2:
|
||||
; AVX512: # %bb.0:
|
||||
; AVX512-NEXT: vpbroadcastq {{.*#+}} ymm1 = [4611686019501129728,4611686019501129728,4611686019501129728,4611686019501129728]
|
||||
; AVX512-NEXT: vptest %ymm1, %ymm0
|
||||
; AVX512-NEXT: sete %al
|
||||
; AVX512-NEXT: vzeroupper
|
||||
; AVX512-NEXT: retq
|
||||
%1 = call i32 @llvm.vector.reduce.or.v8i32(<8 x i32> %a0)
|
||||
%2 = and i32 %1, 1073741824
|
||||
%3 = icmp eq i32 %2, 0
|
||||
ret i1 %3
|
||||
}
|
||||
|
||||
|
||||
define i1 @signtest_v8i32(<8 x i32> %a0) {
|
||||
; SSE2-LABEL: signtest_v8i32:
|
||||
; SSE2: # %bb.0:
|
||||
; SSE2-NEXT: orps %xmm1, %xmm0
|
||||
; SSE2-NEXT: movmskps %xmm0, %eax
|
||||
; SSE2-NEXT: testl %eax, %eax
|
||||
; SSE2-NEXT: sete %al
|
||||
; SSE2-NEXT: retq
|
||||
;
|
||||
; SSE41-LABEL: signtest_v8i32:
|
||||
; SSE41: # %bb.0:
|
||||
; SSE41-NEXT: por %xmm1, %xmm0
|
||||
; SSE41-NEXT: ptest {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
|
||||
; SSE41-NEXT: sete %al
|
||||
; SSE41-NEXT: retq
|
||||
;
|
||||
; AVX1-LABEL: signtest_v8i32:
|
||||
; AVX1: # %bb.0:
|
||||
; AVX1-NEXT: vptest {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm0
|
||||
; AVX1-NEXT: sete %al
|
||||
; AVX1-NEXT: vzeroupper
|
||||
; AVX1-NEXT: retq
|
||||
;
|
||||
; AVX2-LABEL: signtest_v8i32:
|
||||
; AVX2: # %bb.0:
|
||||
; AVX2-NEXT: vpbroadcastq {{.*#+}} ymm1 = [9223372039002259456,9223372039002259456,9223372039002259456,9223372039002259456]
|
||||
; AVX2-NEXT: vptest %ymm1, %ymm0
|
||||
; AVX2-NEXT: sete %al
|
||||
; AVX2-NEXT: vzeroupper
|
||||
; AVX2-NEXT: retq
|
||||
;
|
||||
; AVX512-LABEL: signtest_v8i32:
|
||||
; AVX512: # %bb.0:
|
||||
; AVX512-NEXT: vpbroadcastq {{.*#+}} ymm1 = [9223372039002259456,9223372039002259456,9223372039002259456,9223372039002259456]
|
||||
; AVX512-NEXT: vptest %ymm1, %ymm0
|
||||
; AVX512-NEXT: sete %al
|
||||
; AVX512-NEXT: vzeroupper
|
||||
; AVX512-NEXT: retq
|
||||
%1 = call i32 @llvm.vector.reduce.or.v8i32(<8 x i32> %a0)
|
||||
%2 = icmp sgt i32 %1, -1
|
||||
ret i1 %2
|
||||
}
|
||||
|
||||
define i1 @trunc_v16i16(<16 x i16> %a0) {
|
||||
; SSE2-LABEL: trunc_v16i16:
|
||||
; SSE2: # %bb.0:
|
||||
@ -1073,11 +1162,11 @@ define i32 @mask_v3i1(<3 x i32> %a, <3 x i32> %b) {
|
||||
; SSE2-NEXT: movd %xmm0, %eax
|
||||
; SSE2-NEXT: orl %ecx, %eax
|
||||
; SSE2-NEXT: testb $1, %al
|
||||
; SSE2-NEXT: je .LBB27_2
|
||||
; SSE2-NEXT: je .LBB29_2
|
||||
; SSE2-NEXT: # %bb.1:
|
||||
; SSE2-NEXT: xorl %eax, %eax
|
||||
; SSE2-NEXT: retq
|
||||
; SSE2-NEXT: .LBB27_2:
|
||||
; SSE2-NEXT: .LBB29_2:
|
||||
; SSE2-NEXT: movl $1, %eax
|
||||
; SSE2-NEXT: retq
|
||||
;
|
||||
@ -1092,11 +1181,11 @@ define i32 @mask_v3i1(<3 x i32> %a, <3 x i32> %b) {
|
||||
; SSE41-NEXT: pextrd $2, %xmm1, %eax
|
||||
; SSE41-NEXT: orl %ecx, %eax
|
||||
; SSE41-NEXT: testb $1, %al
|
||||
; SSE41-NEXT: je .LBB27_2
|
||||
; SSE41-NEXT: je .LBB29_2
|
||||
; SSE41-NEXT: # %bb.1:
|
||||
; SSE41-NEXT: xorl %eax, %eax
|
||||
; SSE41-NEXT: retq
|
||||
; SSE41-NEXT: .LBB27_2:
|
||||
; SSE41-NEXT: .LBB29_2:
|
||||
; SSE41-NEXT: movl $1, %eax
|
||||
; SSE41-NEXT: retq
|
||||
;
|
||||
@ -1111,11 +1200,11 @@ define i32 @mask_v3i1(<3 x i32> %a, <3 x i32> %b) {
|
||||
; AVX1OR2-NEXT: vpextrd $2, %xmm0, %eax
|
||||
; AVX1OR2-NEXT: orl %ecx, %eax
|
||||
; AVX1OR2-NEXT: testb $1, %al
|
||||
; AVX1OR2-NEXT: je .LBB27_2
|
||||
; AVX1OR2-NEXT: je .LBB29_2
|
||||
; AVX1OR2-NEXT: # %bb.1:
|
||||
; AVX1OR2-NEXT: xorl %eax, %eax
|
||||
; AVX1OR2-NEXT: retq
|
||||
; AVX1OR2-NEXT: .LBB27_2:
|
||||
; AVX1OR2-NEXT: .LBB29_2:
|
||||
; AVX1OR2-NEXT: movl $1, %eax
|
||||
; AVX1OR2-NEXT: retq
|
||||
;
|
||||
@ -1130,12 +1219,12 @@ define i32 @mask_v3i1(<3 x i32> %a, <3 x i32> %b) {
|
||||
; AVX512F-NEXT: korw %k0, %k1, %k0
|
||||
; AVX512F-NEXT: kmovw %k0, %eax
|
||||
; AVX512F-NEXT: testb $1, %al
|
||||
; AVX512F-NEXT: je .LBB27_2
|
||||
; AVX512F-NEXT: je .LBB29_2
|
||||
; AVX512F-NEXT: # %bb.1:
|
||||
; AVX512F-NEXT: xorl %eax, %eax
|
||||
; AVX512F-NEXT: vzeroupper
|
||||
; AVX512F-NEXT: retq
|
||||
; AVX512F-NEXT: .LBB27_2:
|
||||
; AVX512F-NEXT: .LBB29_2:
|
||||
; AVX512F-NEXT: movl $1, %eax
|
||||
; AVX512F-NEXT: vzeroupper
|
||||
; AVX512F-NEXT: retq
|
||||
@ -1151,12 +1240,12 @@ define i32 @mask_v3i1(<3 x i32> %a, <3 x i32> %b) {
|
||||
; AVX512BW-NEXT: korw %k0, %k1, %k0
|
||||
; AVX512BW-NEXT: kmovd %k0, %eax
|
||||
; AVX512BW-NEXT: testb $1, %al
|
||||
; AVX512BW-NEXT: je .LBB27_2
|
||||
; AVX512BW-NEXT: je .LBB29_2
|
||||
; AVX512BW-NEXT: # %bb.1:
|
||||
; AVX512BW-NEXT: xorl %eax, %eax
|
||||
; AVX512BW-NEXT: vzeroupper
|
||||
; AVX512BW-NEXT: retq
|
||||
; AVX512BW-NEXT: .LBB27_2:
|
||||
; AVX512BW-NEXT: .LBB29_2:
|
||||
; AVX512BW-NEXT: movl $1, %eax
|
||||
; AVX512BW-NEXT: vzeroupper
|
||||
; AVX512BW-NEXT: retq
|
||||
@ -1170,11 +1259,11 @@ define i32 @mask_v3i1(<3 x i32> %a, <3 x i32> %b) {
|
||||
; AVX512BWVL-NEXT: korw %k0, %k1, %k0
|
||||
; AVX512BWVL-NEXT: kmovd %k0, %eax
|
||||
; AVX512BWVL-NEXT: testb $1, %al
|
||||
; AVX512BWVL-NEXT: je .LBB27_2
|
||||
; AVX512BWVL-NEXT: je .LBB29_2
|
||||
; AVX512BWVL-NEXT: # %bb.1:
|
||||
; AVX512BWVL-NEXT: xorl %eax, %eax
|
||||
; AVX512BWVL-NEXT: retq
|
||||
; AVX512BWVL-NEXT: .LBB27_2:
|
||||
; AVX512BWVL-NEXT: .LBB29_2:
|
||||
; AVX512BWVL-NEXT: movl $1, %eax
|
||||
; AVX512BWVL-NEXT: retq
|
||||
%1 = icmp ne <3 x i32> %a, %b
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user