Skip to content

Commit 752e4d3

Browse files
[SYCL] Implement host pipe unique name generation and mapping calls (#8009)
Implementation of host pipes outlined in the design document in this PR: #5850 1. Generation a unique pipe id for GVs marked with the new "sycl-host-pipe" attribute. Id generation utilizes the same method as used for name generation for device global. 2. Added a host pipe map to map the addresses of marked GVs with the unique id. This host pipe map is generated by a constructor and method calls added to the header and footer. 3. Modified the sycl-post-link tool to generate compile time properties metadata for these GVs. This metadata contains the unique id generated for the GV to be consumed by the device backend compiler. PR for accompanying runtime changes: #7468 --------- Co-authored-by: Alexey Sachkov <[email protected]>
1 parent aab0ba7 commit 752e4d3

File tree

11 files changed

+242
-13
lines changed

11 files changed

+242
-13
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,12 +1331,12 @@ def SYCLType: InheritableAttr {
13311331
"specialization_id", "kernel_handler", "buffer_location",
13321332
"no_alias", "accessor_property_list", "group",
13331333
"private_memory", "aspect", "annotated_ptr", "annotated_arg",
1334-
"stream", "sampler"],
1334+
"stream", "sampler", "host_pipe"],
13351335
["accessor", "local_accessor", "spec_constant",
13361336
"specialization_id", "kernel_handler", "buffer_location",
13371337
"no_alias", "accessor_property_list", "group",
13381338
"private_memory", "aspect", "annotated_ptr", "annotated_arg",
1339-
"stream", "sampler"]>];
1339+
"stream", "sampler", "host_pipe"]>];
13401340
// Only used internally by SYCL implementation
13411341
let Documentation = [InternalOnly];
13421342
}

clang/include/clang/Sema/Sema.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,13 @@ class SYCLIntegrationHeader {
371371
NeedToEmitDeviceGlobalRegistration = true;
372372
}
373373

