1 /*
2 * Copyright (C) 2018-2021 Intel Corporation
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 */
7
8 #include "shared/source/compiler_interface/compiler_interface.h"
9 #include "shared/source/device/device.h"
10 #include "shared/source/device_binary_format/elf/elf.h"
11 #include "shared/source/device_binary_format/elf/elf_encoder.h"
12 #include "shared/source/device_binary_format/elf/ocl_elf.h"
13 #include "shared/source/execution_environment/execution_environment.h"
14 #include "shared/source/program/kernel_info.h"
15 #include "shared/source/source_level_debugger/source_level_debugger.h"
16 #include "shared/source/utilities/stackvec.h"
17
18 #include "opencl/source/cl_device/cl_device.h"
19 #include "opencl/source/gtpin/gtpin_notify.h"
20 #include "opencl/source/helpers/cl_validators.h"
21 #include "opencl/source/platform/platform.h"
22 #include "opencl/source/program/program.h"
23
24 #include "compiler_options.h"
25
26 #include <cstring>
27
28 namespace NEO {
29
link(const ClDeviceVector & deviceVector,const char * buildOptions,cl_uint numInputPrograms,const cl_program * inputPrograms)30 cl_int Program::link(
31 const ClDeviceVector &deviceVector,
32 const char *buildOptions,
33 cl_uint numInputPrograms,
34 const cl_program *inputPrograms) {
35 cl_int retVal = CL_SUCCESS;
36 bool isCreateLibrary;
37
38 auto defaultClDevice = deviceVector[0];
39 UNRECOVERABLE_IF(defaultClDevice == nullptr);
40 auto &defaultDevice = defaultClDevice->getDevice();
41 std::unordered_map<uint32_t, bool> kernelDebugDataNotified;
42 std::unordered_map<uint32_t, bool> debugOptionsAppended;
43 std::string internalOptions;
44 initInternalOptions(internalOptions);
45 cl_program_binary_type binaryType = CL_PROGRAM_BINARY_TYPE_NONE;
46 do {
47 if ((numInputPrograms == 0) || (inputPrograms == nullptr)) {
48 retVal = CL_INVALID_VALUE;
49 break;
50 }
51
52 if (std::any_of(deviceVector.begin(), deviceVector.end(), [&](auto device) { return CL_BUILD_IN_PROGRESS == deviceBuildInfos[device].buildStatus; })) {
53 retVal = CL_INVALID_OPERATION;
54 break;
55 }
56
57 for (const auto &device : deviceVector) {
58 kernelDebugDataNotified[device->getRootDeviceIndex()] = false;
59 debugOptionsAppended[device->getRootDeviceIndex()] = false;
60 deviceBuildInfos[device].buildStatus = CL_BUILD_IN_PROGRESS;
61 }
62
63 options = (buildOptions != nullptr) ? buildOptions : "";
64
65 for (const auto &optionString : {CompilerOptions::gtpinRera, CompilerOptions::greaterThan4gbBuffersRequired}) {
66 size_t pos = options.find(optionString.data());
67 if (pos != std::string::npos) {
68 options.erase(pos, optionString.length());
69 CompilerOptions::concatenateAppend(internalOptions, optionString);
70 }
71 }
72
73 if (isKernelDebugEnabled()) {
74 for (auto &device : deviceVector) {
75 if (debugOptionsAppended[device->getRootDeviceIndex()]) {
76 continue;
77 }
78 appendKernelDebugOptions(*device, internalOptions);
79
80 debugOptionsAppended[device->getRootDeviceIndex()] = true;
81 }
82 }
83
84 isCreateLibrary = CompilerOptions::contains(options, CompilerOptions::createLibrary);
85
86 NEO::Elf::ElfEncoder<> elfEncoder(true, false, 1U);
87 elfEncoder.getElfFileHeader().type = NEO::Elf::ET_OPENCL_OBJECTS;
88
89 StackVec<const Program *, 16> inputProgramsInternal;
90 StackVec<uint32_t, 64> specConstIds;
91 StackVec<uint64_t, 64> specConstValues;
92 for (cl_uint i = 0; i < numInputPrograms; i++) {
93 auto program = inputPrograms[i];
94 if (program == nullptr) {
95 retVal = CL_INVALID_PROGRAM;
96 break;
97 }
98 auto pInputProgObj = castToObject<Program>(program);
99 if (pInputProgObj == nullptr) {
100 retVal = CL_INVALID_PROGRAM;
101 break;
102 }
103 inputProgramsInternal.push_back(pInputProgObj);
104 if ((pInputProgObj->irBinary == nullptr) || (pInputProgObj->irBinarySize == 0)) {
105 retVal = CL_INVALID_PROGRAM;
106 break;
107 }
108
109 if (pInputProgObj->areSpecializationConstantsInitialized) {
110 specConstIds.clear();
111 specConstValues.clear();
112 specConstIds.reserve(pInputProgObj->specConstantsValues.size());
113 specConstValues.reserve(pInputProgObj->specConstantsValues.size());
114 for (const auto &specConst : pInputProgObj->specConstantsValues) {
115 specConstIds.push_back(specConst.first);
116 specConstValues.push_back(specConst.second);
117 }
118 elfEncoder.appendSection(NEO::Elf::SHT_OPENCL_SPIRV_SC_IDS, NEO::Elf::SectionNamesOpenCl::spirvSpecConstIds,
119 ArrayRef<const uint8_t>::fromAny(specConstIds.begin(), specConstIds.size()));
120 elfEncoder.appendSection(NEO::Elf::SHT_OPENCL_SPIRV_SC_VALUES, NEO::Elf::SectionNamesOpenCl::spirvSpecConstValues,
121 ArrayRef<const uint8_t>::fromAny(specConstValues.begin(), specConstValues.size()));
122 }
123
124 auto sectionType = pInputProgObj->getIsSpirV() ? NEO::Elf::SHT_OPENCL_SPIRV : NEO::Elf::SHT_OPENCL_LLVM_BINARY;
125 ConstStringRef sectionName = pInputProgObj->getIsSpirV() ? NEO::Elf::SectionNamesOpenCl::spirvObject : NEO::Elf::SectionNamesOpenCl::llvmObject;
126 elfEncoder.appendSection(sectionType, sectionName, ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(pInputProgObj->irBinary.get()), pInputProgObj->irBinarySize));
127 }
128 if (retVal != CL_SUCCESS) {
129 break;
130 }
131
132 auto clLinkInput = elfEncoder.encode();
133
134 CompilerInterface *pCompilerInterface = defaultDevice.getCompilerInterface();
135 if (!pCompilerInterface) {
136 retVal = CL_OUT_OF_HOST_MEMORY;
137 break;
138 }
139
140 TranslationInput inputArgs = {IGC::CodeType::elf, IGC::CodeType::undefined};
141
142 inputArgs.src = ArrayRef<const char>(reinterpret_cast<const char *>(clLinkInput.data()), clLinkInput.size());
143 inputArgs.apiOptions = ArrayRef<const char>(options.c_str(), options.length());
144 inputArgs.internalOptions = ArrayRef<const char>(internalOptions.c_str(), internalOptions.length());
145 inputArgs.GTPinInput = gtpinGetIgcInit();
146
147 if (!isCreateLibrary) {
148 for (const auto &device : deviceVector) {
149 auto rootDeviceIndex = device->getRootDeviceIndex();
150 inputArgs.outType = IGC::CodeType::oclGenBin;
151 NEO::TranslationOutput compilerOuput = {};
152 auto compilerErr = pCompilerInterface->link(device->getDevice(), inputArgs, compilerOuput);
153 this->updateBuildLog(device->getRootDeviceIndex(), compilerOuput.frontendCompilerLog.c_str(), compilerOuput.frontendCompilerLog.size());
154 this->updateBuildLog(device->getRootDeviceIndex(), compilerOuput.backendCompilerLog.c_str(), compilerOuput.backendCompilerLog.size());
155 retVal = asClError(compilerErr);
156 if (retVal != CL_SUCCESS) {
157 break;
158 }
159
160 this->replaceDeviceBinary(std::move(compilerOuput.deviceBinary.mem), compilerOuput.deviceBinary.size, rootDeviceIndex);
161 this->debugData = std::move(compilerOuput.debugData.mem);
162 this->debugDataSize = compilerOuput.debugData.size;
163
164 retVal = processGenBinary(*device);
165 if (retVal != CL_SUCCESS) {
166 break;
167 }
168 binaryType = CL_PROGRAM_BINARY_TYPE_EXECUTABLE;
169
170 if (isKernelDebugEnabled()) {
171 if (kernelDebugDataNotified[rootDeviceIndex]) {
172 continue;
173 }
174 processDebugData(rootDeviceIndex);
175 for (auto kernelInfo : buildInfos[rootDeviceIndex].kernelInfoArray) {
176 device->getSourceLevelDebugger()->notifyKernelDebugData(&kernelInfo->debugData,
177 kernelInfo->kernelDescriptor.kernelMetadata.kernelName,
178 kernelInfo->heapInfo.pKernelHeap,
179 kernelInfo->heapInfo.KernelHeapSize);
180 }
181 kernelDebugDataNotified[device->getRootDeviceIndex()] = true;
182 }
183 }
184
185 } else {
186 inputArgs.outType = IGC::CodeType::llvmBc;
187 NEO::TranslationOutput compilerOuput = {};
188 auto compilerErr = pCompilerInterface->createLibrary(defaultDevice, inputArgs, compilerOuput);
189 for (const auto &device : deviceVector) {
190 this->updateBuildLog(device->getRootDeviceIndex(), compilerOuput.frontendCompilerLog.c_str(), compilerOuput.frontendCompilerLog.size());
191 this->updateBuildLog(device->getRootDeviceIndex(), compilerOuput.backendCompilerLog.c_str(), compilerOuput.backendCompilerLog.size());
192 }
193 retVal = asClError(compilerErr);
194 if (retVal != CL_SUCCESS) {
195 break;
196 }
197 this->irBinary = std::move(compilerOuput.intermediateRepresentation.mem);
198 this->irBinarySize = compilerOuput.intermediateRepresentation.size;
199 this->isSpirV = (compilerOuput.intermediateCodeType == IGC::CodeType::spirV);
200 this->debugData = std::move(compilerOuput.debugData.mem);
201 this->debugDataSize = compilerOuput.debugData.size;
202 binaryType = CL_PROGRAM_BINARY_TYPE_LIBRARY;
203 }
204 if (retVal != CL_SUCCESS) {
205 break;
206 }
207 updateNonUniformFlag(&*inputProgramsInternal.begin(), inputProgramsInternal.size());
208 for (const auto &device : deviceVector) {
209 separateBlockKernels(device->getRootDeviceIndex());
210 }
211 } while (false);
212
213 if (retVal != CL_SUCCESS) {
214 for (const auto &device : deviceVector) {
215 deviceBuildInfos[device].buildStatus = CL_BUILD_ERROR;
216 deviceBuildInfos[device].programBinaryType = CL_PROGRAM_BINARY_TYPE_NONE;
217 }
218 } else {
219 setBuildStatusSuccess(deviceVector, binaryType);
220 }
221
222 return retVal;
223 }
224 } // namespace NEO
225