Skip to content

Commit abb7f65

Browse files
committed
Removing Manifest from the offload binary structure.
1 parent 2af08ff commit abb7f65

File tree

17 files changed

+659
-157
lines changed

17 files changed

+659
-157
lines changed

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10097,8 +10097,13 @@ void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA,
1009710097
// clang-offload-wrapper
1009810098
// -o=<outputfile>.bc
1009910099
// -host=x86_64-pc-linux-gnu -kind=sycl
10100+
#ifndef __INTEL_PREVIEW_BREAKING_CHANGES
1010010101
// -format=spirv <inputfile1>.spv <manifest1>(optional)
1010110102
// -format=spirv <inputfile2>.spv <manifest2>(optional)
10103+
#else
10104+
// -format=spirv <inputfile1>.spv
10105+
// -format=spirv <inputfile2>.spv
10106+
#endif
1010210107
// ...
1010310108
ArgStringList WrapperArgs;
1010410109

@@ -10163,6 +10168,9 @@ void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA,
1016310168
WrapperArgs.push_back(
1016410169
C.getArgs().MakeArgString(Twine("-kind=") + Twine(Kind)));
1016510170

10171+
if (C.getArgs().hasArg(options::OPT_fpreview_breaking_changes))
10172+
WrapperArgs.push_back("-fpreview-breaking-changes");
10173+
1016610174
assert((Inputs.size() > 0) && "no inputs for clang-offload-wrapper");
1016710175
assert(((Inputs[0].getType() != types::TY_Tempfiletable) ||
1016810176
(Inputs.size() == 1)) &&
@@ -11580,6 +11588,9 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
1158011588
Args.MakeArgString("--wrapper-jobs=" + Twine(NumThreads)));
1158111589
}
1158211590

