1 /*
2  * Copyright (C) 2018-2021 Intel Corporation
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  */
7 
8 #include "shared/source/helpers/string.h"
9 #include "shared/source/memory_manager/allocations_list.h"
10 #include "shared/source/memory_manager/graphics_allocation.h"
11 #include "shared/source/memory_manager/unified_memory_manager.h"
12 #include "shared/source/program/program_info_from_patchtokens.h"
13 #include "shared/test/common/helpers/debug_manager_state_restore.h"
14 #include "shared/test/common/mocks/mock_csr.h"
15 #include "shared/test/common/mocks/mock_execution_environment.h"
16 #include "shared/test/common/mocks/mock_memory_manager.h"
17 #include "shared/test/common/test_macros/test.h"
18 #include "shared/test/unit_test/compiler_interface/linker_mock.h"
19 #include "shared/test/unit_test/device_binary_format/patchtokens_tests.h"
20 
21 #include "opencl/source/platform/platform.h"
22 #include "opencl/source/program/program.h"
23 #include "opencl/test/unit_test/mocks/mock_buffer.h"
24 #include "opencl/test/unit_test/mocks/mock_cl_device.h"
25 #include "opencl/test/unit_test/mocks/mock_program.h"
26 #include "opencl/test/unit_test/program/program_with_source.h"
27 
28 using namespace NEO;
29 
30 using namespace iOpenCL;
31 static const char constValue[] = "11223344";
32 static const char globalValue[] = "55667788";
33 
34 class ProgramDataTestBase : public testing::Test,
35                             public ContextFixture,
36                             public PlatformFixture,
37                             public ProgramFixture {
38 
39     using ContextFixture::SetUp;
40     using PlatformFixture::SetUp;
41 
42   public:
ProgramDataTestBase()43     ProgramDataTestBase() {
44         memset(&programBinaryHeader, 0x00, sizeof(SProgramBinaryHeader));
45         pCurPtr = nullptr;
46         pProgramPatchList = nullptr;
47         programPatchListSize = 0;
48     }
49 
50     void buildAndDecodeProgramPatchList();
51 
SetUp()52     void SetUp() override {
53         PlatformFixture::SetUp();
54         pClDevice = pPlatform->getClDevice(0);
55         rootDeviceIndex = pClDevice->getRootDeviceIndex();
56         cl_device_id device = pClDevice;
57 
58         ContextFixture::SetUp(1, &device);
59         ProgramFixture::SetUp();
60 
61         CreateProgramWithSource(
62             pContext,
63             "CopyBuffer_simd16.cl");
64     }
65 
TearDown()66     void TearDown() override {
67         knownSource.reset();
68         ProgramFixture::TearDown();
69         ContextFixture::TearDown();
70         PlatformFixture::TearDown();
71     }
72 
setupConstantAllocation()73     size_t setupConstantAllocation() {
74         size_t constSize = strlen(constValue) + 1;
75 
76         EXPECT_EQ(nullptr, pProgram->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex()));
77 
78         SPatchAllocateConstantMemorySurfaceProgramBinaryInfo allocateConstMemorySurface;
79         allocateConstMemorySurface.Token = PATCH_TOKEN_ALLOCATE_CONSTANT_MEMORY_SURFACE_PROGRAM_BINARY_INFO;
80         allocateConstMemorySurface.Size = static_cast<uint32_t>(sizeof(SPatchAllocateConstantMemorySurfaceProgramBinaryInfo));
81 
82         allocateConstMemorySurface.ConstantBufferIndex = 0;
83         allocateConstMemorySurface.InlineDataSize = static_cast<uint32_t>(constSize);
84 
85         pAllocateConstMemorySurface.reset(new cl_char[allocateConstMemorySurface.Size + constSize]);
86 
87         memcpy_s(pAllocateConstMemorySurface.get(),
88                  sizeof(SPatchAllocateConstantMemorySurfaceProgramBinaryInfo),
89                  &allocateConstMemorySurface,
90                  sizeof(SPatchAllocateConstantMemorySurfaceProgramBinaryInfo));
91 
92         memcpy_s((cl_char *)pAllocateConstMemorySurface.get() + sizeof(allocateConstMemorySurface), constSize, constValue, constSize);
93 
94         pProgramPatchList = (void *)pAllocateConstMemorySurface.get();
95         programPatchListSize = static_cast<uint32_t>(allocateConstMemorySurface.Size + constSize);
96         return constSize;
97     }
98 
setupGlobalAllocation()99     size_t setupGlobalAllocation() {
100         size_t globalSize = strlen(globalValue) + 1;
101 
102         EXPECT_EQ(nullptr, pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex()));
103 
104         SPatchAllocateGlobalMemorySurfaceProgramBinaryInfo allocateGlobalMemorySurface;
105         allocateGlobalMemorySurface.Token = PATCH_TOKEN_ALLOCATE_GLOBAL_MEMORY_SURFACE_PROGRAM_BINARY_INFO;
106         allocateGlobalMemorySurface.Size = static_cast<uint32_t>(sizeof(SPatchAllocateGlobalMemorySurfaceProgramBinaryInfo));
107 
108         allocateGlobalMemorySurface.GlobalBufferIndex = 0;
109         allocateGlobalMemorySurface.InlineDataSize = static_cast<uint32_t>(globalSize);
110 
111         pAllocateGlobalMemorySurface.reset(new cl_char[allocateGlobalMemorySurface.Size + globalSize]);
112 
113         memcpy_s(pAllocateGlobalMemorySurface.get(),
114                  sizeof(SPatchAllocateGlobalMemorySurfaceProgramBinaryInfo),
115                  &allocateGlobalMemorySurface,
116                  sizeof(SPatchAllocateGlobalMemorySurfaceProgramBinaryInfo));
117 
118         memcpy_s((cl_char *)pAllocateGlobalMemorySurface.get() + sizeof(allocateGlobalMemorySurface), globalSize, globalValue, globalSize);
119 
120         pProgramPatchList = pAllocateGlobalMemorySurface.get();
121         programPatchListSize = static_cast<uint32_t>(allocateGlobalMemorySurface.Size + globalSize);
122         return globalSize;
123     }
124     std::unique_ptr<cl_char[]> pAllocateConstMemorySurface;
125     std::unique_ptr<cl_char[]> pAllocateGlobalMemorySurface;
126     char *pCurPtr;
127     SProgramBinaryHeader programBinaryHeader;
128     void *pProgramPatchList;
129     uint32_t programPatchListSize;
130     cl_int patchlistDecodeErrorCode = 0;
131     bool allowDecodeFailure = false;
132     ClDevice *pClDevice = nullptr;
133     uint32_t rootDeviceIndex;
134 };
135 
buildAndDecodeProgramPatchList()136 void ProgramDataTestBase::buildAndDecodeProgramPatchList() {
137     size_t headerSize = sizeof(SProgramBinaryHeader);
138 
139     cl_int error = CL_SUCCESS;
140     programBinaryHeader.Magic = 0x494E5443;
141     programBinaryHeader.Version = CURRENT_ICBE_VERSION;
142     programBinaryHeader.Device = defaultHwInfo->platform.eRenderCoreFamily;
143     programBinaryHeader.GPUPointerSizeInBytes = 8;
144     programBinaryHeader.NumberOfKernels = 0;
145     programBinaryHeader.PatchListSize = programPatchListSize;
146 
147     char *pProgramData = new char[headerSize + programBinaryHeader.PatchListSize];
148     ASSERT_NE(nullptr, pProgramData);
149 
150     pCurPtr = pProgramData;
151 
152     // program header
153     memset(pCurPtr, 0, sizeof(SProgramBinaryHeader));
154     *(SProgramBinaryHeader *)pCurPtr = programBinaryHeader;
155 
156     pCurPtr += sizeof(SProgramBinaryHeader);
157 
158     // patch list
159     memcpy_s(pCurPtr, programPatchListSize, pProgramPatchList, programPatchListSize);
160     pCurPtr += programPatchListSize;
161 
162     auto rootDeviceIndex = pPlatform->getClDevice(0)->getRootDeviceIndex();
163     //as we use mock compiler in unit test, replace the genBinary here.
164     pProgram->buildInfos[rootDeviceIndex].unpackedDeviceBinary = makeCopy(pProgramData, headerSize + programBinaryHeader.PatchListSize);
165     pProgram->buildInfos[rootDeviceIndex].unpackedDeviceBinarySize = headerSize + programBinaryHeader.PatchListSize;
166 
167     error = pProgram->processGenBinary(*pClDevice);
168     patchlistDecodeErrorCode = error;
169     if (allowDecodeFailure == false) {
170         EXPECT_EQ(CL_SUCCESS, error);
171     }
172     delete[] pProgramData;
173 }
174 
175 using ProgramDataTest = ProgramDataTestBase;
176 
TEST_F(ProgramDataTest,GivenEmptyProgramBinaryHeaderWhenBuildingAndDecodingThenSucessIsReturned)177 TEST_F(ProgramDataTest, GivenEmptyProgramBinaryHeaderWhenBuildingAndDecodingThenSucessIsReturned) {
178     buildAndDecodeProgramPatchList();
179 }
180 
TEST_F(ProgramDataTest,WhenAllocatingConstantMemorySurfaceThenUnderlyingBufferIsSetCorrectly)181 TEST_F(ProgramDataTest, WhenAllocatingConstantMemorySurfaceThenUnderlyingBufferIsSetCorrectly) {
182 
183     auto constSize = setupConstantAllocation();
184 
185     buildAndDecodeProgramPatchList();
186 
187     EXPECT_NE(nullptr, pProgram->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex()));
188     EXPECT_EQ(0, memcmp(constValue, pProgram->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex())->getUnderlyingBuffer(), constSize));
189 }
190 
TEST_F(ProgramDataTest,givenProgramWhenAllocatingConstantMemorySurfaceThenProperDeviceBitfieldIsPassed)191 TEST_F(ProgramDataTest, givenProgramWhenAllocatingConstantMemorySurfaceThenProperDeviceBitfieldIsPassed) {
192     auto executionEnvironment = pClDevice->getExecutionEnvironment();
193     auto memoryManager = new MockMemoryManager(*executionEnvironment);
194 
195     std::unique_ptr<MemoryManager> memoryManagerBackup(memoryManager);
196     std::swap(memoryManagerBackup, executionEnvironment->memoryManager);
197     EXPECT_NE(pClDevice->getDeviceBitfield(), memoryManager->recentlyPassedDeviceBitfield);
198     setupConstantAllocation();
199     buildAndDecodeProgramPatchList();
200     EXPECT_NE(nullptr, pProgram->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex()));
201     EXPECT_EQ(pClDevice->getDeviceBitfield(), memoryManager->recentlyPassedDeviceBitfield);
202     std::swap(memoryManagerBackup, executionEnvironment->memoryManager);
203 }
204 
TEST_F(ProgramDataTest,whenGlobalConstantsAreExportedThenAllocateSurfacesAsSvm)205 TEST_F(ProgramDataTest, whenGlobalConstantsAreExportedThenAllocateSurfacesAsSvm) {
206     if (this->pContext->getSVMAllocsManager() == nullptr) {
207         return;
208     }
209 
210     char constantData[128] = {};
211     ProgramInfo programInfo;
212     programInfo.globalConstants.initData = constantData;
213     programInfo.globalConstants.size = sizeof(constantData);
214     std::unique_ptr<WhiteBox<NEO::LinkerInput>> mockLinkerInput = std::make_unique<WhiteBox<NEO::LinkerInput>>();
215     mockLinkerInput->traits.exportsGlobalConstants = true;
216     programInfo.linkerInput = std::move(mockLinkerInput);
217     this->pProgram->processProgramInfo(programInfo, *pClDevice);
218 
219     ASSERT_NE(nullptr, pProgram->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex()));
220     EXPECT_NE(nullptr, this->pContext->getSVMAllocsManager()->getSVMAlloc(reinterpret_cast<const void *>(pProgram->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex())->getGpuAddress())));
221 }
222 
TEST_F(ProgramDataTest,whenGlobalConstantsAreNotExportedThenAllocateSurfacesAsNonSvm)223 TEST_F(ProgramDataTest, whenGlobalConstantsAreNotExportedThenAllocateSurfacesAsNonSvm) {
224     if (this->pContext->getSVMAllocsManager() == nullptr) {
225         return;
226     }
227 
228     char constantData[128] = {};
229     ProgramInfo programInfo;
230     programInfo.globalConstants.initData = constantData;
231     programInfo.globalConstants.size = sizeof(constantData);
232     std::unique_ptr<WhiteBox<NEO::LinkerInput>> mockLinkerInput = std::make_unique<WhiteBox<NEO::LinkerInput>>();
233     mockLinkerInput->traits.exportsGlobalConstants = false;
234     programInfo.linkerInput = std::move(mockLinkerInput);
235     this->pProgram->processProgramInfo(programInfo, *pClDevice);
236 
237     ASSERT_NE(nullptr, pProgram->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex()));
238     EXPECT_EQ(nullptr, this->pContext->getSVMAllocsManager()->getSVMAlloc(reinterpret_cast<const void *>(
239                            pProgram->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex())->getGpuAddress())));
240 }
241 
TEST_F(ProgramDataTest,whenGlobalConstantsAreExportedButContextUnavailableThenAllocateSurfacesAsNonSvm)242 TEST_F(ProgramDataTest, whenGlobalConstantsAreExportedButContextUnavailableThenAllocateSurfacesAsNonSvm) {
243     if (this->pContext->getSVMAllocsManager() == nullptr) {
244         return;
245     }
246 
247     char constantData[128] = {};
248     ProgramInfo programInfo;
249     programInfo.globalConstants.initData = constantData;
250     programInfo.globalConstants.size = sizeof(constantData);
251     std::unique_ptr<WhiteBox<NEO::LinkerInput>> mockLinkerInput = std::make_unique<WhiteBox<NEO::LinkerInput>>();
252     mockLinkerInput->traits.exportsGlobalConstants = true;
253     programInfo.linkerInput = std::move(mockLinkerInput);
254 
255     pProgram->context = nullptr;
256 
257     this->pProgram->processProgramInfo(programInfo, *pClDevice);
258 
259     pProgram->context = pContext;
260 
261     ASSERT_NE(nullptr, pProgram->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex()));
262     EXPECT_EQ(nullptr, this->pContext->getSVMAllocsManager()->getSVMAlloc(reinterpret_cast<const void *>(
263                            pProgram->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex())->getGpuAddress())));
264 }
265 
TEST_F(ProgramDataTest,whenGlobalVariablesAreExportedThenAllocateSurfacesAsSvm)266 TEST_F(ProgramDataTest, whenGlobalVariablesAreExportedThenAllocateSurfacesAsSvm) {
267     if (this->pContext->getSVMAllocsManager() == nullptr) {
268         return;
269     }
270     char globalData[128] = {};
271     ProgramInfo programInfo;
272     programInfo.globalVariables.initData = globalData;
273     programInfo.globalVariables.size = sizeof(globalData);
274     std::unique_ptr<WhiteBox<NEO::LinkerInput>> mockLinkerInput = std::make_unique<WhiteBox<NEO::LinkerInput>>();
275     mockLinkerInput->traits.exportsGlobalVariables = true;
276     programInfo.linkerInput = std::move(mockLinkerInput);
277     this->pProgram->processProgramInfo(programInfo, *pClDevice);
278 
279     ASSERT_NE(nullptr, pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex()));
280     EXPECT_NE(nullptr, this->pContext->getSVMAllocsManager()->getSVMAlloc(reinterpret_cast<const void *>(pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex())->getGpuAddress())));
281 }
282 
TEST_F(ProgramDataTest,whenGlobalVariablesAreExportedButContextUnavailableThenAllocateSurfacesAsNonSvm)283 TEST_F(ProgramDataTest, whenGlobalVariablesAreExportedButContextUnavailableThenAllocateSurfacesAsNonSvm) {
284     if (this->pContext->getSVMAllocsManager() == nullptr) {
285         return;
286     }
287 
288     char globalData[128] = {};
289     ProgramInfo programInfo;
290     programInfo.globalVariables.initData = globalData;
291     programInfo.globalVariables.size = sizeof(globalData);
292     std::unique_ptr<WhiteBox<NEO::LinkerInput>> mockLinkerInput = std::make_unique<WhiteBox<NEO::LinkerInput>>();
293     mockLinkerInput->traits.exportsGlobalVariables = true;
294     programInfo.linkerInput = std::move(mockLinkerInput);
295 
296     pProgram->context = nullptr;
297 
298     this->pProgram->processProgramInfo(programInfo, *pClDevice);
299 
300     pProgram->context = pContext;
301 
302     ASSERT_NE(nullptr, pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex()));
303     EXPECT_EQ(nullptr, this->pContext->getSVMAllocsManager()->getSVMAlloc(reinterpret_cast<const void *>(pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex())->getGpuAddress())));
304 }
305 
TEST_F(ProgramDataTest,whenGlobalVariablesAreNotExportedThenAllocateSurfacesAsNonSvm)306 TEST_F(ProgramDataTest, whenGlobalVariablesAreNotExportedThenAllocateSurfacesAsNonSvm) {
307     if (this->pContext->getSVMAllocsManager() == nullptr) {
308         return;
309     }
310 
311     char globalData[128] = {};
312     ProgramInfo programInfo;
313     programInfo.globalVariables.initData = globalData;
314     programInfo.globalVariables.size = sizeof(globalData);
315     std::unique_ptr<WhiteBox<NEO::LinkerInput>> mockLinkerInput = std::make_unique<WhiteBox<NEO::LinkerInput>>();
316     mockLinkerInput->traits.exportsGlobalVariables = false;
317     programInfo.linkerInput = std::move(mockLinkerInput);
318     this->pProgram->processProgramInfo(programInfo, *pClDevice);
319 
320     ASSERT_NE(nullptr, pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex()));
321     EXPECT_EQ(nullptr, this->pContext->getSVMAllocsManager()->getSVMAlloc(reinterpret_cast<const void *>(pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex())->getGpuAddress())));
322 }
323 
TEST_F(ProgramDataTest,givenConstantAllocationThatIsInUseByGpuWhenProgramIsBeingDestroyedThenItIsAddedToTemporaryAllocationList)324 TEST_F(ProgramDataTest, givenConstantAllocationThatIsInUseByGpuWhenProgramIsBeingDestroyedThenItIsAddedToTemporaryAllocationList) {
325 
326     setupConstantAllocation();
327 
328     buildAndDecodeProgramPatchList();
329 
330     auto &csr = *pPlatform->getClDevice(0)->getDefaultEngine().commandStreamReceiver;
331     auto tagAddress = csr.getTagAddress();
332     auto constantSurface = pProgram->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex());
333     constantSurface->updateTaskCount(*tagAddress + 1, csr.getOsContext().getContextId());
334 
335     EXPECT_TRUE(csr.getTemporaryAllocations().peekIsEmpty());
336     delete pProgram;
337     pProgram = nullptr;
338     EXPECT_FALSE(csr.getTemporaryAllocations().peekIsEmpty());
339     EXPECT_EQ(constantSurface, csr.getTemporaryAllocations().peekHead());
340 }
341 
TEST_F(ProgramDataTest,givenGlobalAllocationThatIsInUseByGpuWhenProgramIsBeingDestroyedThenItIsAddedToTemporaryAllocationList)342 TEST_F(ProgramDataTest, givenGlobalAllocationThatIsInUseByGpuWhenProgramIsBeingDestroyedThenItIsAddedToTemporaryAllocationList) {
343     setupGlobalAllocation();
344 
345     buildAndDecodeProgramPatchList();
346 
347     auto &csr = *pPlatform->getClDevice(0)->getDefaultEngine().commandStreamReceiver;
348     auto tagAddress = csr.getTagAddress();
349     auto globalSurface = pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex());
350     globalSurface->updateTaskCount(*tagAddress + 1, csr.getOsContext().getContextId());
351 
352     EXPECT_TRUE(csr.getTemporaryAllocations().peekIsEmpty());
353     delete pProgram;
354     pProgram = nullptr;
355     EXPECT_FALSE(csr.getTemporaryAllocations().peekIsEmpty());
356     EXPECT_EQ(globalSurface, csr.getTemporaryAllocations().peekHead());
357 }
358 
TEST_F(ProgramDataTest,GivenDeviceForcing32BitMessagesWhenConstAllocationIsPresentInProgramBinariesThen32BitStorageIsAllocated)359 TEST_F(ProgramDataTest, GivenDeviceForcing32BitMessagesWhenConstAllocationIsPresentInProgramBinariesThen32BitStorageIsAllocated) {
360     auto constSize = setupConstantAllocation();
361     this->pContext->getDevice(0)->getMemoryManager()->setForce32BitAllocations(true);
362 
363     buildAndDecodeProgramPatchList();
364 
365     EXPECT_NE(nullptr, pProgram->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex()));
366     EXPECT_EQ(0, memcmp(constValue, pProgram->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex())->getUnderlyingBuffer(), constSize));
367 
368     if constexpr (is64bit) {
369         EXPECT_TRUE(pProgram->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex())->is32BitAllocation());
370     }
371 }
372 
TEST_F(ProgramDataTest,WhenAllocatingGlobalMemorySurfaceThenUnderlyingBufferIsSetCorrectly)373 TEST_F(ProgramDataTest, WhenAllocatingGlobalMemorySurfaceThenUnderlyingBufferIsSetCorrectly) {
374     auto globalSize = setupGlobalAllocation();
375     buildAndDecodeProgramPatchList();
376     EXPECT_NE(nullptr, pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex()));
377     EXPECT_EQ(0, memcmp(globalValue, pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex())->getUnderlyingBuffer(), globalSize));
378 }
TEST_F(ProgramDataTest,givenProgramWhenAllocatingGlobalMemorySurfaceThenProperDeviceBitfieldIsPassed)379 TEST_F(ProgramDataTest, givenProgramWhenAllocatingGlobalMemorySurfaceThenProperDeviceBitfieldIsPassed) {
380     auto executionEnvironment = pClDevice->getExecutionEnvironment();
381     auto memoryManager = new MockMemoryManager(*executionEnvironment);
382 
383     std::unique_ptr<MemoryManager> memoryManagerBackup(memoryManager);
384     std::swap(memoryManagerBackup, executionEnvironment->memoryManager);
385     EXPECT_NE(pClDevice->getDeviceBitfield(), memoryManager->recentlyPassedDeviceBitfield);
386 
387     setupGlobalAllocation();
388     buildAndDecodeProgramPatchList();
389     EXPECT_NE(nullptr, pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex()));
390     EXPECT_EQ(pClDevice->getDeviceBitfield(), memoryManager->recentlyPassedDeviceBitfield);
391     std::swap(memoryManagerBackup, executionEnvironment->memoryManager);
392 }
393 
TEST_F(ProgramDataTest,Given32BitDeviceWhenGlobalMemorySurfaceIsPresentThenItHas32BitStorage)394 TEST_F(ProgramDataTest, Given32BitDeviceWhenGlobalMemorySurfaceIsPresentThenItHas32BitStorage) {
395     char globalValue[] = "55667788";
396     size_t globalSize = strlen(globalValue) + 1;
397     this->pContext->getDevice(0)->getMemoryManager()->setForce32BitAllocations(true);
398     EXPECT_EQ(nullptr, pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex()));
399 
400     SPatchAllocateGlobalMemorySurfaceProgramBinaryInfo allocateGlobalMemorySurface;
401     allocateGlobalMemorySurface.Token = PATCH_TOKEN_ALLOCATE_GLOBAL_MEMORY_SURFACE_PROGRAM_BINARY_INFO;
402     allocateGlobalMemorySurface.Size = static_cast<uint32_t>(sizeof(SPatchAllocateGlobalMemorySurfaceProgramBinaryInfo));
403 
404     allocateGlobalMemorySurface.GlobalBufferIndex = 0;
405     allocateGlobalMemorySurface.InlineDataSize = static_cast<uint32_t>(globalSize);
406 
407     cl_char *pAllocateGlobalMemorySurface = new cl_char[allocateGlobalMemorySurface.Size + globalSize];
408 
409     memcpy_s(pAllocateGlobalMemorySurface,
410              sizeof(SPatchAllocateGlobalMemorySurfaceProgramBinaryInfo),
411              &allocateGlobalMemorySurface,
412              sizeof(SPatchAllocateGlobalMemorySurfaceProgramBinaryInfo));
413 
414     memcpy_s((cl_char *)pAllocateGlobalMemorySurface + sizeof(allocateGlobalMemorySurface), globalSize, globalValue, globalSize);
415 
416     pProgramPatchList = (void *)pAllocateGlobalMemorySurface;
417     programPatchListSize = static_cast<uint32_t>(allocateGlobalMemorySurface.Size + globalSize);
418 
419     buildAndDecodeProgramPatchList();
420 
421     EXPECT_NE(nullptr, pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex()));
422     EXPECT_EQ(0, memcmp(globalValue, pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex())->getUnderlyingBuffer(), globalSize));
423     if constexpr (is64bit) {
424         EXPECT_TRUE(pProgram->getGlobalSurface(pContext->getDevice(0)->getRootDeviceIndex())->is32BitAllocation());
425     }
426 
427     delete[] pAllocateGlobalMemorySurface;
428 }
429 
TEST(ProgramScopeMetadataTest,WhenPatchingGlobalSurfaceThenPickProperSourceBuffer)430 TEST(ProgramScopeMetadataTest, WhenPatchingGlobalSurfaceThenPickProperSourceBuffer) {
431     MockExecutionEnvironment execEnv;
432     execEnv.incRefInternal();
433     MockClDevice device{new MockDevice(&execEnv, 0)};
434     execEnv.memoryManager = std::make_unique<MockMemoryManager>();
435     PatchTokensTestData::ValidProgramWithMixedGlobalVarAndConstSurfacesAndPointers decodedProgram;
436     decodedProgram.globalPointerMutable->GlobalPointerOffset = 0U;
437     decodedProgram.constantPointerMutable->ConstantPointerOffset = 0U;
438     memset(decodedProgram.globalSurfMutable + 1, 0U, sizeof(uintptr_t));
439     memset(decodedProgram.constSurfMutable + 1, 0U, sizeof(uintptr_t));
440     ProgramInfo programInfo;
441     MockProgram program(toClDeviceVector(device));
442     NEO::populateProgramInfo(programInfo, decodedProgram);
443     program.processProgramInfo(programInfo, device);
444     auto &buildInfo = program.buildInfos[device.getRootDeviceIndex()];
445     ASSERT_NE(nullptr, buildInfo.globalSurface);
446     ASSERT_NE(nullptr, buildInfo.constantSurface);
447     ASSERT_NE(nullptr, buildInfo.globalSurface->getUnderlyingBuffer());
448     ASSERT_NE(nullptr, buildInfo.constantSurface->getUnderlyingBuffer());
449     EXPECT_EQ(static_cast<uintptr_t>(buildInfo.globalSurface->getGpuAddressToPatch()), *reinterpret_cast<uintptr_t *>(buildInfo.constantSurface->getUnderlyingBuffer()));
450     EXPECT_EQ(static_cast<uintptr_t>(buildInfo.constantSurface->getGpuAddressToPatch()), *reinterpret_cast<uintptr_t *>(buildInfo.globalSurface->getUnderlyingBuffer()));
451 }
452 
TEST_F(ProgramDataTest,GivenProgramWith32bitPointerOptWhenProgramScopeConstantBufferPatchTokensAreReadThenConstantPointerOffsetIsPatchedWith32bitPointer)453 TEST_F(ProgramDataTest, GivenProgramWith32bitPointerOptWhenProgramScopeConstantBufferPatchTokensAreReadThenConstantPointerOffsetIsPatchedWith32bitPointer) {
454     CreateProgramWithSource(pContext, "CopyBuffer_simd16.cl");
455     ASSERT_NE(nullptr, pProgram);
456 
457     MockProgram *prog = pProgram;
458 
459     // simulate case when constant surface was not allocated
460     EXPECT_EQ(nullptr, prog->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex()));
461     ProgramInfo programInfo;
462     programInfo.prepareLinkerInputStorage();
463 
464     NEO::LinkerInput::RelocationInfo relocInfo;
465     relocInfo.relocationSegment = NEO::SegmentType::GlobalConstants;
466     relocInfo.offset = 0U;
467     relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
468     relocInfo.symbolName = "GlobalConstantPointer";
469 
470     NEO::SymbolInfo symbol = {};
471     symbol.offset = 0U;
472     symbol.size = 8U;
473     symbol.segment = NEO::SegmentType::GlobalConstants;
474 
475     programInfo.linkerInput->addSymbol("GlobalConstantPointer", symbol);
476     programInfo.linkerInput->addDataRelocationInfo(relocInfo);
477     programInfo.linkerInput->setPointerSize(LinkerInput::Traits::PointerSize::Ptr32bit);
478 
479     MockBuffer constantSurface;
480     ASSERT_LT(8U, constantSurface.getSize());
481     prog->setConstantSurface(&constantSurface.mockGfxAllocation);
482     constantSurface.mockGfxAllocation.set32BitAllocation(true);
483     uint32_t *constantSurfaceStorage = reinterpret_cast<uint32_t *>(constantSurface.getCpuAddress());
484     uint32_t sentinel = 0x17192329U;
485     constantSurfaceStorage[0] = 0U;
486     constantSurfaceStorage[1] = sentinel;
487 
488     programInfo.globalConstants.initData = constantSurface.mockGfxAllocation.getUnderlyingBuffer();
489 
490     pProgram->setLinkerInput(pClDevice->getRootDeviceIndex(), std::move(programInfo.linkerInput));
491     pProgram->linkBinary(&pClDevice->getDevice(), programInfo.globalConstants.initData, programInfo.globalVariables.initData, {});
492     uint32_t expectedAddr = static_cast<uint32_t>(constantSurface.getGraphicsAllocation(pClDevice->getRootDeviceIndex())->getGpuAddressToPatch());
493     EXPECT_EQ(expectedAddr, constantSurfaceStorage[0]);
494     EXPECT_EQ(sentinel, constantSurfaceStorage[1]);
495     constantSurface.mockGfxAllocation.set32BitAllocation(false);
496     prog->setConstantSurface(nullptr);
497 }
498 
TEST_F(ProgramDataTest,GivenProgramWith32bitPointerOptWhenProgramScopeGlobalPointerPatchTokensAreReadThenGlobalPointerOffsetIsPatchedWith32bitPointer)499 TEST_F(ProgramDataTest, GivenProgramWith32bitPointerOptWhenProgramScopeGlobalPointerPatchTokensAreReadThenGlobalPointerOffsetIsPatchedWith32bitPointer) {
500     CreateProgramWithSource(pContext, "CopyBuffer_simd16.cl");
501     ASSERT_NE(nullptr, pProgram);
502 
503     MockProgram *prog = pProgram;
504 
505     // simulate case when constant surface was not allocated
506     EXPECT_EQ(nullptr, prog->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex()));
507 
508     ProgramInfo programInfo;
509     programInfo.prepareLinkerInputStorage();
510     NEO::LinkerInput::RelocationInfo relocInfo;
511     relocInfo.offset = 0U;
512     relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
513     relocInfo.relocationSegment = NEO::SegmentType::GlobalVariables;
514     relocInfo.symbolName = "GlobalVariablePointer";
515 
516     NEO::SymbolInfo symbol = {};
517     symbol.offset = 0U;
518     symbol.size = 8U;
519     symbol.segment = NEO::SegmentType::GlobalVariables;
520 
521     programInfo.linkerInput->addSymbol("GlobalVariablePointer", symbol);
522     programInfo.linkerInput->addDataRelocationInfo(relocInfo);
523     programInfo.linkerInput->setPointerSize(LinkerInput::Traits::PointerSize::Ptr32bit);
524 
525     MockBuffer globalSurface;
526     ASSERT_LT(8U, globalSurface.getSize());
527     prog->setGlobalSurface(&globalSurface.mockGfxAllocation);
528     globalSurface.mockGfxAllocation.set32BitAllocation(true);
529     uint32_t *globalSurfaceStorage = reinterpret_cast<uint32_t *>(globalSurface.getCpuAddress());
530     uint32_t sentinel = 0x17192329U;
531     globalSurfaceStorage[0] = 0U;
532     globalSurfaceStorage[1] = sentinel;
533 
534     programInfo.globalVariables.initData = globalSurface.mockGfxAllocation.getUnderlyingBuffer();
535 
536     pProgram->setLinkerInput(pClDevice->getRootDeviceIndex(), std::move(programInfo.linkerInput));
537     pProgram->linkBinary(&pClDevice->getDevice(), programInfo.globalConstants.initData, programInfo.globalVariables.initData, {});
538     uint32_t expectedAddr = static_cast<uint32_t>(globalSurface.getGraphicsAllocation(pClDevice->getRootDeviceIndex())->getGpuAddressToPatch());
539     EXPECT_EQ(expectedAddr, globalSurfaceStorage[0]);
540     EXPECT_EQ(sentinel, globalSurfaceStorage[1]);
541     globalSurface.mockGfxAllocation.set32BitAllocation(false);
542     prog->setGlobalSurface(nullptr);
543 }
544 
TEST_F(ProgramDataTest,givenSymbolTablePatchTokenThenLinkerInputIsCreated)545 TEST_F(ProgramDataTest, givenSymbolTablePatchTokenThenLinkerInputIsCreated) {
546     SPatchFunctionTableInfo token;
547     token.Token = PATCH_TOKEN_PROGRAM_SYMBOL_TABLE;
548     token.Size = static_cast<uint32_t>(sizeof(SPatchFunctionTableInfo));
549     token.NumEntries = 0;
550 
551     pProgramPatchList = &token;
552     programPatchListSize = token.Size;
553 
554     buildAndDecodeProgramPatchList();
555 
556     EXPECT_NE(nullptr, pProgram->getLinkerInput(pContext->getDevice(0)->getRootDeviceIndex()));
557 }
558 
TEST(ProgramLinkBinaryTest,whenLinkerInputEmptyThenLinkSuccessful)559 TEST(ProgramLinkBinaryTest, whenLinkerInputEmptyThenLinkSuccessful) {
560     auto linkerInput = std::make_unique<WhiteBox<LinkerInput>>();
561     auto device = std::make_unique<MockClDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(defaultHwInfo.get()));
562     MockProgram program{nullptr, false, toClDeviceVector(*device)};
563     program.setLinkerInput(device->getRootDeviceIndex(), std::move(linkerInput));
564     auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr, {});
565     EXPECT_EQ(CL_SUCCESS, ret);
566 }
567 
TEST(ProgramLinkBinaryTest,whenLinkerUnresolvedExternalThenLinkFailedAndBuildLogAvailable)568 TEST(ProgramLinkBinaryTest, whenLinkerUnresolvedExternalThenLinkFailedAndBuildLogAvailable) {
569     auto linkerInput = std::make_unique<WhiteBox<LinkerInput>>();
570     NEO::LinkerInput::RelocationInfo relocation = {};
571     relocation.symbolName = "A";
572     relocation.offset = 0;
573     linkerInput->relocations.push_back(NEO::LinkerInput::Relocations{relocation});
574     linkerInput->traits.requiresPatchingOfInstructionSegments = true;
575     auto device = std::make_unique<MockClDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(defaultHwInfo.get()));
576     auto rootDeviceIndex = device->getRootDeviceIndex();
577     MockProgram program{nullptr, false, toClDeviceVector(*device)};
578     KernelInfo kernelInfo = {};
579     kernelInfo.kernelDescriptor.kernelMetadata.kernelName = "onlyKernel";
580     std::vector<char> kernelHeap;
581     kernelHeap.resize(32, 7);
582     kernelInfo.heapInfo.pKernelHeap = kernelHeap.data();
583     kernelInfo.heapInfo.KernelHeapSize = static_cast<uint32_t>(kernelHeap.size());
584     program.getKernelInfoArray(rootDeviceIndex).push_back(&kernelInfo);
585     program.setLinkerInput(rootDeviceIndex, std::move(linkerInput));
586 
587     std::string buildLog = program.getBuildLog(device->getRootDeviceIndex());
588     EXPECT_TRUE(buildLog.empty());
589     auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr, {});
590     EXPECT_NE(CL_SUCCESS, ret);
591     program.getKernelInfoArray(rootDeviceIndex).clear();
592     buildLog = program.getBuildLog(rootDeviceIndex);
593     EXPECT_FALSE(buildLog.empty());
594     Linker::UnresolvedExternals expectedUnresolvedExternals;
595     expectedUnresolvedExternals.push_back(Linker::UnresolvedExternal{relocation, 0, false});
596     auto expectedError = constructLinkerErrorMessage(expectedUnresolvedExternals, std::vector<std::string>{"kernel : " + kernelInfo.kernelDescriptor.kernelMetadata.kernelName});
597     EXPECT_THAT(buildLog.c_str(), ::testing::HasSubstr(expectedError));
598 }
599 
TEST_F(ProgramDataTest,whenLinkerInputValidThenIsaIsProperlyPatched)600 TEST_F(ProgramDataTest, whenLinkerInputValidThenIsaIsProperlyPatched) {
601     auto linkerInput = std::make_unique<WhiteBox<LinkerInput>>();
602     linkerInput->symbols["A"] = NEO::SymbolInfo{4U, 4U, NEO::SegmentType::GlobalVariables};
603     linkerInput->symbols["B"] = NEO::SymbolInfo{8U, 4U, NEO::SegmentType::GlobalConstants};
604     linkerInput->symbols["C"] = NEO::SymbolInfo{16U, 4U, NEO::SegmentType::Instructions};
605 
606     auto relocationType = NEO::LinkerInput::RelocationInfo::Type::Address;
607     linkerInput->relocations.push_back({NEO::LinkerInput::RelocationInfo{"A", 8U, relocationType},
608                                         NEO::LinkerInput::RelocationInfo{"B", 16U, relocationType},
609                                         NEO::LinkerInput::RelocationInfo{"C", 24U, relocationType}});
610     linkerInput->traits.requiresPatchingOfInstructionSegments = true;
611     linkerInput->exportedFunctionsSegmentId = 0;
612     auto device = std::make_unique<MockClDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(defaultHwInfo.get()));
613     MockProgram program{nullptr, false, toClDeviceVector(*device)};
614     auto &buildInfo = program.buildInfos[device->getRootDeviceIndex()];
615     KernelInfo kernelInfo = {};
616     kernelInfo.kernelDescriptor.kernelMetadata.kernelName = "onlyKernel";
617     std::vector<char> kernelHeap;
618     kernelHeap.resize(32, 7);
619     kernelInfo.heapInfo.pKernelHeap = kernelHeap.data();
620     kernelInfo.heapInfo.KernelHeapSize = static_cast<uint32_t>(kernelHeap.size());
621     MockGraphicsAllocation kernelIsa(kernelHeap.data(), kernelHeap.size());
622     kernelInfo.kernelAllocation = &kernelIsa;
623     program.getKernelInfoArray(rootDeviceIndex).push_back(&kernelInfo);
624     program.setLinkerInput(device->getRootDeviceIndex(), std::move(linkerInput));
625 
626     buildInfo.exportedFunctionsSurface = kernelInfo.kernelAllocation;
627     std::vector<char> globalVariablesBuffer;
628     globalVariablesBuffer.resize(32, 7);
629     std::vector<char> globalConstantsBuffer;
630     globalConstantsBuffer.resize(32, 7);
631     std::vector<char> globalVariablesInitData{32, 0};
632     std::vector<char> globalConstantsInitData{32, 0};
633     buildInfo.globalSurface = new MockGraphicsAllocation(globalVariablesBuffer.data(), globalVariablesBuffer.size());
634     buildInfo.constantSurface = new MockGraphicsAllocation(globalConstantsBuffer.data(), globalConstantsBuffer.size());
635 
636     auto ret = program.linkBinary(&pClDevice->getDevice(), globalConstantsInitData.data(), globalVariablesInitData.data(), {});
637     EXPECT_EQ(CL_SUCCESS, ret);
638 
639     linkerInput.reset(static_cast<WhiteBox<LinkerInput> *>(buildInfo.linkerInput.release()));
640 
641     for (size_t i = 0; i < linkerInput->relocations.size(); ++i) {
642         auto expectedPatch = buildInfo.globalSurface->getGpuAddress() + linkerInput->symbols[linkerInput->relocations[0][0].symbolName].offset;
643         auto relocationAddress = kernelHeap.data() + linkerInput->relocations[0][0].offset;
644 
645         EXPECT_EQ(static_cast<uintptr_t>(expectedPatch), *reinterpret_cast<uintptr_t *>(relocationAddress)) << i;
646     }
647 
648     program.getKernelInfoArray(rootDeviceIndex).clear();
649     delete buildInfo.globalSurface;
650     buildInfo.globalSurface = nullptr;
651     delete buildInfo.constantSurface;
652     buildInfo.constantSurface = nullptr;
653 }
654 
TEST_F(ProgramDataTest,whenRelocationsAreNotNeededThenIsaIsPreserved)655 TEST_F(ProgramDataTest, whenRelocationsAreNotNeededThenIsaIsPreserved) {
656     auto linkerInput = std::make_unique<WhiteBox<LinkerInput>>();
657     linkerInput->symbols["A"] = NEO::SymbolInfo{4U, 4U, NEO::SegmentType::GlobalVariables};
658     linkerInput->symbols["B"] = NEO::SymbolInfo{8U, 4U, NEO::SegmentType::GlobalConstants};
659 
660     auto device = std::make_unique<MockClDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(defaultHwInfo.get()));
661     MockProgram program{nullptr, false, toClDeviceVector(*device)};
662     auto &buildInfo = program.buildInfos[device->getRootDeviceIndex()];
663     KernelInfo kernelInfo = {};
664     kernelInfo.kernelDescriptor.kernelMetadata.kernelName = "onlyKernel";
665     std::vector<char> kernelHeapData;
666     kernelHeapData.resize(32, 7);
667     std::vector<char> kernelHeap(kernelHeapData.begin(), kernelHeapData.end());
668     kernelInfo.heapInfo.pKernelHeap = kernelHeap.data();
669     kernelInfo.heapInfo.KernelHeapSize = static_cast<uint32_t>(kernelHeap.size());
670     MockGraphicsAllocation kernelIsa(kernelHeap.data(), kernelHeap.size());
671     kernelInfo.kernelAllocation = &kernelIsa;
672     program.getKernelInfoArray(rootDeviceIndex).push_back(&kernelInfo);
673     program.setLinkerInput(rootDeviceIndex, std::move(linkerInput));
674 
675     std::vector<char> globalVariablesBuffer;
676     globalVariablesBuffer.resize(32, 7);
677     std::vector<char> globalConstantsBuffer;
678     globalConstantsBuffer.resize(32, 7);
679     std::vector<char> globalVariablesInitData{32, 0};
680     std::vector<char> globalConstantsInitData{32, 0};
681     buildInfo.globalSurface = new MockGraphicsAllocation(globalVariablesBuffer.data(), globalVariablesBuffer.size());
682     buildInfo.constantSurface = new MockGraphicsAllocation(globalConstantsBuffer.data(), globalConstantsBuffer.size());
683 
684     auto ret = program.linkBinary(&pClDevice->getDevice(), globalConstantsInitData.data(), globalVariablesInitData.data(), {});
685     EXPECT_EQ(CL_SUCCESS, ret);
686     EXPECT_EQ(kernelHeapData, kernelHeap);
687 
688     program.getKernelInfoArray(rootDeviceIndex).clear();
689     delete buildInfo.globalSurface;
690     buildInfo.globalSurface = nullptr;
691     delete buildInfo.constantSurface;
692     buildInfo.constantSurface = nullptr;
693 }
694 
TEST(ProgramStringSectionTest,WhenConstStringBufferIsPresentThenUseItForLinking)695 TEST(ProgramStringSectionTest, WhenConstStringBufferIsPresentThenUseItForLinking) {
696     auto device = std::make_unique<MockClDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(defaultHwInfo.get()));
697     auto rootDeviceIndex = device->getRootDeviceIndex();
698 
699     MockProgram program{nullptr, false, toClDeviceVector(*device)};
700 
701     uint8_t kernelHeapData[64] = {};
702     MockGraphicsAllocation kernelIsa(kernelHeapData, 64);
703 
704     KernelInfo kernelInfo = {};
705     kernelInfo.kernelDescriptor.kernelMetadata.kernelName = "onlyKernel";
706     kernelInfo.heapInfo.pKernelHeap = kernelHeapData;
707     kernelInfo.heapInfo.KernelHeapSize = 64;
708     kernelInfo.kernelAllocation = &kernelIsa;
709 
710     program.getKernelInfoArray(rootDeviceIndex).push_back(&kernelInfo);
711 
712     auto linkerInput = std::make_unique<WhiteBox<LinkerInput>>();
713     linkerInput->relocations.push_back({{".str", 0x8, LinkerInput::RelocationInfo::Type::Address, SegmentType::Instructions}});
714     linkerInput->symbols.insert({".str", {0x0, 0x8, SegmentType::GlobalStrings}});
715     linkerInput->traits.requiresPatchingOfInstructionSegments = true;
716 
717     program.setLinkerInput(rootDeviceIndex, std::move(linkerInput));
718 
719     auto isaCpuPtr = reinterpret_cast<char *>(kernelInfo.getGraphicsAllocation()->getUnderlyingBuffer());
720     auto patchAddr = ptrOffset(isaCpuPtr, 0x8);
721 
722     const char constStringData[] = "Hello World!\n";
723     auto stringsAddr = reinterpret_cast<uintptr_t>(constStringData);
724 
725     auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr, {constStringData, sizeof(constStringData)});
726     EXPECT_EQ(CL_SUCCESS, ret);
727     EXPECT_EQ(static_cast<size_t>(stringsAddr), *reinterpret_cast<size_t *>(patchAddr));
728 
729     program.getKernelInfoArray(rootDeviceIndex).clear();
730 }
731 
TEST(ProgramImplicitArgsTest,givenImplicitRelocationAndStackCallsThenKernelRequiresImplicitArgs)732 TEST(ProgramImplicitArgsTest, givenImplicitRelocationAndStackCallsThenKernelRequiresImplicitArgs) {
733     auto device = std::make_unique<MockClDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(defaultHwInfo.get()));
734     auto rootDeviceIndex = device->getRootDeviceIndex();
735     MockProgram program{nullptr, false, toClDeviceVector(*device)};
736     KernelInfo kernelInfo = {};
737     kernelInfo.kernelDescriptor.kernelMetadata.kernelName = "onlyKernel";
738     kernelInfo.kernelDescriptor.kernelAttributes.flags.useStackCalls = true;
739     uint8_t kernelHeapData[64] = {};
740     kernelInfo.heapInfo.pKernelHeap = kernelHeapData;
741     kernelInfo.heapInfo.KernelHeapSize = 64;
742     MockGraphicsAllocation kernelIsa(kernelHeapData, 64);
743     kernelInfo.kernelAllocation = &kernelIsa;
744     program.getKernelInfoArray(rootDeviceIndex).push_back(&kernelInfo);
745 
746     auto linkerInput = std::make_unique<WhiteBox<LinkerInput>>();
747     linkerInput->relocations.push_back({{implicitArgsRelocationSymbolName, 0x8, LinkerInput::RelocationInfo::Type::AddressLow, SegmentType::Instructions}});
748     linkerInput->traits.requiresPatchingOfInstructionSegments = true;
749     program.setLinkerInput(rootDeviceIndex, std::move(linkerInput));
750     auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr, {});
751     EXPECT_EQ(CL_SUCCESS, ret);
752 
753     EXPECT_TRUE(kernelInfo.kernelDescriptor.kernelAttributes.flags.requiresImplicitArgs);
754     program.getKernelInfoArray(rootDeviceIndex).clear();
755 }
756 
TEST(ProgramImplicitArgsTest,givenImplicitRelocationAndEnabledDebuggerThenKernelRequiresImplicitArgs)757 TEST(ProgramImplicitArgsTest, givenImplicitRelocationAndEnabledDebuggerThenKernelRequiresImplicitArgs) {
758     if (!defaultHwInfo->capabilityTable.debuggerSupported) {
759         GTEST_SKIP();
760     }
761     DebugManagerStateRestore restorer;
762     DebugManager.flags.EnableMockSourceLevelDebugger.set(1);
763     auto device = std::make_unique<MockClDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(defaultHwInfo.get()));
764 
765     EXPECT_NE(nullptr, device->getDebugger());
766     auto rootDeviceIndex = device->getRootDeviceIndex();
767     MockProgram program{nullptr, false, toClDeviceVector(*device)};
768     KernelInfo kernelInfo = {};
769     kernelInfo.kernelDescriptor.kernelMetadata.kernelName = "onlyKernel";
770     kernelInfo.kernelDescriptor.kernelAttributes.flags.useStackCalls = false;
771     uint8_t kernelHeapData[64] = {};
772     kernelInfo.heapInfo.pKernelHeap = kernelHeapData;
773     kernelInfo.heapInfo.KernelHeapSize = 64;
774     MockGraphicsAllocation kernelIsa(kernelHeapData, 64);
775     kernelInfo.kernelAllocation = &kernelIsa;
776     program.getKernelInfoArray(rootDeviceIndex).push_back(&kernelInfo);
777 
778     auto linkerInput = std::make_unique<WhiteBox<LinkerInput>>();
779     linkerInput->relocations.push_back({{implicitArgsRelocationSymbolName, 0x8, LinkerInput::RelocationInfo::Type::AddressLow, SegmentType::Instructions}});
780     linkerInput->traits.requiresPatchingOfInstructionSegments = true;
781     program.setLinkerInput(rootDeviceIndex, std::move(linkerInput));
782     auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr, {});
783     EXPECT_EQ(CL_SUCCESS, ret);
784 
785     EXPECT_TRUE(kernelInfo.kernelDescriptor.kernelAttributes.flags.requiresImplicitArgs);
786     program.getKernelInfoArray(rootDeviceIndex).clear();
787 }
788 
TEST(ProgramImplicitArgsTest,givenImplicitRelocationAndNoStackCallsAndDisabledDebuggerThenKernelDoesntRequireImplicitArgs)789 TEST(ProgramImplicitArgsTest, givenImplicitRelocationAndNoStackCallsAndDisabledDebuggerThenKernelDoesntRequireImplicitArgs) {
790     auto device = std::make_unique<MockClDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(defaultHwInfo.get()));
791     EXPECT_EQ(nullptr, device->getDebugger());
792     auto rootDeviceIndex = device->getRootDeviceIndex();
793     MockProgram program{nullptr, false, toClDeviceVector(*device)};
794     KernelInfo kernelInfo = {};
795     kernelInfo.kernelDescriptor.kernelMetadata.kernelName = "onlyKernel";
796     kernelInfo.kernelDescriptor.kernelAttributes.flags.useStackCalls = false;
797     uint8_t kernelHeapData[64] = {};
798     kernelInfo.heapInfo.pKernelHeap = kernelHeapData;
799     kernelInfo.heapInfo.KernelHeapSize = 64;
800     MockGraphicsAllocation kernelIsa(kernelHeapData, 64);
801     kernelInfo.kernelAllocation = &kernelIsa;
802     program.getKernelInfoArray(rootDeviceIndex).push_back(&kernelInfo);
803 
804     auto linkerInput = std::make_unique<WhiteBox<LinkerInput>>();
805     linkerInput->relocations.push_back({{implicitArgsRelocationSymbolName, 0x8, LinkerInput::RelocationInfo::Type::AddressLow, SegmentType::Instructions}});
806     linkerInput->traits.requiresPatchingOfInstructionSegments = true;
807     program.setLinkerInput(rootDeviceIndex, std::move(linkerInput));
808     auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr, {});
809     EXPECT_EQ(CL_SUCCESS, ret);
810 
811     EXPECT_FALSE(kernelInfo.kernelDescriptor.kernelAttributes.flags.requiresImplicitArgs);
812     program.getKernelInfoArray(rootDeviceIndex).clear();
813 }
814