374+
/// Signals that emission of __sycl_host_pipe_registration type and
375+
/// declaration of variable __sycl_host_pipe_registrar of this type in
376+
/// integration header is required.
377+
void addHostPipeRegistration() {
378+
NeedToEmitHostPipeRegistration = true;
379+
}
380+
374381
private:
375382
// Kernel actual parameter descriptor.
376383
struct KernelParamDesc {
@@ -454,6 +461,10 @@ class SYCLIntegrationHeader {
454461
/// Keeps track of whether declaration of __sycl_device_global_registration
455462
/// type and __sycl_device_global_registrar variable are required to emit.
456463
bool NeedToEmitDeviceGlobalRegistration = false;
464+
465+
/// Keeps track of whether declaration of __sycl_host_pipe_registration
466+
/// type and __sycl_host_pipe_registrar variable are required to emit.
467+
bool NeedToEmitHostPipeRegistration = false;
457468
};
458469

459470
class SYCLIntegrationFooter {

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5508,14 +5508,22 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
55085508

55095509
if (getLangOpts().SYCLIsDevice) {
55105510
const RecordDecl *RD = D->getType()->getAsRecordDecl();
5511-
// Add IR attributes if add_ir_attribute_global_variable is attached to
5512-
// type.
5513-
if (RD && RD->hasAttr<SYCLAddIRAttributesGlobalVariableAttr>())
5514-
AddGlobalSYCLIRAttributes(GV, RD);
5515-
// If VarDecl has a type decorated with SYCL device_global attribute, emit
5516-
// IR attribute 'sycl-unique-id'.
5517-
if (RD && RD->hasAttr<SYCLDeviceGlobalAttr>())
5518-
addSYCLUniqueID(GV, D, Context);
5511+
5512+
if (RD) {
5513+
// Add IR attributes if add_ir_attribute_global_variable is attached to
5514+
// type.
5515+
if (RD->hasAttr<SYCLAddIRAttributesGlobalVariableAttr>())
5516+
AddGlobalSYCLIRAttributes(GV, RD);
5517+
// If VarDecl has a type decorated with SYCL device_global attribute
5518+
// emit IR attribute 'sycl-unique-id'.
5519+
if (RD->hasAttr<SYCLDeviceGlobalAttr>())
5520+
addSYCLUniqueID(GV, D, Context);
5521+
// If VarDecl type is SYCLTypeAttr::host_pipe, emit the IR attribute
5522+
// 'sycl-unique-id'.
5523+
if (const auto *Attr = RD->getAttr<SYCLTypeAttr>())
5524+
if (Attr->getType() == SYCLTypeAttr::SYCLType::host_pipe)
5525+
addSYCLUniqueID(GV, D, Context);
5526+
}
55195527
}
55205528

55215529
if (D->getType().isRestrictQualified()) {

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5169,6 +5169,24 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) {
51695169
O << "\n";
51705170
}
51715171

5172+
// Generate declaration of variable of type __sycl_host_pipe_registration
5173+
// whose sole purpose is to run its constructor before the application's
5174+
// main() function.
5175+
if (NeedToEmitHostPipeRegistration) {
5176+
O << "namespace {\n";
5177+
5178+
O << "class __sycl_host_pipe_registration {\n";
5179+
O << "public:\n";
5180+
O << " __sycl_host_pipe_registration() noexcept;\n";
5181+
O << "};\n";
5182+
O << "__sycl_host_pipe_registration __sycl_host_pipe_registrar;\n";
5183+
5184+
O << "} // namespace\n";
5185+
5186+
O << "\n";
5187+
}
5188+
5189+
51725190
O << "// names of all kernels defined in the corresponding source\n";
51735191
O << "static constexpr\n";
51745192
O << "const char* const kernel_names[] = {\n";
@@ -5359,6 +5377,7 @@ void SYCLIntegrationFooter::addVarDecl(const VarDecl *VD) {
53595377
return;
53605378
// Step 1: ensure that this is of the correct type template specialization.
53615379
if (!isSyclType(VD->getType(), SYCLTypeAttr::specialization_id) &&
5380+
!isSyclType(VD->getType(), SYCLTypeAttr::host_pipe) &&
53625381
!S.isTypeDecoratedWithDeclAttribute<SYCLDeviceGlobalAttr>(
53635382
VD->getType())) {
53645383
// Handle the case where this could be a deduced type, such as a deduction
@@ -5528,19 +5547,23 @@ bool SYCLIntegrationFooter::emit(raw_ostream &OS) {
55285547
llvm::SmallSet<const VarDecl *, 8> Visited;
55295548
bool EmittedFirstSpecConstant = false;
55305549
bool DeviceGlobalsEmitted = false;
5550+
bool HostPipesEmitted = false;
55315551

55325552
// Used to uniquely name the 'shim's as we generate the names in each
55335553
// anonymous namespace.
55345554
unsigned ShimCounter = 0;
55355555

55365556
std::string DeviceGlobalsBuf;
55375557
llvm::raw_string_ostream DeviceGlobOS(DeviceGlobalsBuf);
5558+
std::string HostPipesBuf;
5559+
llvm::raw_string_ostream HostPipesOS(HostPipesBuf);
55385560
for (const VarDecl *VD : GlobalVars) {
55395561
VD = VD->getCanonicalDecl();
55405562

5541-
// Skip if this isn't a SpecIdType or DeviceGlobal. This can happen if it
5542-
// was a deduced type.
5563+
// Skip if this isn't a SpecIdType, DeviceGlobal, or HostPipe. This
5564+
// can happen if it was a deduced type.
55435565
if (!isSyclType(VD->getType(), SYCLTypeAttr::specialization_id) &&
5566+
!isSyclType(VD->getType(), SYCLTypeAttr::host_pipe) &&
55445567
!S.isTypeDecoratedWithDeclAttribute<SYCLDeviceGlobalAttr>(
55455568
VD->getType()))
55465569
continue;
@@ -5551,7 +5574,7 @@ bool SYCLIntegrationFooter::emit(raw_ostream &OS) {
55515574

55525575
// We only want to emit the #includes if we have a variable that needs
55535576
// them, so emit this one on the first time through the loop.
5554-
if (!EmittedFirstSpecConstant && !DeviceGlobalsEmitted)
5577+
if (!EmittedFirstSpecConstant && !DeviceGlobalsEmitted && !HostPipesEmitted)
55555578
OS << "#include <sycl/detail/defines_elementary.hpp>\n";
55565579

55575580
Visited.insert(VD);
@@ -5571,6 +5594,20 @@ bool SYCLIntegrationFooter::emit(raw_ostream &OS) {
55715594
DeviceGlobOS << SYCLUniqueStableIdExpr::ComputeName(S.getASTContext(),
55725595
VD);
55735596
DeviceGlobOS << "\");\n";
5597+
} else if (isSyclType(VD->getType(), SYCLTypeAttr::host_pipe)) {
5598+
HostPipesEmitted = true;
5599+
HostPipesOS << "host_pipe_map::add(";
5600+
HostPipesOS << "(void *)&";
5601+
if (VD->isInAnonymousNamespace()) {
5602+
HostPipesOS << TopShim;
5603+
} else {
5604+
HostPipesOS << "::";
5605+
VD->getNameForDiagnostic(HostPipesOS, Policy, true);
5606+
}
5607+
HostPipesOS << ", \"";
5608+
HostPipesOS << SYCLUniqueStableIdExpr::ComputeName(S.getASTContext(),
5609+
VD);
5610+
HostPipesOS << "\");\n";
55745611
} else {
55755612
EmittedFirstSpecConstant = true;
55765613
OS << "namespace sycl {\n";
@@ -5614,5 +5651,21 @@ bool SYCLIntegrationFooter::emit(raw_ostream &OS) {
56145651

56155652
S.getSyclIntegrationHeader().addDeviceGlobalRegistration();
56165653
}
5654+
5655+
if (HostPipesEmitted) {
5656+
OS << "#include <sycl/detail/host_pipe_map.hpp>\n";
5657+
HostPipesOS.flush();
5658+
OS << "namespace sycl::detail {\n";
5659+
OS << "namespace {\n";
5660+
OS << "__sycl_host_pipe_registration::__sycl_host_pipe_"
5661+
"registration() noexcept {\n";
5662+
OS << HostPipesBuf;
5663+
OS << "}\n";
5664+
OS << "} // namespace (unnamed)\n";
5665+
OS << "} // namespace sycl::detail\n";
5666+
5667+
S.getSyclIntegrationHeader().addHostPipeRegistration();
5668+
}
5669+
56175670
return true;
56185671
}

clang/test/CodeGenSYCL/Inputs/sycl.hpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,32 @@ class [[__sycl_detail__::device_global]] [[__sycl_detail__::global_variable_allo
151151
} // namespace oneapi
152152
} // namespace ext
153153

154+
namespace ext {
155+
namespace intel {
156+
namespace experimental {
157+
158+
// host_pipe class decorated with attribute
159+
template <class _name, class _dataT>
160+
class
161+
host_pipe {
162+
163+
public:
164+
struct
165+
#ifdef __SYCL_DEVICE_ONLY__
166+
[[__sycl_detail__::sycl_type(host_pipe)]]
167+
#endif
168+
__pipeType { const char __p; };
169+
170+
static constexpr __pipeType __pipe = {0};
171+
static _dataT read() {
172+
(void)__pipe;
173+
}
174+
};
175+
176+
} // namespace experimental
177+
} // namespace intel
178+
} // namespace ext
179+
154180
template <int dim>
155181
struct id {
156182
template <typename... T>

clang/test/CodeGenSYCL/host_pipe.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -triple spir64-unknown-unknown-sycldevice -fsycl-unique-prefix=THE_PREFIX -opaque-pointers -emit-llvm %s -o - | FileCheck %s
2+
#include "sycl.hpp"
3+
4+
// Test cases below show that 'sycl-unique-id' LLVM IR attribute is attached to the
5+
// global variable whose type is decorated with host_pipe attribute, and that a
6+
// unique string is generated.
7+
8+
using namespace sycl::ext::intel::experimental;
9+
using namespace sycl;
10+
queue q;
11+
12+
// check that "sycl-unique-id" attribute is created for host pipes
13+
// CHECK: @_ZN4sycl3_V13ext5intel12experimental9host_pipeIZZZ3foovENKUlRNS0_7handlerEE_clES6_ENKUlvE_clEvE5HPIntiE6__pipeE = internal addrspace(1) constant %"struct.sycl::_V1::ext::intel::experimental::host_pipe<HPInt, int>::__pipeType" zeroinitializer, align 1 #[[HPINT_ATTRS:[0-9]+]]
14+
// CHECK: @_ZN4sycl3_V13ext5intel12experimental9host_pipeIZZZ3foovENKUlRNS0_7handlerEE_clES6_ENKUlvE_clEvE7HPFloatiE6__pipeE = internal addrspace(1) constant %"struct.sycl::_V1::ext::intel::experimental::host_pipe<HPFloat, int>::__pipeType" zeroinitializer, align 1 #[[HPFLOAT_ATTRS:[0-9]+]]
15+
16+
void foo() {
17+
q.submit([&](handler &h) {
18+
h.single_task<class kernel_name_1>([=]() {
19+
host_pipe<class HPInt, int>::read();
20+
host_pipe<class HPFloat, int>::read();
21+
});
22+
});
23+
}
24+
25+
// CHECK: attributes #[[HPINT_ATTRS]] = { "sycl-unique-id"="THE_PREFIX____ZN4sycl3_V13ext5intel12experimental9host_pipeIZZZ3foovENKUlRNS0_7handlerEE_clES6_ENKUlvE_clEvE5HPIntiE6__pipeE" }
26+
// CHECK: attributes #[[HPFLOAT_ATTRS]] = { "sycl-unique-id"="THE_PREFIX____ZN4sycl3_V13ext5intel12experimental9host_pipeIZZZ3foovENKUlRNS0_7handlerEE_clES6_ENKUlvE_clEvE7HPFloatiE6__pipeE"
27+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -triple spir64-unknown-unknown -fsycl-int-footer=%t.footer.h -fsycl-int-header=%t.header.h -fsycl-unique-prefix=THE_PREFIX %s -emit-llvm -o %t.ll
2+
// RUN: FileCheck -input-file=%t.footer.h %s --check-prefix=CHECK-FOOTER
3+
// RUN: FileCheck -input-file=%t.header.h %s --check-prefix=CHECK-HEADER
4+
#include "sycl.hpp"
5+
6+
// Test cases below show that 'sycl-unique-id' LLVM IR attribute is attached to the
7+
// global variable whose type is decorated with host_pipe attribute, and that a
8+
// unique string is generated.
9+
10+
using namespace sycl::ext::intel::experimental;
11+
using namespace sycl;
12+
queue q;
13+
14+
void foo() {
15+
q.submit([&](handler &h) {
16+
h.single_task<class kernel_name_1>([=]() {
17+
host_pipe<class HPInt, int>::read();
18+
host_pipe<class HPFloat, int>::read();
19+
});
20+
});
21+
}
22+
23+
// CHECK-HEADER: namespace sycl {
24+
// CHECK-HEADER-NEXT: __SYCL_INLINE_VER_NAMESPACE(_V1) {
25+
// CHECK-HEADER-NEXT: namespace detail {
26+
// CHECK-HEADER-NEXT: namespace {
27+
// CHECK-HEADER-NEXT: class __sycl_host_pipe_registration {
28+
// CHECK-HEADER-NEXT: public:
29+
// CHECK-HEADER-NEXT: __sycl_host_pipe_registration() noexcept;
30+
// CHECK-HEADER-NEXT: };
31+
// CHECK-HEADER-NEXT: __sycl_host_pipe_registration __sycl_host_pipe_registrar;
32+
// CHECK-HEADER-NEXT: } // namespace
33+
// CHECK-HEADER: } // namespace detail
34+
// CHECK-HEADER: } // __SYCL_INLINE_VER_NAMESPACE(_V1)
35+
// CHECK-HEADER: } // namespace sycl
36+
37+
// CHECK-FOOTER: #include <sycl/detail/defines_elementary.hpp>
38+
// CHECK-FOOTER: #include <sycl/detail/host_pipe_map.hpp>
39+
// CHECK-FOOTER-NEXT: namespace sycl::detail {
40+
// CHECK-FOOTER-NEXT: namespace {
41+
// CHECK-FOOTER-NEXT: __sycl_host_pipe_registration::__sycl_host_pipe_registration() noexcept {
42+
43+
// CHECK-FOOTER: host_pipe_map::add((void *)&::sycl::ext::intel::experimental::host_pipe<HPInt, int>::__pipe, "THE_PREFIX____ZN4sycl3_V13ext5intel12experimental9host_pipeIZZZ3foovENKUlRNS0_7handlerEE_clES6_ENKUlvE_clEvE5HPIntiE6__pipeE");
44+
// CHECK-FOOTER: host_pipe_map::add((void *)&::sycl::ext::intel::experimental::host_pipe<HPFloat, int>::__pipe, "THE_PREFIX____ZN4sycl3_V13ext5intel12experimental9host_pipeIZZZ3foovENKUlRNS0_7handlerEE_clES6_ENKUlvE_clEvE7HPFloatiE6__pipeE");
45+
46+
// CHECK-FOOTER: } // namespace (unnamed)
47+
// CHECK-FOOTER: } // namespace sycl::detail
48+

llvm/include/llvm/SYCLLowerIR/SYCLUtils.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "llvm/ADT/STLExtras.h"
1313
#include "llvm/ADT/SmallPtrSet.h"
1414
#include "llvm/IR/Function.h"
15+
#include "llvm/IR/GlobalVariable.h"
1516
#include "llvm/IR/Instructions.h"
1617
#include "llvm/IR/Operator.h"
1718

@@ -21,6 +22,7 @@ namespace llvm {
2122
namespace sycl {
2223
namespace utils {
2324
constexpr char ATTR_SYCL_MODULE_ID[] = "sycl-module-id";
25+
constexpr StringRef SYCL_HOST_PIPE_ATTR = "sycl-host-pipe";
2426

2527
using CallGraphNodeAction = ::std::function<void(Function *)>;
2628
using CallGraphFunctionFilter =
@@ -115,6 +117,10 @@ inline bool isSYCLExternalFunction(const Function *F) {
115117
return F->hasFnAttribute(ATTR_SYCL_MODULE_ID);
116118
}
117119

120+
inline bool isHostPipeVariable(const GlobalVariable &GV) {
121+
return GV.hasAttribute(SYCL_HOST_PIPE_ATTR);
122+
}
123+
118124
} // namespace utils
119125
} // namespace sycl
120126
} // namespace llvm

llvm/lib/SYCLLowerIR/CompileTimePropertiesPass.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "llvm/SYCLLowerIR/CompileTimePropertiesPass.h"
1212
#include "llvm/SYCLLowerIR/DeviceGlobals.h"
13+
#include "llvm/SYCLLowerIR/SYCLUtils.h"
1314

1415
#include "llvm/ADT/APInt.h"
1516
#include "llvm/ADT/StringMap.h"
@@ -266,6 +267,13 @@ PreservedAnalyses CompileTimePropertiesPass::run(Module &M,
266267
HostAccessDecorValue, VarName));
267268
}
268269

270+
if (sycl::utils::isHostPipeVariable(GV)) {
271+
auto VarName = getGlobalVariableUniqueId(GV);
272+
MDOps.push_back(buildSpirvDecorMetadata(Ctx, SPIRV_HOST_ACCESS_DECOR,
273+
SPIRV_HOST_ACCESS_DEFAULT_VALUE,
274+
VarName));
275+
}
276+
269277
// Add the generated metadata to the variable
270278
if (!MDOps.empty()) {
271279
GV.addMetadata(MDKindID, *MDNode::get(Ctx, MDOps));
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
; RUN: opt -passes=compile-time-properties %s -S | FileCheck %s --check-prefix CHECK-IR
2+
3+
; This test is intended to check that CompileTimePropertiesPass adds all the required
4+
; metadata nodes to host pipe vars decorated with the "sycl-host-pipe" attribute
5+
6+
source_filename = "basic.cpp"
7+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
8+
target triple = "spir64_fpga-unknown-unknown"
9+
10+
%struct.BasicKernel = type { i8 }
11+
12+
$_ZN4sycl3_V13ext5intel12experimental9host_pipeI9D2HPipeIDiNS1_6oneapi12experimental10propertiesISt5tupleIJEEEEE6__pipeE = comdat any
13+
14+
@_ZN4sycl3_V13ext5intel12experimental9host_pipeI9D2HPipeIDiNS1_6oneapi12experimental10propertiesISt5tupleIJEEEEE6__pipeE = linkonce_odr dso_local addrspace(1) constant %struct.BasicKernel zeroinitializer, comdat, align 1 #0
15+
; CHECK-IR: @_ZN4sycl3_V13ext5intel12experimental9host_pipeI9D2HPipeIDiNS1_6oneapi12experimental10propertiesISt5tupleIJEEEEE6__pipeE = linkonce_odr dso_local addrspace(1) constant %struct.BasicKernel zeroinitializer, comdat, align 1, !spirv.Decorations ![[#MN0:]]
16+
17+
attributes #0 = { "sycl-host-pipe" "sycl-unique-id"="_ZN4sycl3_V13ext5intel12experimental9host_pipeI9H2DPipeIDiNS1_6oneapi12experimental10propertiesISt5tupleIJEEEEE6__pipeE" }
18+
19+
; Ensure that the generated metadata nodes are correct
20+
; CHECK-IR-DAG: ![[#MN0]] = !{![[#MN1:]]}
21+
; CHECK-IR-DAG: ![[#MN1]] = !{i32 6147, i32 2, !"_ZN4sycl3_V13ext5intel12experimental9host_pipeI9H2DPipeIDiNS1_6oneapi12experimental10propertiesISt5tupleIJEEEEE6__pipeE"}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//==-------------------- host_pipe_map.hpp -----------------------------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#pragma once
10+
11+
namespace sycl {
12+
__SYCL_INLINE_VER_NAMESPACE(_V1) {
13+
namespace detail {
14+
namespace host_pipe_map {
15+
16+
__SYCL_EXPORT void add(const void *HostPipePtr, const char *UniqueId);
17+
18+
} // namespace host_pipe_map
19+
} // namespace detail
20+
} // __SYCL_INLINE_VER_NAMESPACE(_V1)
21+
} // namespace sycl

0 commit comments

Comments
 (0)