11591+
if (Args.hasArg(options::OPT_fpreview_breaking_changes))
11592+
CmdArgs.push_back("-fpreview-breaking-changes");
11593+
1158311594
const char *Exec =
1158411595
Args.MakeArgString(getToolChain().GetProgramPath("clang-linker-wrapper"));
1158511596

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
// REQUIRES: system-linux || system-windows
2+
3+
// End-to-end clang-offload-wrapper executable test: check that -batch options
4+
// works, and that the tool generates data properly accessible at runtime.
5+
6+
// --- Prepare test data
7+
// - create the first binary image
8+
// RUN: echo -e -n 'device binary image1\n' > %t.bin
9+
// RUN: echo -e -n '[Category1]\nint_prop1=1|10\n[Category2]\nint_prop2=1|20\n' > %t.props
10+
// RUN: echo -e -n 'kernel1\nkernel2\n' > %t.sym
11+
12+
// - create the second binary image with byte array property values
13+
// RUN: echo -e -n 'device binary image2\n' > %t_1.bin
14+
// RUN: echo -e -n '[Category3]\n' > %t_1.props
15+
// RUN: echo -e -n 'kernel1=2|IAAAAAAAAAQA\n' >> %t_1.props
16+
// RUN: echo -e -n 'kernel2=2|oAAAAAAAAAw///3/wB\n' >> %t_1.props
17+
18+
// - create the batch file input for the wrapper
19+
// RUN: echo '[Code|Properties|Symbols]' > %t.batch
20+
// RUN: echo %t.bin"|"%t.props"|"%t.sym >> %t.batch
21+
// RUN: echo %t_1.bin"|"%t_1.props"|" >> %t.batch
22+
// --- Generate "gold" output
23+
// RUN: cat %t.bin %t.props %t.sym > %t.all
24+
// --- Create the wrapper object
25+
// -host omitted - generate object for the host triple:
26+
#ifdef __INTEL_PREVIEW_BREAKING_CHANGES
27+
/// TODO: Remove -fpreview-breaking-changes from the command line, when removing the macro
28+
// RUN: clang-offload-wrapper -kind=sycl -target=TARGET -format=native -batch %t.batch -o %t.wrapped.bc -fpreview-breaking-changes
29+
#endif // __INTEL_PREVIEW_BREAKING_CHANGES
30+
// RUN: llc --filetype=obj %t.wrapped.bc -o %t.wrapped.o
31+
// --- Compile & link the test with the wrapper
32+
// RUN: %clangxx %t.wrapped.o %s -o %t.batch.exe -v
33+
// --- Run and check ignoring white spaces
34+
// RUN: %t.batch.exe > %t.batch.exe.out
35+
// RUN: diff -b %t.batch.exe.out %t.all
36+
37+
#include <cassert>
38+
#include <cstdint>
39+
#include <cstring>
40+
#include <iostream>
41+
#include <string>
42+
43+
// Data types created by the offload wrapper and inserted in the wrapper object.
44+
// Match those defined in SYCL runtime Plugin Interface.
45+
struct _pi_offload_entry_struct {
46+
void *addr;
47+
char *name;
48+
size_t size;
49+
int32_t flags;
50+
int32_t reserved;
51+
};
52+
53+
typedef _pi_offload_entry_struct *_pi_offload_entry;
54+
55+
struct _pi_device_binary_property_struct {
56+
char *Name; // null-terminated property name
57+
void *ValAddr; // address of property value
58+
uint32_t Type; // pi_property_type
59+
uint64_t ValSize; // size of property value in bytes
60+
};
61+
62+
typedef _pi_device_binary_property_struct *pi_device_binary_property;
63+
64+
struct _pi_device_binary_property_set_struct {
65+
char *Name; // the name
66+
pi_device_binary_property PropertiesBegin; // array start
67+
pi_device_binary_property PropertiesEnd; // array end
68+
};
69+
70+
typedef _pi_device_binary_property_set_struct *pi_device_binary_property_set;
71+
72+
struct pi_device_binary_struct {
73+
uint16_t Version;
74+
uint8_t Kind; // 4 for SYCL
75+
uint8_t Format; // 1 for native
76+
const char *DeviceTargetSpec;
77+
const char *CompileOptions;
78+
const char *LinkOptions;
79+
const unsigned char *BinaryStart;
80+
const unsigned char *BinaryEnd;
81+
_pi_offload_entry EntriesBegin;
82+
_pi_offload_entry EntriesEnd;
83+
pi_device_binary_property_set PropertySetsBegin;
84+
pi_device_binary_property_set PropertySetsEnd;
85+
};
86+
typedef pi_device_binary_struct *pi_device_binary;
87+
88+
struct pi_device_binaries_struct {
89+
uint16_t Version;
90+
uint16_t NumDeviceBinaries;
91+
pi_device_binary DeviceBinaries;
92+
_pi_offload_entry *HostEntriesBegin;
93+
_pi_offload_entry *HostEntriesEnd;
94+
};
95+
typedef pi_device_binaries_struct *pi_device_binaries;
96+
97+
static pi_device_binaries BinDesc = nullptr;
98+
99+
// Wrapper object has code which calls these 2 functions below
100+
extern "C" void __sycl_register_lib(pi_device_binaries desc) {
101+
BinDesc = desc;
102+
}
103+
104+
extern "C" void __sycl_unregister_lib() {}
105+
106+
#define ASSERT(Cond, Msg) \
107+
if (!(Cond)) { \
108+
std::cerr << "*** ERROR: wrong " << Msg << "\n"; \
109+
return 1; \
110+
}
111+
112+
static std::string getString(const unsigned char *B, const unsigned char *E) {
113+
return std::string(reinterpret_cast<const char *>(B), E - B);
114+
}
115+
116+
static int getInt(void *Addr) {
117+
const char *Ptr = reinterpret_cast<const char *>(Addr);
118+
return Ptr[0] | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24);
119+
}
120+
121+
using byte = unsigned char;
122+
123+
static void printProp(const pi_device_binary_property &Prop) {
124+
std::cerr << "Property " << Prop->Name << " {\n";
125+
std::cerr << " Type: " << Prop->Type << "\n";
126+
if (Prop->Type != 1)
127+
std::cerr << " Size = " << Prop->ValSize << "\n";
128+
129+
std::cerr << " Value = ";
130+
if (Prop->Type == 1)
131+
std::cerr << getInt(&Prop->ValSize);
132+
else {
133+
std::cerr << " {\n ";
134+
135+
byte *Ptr = (byte *)Prop->ValAddr;
136+
137+
for (auto I = 0; I < Prop->ValSize && I < 100; ++I) {
138+
std::cerr << " 0x" << std::hex << (unsigned int)Ptr[I];
139+
std::cerr << std::dec;
140+
}
141+
std::cerr << "\n }";
142+
}
143+
std::cerr << "\n";
144+
std::cerr << "}\n";
145+
}
146+
147+
static int dumpBinary0() {
148+
pi_device_binary Bin = &BinDesc->DeviceBinaries[0];
149+
ASSERT(Bin->Kind == 4, "Bin->Kind");
150+
ASSERT(Bin->Format == 1, "Bin->Format");
151+
152+
// dump code
153+
std::cout << getString(Bin->BinaryStart, Bin->BinaryEnd);
154+
// dump properties
155+
for (pi_device_binary_property_set PropSet = Bin->PropertySetsBegin; PropSet != Bin->PropertySetsEnd; ++PropSet) {
156+
std::cout << "[" << PropSet->Name << "]"
157+
<< "\n";
158+
159+
for (pi_device_binary_property Prop = PropSet->PropertiesBegin; Prop != PropSet->PropertiesEnd; ++Prop) {
160+
ASSERT(Prop->Type == 1, "Prop->Type");
161+
std::cout << Prop->Name << "=" << Prop->Type << "|" << getInt(&Prop->ValSize) << "\n";
162+
}
163+
}
164+
// dump symbols
165+
for (_pi_offload_entry Entry = Bin->EntriesBegin; Entry != Bin->EntriesEnd; ++Entry)
166+
std::cout << Entry->name << "\n";
167+
return 0;
168+
}
169+
170+
// Clang offload wrapper does Base64 decoding on byte array property values, so
171+
// they can't be dumped as is and compared to the original. Instead, this
172+
// testcase checks that the byte array in the property value is equal to the
173+
// pre-decoded byte array.
174+
static int checkBinary1() {
175+
// Decoded from "IAAAAAAAAAQA":
176+
const byte Arr0[] = {8, 0, 0, 0, 0, 0, 0, 0, 0x1};
177+
// Decoded from "oAAAAAAAAAw///3/wB":
178+
const byte Arr1[] = {40, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0x7F, 0xFF, 0x70};
179+
180+
struct {
181+
const byte *Ptr;
182+
const size_t Size;
183+
} GoldArrays[] = {
184+
{Arr0, sizeof(Arr0)},
185+
{Arr1, sizeof(Arr1)}};
186+
pi_device_binary Bin = &BinDesc->DeviceBinaries[1];
187+
ASSERT(Bin->Kind == 4, "Bin->Kind");
188+
ASSERT(Bin->Format == 1, "Bin->Format");
189+
190+
for (pi_device_binary_property_set PropSet = Bin->PropertySetsBegin; PropSet != Bin->PropertySetsEnd; ++PropSet) {
191+
int Cnt = 0;
192+
193+
for (pi_device_binary_property Prop = PropSet->PropertiesBegin; Prop != PropSet->PropertiesEnd; ++Prop, ++Cnt) {
194+
ASSERT(Prop->Type == 2, "Prop->Type"); // must be a byte array
195+
char *Ptr = reinterpret_cast<char *>(Prop->ValAddr);
196+
int Cmp = std::memcmp(Prop->ValAddr, GoldArrays[Cnt].Ptr, GoldArrays[Cnt].Size);
197+
ASSERT(Cmp == 0, "byte array property");
198+
}
199+
}
200+
return 0;
201+
}
202+
203+
int main(int argc, char **argv) {
204+
ASSERT(BinDesc->NumDeviceBinaries == 2, "BinDesc->NumDeviceBinaries");
205+
ASSERT(BinDesc->Version == 1, "BinDesc->Version");
206+
207+
if (dumpBinary0() != 0)
208+
return 1;
209+
if (checkBinary1() != 0)
210+
return 1;
211+
return 0;
212+
}

