1 /*
2  * Copyright (C) 2020-2021 Intel Corporation
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  */
7 
8 #include "ocloc_arg_helper.h"
9 
10 #include "shared/source/helpers/file_io.h"
11 #include "shared/source/helpers/hw_info.h"
12 #include "shared/source/helpers/string.h"
13 
14 #include "hw_cmds.h"
15 
16 #include <algorithm>
17 #include <cstring>
18 #include <sstream>
19 
toVectorOfStrings(std::vector<std::string> & lines,bool replaceTabs)20 void Source::toVectorOfStrings(std::vector<std::string> &lines, bool replaceTabs) {
21     std::string line;
22     const char *file = reinterpret_cast<const char *>(data);
23 
24     while (*file != '\0') {
25         if (replaceTabs && *file == '\t') {
26             line += ' ';
27         } else if (*file == '\n') {
28             lines.push_back(line);
29             line = "";
30         } else {
31             line += *file;
32         }
33         file++;
34     }
35 }
36 
Output(const std::string & name,const void * data,const size_t & size)37 Output::Output(const std::string &name, const void *data, const size_t &size)
38     : name(name), size(size) {
39     this->data = new uint8_t[size];
40     memcpy_s(reinterpret_cast<void *>(this->data), this->size, data, size);
41 };
42 
OclocArgHelper(const uint32_t numSources,const uint8_t ** dataSources,const uint64_t * lenSources,const char ** nameSources,const uint32_t numInputHeaders,const uint8_t ** dataInputHeaders,const uint64_t * lenInputHeaders,const char ** nameInputHeaders,uint32_t * numOutputs,uint8_t *** dataOutputs,uint64_t ** lenOutputs,char *** nameOutputs)43 OclocArgHelper::OclocArgHelper(const uint32_t numSources, const uint8_t **dataSources,
44                                const uint64_t *lenSources, const char **nameSources,
45                                const uint32_t numInputHeaders,
46                                const uint8_t **dataInputHeaders,
47                                const uint64_t *lenInputHeaders, const char **nameInputHeaders,
48                                uint32_t *numOutputs, uint8_t ***dataOutputs,
49                                uint64_t **lenOutputs, char ***nameOutputs)
50     : numOutputs(numOutputs), nameOutputs(nameOutputs),
51       dataOutputs(dataOutputs), lenOutputs(lenOutputs), hasOutput(numOutputs != nullptr), deviceProductTable({
52 #define NAMEDDEVICE(devId, product, ignored_gtType, ignored_devName) {devId, NEO::hardwarePrefix[NEO::product::hwInfo.platform.eProductFamily]},
53 #define DEVICE(devId, product, ignored_gtType) {devId, NEO::hardwarePrefix[NEO::product::hwInfo.platform.eProductFamily]},
54 #include "devices.inl"
55 #undef DEVICE
56 #undef NAMEDDEVICE
57                                                                                               {0u, std::string("")}}),
58       deviceMap({
59 #define DEVICE_CONFIG_REVISION(product, productConfig, revision_id) {product, &NEO::productConfig::hwInfo, NEO::productConfig::setupHardwareInfo, revision_id},
60 #define DEVICE_CONFIG(product, productConfig) {product, &NEO::productConfig::hwInfo, NEO::productConfig::setupHardwareInfo, NEO::productConfig::hwInfo.platform.usRevId},
61 #include "product_config.inl"
62 #undef DEVICE_CONFIG
63 #undef DEVICE_CONFIG_REVISION
64           {PRODUCT_CONFIG::UNKNOWN_ISA, {}, 0x0}}) {
65     for (uint32_t i = 0; i < numSources; ++i) {
66         inputs.push_back(Source(dataSources[i], static_cast<size_t>(lenSources[i]), nameSources[i]));
67     }
68     for (uint32_t i = 0; i < numInputHeaders; ++i) {
69         headers.push_back(Source(dataInputHeaders[i], static_cast<size_t>(lenInputHeaders[i]), nameInputHeaders[i]));
70     }
71     for (unsigned int i = 0; i < IGFX_MAX_CORE; ++i) {
72         if (NEO::familyName[i] == nullptr)
73             continue;
74         std::string gen = NEO::familyName[i];
75         std::transform(gen.begin(), gen.end(), gen.begin(), ::tolower);
76         genIGFXMap.insert({gen, i});
77     }
78 }
79 
OclocArgHelper()80 OclocArgHelper::OclocArgHelper() : OclocArgHelper(0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr) {}
81 
~OclocArgHelper()82 OclocArgHelper::~OclocArgHelper() {
83     if (outputEnabled()) {
84         saveOutput(oclocStdoutLogName, messagePrinter.getLog());
85         moveOutputs();
86     }
87 }
88 
fileExists(const std::string & filename) const89 bool OclocArgHelper::fileExists(const std::string &filename) const {
90     return sourceFileExists(filename) || ::fileExists(filename);
91 }
92 
moveOutputs()93 void OclocArgHelper::moveOutputs() {
94     *numOutputs = static_cast<uint32_t>(outputs.size());
95     *nameOutputs = new char *[outputs.size()];
96     *dataOutputs = new uint8_t *[outputs.size()];
97     *lenOutputs = new uint64_t[outputs.size()];
98     for (size_t i = 0; i < outputs.size(); ++i) {
99         size_t size = outputs[i]->name.length() + 1;
100         (*nameOutputs)[i] = new char[size];
101         strncpy_s((*nameOutputs)[i], size, outputs[i]->name.c_str(), outputs[i]->name.length() + 1);
102         (*dataOutputs)[i] = outputs[i]->data;
103         (*lenOutputs)[i] = outputs[i]->size;
104     }
105 }
106 
findSourceFile(const std::string & filename)107 Source *OclocArgHelper::findSourceFile(const std::string &filename) {
108     for (auto &source : inputs) {
109         if (filename == source.name) {
110             return &source;
111         }
112     }
113     return nullptr;
114 }
115 
sourceFileExists(const std::string & filename) const116 bool OclocArgHelper::sourceFileExists(const std::string &filename) const {
117     for (auto &input : inputs) {
118         if (filename == input.name) {
119             return true;
120         }
121     }
122     return false;
123 }
124 
headersToVectorOfStrings()125 std::vector<std::string> OclocArgHelper::headersToVectorOfStrings() {
126     std::vector<std::string> lines;
127     for (auto &header : headers) {
128         header.toVectorOfStrings(lines, true);
129     }
130     return lines;
131 }
132 
readFileToVectorOfStrings(const std::string & filename,std::vector<std::string> & lines)133 void OclocArgHelper::readFileToVectorOfStrings(const std::string &filename, std::vector<std::string> &lines) {
134     if (Source *s = findSourceFile(filename)) {
135         s->toVectorOfStrings(lines);
136     } else {
137         ::readFileToVectorOfStrings(lines, filename);
138     }
139 }
140 
readBinaryFile(const std::string & filename)141 std::vector<char> OclocArgHelper::readBinaryFile(const std::string &filename) {
142     if (Source *s = findSourceFile(filename)) {
143         return s->toBinaryVector();
144     } else {
145         return ::readBinaryFile(filename);
146     }
147 }
148 
loadDataFromFile(const std::string & filename,size_t & retSize)149 std::unique_ptr<char[]> OclocArgHelper::loadDataFromFile(const std::string &filename, size_t &retSize) {
150     if (Source *s = findSourceFile(filename)) {
151         auto size = s->length;
152         std::unique_ptr<char[]> ret(new char[size]());
153         memcpy_s(ret.get(), size, s->data, s->length);
154         retSize = s->length;
155         return ret;
156     } else {
157         return ::loadDataFromFile(filename.c_str(), retSize);
158     }
159 }
160 
setDeviceInfoForFatbinaryTarget(const DeviceMapping & device)161 void OclocArgHelper::setDeviceInfoForFatbinaryTarget(const DeviceMapping &device) {
162     deviceForFatbinary.hwInfo = device.hwInfo;
163     deviceForFatbinary.setupHardwareInfo = device.setupHardwareInfo;
164     deviceForFatbinary.revId = device.revId;
165 }
166 
setHwInfoForFatbinaryTarget(NEO::HardwareInfo & hwInfo)167 void OclocArgHelper::setHwInfoForFatbinaryTarget(NEO::HardwareInfo &hwInfo) {
168     hwInfo = *deviceForFatbinary.hwInfo;
169     deviceForFatbinary.setupHardwareInfo(&hwInfo, true);
170     hwInfo.platform.usRevId = deviceForFatbinary.revId;
171 }
172 
getHwInfoForProductConfig(uint32_t config,NEO::HardwareInfo & hwInfo)173 bool OclocArgHelper::getHwInfoForProductConfig(uint32_t config, NEO::HardwareInfo &hwInfo) {
174     bool retVal = false;
175     if (config == UNKNOWN_ISA) {
176         return retVal;
177     }
178     for (auto &deviceConfig : deviceMap) {
179         if (deviceConfig.config == config) {
180             hwInfo = *deviceConfig.hwInfo;
181             deviceConfig.setupHardwareInfo(&hwInfo, true);
182             hwInfo.platform.usRevId = deviceConfig.revId;
183             retVal = true;
184             return retVal;
185         }
186     }
187     return retVal;
188 }
189 
getProductConfigsForGfxCoreFamily(GFXCORE_FAMILY core,std::vector<DeviceMapping> & out)190 void OclocArgHelper::getProductConfigsForGfxCoreFamily(GFXCORE_FAMILY core, std::vector<DeviceMapping> &out) {
191     for (auto &deviceConfig : deviceMap) {
192         if (deviceConfig.config == PRODUCT_CONFIG::UNKNOWN_ISA)
193             continue;
194         if (deviceConfig.hwInfo->platform.eRenderCoreFamily == core) {
195             out.push_back(deviceConfig);
196         }
197     }
198 }
199 
saveOutput(const std::string & filename,const void * pData,const size_t & dataSize)200 void OclocArgHelper::saveOutput(const std::string &filename, const void *pData, const size_t &dataSize) {
201     if (outputEnabled()) {
202         addOutput(filename, pData, dataSize);
203     } else {
204         writeDataToFile(filename.c_str(), pData, dataSize);
205     }
206 }
207 
saveOutput(const std::string & filename,const std::ostream & stream)208 void OclocArgHelper::saveOutput(const std::string &filename, const std::ostream &stream) {
209     std::stringstream ss;
210     ss << stream.rdbuf();
211     if (outputEnabled()) {
212         addOutput(filename, ss.str().c_str(), ss.str().length());
213     } else {
214         std::ofstream file(filename);
215         file << ss.str();
216     }
217 }
218 
returnProductNameForDevice(unsigned short deviceId)219 std::string OclocArgHelper::returnProductNameForDevice(unsigned short deviceId) {
220     std::string res = "";
221     for (int i = 0; deviceProductTable[i].deviceId != 0; i++) {
222         if (deviceProductTable[i].deviceId == deviceId) {
223             res = deviceProductTable[i].product;
224         }
225     }
226     return res;
227 }
228 
getAllSupportedDeviceConfigs()229 std::vector<DeviceMapping> OclocArgHelper::getAllSupportedDeviceConfigs() {
230     std::vector<DeviceMapping> allConfigs;
231 
232     for (auto &deviceConfig : deviceMap) {
233         if (deviceConfig.config != PRODUCT_CONFIG::UNKNOWN_ISA) {
234             allConfigs.push_back(deviceConfig);
235         }
236     }
237     std::sort(allConfigs.begin(), allConfigs.end(), compareConfigs);
238     return allConfigs;
239 }
240 
parseProductConfigFromValue(PRODUCT_CONFIG config)241 const std::string OclocArgHelper::parseProductConfigFromValue(PRODUCT_CONFIG config) {
242     auto configValue = static_cast<uint32_t>(config);
243     std::stringstream stringConfig;
244     uint32_t major = (configValue & 0xff0000) >> 16;
245     uint32_t minor = (configValue & 0x00ff00) >> 8;
246     uint32_t revision = configValue & 0x0000ff;
247     stringConfig << major << "." << minor << "." << revision;
248     return stringConfig.str();
249 }
250 
getAllSupportedProductConfigs()251 std::vector<PRODUCT_CONFIG> OclocArgHelper::getAllSupportedProductConfigs() {
252     std::vector<PRODUCT_CONFIG> allConfigs;
253     for (auto &deviceConfig : deviceMap) {
254         if (deviceConfig.config != PRODUCT_CONFIG::UNKNOWN_ISA) {
255             allConfigs.push_back(deviceConfig.config);
256         }
257     }
258     std::sort(allConfigs.begin(), allConfigs.end());
259     return allConfigs;
260 }
261 
parseProductConfigFromString(const std::string & device,size_t begin,size_t end)262 int OclocArgHelper::parseProductConfigFromString(const std::string &device, size_t begin, size_t end) {
263     if (begin == end) {
264         return CONFIG_STATUS::MISMATCHED_VALUE;
265     }
266     if (end == std::string::npos) {
267         if (!std::all_of(device.begin() + begin, device.end(), (::isdigit))) {
268             return CONFIG_STATUS::MISMATCHED_VALUE;
269         }
270         return std::stoi(device.substr(begin, device.size() - begin));
271     } else {
272         if (!std::all_of(device.begin() + begin, device.begin() + end, (::isdigit))) {
273             return CONFIG_STATUS::MISMATCHED_VALUE;
274         }
275         return std::stoi(device.substr(begin, end - begin));
276     }
277 }
278 
getMajorMinorRevision(const std::string & device)279 std::vector<uint32_t> OclocArgHelper::getMajorMinorRevision(const std::string &device) {
280     std::vector<uint32_t> numeration;
281     auto major_pos = device.find(".");
282     auto major = parseProductConfigFromString(device, 0, major_pos);
283     if (major == CONFIG_STATUS::MISMATCHED_VALUE) {
284         return {};
285     }
286     numeration.push_back(major);
287     if (major_pos == std::string::npos) {
288         return numeration;
289     }
290 
291     auto minor_pos = device.find(".", ++major_pos);
292     auto minor = parseProductConfigFromString(device, major_pos, minor_pos);
293 
294     if (minor == CONFIG_STATUS::MISMATCHED_VALUE) {
295         return {};
296     }
297     numeration.push_back(minor);
298     if (minor_pos == std::string::npos) {
299         return numeration;
300     }
301     auto revision = parseProductConfigFromString(device, minor_pos + 1, device.size());
302     if (revision == CONFIG_STATUS::MISMATCHED_VALUE) {
303         return {};
304     }
305     numeration.push_back(revision);
306     return numeration;
307 }
308 
getProductConfig(std::vector<uint32_t> & numeration)309 uint32_t OclocArgHelper::getProductConfig(std::vector<uint32_t> &numeration) {
310     uint32_t config = 0x0;
311 
312     config = numeration.at(0) << 16;
313     if (numeration.size() > 1) {
314         config |= (numeration.at(1) << 8);
315     }
316     if (numeration.size() > 2) {
317         config |= numeration.at(2);
318     }
319 
320     return config;
321 }
322 
getMaskForConfig(std::vector<uint32_t> & numeration)323 uint32_t OclocArgHelper::getMaskForConfig(std::vector<uint32_t> &numeration) {
324     uint32_t mask = 0xffffff;
325     if (numeration.size() == 1) {
326         mask = 0xff0000;
327     } else if (numeration.size() == 2) {
328         mask = 0xffff00;
329     }
330     return mask;
331 }
332 
isGen(const std::string & device)333 bool OclocArgHelper::isGen(const std::string &device) {
334     std::string buf(device);
335     std::transform(buf.begin(), buf.end(), buf.begin(), ::tolower);
336     auto it = genIGFXMap.find(buf);
337     return it == genIGFXMap.end() ? false : true;
338 }
339 
returnIGFXforGen(const std::string & device)340 unsigned int OclocArgHelper::returnIGFXforGen(const std::string &device) {
341     std::string buf(device);
342     std::transform(buf.begin(), buf.end(), buf.begin(), ::tolower);
343     auto it = genIGFXMap.find(buf);
344     if (it == genIGFXMap.end())
345         return 0;
346     return it->second;
347 }
348 
areQuotesRequired(const std::string_view & argName)349 bool OclocArgHelper::areQuotesRequired(const std::string_view &argName) {
350     return argName == "-options" || argName == "-internal_options";
351 }
352 
findConfigMatch(const std::string & device,bool firstAppearance)353 PRODUCT_CONFIG OclocArgHelper::findConfigMatch(const std::string &device, bool firstAppearance) {
354     auto numeration = getMajorMinorRevision(device);
355     if (numeration.empty()) {
356         return PRODUCT_CONFIG::UNKNOWN_ISA;
357     }
358 
359     std::vector<PRODUCT_CONFIG> allMatchedConfigs;
360     std::vector<PRODUCT_CONFIG> allConfigs = getAllSupportedProductConfigs();
361     auto configValue = getProductConfig(numeration);
362     uint32_t mask = getMaskForConfig(numeration);
363 
364     if (!firstAppearance) {
365         // find last appearance
366         std::reverse(allConfigs.begin(), allConfigs.end());
367     }
368 
369     for (auto &productConfig : allConfigs) {
370         uint32_t value = static_cast<uint32_t>(productConfig) & mask;
371         if (value == configValue) {
372             return productConfig;
373         }
374     }
375     return PRODUCT_CONFIG::UNKNOWN_ISA;
376 }
377