update comments

Created using spr 1.3.6
This commit is contained in:
Steven Wu 2025-08-20 10:42:15 -07:00
commit fd9ca0bab8
115 changed files with 2717 additions and 830 deletions

View File

@ -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()

View File

@ -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) {

View File

@ -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()

View File

@ -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
=====================

View File

@ -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.

View File

@ -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,

View File

@ -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.

View File

@ -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())); })

View File

@ -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();

View File

@ -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;

View File

@ -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() }];

View File

@ -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 &&

View File

@ -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()};
}

View File

@ -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 = [

View File

@ -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 = [{

View File

@ -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>]>;

View File

@ -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

View File

@ -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<

View File

@ -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>;

View File

@ -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

View File

@ -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 {

View File

@ -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);
};

View File

@ -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

View File

@ -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)

View File

@ -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());

View File

@ -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);

View File

@ -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>();

View File

@ -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) {

View File

@ -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';

View File

@ -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

View File

@ -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:

View File

@ -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) {

View File

@ -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());

View File

@ -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);

View File

@ -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;

View File

@ -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().

View File

@ -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;

View File

@ -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();

View File

@ -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.

View File

@ -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;

View File

@ -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;
}

View File

@ -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,

View File

@ -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;

View File

@ -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)) {

View File

@ -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) {

View File

@ -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();

View File

@ -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);

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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 %

View File

@ -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;

View File

@ -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;

View File

@ -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 %

View File

@ -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

View File

@ -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;
}

View File

@ -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]]

View File

@ -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}
//.

View File

@ -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; }

View File

@ -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

View 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;
}

View File

@ -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]])

View File

@ -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);

View File

@ -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);

View File

@ -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 {};

View File

@ -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
}

View File

@ -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)

View 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>>{};
}

View File

@ -1,5 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s
// XFAIL: asserts
template <class> struct Pair;
template <class...> struct Tuple {

View 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

View 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();

View 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);

View 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

View 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}}

View File

@ -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)

View File

@ -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.

View File

@ -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++.

View File

@ -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"))),

View File

@ -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) {

View File

@ -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()

View File

@ -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})

View File

@ -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()

View File

@ -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()

View File

@ -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
)

View File

@ -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
)

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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.

View File

@ -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)

View File

@ -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}")

View File

@ -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()

View File

@ -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);

View File

@ -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>,

View File

@ -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);

View File

@ -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()

View File

@ -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.

View File

@ -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);

View File

@ -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)

View File

@ -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()

View File

@ -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