ptr32_uptr,
ptr64,
+ // HLSL specific address spaces.
+ hlsl_groupshared,
+
// This denotes the count of language-specific address spaces and also
// the offset added to the target-specific address spaces, which are usually
// specified by address space attributes __attribute__(address_space(n))).
let Documentation = [InternalOnly];
}
+def HLSLGroupSharedAddressSpace : TypeAttr {
+ let Spellings = [Keyword<"groupshared">];
+ let Subjects = SubjectList<[Var]>;
+ let Documentation = [HLSLGroupSharedAddressSpaceDocs];
+}
+
def RandomizeLayout : InheritableAttr {
let Spellings = [GCC<"randomize_layout">];
let Subjects = SubjectList<[Record]>;
}];
}
+def HLSLGroupSharedAddressSpaceDocs : Documentation {
+ let Category = DocCatVariable;
+ let Content = [{
+HLSL enables threads of a compute shader to exchange values via shared memory.
+HLSL provides barrier primitives such as GroupMemoryBarrierWithGroupSync,
+and so on to ensure the correct ordering of reads and writes to shared memory
+in the shader and to avoid data races.
+Here's an example to declare a groupshared variable.
+.. code-block:: c++
+
+ groupshared GSData data[5*5*1];
+
+The full documentation is available here: https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-variable-syntax#group-shared
+ }];
+}
+
def AnnotateTypeDocs : Documentation {
let Category = DocCatType;
let Heading = "annotate_type";
def err_opencl_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">;
def err_opencl_kernel_attr :
Error<"attribute %0 can only be applied to an OpenCL kernel function">;
-def err_opencl_return_value_with_address_space : Error<
- "return value cannot be qualified with address space">;
+def err_return_value_with_address_space : Error<
+ "return type cannot be qualified with address space">;
def err_opencl_constant_no_init : Error<
"variable in constant address space must be initialized">;
def err_opencl_atomic_init: Error<
// HLSL keywords.
KEYWORD(cbuffer , KEYHLSL)
KEYWORD(tbuffer , KEYHLSL)
+KEYWORD(groupshared , KEYHLSL)
// OpenMP Type Traits
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)
void ParseOpenCLQualifiers(ParsedAttributes &Attrs);
void ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs);
void ParseCUDAFunctionAttributes(ParsedAttributes &attrs);
+ bool isHLSLQualifier(const Token &Tok) const;
+ void ParseHLSLQualifiers(ParsedAttributes &Attrs);
VersionTuple ParseVersionTuple(SourceRange &Range);
void ParseAvailabilityAttribute(IdentifierInfo &Availability,
}
}
+ /// If this is an HLSL address space attribute, returns its representation
+ /// in LangAS, otherwise returns default address space.
+ LangAS asHLSLLangAS() const {
+ switch (getParsedKind()) {
+ case ParsedAttr::AT_HLSLGroupSharedAddressSpace:
+ return LangAS::hlsl_groupshared;
+ default:
+ return LangAS::Default;
+ }
+ }
+
AttributeCommonInfo::Kind getKind() const {
return AttributeCommonInfo::Kind(Info.AttrKind);
}
0, // sycl_private
10, // ptr32_sptr
11, // ptr32_uptr
- 12 // ptr64
+ 12, // ptr64
+ 13, // hlsl_groupshared
};
return &FakeAddrSpaceMap;
} else {
case attr::OpenCLLocalAddressSpace:
case attr::OpenCLConstantAddressSpace:
case attr::OpenCLGenericAddressSpace:
+ case attr::HLSLGroupSharedAddressSpace:
// FIXME: Update printAttributedBefore to print these once we generate
// AttributedType nodes for them.
break;
return "__uptr __ptr32";
case LangAS::ptr64:
return "__ptr64";
+ case LangAS::hlsl_groupshared:
+ return "groupshared";
default:
return std::to_string(toTargetAddressSpace(AS));
}
Private, // sycl_private
Generic, // ptr32_sptr
Generic, // ptr32_uptr
- Generic // ptr64
+ Generic, // ptr64
+ Generic, // hlsl_groupshared
};
const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
Constant, // cuda_constant
Local, // cuda_shared
// SYCL address space values for this map are dummy
- Generic, // sycl_global
- Generic, // sycl_global_device
- Generic, // sycl_global_host
- Generic, // sycl_local
- Generic, // sycl_private
- Generic, // ptr32_sptr
- Generic, // ptr32_uptr
- Generic // ptr64
+ Generic, // sycl_global
+ Generic, // sycl_global_device
+ Generic, // sycl_global_host
+ Generic, // sycl_local
+ Generic, // sycl_private
+ Generic, // ptr32_sptr
+ Generic, // ptr32_uptr
+ Generic, // ptr64
+ Generic, // hlsl_groupshared
};
} // namespace targets
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
- 0 // ptr64
+ 0, // ptr64
+ 3, // hlsl_groupshared
};
class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo {
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
- 0 // ptr64
+ 0, // ptr64
+ 0, // hlsl_groupshared
};
/// The DWARF address class. Taken from
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
- 0 // ptr64
+ 0, // ptr64
+ 0, // hlsl_groupshared
};
// Used by both the SPIR and SPIR-V targets.
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
- 0 // ptr64
+ 0, // ptr64
+ 0, // hlsl_groupshared
};
// Base class for SPIR and SPIR-V target info.
0, // ptr32_sptr
0, // ptr32_uptr
0, // ptr64
+ 0, // hlsl_groupshared
};
class LLVM_LIBRARY_VISIBILITY TCETargetInfo : public TargetInfo {
0, // sycl_private
270, // ptr32_sptr
271, // ptr32_uptr
- 272 // ptr64
+ 272, // ptr64
+ 0, // hlsl_groupshared
};
// X86 target abstract base class; x86-32 and x86-64 are very close, so
ParsedAttr::AS_Keyword);
}
+bool Parser::isHLSLQualifier(const Token &Tok) const {
+ return Tok.is(tok::kw_groupshared);
+}
+
+void Parser::ParseHLSLQualifiers(ParsedAttributes &Attrs) {
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+ SourceLocation AttrNameLoc = ConsumeToken();
+ Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
+ ParsedAttr::AS_Keyword);
+}
+
void Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) {
// Treat these like attributes, even though they're type specifiers.
while (true) {
ParseOpenCLQualifiers(DS.getAttributes());
break;
+ case tok::kw_groupshared:
+ // NOTE: ParseHLSLQualifiers will consume the qualifier token.
+ ParseHLSLQualifiers(DS.getAttributes());
+ continue;
+
case tok::less:
// GCC ObjC supports types like "<SomeProtocol>" as a synonym for
// "id<SomeProtocol>". This is hopelessly old fashioned and dangerous,
case tok::kw___read_only:
case tok::kw___read_write:
case tok::kw___write_only:
+
+ case tok::kw_groupshared:
return true;
case tok::kw_private:
#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t:
#include "clang/Basic/OpenCLImageTypes.def"
+ case tok::kw_groupshared:
return true;
case tok::kw_private:
ParseOpenCLQualifiers(DS.getAttributes());
break;
+ case tok::kw_groupshared:
+ // NOTE: ParseHLSLQualifiers will consume the qualifier token.
+ ParseHLSLQualifiers(DS.getAttributes());
+ continue;
+
case tok::kw___unaligned:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_unaligned, Loc, PrevSpec, DiagID,
getLangOpts());
tok::kw_constexpr, tok::kw_consteval, tok::kw_static,
tok::kw___private, tok::kw___global, tok::kw___local,
tok::kw___constant, tok::kw___generic,
- tok::kw_requires, tok::kw_noexcept) ||
+ tok::kw_groupshared, tok::kw_requires,
+ tok::kw_noexcept) ||
(Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
if (!getLangOpts().CPlusPlus2b)
// It's common to forget that one needs '()' before 'mutable', an
// OpenCL pipe
case tok::kw_pipe:
+ // HLSL address space qualifiers
+ case tok::kw_groupshared:
+
// GNU
case tok::kw_restrict:
case tok::kw__Complex:
// type declaration will generate a compilation error.
LangAS AddressSpace = NewFD->getReturnType().getAddressSpace();
if (AddressSpace != LangAS::Default) {
- Diag(NewFD->getLocation(),
- diag::err_opencl_return_value_with_address_space);
+ Diag(NewFD->getLocation(), diag::err_return_value_with_address_space);
NewFD->setInvalidDecl();
}
}
NewFD->addAttr(Attr);
}
}
+ // HLSL does not support specifying an address space on a function return
+ // type.
+ LangAS AddressSpace = NewFD->getReturnType().getAddressSpace();
+ if (AddressSpace != LangAS::Default) {
+ Diag(NewFD->getLocation(), diag::err_return_value_with_address_space);
+ NewFD->setInvalidDecl();
+ }
}
if (!getLangOpts().CPlusPlus) {
ExplicitResultType = FTI.hasTrailingReturnType();
+ if (ExplicitResultType && getLangOpts().HLSL) {
+ QualType RetTy = FTI.getTrailingReturnType().get();
+ if (!RetTy.isNull()) {
+ // HLSL does not support specifying an address space on a lambda return
+ // type.
+ LangAS AddressSpace = RetTy.getAddressSpace();
+ if (AddressSpace != LangAS::Default)
+ Diag(FTI.getTrailingReturnTypeLoc(),
+ diag::err_return_value_with_address_space);
+ }
+ }
+
if (FTIHasNonVoidParameters(FTI)) {
Params.reserve(FTI.NumParams);
for (unsigned i = 0, e = FTI.NumParams; i != e; ++i)
if (T.isVolatileQualified() && getLangOpts().CPlusPlus20)
Diag(Loc, diag::warn_deprecated_volatile_return) << T;
+ if (T.getAddressSpace() != LangAS::Default && getLangOpts().HLSL)
+ return true;
return false;
}
// The keyword-based type attributes imply which address space to use.
ASIdx = S.getLangOpts().SYCLIsDevice ? Attr.asSYCLLangAS()
: Attr.asOpenCLLangAS();
+ if (S.getLangOpts().HLSL)
+ ASIdx = Attr.asHLSLLangAS();
if (ASIdx == LangAS::Default)
llvm_unreachable("Invalid address space");
case ParsedAttr::AT_OpenCLLocalAddressSpace:
case ParsedAttr::AT_OpenCLConstantAddressSpace:
case ParsedAttr::AT_OpenCLGenericAddressSpace:
+ case ParsedAttr::AT_HLSLGroupSharedAddressSpace:
case ParsedAttr::AT_AddressSpace:
HandleAddressSpaceTypeAttribute(type, attr, state);
attr.setUsedAsTypeAttr();
--- /dev/null
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -ast-dump -o - %s | FileCheck %s
+
+//CHECK:VarDecl 0x[[A:[0-9a-f]+]] <{{.*}} col:24> col:20 used a 'groupshared float[10]'
+ groupshared float a[10];
+
+// CHECK:FunctionDecl 0x{{[0-9a-f]+}} <{{.*}}> line:[[@LINE+2]]:7 main 'void ()'
+ [numthreads(8,8,1)]
+ void main() {
+// CHECK:BinaryOperator 0x{{[0-9a-f]+}} <{{.*}}> 'groupshared float' lvalue '='
+// CHECK:ArraySubscriptExpr 0x{{[0-9a-f]+}} <col:4, col:7> 'groupshared float' lvalue
+// CHECK:ImplicitCastExpr 0x{{[0-9a-f]+}} <col:4> 'groupshared float *' <ArrayToPointerDecay>
+// CHECK:DeclRefExpr 0x{{[0-9a-f]+}} <col:4> 'groupshared float[10]' lvalue Var 0x[[A]] 'a' 'groupshared float[10]'
+// CHECK:IntegerLiteral 0x{{[0-9a-f]+}} <col:6> 'int' 0
+// CHECK:ImplicitCastExpr 0x{{[0-9a-f]+}} <col:11> 'float' <IntegralToFloating>
+// CHECK:IntegerLiteral 0x{{[0-9a-f]+}} <col:11> 'int' 1
+ a[0] = 1;
+ }
+
+
+// CHECK:HLSLNumThreadsAttr 0x{{[0-9a-f]+}} <{{.*}}> 8 8 1
--- /dev/null
+
+// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s \
+// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// Make sure groupshared translated into address space 3.
+// CHECK:@"?a@@3PAMA" = addrspace(3) global [10 x float]
+
+ groupshared float a[10];
+
+ [numthreads(8,8,1)]
+ void main() {
+ a[0] = 1;
+ }
+
void foo(private int i);
-private int bar(); //expected-error{{return value cannot be qualified with address space}}
+private int bar(); //expected-error{{return type cannot be qualified with address space}}
--- /dev/null
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
+extern groupshared float f;
+extern float groupshared f; // Ok, redeclaration?
+
+
+// NOTE:lambda is not enabled except for hlsl202x.
+// expected-error@+2 {{expected expression}}
+// expected-warning@+1 {{'auto' type specifier is a C++11 extension}}
+auto l = []() groupshared {};
+
+
+// NOTE: remove this error once [[]] attribute is supported except for hlsl202x.
+// expected-error@+1 {{expected expression}}
+float groupshared [[]] i = 12;
+
+float groupshared const i2 = 12;
--- /dev/null
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -std=hlsl202x -o - -fsyntax-only %s -verify
+extern groupshared float f;
+extern float groupshared f; // Ok, redeclaration?
+
+// expected-error@+1 {{return type cannot be qualified with address space}}
+auto l = []() -> groupshared void {};
+// expected-error@+1 {{expected a type}}
+auto l2 = []() -> groupshared {};
+
+float groupshared [[]] i = 12;
+
+float groupshared const i2 = 12;
+
+void foo() {
+ l();
+}
+
+extern groupshared float f;
+const float cf = f;
+// expected-error@+1 {{'auto' return without trailing return type; deduced return types are a C++14 extension}}
+auto func() {
+ return f;
+}
+
+void other() {
+ // NOTE: groupshared and const are stripped off thanks to lvalue to rvalue conversions and we deduce float for the return type.
+ auto l = [&]() { return f; };
+ auto l2 = [&]() { return cf; };
+}
--- /dev/null
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
+
+ groupshared float a[10];
+
+ [numthreads(8,8,1)]
+ void main() {
+ a[0] = 1;
+ // expected-error@+1 {{automatic variable qualified with an address space}}
+ groupshared float b;
+ }
+
+// expected-warning@+2 {{'groupshared' attribute only applies to variables}}
+// expected-error@+1 {{return type cannot be qualified with address space}}
+ groupshared float foo() {
+ static groupshared float foo0;
+ return 1;
+ }
+// expected-warning@+2 {{'groupshared' attribute only applies to variables}}
+// expected-error@+1 {{return type cannot be qualified with address space}}
+ groupshared void bar() {
+ extern groupshared float bar0;
+ }
+// expected-warning@+2 {{'groupshared' attribute only applies to variables}}
+// expected-error@+1 {{return type cannot be qualified with address space}}
+ groupshared float decl() {
+ return 1;
+ }
+
+ class C {
+ // expected-warning@+2 {{'groupshared' attribute only applies to variables}}
+ // expected-error@+1 {{return type cannot be qualified with address space}}
+ groupshared void foo() {}
+ // expected-warning@+2 {{'groupshared' attribute only applies to variables}}
+ // expected-error@+1 {{return type cannot be qualified with address space}}
+ groupshared void bar();
+ // expected-warning@+2 {{'groupshared' attribute only applies to variables}}
+ // expected-error@+1 {{return type cannot be qualified with address space}}
+ friend groupshared void friend_def() {}
+ // expected-warning@+2 {{'groupshared' attribute only applies to variables}}
+ // expected-error@+1 {{return type cannot be qualified with address space}}
+ friend groupshared void friend_decl();
+ };
+
+ struct S {
+ // expected-warning@+2 {{'groupshared' attribute only applies to variables}}
+ // expected-error@+1 {{field may not be qualified with an address space}}
+ groupshared float f;
+ static groupshared float g;
+ };
+
+ // expected-error@+1 {{parameter may not be qualified with an address space}}
+ float foo2(groupshared float a) {
+ return a;
+ }
+
+// expected-note@+2 {{parameter may not be qualified with an address space}}
+template<typename T>
+ T tfoo(T t) {
+ return t;
+ }
+ // expected-warning@+1 {{alias declarations are a C++11 extension}}
+ using GSF = groupshared float;
+ GSF gs;
+ // expected-error@+1 {{no matching function for call to 'tfoo'}}
+ GSF gs2 = tfoo<GSF>(gs);
+
+// NOTE:This one didn't report error on the groupshared return type,
+// it is caused by return type check is after pointer check which is acceptable.
+// expected-error@+1 {{pointers are unsupported in HLSL}}
+groupshared void (*fp)();
+// expected-error@+2 {{pointers are unsupported in HLSL}}
+// expected-error@+1 {{parameter may not be qualified with an address space}}
+void (*fp2)(groupshared float);
+// NOTE: HLSL not support trailing return types.
+// expected-warning@+2 {{'auto' type specifier is a C++11 extension}}
+// expected-error@+1 {{expected function body after function declarator}}
+auto func() -> groupshared void;
+// expected-warning@+2 {{'groupshared' attribute only applies to variables}}
+// expected-error@+1 {{return type cannot be qualified with address space}}
+void groupshared f();
+
+struct S2 {
+ // Do we reject it as a function qualifier on a member function?
+ void f() groupshared;
+};
+
+// Does it impact size or alignment?
+_Static_assert(sizeof(float) == sizeof(groupshared float), "");
+_Static_assert(_Alignof(double) == _Alignof(groupshared double),"");
+
+// Does it impact type identity for templates?
+template <typename Ty>
+struct S3 {
+ static const bool value = false;
+};
+
+template <>
+struct S3<groupshared float> {
+ static const bool value = true;
+};
+_Static_assert(!S3<float>::value, "");
+_Static_assert(S3<groupshared float>::value, "");
+
+// Can you overload based on the qualifier?
+void func(float f) {}
+// expected-error@+1 {{parameter may not be qualified with an address space}}
+void func(groupshared float f) {}
--- /dev/null
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -std=hlsl202x -o - -fsyntax-only %s -verify
+
+// expected-error@+1 {{return type cannot be qualified with address space}}
+auto func() -> groupshared void;
+
+// expected-error@+1 {{parameter may not be qualified with an address space}}
+auto func(float groupshared) -> void;
+
+// expected-error@+1 {{parameter may not be qualified with an address space}}
+auto l = [](groupshared float ) {};
+
+// expected-error@+1 {{return type cannot be qualified with address space}}
+auto l2 = []() -> groupshared void {};
+
+struct S {
+// expected-error@+1 {{return type cannot be qualified with address space}}
+operator groupshared int() const;
+
+};
}
#endif
-__private int func_return_priv(void); //expected-error {{return value cannot be qualified with address space}}
-__global int func_return_global(void); //expected-error {{return value cannot be qualified with address space}}
-__local int func_return_local(void); //expected-error {{return value cannot be qualified with address space}}
-__constant int func_return_constant(void); //expected-error {{return value cannot be qualified with address space}}
+__private int func_return_priv(void); //expected-error {{return type cannot be qualified with address space}}
+__global int func_return_global(void); //expected-error {{return type cannot be qualified with address space}}
+__local int func_return_local(void); //expected-error {{return type cannot be qualified with address space}}
+__constant int func_return_constant(void); //expected-error {{return type cannot be qualified with address space}}
#if __OPENCL_C_VERSION__ >= 200
-__generic int func_return_generic(void); //expected-error {{return value cannot be qualified with address space}}
+__generic int func_return_generic(void); //expected-error {{return type cannot be qualified with address space}}
#endif
void func_multiple_addr(void) {
return 0;
}
-int* global x(int* x) { // expected-error {{return value cannot be qualified with address space}}
+int* global x(int* x) { // expected-error {{return type cannot be qualified with address space}}
return x + 1;
}
-int* local x(int* x) { // expected-error {{return value cannot be qualified with address space}}
+int* local x(int* x) { // expected-error {{return type cannot be qualified with address space}}
return x + 1;
}
-int* constant x(int* x) { // expected-error {{return value cannot be qualified with address space}}
+int* constant x(int* x) { // expected-error {{return type cannot be qualified with address space}}
return x + 1;
}
template <long int I>
void tooBig() {
- __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388588)}}
+ __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388587)}}
}
template <long int I>