clang/test/Driver/clang-offload-wrapper-exe.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
// End-to-end clang-offload-wrapper executable test: check that -batch options
44
// works, and that the tool generates data properly accessible at runtime.
55

6+
#ifdef __INTEL_PREVIEW_BREAKING_CHANGES
7+
/// TODO: Delete this test when the preview changes are enabled by default.
8+
/// Rename clang-offload-wrapper-exe-preview.cpp to clang-offload-wrapper-exe.cpp
9+
#endif // __INTEL_PREVIEW_BREAKING_CHANGES
10+
611
// --- Prepare test data
712
// - create the first binary image
813
// RUN: echo -e -n 'device binary image1\n' > %t.bin

clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ static cl::opt<std::string> PassPipeline(
121121
static cl::alias PassPipeline2("p", cl::aliasopt(PassPipeline),
122122
cl::desc("Alias for -passes"));
123123

124+
static cl::opt<bool>
125+
PreviewBreakingChanges("fpreview-breaking-changes",
126+
cl::desc("Enable preview breaking changes"),
127+
cl::init(false), cl::Hidden);
128+
124129
/// Path of the current binary.
125130
static const char *LinkerExecutable;
126131

@@ -303,7 +308,6 @@ Expected<StringRef> writeOffloadFile(const OffloadFile &File,
303308

304309
StringRef Prefix =
305310
sys::path::stem(Binary.getMemoryBufferRef().getBufferIdentifier());
306-
StringRef Suffix = getImageKindName(Binary.getImageKind());
307311

308312
StringRef BinArch = (Binary.getArch() == "*") ? "any" : Binary.getArch();
309313
auto TempFileOrErr = createOutputFile(
@@ -1129,7 +1133,8 @@ wrapSYCLBinariesFromFile(std::vector<module_split::SplitModule> &SplitModules,
11291133
errs() << formatv(" offload-wrapper: compile-opts: {0}, link-opts: {1}\n",
11301134
CompileOptions, LinkOptions);
11311135
}
1132-
if (Error E = offloading::wrapSYCLBinaries(M, Images, WrappingOptions))
1136+
if (Error E = offloading::wrapSYCLBinaries(M, Images, WrappingOptions,
1137+
PreviewBreakingChanges))
11331138
return E;
11341139

11351140
if (Args.hasArg(OPT_print_wrapped_module))

0 commit comments

Comments
 (0)