Skip to content

Commit 4d0df22

Browse files
[SYCL] Add aspect enum value information to LLVM IR metadata (#6804)
This commit adds a new module-level metadata node !intel_sycl_aspects which contains metadata pairs of the enum element names and integral values of the SYCL aspects enum, identified by the [[__sycl_detail__::sycl_type(aspect)]] attribute. This commit also makes the SYCLPropagateAspectsUsage pass read !intel_sycl_aspects and use this information to determine the value of the fp64 aspect instead of relying on it being synchronized with the SYCL implementation headers. Signed-off-by: Larsen, Steffen <[email protected]>
1 parent c2c6baf commit 4d0df22

File tree

14 files changed

+170
-25
lines changed

14 files changed

+170
-25
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,17 @@ static llvm::MDNode *getAspectsMD(ASTContext &ASTContext,
527527
return llvm::MDNode::get(Ctx, AspectsMD);
528528
}
529529

530+
static llvm::MDNode *getAspectEnumValueMD(ASTContext &ASTContext,
531+
llvm::LLVMContext &Ctx,
532+
const EnumConstantDecl *ECD) {
533+
SmallVector<llvm::Metadata *, 2> AspectEnumValMD;
534+
AspectEnumValMD.push_back(llvm::MDString::get(Ctx, ECD->getName()));
535+
AspectEnumValMD.push_back(
536+
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
537+
llvm::Type::getInt32Ty(Ctx), ECD->getInitVal().getSExtValue())));
538+
return llvm::MDNode::get(Ctx, AspectEnumValMD);
539+
}
540+
530541
void CodeGenModule::Release() {
531542
Module *Primary = getContext().getModuleForCodeGen();
532543
if (CXX20ModuleInits && Primary && !Primary->isHeaderLikeModule())
@@ -924,6 +935,15 @@ void CodeGenModule::Release() {
924935
RD->getAttr<SYCLUsesAspectsAttr>()));
925936
}
926937
}
938+
939+
// Emit metadata for all aspects defined in the aspects enum.
940+
if (AspectsEnumDecl) {
941+
llvm::NamedMDNode *AspectEnumValsMD =
942+
TheModule.getOrInsertNamedMetadata("sycl_aspects");
943+
for (const EnumConstantDecl *ECD : AspectsEnumDecl->enumerators())
944+
AspectEnumValsMD->addOperand(
945+
getAspectEnumValueMD(Context, TheModule.getContext(), ECD));
946+
}
927947
}
928948

929949
// HLSL related end of code gen work items.
@@ -5063,6 +5083,16 @@ void CodeGenModule::maybeSetTrivialComdat(const Decl &D,
50635083
GO.setComdat(TheModule.getOrInsertComdat(GO.getName()));
50645084
}
50655085

