Skip to content

Commit 3b4de41

Browse files
committed
Merge branches 'dummy-image-runtime' and 'dummy-images' into HEAD
3 parents 026ee74 + 0bb5394 + befd24b commit 3b4de41

File tree

7 files changed

+248
-21
lines changed

7 files changed

+248
-21
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
; RUN: sycl-post-link -split=auto -properties -S < %s -o %t.table
2+
; RUN: FileCheck %s --input-file=%t.table --check-prefix=CHECK-TABLE
3+
; RUN: FileCheck %s --input-file=%t_0.ll --check-prefix=CHECK-FP64-SPLIT
4+
; RUN: FileCheck %s --input-file=%t_1.ll --check-prefix=CHECK-FP64-DUMMY
5+
; RUN: FileCheck %s --input-file=%t_1.prop --check-prefix=CHECK-FP64-DUMMY-PROPS
6+
; RUN: FileCheck %s --input-file=%t_2.ll --check-prefix=CHECK-FP32-SPLIT
7+
8+
; CHECK-TABLE: _0.prop
9+
; CHECK-TABLE-NEXT: _1.prop
10+
; CHECK-TABLE-NEXT: _2.prop
11+
12+
; CHECK-FP64-SPLIT: define spir_func void @bar()
13+
; CHECK-FP32-SPLIT: define spir_func void @foo()
14+
15+
; CHECK-FP64-DUMMY: define spir_func void @bar()
16+
; CHECK-FP64-DUMMY-NEXT: entry:
17+
; CHECK-FP64-DUMMY-NEXT: ret void
18+
19+
; CHECK-FP64-DUMMY-PROPS: dummy=1
20+
21+
define spir_func void @foo() #1 {
22+
%x = alloca float
23+
ret void
24+
}
25+
26+
define spir_func void @bar() #1 !sycl_used_aspects !1 {
27+
%x = alloca double
28+
%d = load double, ptr %x
29+
%res = fadd double %d, %d
30+
ret void
31+
}
32+
33+
attributes #1 = { "sycl-module-id"="v.cpp" "indirectly-callable"="setA" }
34+
35+
!sycl_aspects = !{!0}
36+
!0 = !{!"fp64", i32 6}
37+
!1 = !{i32 6}

