Skip to content

Commit 61d6ea7

Browse files
committed
[SYCL] Add aspect enum value information to LLVM IR metadata
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 <steffen.larsen@intel.com>
1 parent 9a59ef5 commit 61d6ea7

File tree

13 files changed

+184
-24
lines changed

13 files changed

+184
-24
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().getZExtValue())));
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("intel_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())
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %clang_cc1 -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+
enum class [[__sycl_detail__::sycl_type(aspect)]] aspect {
5+
host = 0,
6+
cpu = 1,
7+
gpu = 2,
8+
accelerator = 3,
9+
custom = 4,
10+
fp16 = 5,
11+
fp64 = 6,
12+
future_aspect = 12
13+
};
14+
15+
// CHECK: !intel_sycl_aspects = !{![[HOST:[0-9]+]], ![[CPU:[0-9]+]], ![[GPU:[0-9]+]], ![[ACC:[0-9]+]], ![[CUSTOM:[0-9]+]], ![[FP16:[0-9]+]], ![[FP64:[0-9]+]], ![[FUTURE_ASPECT:[0-9]+]]}
16+
// CHECK: [[HOST]] = !{!"host", i32 0}
17+
// CHECK: [[CPU]] = !{!"cpu", i32 1}
18+
// CHECK: [[GPU]] = !{!"gpu", i32 2}
19+
// CHECK: [[ACC]] = !{!"accelerator", i32 3}
20+
// CHECK: [[CUSTOM]] = !{!"custom", i32 4}
21+
// CHECK: [[FP16]] = !{!"fp16", i32 5}
22+
// CHECK: [[FP64]] = !{!"fp64", i32 6}
23+
// CHECK: [[FUTURE_ASPECT]] = !{!"future_aspect", i32 12}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown -fsyntax-only -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+
6+
// expected-note@+1{{previous definition is here}}
7+
enum class [[__sycl_detail__::sycl_type(aspect)]] aspect {
8+
host = 0,
9+
cpu = 1,
10+
gpu = 2,
11+
accelerator = 3,
12+
custom = 4,
13+
fp16 = 5,
14+
fp64 = 6,
15+
future_aspect = 12
16+
};
17+
18+
// expected-error@+1{{redefinition of aspect enum}}
19+
enum class [[__sycl_detail__::sycl_type(aspect)]] aspect_redef {
20+
imposter_value = 3
21+
};

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 (intel_sycl_aspects) the mapping between SYCL aspect
85+
/// names and their integral values.
86+
AspectValueToNameMapTy getSYCLAspectsFromMetadata(const Module &M) {
87+
const NamedMDNode *Node = M.getNamedMetadata("intel_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 intel_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 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())
@@ -333,7 +362,19 @@ buildFunctionsToAspectsMap(Module &M, TypeToAspectsMapTy &TypesWithAspects) {
333362
PreservedAnalyses
334363
SYCLPropagateAspectsUsagePass::run(Module &M, ModuleAnalysisManager &MAM) {
335364
TypeToAspectsMapTy TypesWithAspects = getTypesThatUseAspectsFromMetadata(M);
336-
propagateAspectsToOtherTypesInModule(M, TypesWithAspects);
365+
AspectValueToNameMapTy AspectValues = getSYCLAspectsFromMetadata(M);
366+
367+
// If there is no metadata for aspect values the source code must not have
368+
// included the SYCL headers. In that case there should also not be any types
369+
// that use aspects, so we can skip this pass.
370+
if (AspectValues.empty()) {
371+
assert(TypesWithAspects.empty() &&
372+
"intel_sycl_aspects metadata is missing but "
373+
"intel_types_that_use_aspects is present.");
374+
return PreservedAnalyses::all();
375+
}
376+
377+
propagateAspectsToOtherTypesInModule(M, TypesWithAspects, AspectValues);
337378

338379
FunctionToAspectsMapTy FunctionToAspects =
339380
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+
!intel_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+
!intel_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() !intel_used_aspects !1 {
25+
; CHECK: spir_kernel void @kernelD1.uses.optional() !intel_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() !intel_used_aspects !1 {
31+
; CHECK: spir_func void @funcD1.uses.optional() !intel_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() !intel_used_aspects !1 {
49+
; CHECK: spir_kernel void @kernelE.uses.optional() !intel_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() !intel_used_aspects !1 {
55+
; CHECK: spir_func void @funcE.uses.optional() !intel_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() !intel_used_aspects !1 {
85+
; CHECK: spir_func %A.optional @funcA.returns.optional() !intel_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() !intel_used_aspects !1 {
92+
; CHECK: spir_func void @funcA.uses.array.of.optional() !intel_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) !intel_used_aspects !1 {
98+
; CHECK: spir_func void @funcA.assepts.optional(%A.optional %0) !intel_used_aspects ![[MDID]] {
9999
define spir_func void @funcA.assepts.optional(%A.optional %0) {
100100
ret void
101101
}
102102

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

106-
; CHECK: !1 = !{i32 1}
106+
!intel_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() !intel_used_aspects !0 {
7+
; CHECK: spir_kernel void @kernel() !intel_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() !intel_used_aspects !0 {
13+
; CHECK: spir_func void @func() !intel_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() !intel_used_aspects !0 {
19+
; CHECK: spir_func void @func.array() !intel_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() !intel_used_aspects !0 {
25+
; CHECK: spir_func void @func.vector() !intel_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() !intel_used_aspects !0 {
31+
; CHECK: spir_func void @func.composite() !intel_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+
!intel_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+
!intel_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
!intel_types_that_use_aspects = !{!0}
2020
!0 = !{!"MyStruct", i32 1}
21+
22+
!intel_sycl_aspects = !{!2}
23+
!2 = !{!"fp64", i32 6}

sycl/doc/design/OptionalDeviceFeatures.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,20 @@ 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 `!intel_sycl_aspects` metadata is added to the module, based
428+
on the values defined in the enum. Inside this metadata node, each value of the
429+
aspect enum is represented by another metadata node with two operands; the name
430+
of the value and the corresponding integral value. An example of this is:
431+
432+
```
433+
!intel_sycl_aspects = !{!0, !1, !2, ...}
434+
!0 = !{!"host", i32 0}
435+
!1 = !{!"cpu", i32 1}
436+
!2 = !{!"gpu", i32 2}
437+
...
438+
```
439+
426440
We also introduce three metadata that can be attached to a function definition
427441
similar to the existing `!intel_reqd_sub_group_size`:
428442

@@ -484,6 +498,12 @@ to the following rules:
484498
an `!intel_declared_aspects` metadata to the function's definition listing
485499
the aspects from that attribute.
486500

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

488508
### New LLVM IR pass to propagate aspect usage
489509

0 commit comments

Comments
 (0)