5086+
void CodeGenModule::setAspectsEnumDecl(const EnumDecl *ED) {
5087+
if (AspectsEnumDecl && AspectsEnumDecl != ED) {
5088+
// Conflicting definitions of the aspect enum are not allowed.
5089+
Error(ED->getLocation(), "redefinition of aspect enum");
5090+
getDiags().Report(AspectsEnumDecl->getLocation(),
5091+
diag::note_previous_definition);
5092+
}
5093+
AspectsEnumDecl = ED;
5094+
}
5095+
50665096
void CodeGenModule::generateIntelFPGAAnnotation(
50675097
const Decl *D, llvm::SmallString<256> &AnnotStr) {
50685098
llvm::raw_svector_ostream Out(AnnotStr);

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,7 @@ class CodeGenModule : public CodeGenTypeCache {
604604
llvm::DenseMap<const llvm::Constant *, llvm::GlobalVariable *> RTTIProxyMap;
605605

606606
llvm::DenseMap<StringRef, const RecordDecl *> TypesWithAspects;
607+
const EnumDecl *AspectsEnumDecl = nullptr;
607608

608609
public:
609610
CodeGenModule(ASTContext &C, IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
@@ -1098,6 +1099,8 @@ class CodeGenModule : public CodeGenTypeCache {
10981099
TypesWithAspects[TypeName] = RD;
10991100
}
11001101

1102+
void setAspectsEnumDecl(const EnumDecl *ED);
1103+
11011104
void generateIntelFPGAAnnotation(const Decl *D,
11021105
llvm::SmallString<256> &AnnotStr);
11031106
void addGlobalIntelFPGAAnnotation(const VarDecl *VD, llvm::GlobalValue *GV);

clang/lib/CodeGen/CodeGenTypes.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,10 @@ void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) {
321321
if (!ConvertType(ED->getIntegerType())->isIntegerTy(32))
322322
TypeCache.clear();
323323
}
324+
// If this is the SYCL aspect enum it is saved for later processing.
325+
if (const auto *Attr = ED->getAttr<SYCLTypeAttr>())
326+
if (Attr->getType() == SYCLTypeAttr::SYCLType::aspect)
327+
CGM.setAspectsEnumDecl(ED);
324328
// If necessary, provide the full definition of a type only used with a
325329
// declaration so far.
326330
if (CGDebugInfo *DI = CGM.getModuleDebugInfo())

clang/test/CodeGenSYCL/Inputs/sycl.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ enum class address_space : int {
7070
} // namespace access
7171

7272
// Dummy aspect enum with limited enumerators
73-
enum class __SYCL_TYPE(aspect) aspect {
73+
enum class __SYCL_TYPE(aspect) aspect { // #AspectEnum
7474
host = 0,
7575
cpu = 1,
7676
gpu = 2,
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cc1 -internal-isystem %S/Inputs -fsycl-is-device -triple spir64-unknown-unknown -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s
2+
3+
// Tests for IR of [[__sycl_detail__::sycl_type(aspect)]] enum.
4+
#include "sycl.hpp"
5+
6+
// CHECK: !sycl_aspects = !{![[HOST:[0-9]+]], ![[CPU:[0-9]+]], ![[GPU:[0-9]+]], ![[ACC:[0-9]+]], ![[CUSTOM:[0-9]+]], ![[FP16:[0-9]+]], ![[FP64:[0-9]+]]}
7+
// CHECK: ![[HOST]] = !{!"host", i32 0}
8+
// CHECK: ![[CPU]] = !{!"cpu", i32 1}
9+
// CHECK: ![[GPU]] = !{!"gpu", i32 2}
10+
// CHECK: ![[ACC]] = !{!"accelerator", i32 3}
11+
// CHECK: ![[CUSTOM]] = !{!"custom", i32 4}
12+
// CHECK: ![[FP16]] = !{!"fp16", i32 5}
13+
// CHECK: ![[FP64]] = !{!"fp64", i32 6}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang_cc1 -internal-isystem %S/Inputs -fsycl-is-device -triple spir64-unknown-unknown -verify -emit-llvm-only %s
2+
3+
// Tests for error diagnostics when multiple definitions of
4+
// [[__sycl_detail__::sycl_type(aspect)]] enums are present.
5+
#include "sycl.hpp"
6+
7+
// expected-note@#AspectEnum{{previous definition is here}}
8+
9+
// expected-error@+1{{redefinition of aspect enum}}
10+
enum class [[__sycl_detail__::sycl_type(aspect)]] aspect_redef {
11+
imposter_value = 3
12+
};

llvm/lib/SYCLLowerIR/SYCLPropagateAspectsUsage.cpp

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,35 @@ TypeToAspectsMapTy getTypesThatUseAspectsFromMetadata(const Module &M) {
7979
return Result;
8080
}
8181

82+
using AspectValueToNameMapTy = SmallMapVector<StringRef, int, 32>;
83+
84+
/// Retrieves from metadata (sycl_aspects) the mapping between SYCL aspect names
85+
/// and their integral values.
86+
AspectValueToNameMapTy getAspectsFromMetadata(const Module &M) {
87+
const NamedMDNode *Node = M.getNamedMetadata("sycl_aspects");
88+
AspectValueToNameMapTy Result;
89+
if (!Node)
90+
return Result;
91+
92+
for (const auto OperandIt : Node->operands()) {
93+
const MDNode &N = *OperandIt;
94+
assert(N.getNumOperands() == 2 &&
95+
"Each operand of sycl_aspects must be a pair.");
96+
97+
// The aspect's name is the first operand.
98+
const auto *AspectName = cast<MDString>(N.getOperand(0));
99+
100+
// The aspect's integral value is the second operand.
101+
const auto *AspectCAM = cast<ConstantAsMetadata>(N.getOperand(1));
102+
const Constant *AspectC = AspectCAM->getValue();
103+
104+
Result[AspectName->getString()] =
105+
cast<ConstantInt>(AspectC)->getSExtValue();
106+
}
107+
108+
return Result;
109+
}
110+
82111
using TypesEdgesTy =
83112
std::unordered_map<const Type *, std::vector<const Type *>>;
84113

@@ -107,6 +136,7 @@ void propagateAspectsThroughTypes(const TypesEdgesTy &Edges, const Type *Start,
107136
/// another type TT, which in turn uses the aspect A.
108137
/// @TypesWithAspects argument consist of known types with aspects
109138
/// from metadata information.
139+
/// @AspectValues argument consist of known aspect values and their names.
110140
///
111141
/// The algorithm is the following:
112142
/// 1) Make a list of all structure types from module @M. The list also
@@ -121,18 +151,17 @@ void propagateAspectsThroughTypes(const TypesEdgesTy &Edges, const Type *Start,
121151
/// Time complexity: O((V + E) * T) where T is the number of input types
122152
/// containing aspects.
123153
void propagateAspectsToOtherTypesInModule(
124-
const Module &M, TypeToAspectsMapTy &TypesWithAspects) {
154+
const Module &M, TypeToAspectsMapTy &TypesWithAspects,
155+
AspectValueToNameMapTy &AspectValues) {
125156
std::unordered_set<const Type *> TypesToProcess;
126157
const Type *DoubleTy = Type::getDoubleTy(M.getContext());
127158

128-
// 6 is taken from sycl/include/CL/sycl/aspects.hpp
129-
// Note: that magic number must strictly correspond to the one assigned to
130-
// 'fp64' value of 'aspect' enum.
131-
// FIXME: we should develop some kind of mechanism which will allow us to
132-
// avoid hardcoding this number here and having a build dependency between
133-
// the compiler and the runtime. See intel/llvm#5892
134-
static constexpr int AspectFP64 = 6;
135-
TypesWithAspects[DoubleTy].insert(AspectFP64);
159+
// Find the value of the fp64 aspect from the aspect values map and register
160+
// it as a special-case type with aspect for double.
161+
auto FP64AspectIt = AspectValues.find("fp64");
162+
assert(FP64AspectIt != AspectValues.end() &&
163+
"fp64 aspect was not found in the aspect values.");
164+
TypesWithAspects[DoubleTy].insert(FP64AspectIt->second);
136165

137166
TypesToProcess.insert(DoubleTy);
138167
for (const Type *T : M.getIdentifiedStructTypes())
@@ -339,7 +368,19 @@ buildFunctionsToAspectsMap(Module &M, TypeToAspectsMapTy &TypesWithAspects) {
339368
PreservedAnalyses
340369
SYCLPropagateAspectsUsagePass::run(Module &M, ModuleAnalysisManager &MAM) {
341370
TypeToAspectsMapTy TypesWithAspects = getTypesThatUseAspectsFromMetadata(M);
342-
propagateAspectsToOtherTypesInModule(M, TypesWithAspects);
371+
AspectValueToNameMapTy AspectValues = getAspectsFromMetadata(M);
372+
373+
// If there is no metadata for aspect values the source code must not have
374+
// included the SYCL headers. In that case there should also not be any types
375+
// that use aspects, so we can skip this pass.
376+
if (AspectValues.empty()) {
377+
assert(TypesWithAspects.empty() &&
378+
"sycl_aspects metadata is missing but "
379+
"sycl_types_that_use_aspects is present.");
380+
return PreservedAnalyses::all();
381+
}
382+
383+
propagateAspectsToOtherTypesInModule(M, TypesWithAspects, AspectValues);
343384

344385
FunctionToAspectsMapTy FunctionToAspects =
345386
buildFunctionsToAspectsMap(M, TypesWithAspects);

llvm/test/SYCLLowerIR/PropagateAspectsUsage/call-graph-1.ll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ define spir_func void @func3() {
5050
!0 = !{!"Optional.A", i32 1}
5151
!1 = !{!"Optional.B", i32 2}
5252

53+
!sycl_aspects = !{!2}
54+
!2 = !{!"fp64", i32 6}
55+
5356
; CHECK: ![[#ID1]] = !{i32 1}
5457
; CHECK: ![[#ID2]] = !{i32 1, i32 2}
5558
; CHECK: ![[#ID3]] = !{i32 2}

llvm/test/SYCLLowerIR/PropagateAspectsUsage/call-graph-2.ll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ define spir_func void @func4() {
5151
!0 = !{!"Optional.A", i32 1}
5252
!1 = !{!"Optional.B", i32 2}
5353

54+
!sycl_aspects = !{!2}
55+
!2 = !{!"fp64", i32 6}
56+
5457
; CHECK: ![[#ID1]] = !{i32 1, i32 2}
5558
; CHECK: ![[#ID2]] = !{i32 1}
5659
; CHECK: ![[#ID3]] = !{i32 2}

llvm/test/SYCLLowerIR/PropagateAspectsUsage/composite-types-1.ll

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@
2222

2323
%F2.does.not.contain.optional = type { %B.core, %C.core*, %D2.does.not.contain.optional* }
2424

25-
; CHECK: spir_kernel void @kernelD1.uses.optional() !sycl_used_aspects !1 {
25+
; CHECK: spir_kernel void @kernelD1.uses.optional() !sycl_used_aspects ![[MDID:[0-9]+]] {
2626
define spir_kernel void @kernelD1.uses.optional() {
2727
%tmp = alloca %D1.contains.optional
2828
ret void
2929
}
3030

31-
; CHECK: spir_func void @funcD1.uses.optional() !sycl_used_aspects !1 {
31+
; CHECK: spir_func void @funcD1.uses.optional() !sycl_used_aspects ![[MDID]] {
3232
define spir_func void @funcD1.uses.optional() {
3333
%tmp = alloca %D1.contains.optional
3434
ret void
@@ -46,13 +46,13 @@ define spir_func void @funcD2.does.not.use.optional() {
4646
ret void
4747
}
4848

49-
; CHECK: spir_kernel void @kernelE.uses.optional() !sycl_used_aspects !1 {
49+
; CHECK: spir_kernel void @kernelE.uses.optional() !sycl_used_aspects ![[MDID]] {
5050
define spir_kernel void @kernelE.uses.optional() {
5151
%tmp = alloca %E.contains.optional
5252
ret void
5353
}
5454

55-
; CHECK: spir_func void @funcE.uses.optional() !sycl_used_aspects !1 {
55+
; CHECK: spir_func void @funcE.uses.optional() !sycl_used_aspects ![[MDID]] {
5656
define spir_func void @funcE.uses.optional() {
5757
%tmp = alloca %E.contains.optional
5858
ret void
@@ -82,25 +82,28 @@ define spir_func void @funcF2.does.not.use.optional() {
8282
ret void
8383
}
8484

85-
; CHECK: spir_func %A.optional @funcA.returns.optional() !sycl_used_aspects !1 {
85+
; CHECK: spir_func %A.optional @funcA.returns.optional() !sycl_used_aspects ![[MDID]] {
8686
define spir_func %A.optional @funcA.returns.optional() {
8787
%tmp = alloca %A.optional
8888
%ret = load %A.optional, %A.optional* %tmp
8989
ret %A.optional %ret
9090
}
9191

92-
; CHECK: spir_func void @funcA.uses.array.of.optional() !sycl_used_aspects !1 {
92+
; CHECK: spir_func void @funcA.uses.array.of.optional() !sycl_used_aspects ![[MDID]] {
9393
define spir_func void @funcA.uses.array.of.optional() {
9494
%tmp = alloca [4 x %A.optional]
9595
ret void
9696
}
9797

98-
; CHECK: spir_func void @funcA.assepts.optional(%A.optional %0) !sycl_used_aspects !1 {
98+
; CHECK: spir_func void @funcA.assepts.optional(%A.optional %0) !sycl_used_aspects ![[MDID]] {
9999
define spir_func void @funcA.assepts.optional(%A.optional %0) {
100100
ret void
101101
}
102102

103103
!sycl_types_that_use_aspects = !{!0}
104104
!0 = !{!"A.optional", i32 1}
105105

106-
; CHECK: !1 = !{i32 1}
106+
!sycl_aspects = !{!1}
107+
!1 = !{!"fp64", i32 6}
108+
109+
; CHECK: ![[MDID]] = !{i32 1}

llvm/test/SYCLLowerIR/PropagateAspectsUsage/double.ll

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,37 @@
44

55
%composite = type { double }
66

7-
; CHECK: spir_kernel void @kernel() !sycl_used_aspects !0 {
7+
; CHECK: spir_kernel void @kernel() !sycl_used_aspects ![[MDID:[0-9]+]] {
88
define spir_kernel void @kernel() {
99
call spir_func void @func()
1010
ret void
1111
}
1212

13-
; CHECK: spir_func void @func() !sycl_used_aspects !0 {
13+
; CHECK: spir_func void @func() !sycl_used_aspects ![[MDID]] {
1414
define spir_func void @func() {
1515
%tmp = alloca double
1616
ret void
1717
}
1818

19-
; CHECK: spir_func void @func.array() !sycl_used_aspects !0 {
19+
; CHECK: spir_func void @func.array() !sycl_used_aspects ![[MDID]] {
2020
define spir_func void @func.array() {
2121
%tmp = alloca [4 x double]
2222
ret void
2323
}
2424

25-
; CHECK: spir_func void @func.vector() !sycl_used_aspects !0 {
25+
; CHECK: spir_func void @func.vector() !sycl_used_aspects ![[MDID]] {
2626
define spir_func void @func.vector() {
2727
%tmp = alloca <4 x double>
2828
ret void
2929
}
3030

31-
; CHECK: spir_func void @func.composite() !sycl_used_aspects !0 {
31+
; CHECK: spir_func void @func.composite() !sycl_used_aspects ![[MDID]] {
3232
define spir_func void @func.composite() {
3333
%tmp = alloca %composite
3434
ret void
3535
}
3636

37-
; CHECK: !0 = !{i32 6}
37+
!sycl_aspects = !{!0}
38+
!0 = !{!"fp64", i32 6}
39+
40+
; CHECK: ![[MDID]] = !{i32 6}

llvm/test/SYCLLowerIR/PropagateAspectsUsage/multiple-aspects.ll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ define spir_kernel void @kernel() {
4646
!2 = !{!"C", i32 2}
4747
!3 = !{!"D", i32 3, i32 4}
4848

49+
!sycl_aspects = !{!4}
50+
!4 = !{!"fp64", i32 6}
51+
4952
; CHECK: ![[#ID0]] = !{i32 0}
5053
; CHECK: ![[#ID1]] = !{i32 1, i32 0}
5154
; CHECK: ![[#ID2]] = !{i32 2, i32 1, i32 0}

llvm/test/SYCLLowerIR/PropagateAspectsUsage/no-uses-of-optional.ll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@ define weak dso_local spir_func void @func() {
1818

1919
!sycl_types_that_use_aspects = !{!0}
2020
!0 = !{!"MyStruct", i32 1}
21+
22+
!sycl_aspects = !{!2}
23+
!2 = !{!"fp64", i32 6}

sycl/doc/design/OptionalDeviceFeatures.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,24 @@ allow metadata to be attached directly to types. This representation works
423423
around that limitation by creating global named metadata that references the
424424
type's name.
425425

426+
To synchronize the integral values of given aspects between the SYCL headers and
427+
the compiler, the `!sycl_aspects` metadata is added to the module, based on the
428+
values defined in the enum. Inside this metadata node, each value of the aspect
429+
enum is represented by another metadata node with two operands; the name of the
430+
value and the corresponding integral value. An example of this is:
431+
432+
```
433+
!sycl_aspects = !{!0, !1, !2, ...}
434+
!0 = !{!"host", i32 0}
435+
!1 = !{!"cpu", i32 1}
436+
!2 = !{!"gpu", i32 2}
437+
...
438+
```
439+
440+
**NOTE**: The `!sycl_aspects` metadata is both used by the compiler to identify
441+
the aspect values of implicit aspect requirements, such as `aspect::fp64` from
442+
the use of `double`, and to offer better diagnostic messages.
443+
426444
We also introduce three metadata that can be attached to a function definition:
427445

428446
* The `!sycl_declared_aspects` metadata is used for functions that are
@@ -483,6 +501,12 @@ to the following rules:
483501
an `!sycl_declared_aspects` metadata to the function's definition listing
484502
the aspects from that attribute.
485503

504+
* If a completed enum is decorated with `[[sycl_detail::sycl_type(aspect)]]` the
505+
front-end adds an `!sycl_aspects` metadata to the module containing one
506+
metadata node for each value in the enum. If there are multiple enum
507+
definitions with the `[[sycl_detail::sycl_type(aspect)]]` attribute a
508+
diagnostic is issued.
509+
486510

487511
### New LLVM IR pass to propagate aspect usage
488512

0 commit comments

Comments
 (0)