llvm/tools/sycl-post-link/sycl-post-link.cpp

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,8 @@ std::string saveModuleIR(Module &M, int I, StringRef Suff) {
305305

306306
std::string saveModuleProperties(module_split::ModuleDesc &MD,
307307
const GlobalBinImageProps &GlobProps, int I,
308-
StringRef Suff, StringRef Target = "") {
308+
StringRef Suff, StringRef Target = "",
309+
bool IsDummy = false) {
309310
auto PropSet =
310311
computeModuleProperties(MD.getModule(), MD.entries(), GlobProps);
311312

@@ -317,6 +318,10 @@ std::string saveModuleProperties(module_split::ModuleDesc &MD,
317318
NewSuff += Target;
318319
}
319320

321+
if (IsDummy) {
322+
PropSet.add(PropSetRegTy::SYCL_VIRTUAL_FUNCTIONS, "dummy", 1);
323+
}
324+
320325
std::error_code EC;
321326
std::string SCFile = makeResultFileName(".prop", I, NewSuff);
322327
raw_fd_ostream SCOut(SCFile, EC);
@@ -415,7 +420,8 @@ void addTableRow(util::SimpleTable &Table,
415420
// IR component saving is skipped, and this file name is recorded as such in
416421
// the result.
417422
void saveModule(std::vector<std::unique_ptr<util::SimpleTable>> &OutTables,
418-
module_split::ModuleDesc &MD, int I, StringRef IRFilename) {
423+
module_split::ModuleDesc &MD, int I, StringRef IRFilename,
424+
bool IsDummy = false) {
419425
IrPropSymFilenameTriple BaseTriple;
420426
StringRef Suffix = getModuleSuffix(MD);
421427
MD.saveSplitInformationAsMetadata();
@@ -439,8 +445,8 @@ void saveModule(std::vector<std::unique_ptr<util::SimpleTable>> &OutTables,
439445
GlobalBinImageProps Props = {EmitKernelParamInfo, EmitProgramMetadata,
440446
EmitExportedSymbols, EmitImportedSymbols,
441447
DeviceGlobals};
442-
CopyTriple.Prop =
443-
saveModuleProperties(MD, Props, I, Suffix, OutputFile.Target);
448+
CopyTriple.Prop = saveModuleProperties(MD, Props, I, Suffix,
449+
OutputFile.Target, IsDummy);
444450
}
445451
addTableRow(*Table, CopyTriple);
446452
}
@@ -740,6 +746,36 @@ bool isTargetCompatibleWithModule(const std::string &Target,
740746
return true;
741747
}
742748

749+
std::optional<module_split::ModuleDesc>
750+
makeDummy(module_split::ModuleDesc &MD) {
751+
bool hasVirtualFunctions = false;
752+
bool hasOptionalKernelFeatures = false;
753+
for (Function &F : MD.getModule().functions()) {
754+
if (F.hasFnAttribute("indirectly-callable"))
755+
hasVirtualFunctions = true;
756+
if (F.getMetadata("sycl_used_aspects"))
757+
hasOptionalKernelFeatures = true;
758+
if (hasVirtualFunctions && hasOptionalKernelFeatures)
759+
break;
760+
}
761+
if (!hasVirtualFunctions || !hasOptionalKernelFeatures)
762+
return {};
763+
764+
auto MDCopy = MD.clone();
765+
766+
for (Function &F : MDCopy.getModule().functions()) {
767+
if (!F.hasFnAttribute("indirectly-callable"))
768+
continue;
769+
770+
F.erase(F.begin(), F.end());
771+
BasicBlock *newBB = BasicBlock::Create(F.getContext(), "entry", &F);
772+
IRBuilder<> builder(newBB);
773+
builder.CreateRetVoid();
774+
}
775+
776+
return MDCopy;
777+
}
778+
743779
std::vector<std::unique_ptr<util::SimpleTable>>
744780
processInputModule(std::unique_ptr<Module> M) {
745781
// Construct the resulting table which will accumulate all the outputs.
@@ -887,6 +923,16 @@ processInputModule(std::unique_ptr<Module> M) {
887923

888924
++ID;
889925
}
926+
927+
bool dummyEmitted = false;
928+
for (module_split::ModuleDesc &IrMD : MMs) {
929+
if (auto Dummy = makeDummy(IrMD)) {
930+
saveModule(Tables, *Dummy, ID, OutIRFileName, /*IsDummy*/ true);
931+
dummyEmitted = true;
932+
}
933+
}
934+
if (dummyEmitted)
935+
++ID;
890936
}
891937
return Tables;
892938
}

sycl/source/detail/device_binary_image.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ std::ostream &operator<<(std::ostream &Out, const DeviceBinaryProperty &P) {
5252
break;
5353
}
5454
case SYCL_PROPERTY_TYPE_STRING:
55-
Out << P.asCString();
55+
Out << P.asStringView();
5656
break;
5757
default:
5858
assert(false && "Unsupported property");
@@ -77,14 +77,14 @@ ByteArray DeviceBinaryProperty::asByteArray() const {
7777
return {Data, Prop->ValSize};
7878
}
7979

80-
const char *DeviceBinaryProperty::asCString() const {
80+
std::string_view DeviceBinaryProperty::asStringView() const {
8181
assert((Prop->Type == SYCL_PROPERTY_TYPE_STRING ||
8282
Prop->Type == SYCL_PROPERTY_TYPE_BYTE_ARRAY) &&
8383
"property type mismatch");
8484
assert(Prop->ValSize > 0 && "property size mismatch");
8585
// Byte array stores its size in first 8 bytes
8686
size_t Shift = Prop->Type == SYCL_PROPERTY_TYPE_BYTE_ARRAY ? 8 : 0;
87-
return ur::cast<const char *>(Prop->ValAddr) + Shift;
87+
return {ur::cast<const char *>(Prop->ValAddr) + Shift, Prop->ValSize};
8888
}
8989

9090
void RTDeviceBinaryImage::PropertyRange::init(sycl_device_binary Bin,

sycl/source/detail/device_binary_image.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class DeviceBinaryProperty {
7373

7474
uint32_t asUint32() const;
7575
ByteArray asByteArray() const;
76-
const char *asCString() const;
76+
std::string_view asStringView() const;
7777

7878
protected:
7979
friend std::ostream &operator<<(std::ostream &Out,

sycl/source/detail/program_manager/program_manager.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -676,10 +676,11 @@ ProgramManager::collectDependentDeviceImagesForVirtualFunctions(
676676
std::set<std::string> HandledSets;
677677
std::queue<std::string> WorkList;
678678
for (const sycl_device_binary_property &VFProp : Img.getVirtualFunctions()) {
679-
std::string StrValue = DeviceBinaryProperty(VFProp).asCString();
679+
std::string_view StrValue = DeviceBinaryProperty(VFProp).asStringView();
680680
// Device image passed to this function is expected to contain SYCL kernels
681681
// and therefore it may only use virtual function sets, but cannot provide
682-
// them. We expect to see just a single property here
682+
// them. Additionally, it cannot be a dummy image.
683+
// We expect to see just a single property here
683684
assert(std::string(VFProp->Name) == "uses-virtual-functions-set" &&
684685
"Unexpected virtual function property");
685686
for (const auto &SetName : detail::split_string(StrValue, ',')) {
@@ -700,22 +701,38 @@ ProgramManager::collectDependentDeviceImagesForVirtualFunctions(
700701
// virtual-functions-set properties, but their handling is the same: we
701702
// just grab all sets they reference and add them for consideration if
702703
// we haven't done so already.
704+
bool isDummyImage = false;
703705
for (const sycl_device_binary_property &VFProp :
704706
BinImage->getVirtualFunctions()) {
705-
std::string StrValue = DeviceBinaryProperty(VFProp).asCString();
707+
if (VFProp->Name == std::string_view("dummy-image")) {
708+
isDummyImage = true;
709+
continue;
710+
}
711+
std::string_view StrValue = DeviceBinaryProperty(VFProp).asStringView();
706712
for (const auto &SetName : detail::split_string(StrValue, ',')) {
707713
if (HandledSets.insert(SetName).second)
708714
WorkList.push(SetName);
709715
}
710716
}
711717

712-
// TODO: Complete this part about handling of incompatible device images.
713718
// If device image uses the same virtual function set, then we only
714719
// link it if it is compatible.
715720
// However, if device image provides virtual function set and it is
716721
// incompatible, then we should link its "dummy" version to avoid link
717722
// errors about unresolved external symbols.
718-
if (doesDevSupportDeviceRequirements(Dev, *BinImage))
723+
// Note: we only link when exactly one of
724+
// doesDevSupportDeviceRequirements(Dev, *BinImage) and
725+
// isDummyImage is true. We don't want to link every dummy image,
726+
// otherwise we could run into linking errors defining the same symbol
727+
// multiple times. For every image providing virtual functions that has
728+
// a dummy image, the dummy image will have the same device requirements
729+
// as the original image. So when the dummy image does support the
730+
// device requirements, we know that the corresponding image providing
731+
// actual definitions will be linked and not the dummy. And vice versa:
732+
// when the dummy image does not support the device requirements, we
733+
// know the corresponding image providing virtual functions was not
734+
// linked and we must link the dummy image.
735+
if (doesDevSupportDeviceRequirements(Dev, *BinImage) + isDummyImage == 1)
719736
DeviceImagesToLink.insert(BinImage);
720737
}
721738
}
@@ -1773,7 +1790,9 @@ void ProgramManager::addImages(sycl_device_binaries DeviceBinary) {
17731790
// Record mapping between virtual function sets and device images
17741791
for (const sycl_device_binary_property &VFProp :
17751792
Img->getVirtualFunctions()) {
1776-
std::string StrValue = DeviceBinaryProperty(VFProp).asCString();
1793+
if (VFProp->Name == std::string_view("dummy-image"))
1794+
continue;
1795+
std::string_view StrValue = DeviceBinaryProperty(VFProp).asStringView();
17771796
for (const auto &SetName : detail::split_string(StrValue, ','))
17781797
m_VFSet2BinImage[SetName].insert(Img.get());
17791798
}

0 commit comments

Comments
 (0)