1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2017-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #include "CISALinker.h"
10 #include <stdio.h>
11 
12 // *** Macros ***
13 
14 #define ASSERT(assertion, ...)                                          \
15     if (!(assertion)) {                                                 \
16         fprintf(stderr, "Error: " __VA_ARGS__);                         \
17         fprintf(stderr, "!\n");                                         \
18         return 1;                                                       \
19     }
20 
21 #define ALLOC_ASSERT(allocation)                                        \
22     ASSERT(                                                             \
23         allocation, "Memory allocation failure at %s:%u",               \
24         __FILE__, __LINE__);
25 
26 #define INTERNAL_ASSERT(assertion)                                      \
27     ASSERT(                                                             \
28         assertion, "Internal error at %s:%u",                           \
29         __FILE__, __LINE__)
30 
31 
32 #define TRY(x)                                                          \
33     if ((x)) {                                                          \
34         return 1;                                                       \
35     }
36 
37 #define BUF_APPEND_SCALAR(X)                                                \
38     memcpy(                                                                    \
39         (char *)_cisaObjInfos[_numCisaObjInfos].buf + _cisaEmitBufOffset,   \
40         &X, sizeof(X));                                                        \
41     _cisaEmitBufOffset += sizeof(X);
42 
43 #define BUF_APPEND_VECTOR(X, Y)                                                \
44     memcpy(                                                                    \
45         (char *)_cisaObjInfos[_numCisaObjInfos].buf + _cisaEmitBufOffset,    \
46         (X), Y);                                                            \
47     _cisaEmitBufOffset += Y;
48 
49 #define CLOSURE(x)     ((x).scratch)
50 #define UNITCLOSURE(x) (((CompiledUnitClosure *) CLOSURE(x)))
51 #define VARCLOSURE(x)  (((CompiledVarClosure *) CLOSURE(x)))
52 
53 #define cisaBytePos byte_pos
54 
55 // *** Public functions ***
56 
CISALinker(int numOptions,const char * options[],vISA::Mem_Manager & mem,ExternalHeapAllocator * externalAllocator)57 CISALinker::CISALinker(
58     int numOptions, const char *options[],
59     vISA::Mem_Manager& mem, ExternalHeapAllocator *externalAllocator)
60     : _numOptions(numOptions), _options(options), _mem(mem),
61       _countLinkedUnits(0), _countLinkedVars(0), _cisaEmitBufOffset(0),
62       _numCisaObjInfos(0), _cisaObjInfos(NULL)
63 {
64     _linkedUnitIndexToClosureMap.reserve(64);
65     if (externalAllocator) {
66         _allocator = externalAllocator;
67     }
68     else {
69         _allocator = (ExternalHeapAllocator*) malloc;
70     }
71 }
72 
~CISALinker()73 CISALinker::~CISALinker()
74 {
75 }
76 
77 int
LinkCisaMemObjs(const char * knlName,int numCisaObjs,const CisaObj cisaObjs[],CisaObj & cisaLinkedObj)78 CISALinker::LinkCisaMemObjs(
79     const char* knlName, int numCisaObjs, const CisaObj cisaObjs[],
80     CisaObj& cisaLinkedObj)
81 {
82     TRY(AllocateCisaObjInfos(numCisaObjs));
83 
84     for (int i = 0; i < numCisaObjs; i++) {
85         TRY(ReadCisaMemObj(cisaObjs[i], _cisaObjInfos[i]));
86     }
87 
88     std::string knlNameStr(knlName);
89     TRY(LinkCisaObjInfos(knlNameStr));
90     TRY(WriteCisaMemObj(cisaLinkedObj));
91 
92     return 0;
93 }
94 
95 int
LinkCisaFileObjs(const char * knlName,int numCisaObjs,const char * cisaObjs[],const char * cisaLinkedObj)96 CISALinker::LinkCisaFileObjs(
97     const char* knlName, int numCisaObjs, const char *cisaObjs[],
98     const char *cisaLinkedObj)
99 {
100     TRY(AllocateCisaObjInfos(numCisaObjs));
101 
102     for (int i = 0; i < numCisaObjs; i++) {
103         const char *cisaExt = ".isa";
104         const char *cisaObjFile = cisaObjs[i];
105         const char *argExt = strstr(cisaObjFile, cisaExt);
106         ASSERT(
107             argExt != NULL && argExt[4] =='\0',
108             "CISA object file %s must have .isa extension", cisaObjFile);
109         TRY(ReadCisaFileObj(cisaObjFile, _cisaObjInfos[i]));
110     }
111 
112     std::string knlNameStr(knlName);
113     TRY(LinkCisaObjInfos(knlNameStr));
114     TRY(WriteCisaFileObj(cisaLinkedObj));
115 
116     return 0;
117 }
118 
119 // *** Private functions ***
120 
121 int
LinkCisaObjInfos(const std::string & knlName)122 CISALinker::LinkCisaObjInfos(const std::string& knlName)
123 {
124     CisaObjInfo& cisaLinkedObjInfo = _cisaObjInfos[_numCisaObjInfos];
125     TRY(InitGlobalInfoTables());
126     CompiledUnitClosureList cisaKnlClosureList;
127     TRY(CreateKernelClosures(knlName, cisaKnlClosureList));
128     CompiledUnitClosureList::iterator iter = cisaKnlClosureList.begin();
129 
130     for (; iter != cisaKnlClosureList.end(); ++iter) {
131         CompiledUnitClosure& knlClosure = **iter;
132         CisaObjInfo& knlObjInfo = *knlClosure.unitObjInfo;
133         CompiledUnitClosureList localUnitClosureList;
134         localUnitClosureList.push_back(&knlClosure);
135         TRY(LinkLocalCisaObjInfos(knlObjInfo, localUnitClosureList));
136         TRY(LinkExternCisaObjInfos());
137     }
138 
139     TRY(BuildLinkedCisaObj(cisaKnlClosureList));
140     TRY(UpdateLinkedCisaImageOffsetsAndSize());
141     ClearGlobalInfoTables();
142 
143     return 0;
144 }
145 
146 int
InitGlobalInfoTables()147 CISALinker::InitGlobalInfoTables()
148 {
149     for (int i = 0; i < _numCisaObjInfos; i++) {
150         CisaObjInfo& cisaObjInfo = _cisaObjInfos[i];
151 
152         for (int j = 0; j < cisaObjInfo.hdr.num_global_functions; j++) {
153             int k = j + cisaObjInfo.hdr.num_extern_functions;
154             CompiledUnitInfo& unit = cisaObjInfo.hdr.functions[k];
155             CompiledUnitClosure *unitClosure =
156                 (CompiledUnitClosure *)
157                 _mem.alloc(sizeof(CompiledUnitClosure));
158             unitClosure->unit = &unit;
159             unitClosure->unitObjInfo = &cisaObjInfo;
160             unitClosure->linkedUnitIndex = -1;
161             CLOSURE(unit) = unitClosure;
162             std::string key(unit.name, unit.name_len);
163             std::pair<GlobalUnitNameToInfoMap::iterator, bool> loc =
164                 _globalUnitNameToInfoMap.insert(
165                     GlobalUnitNameToInfoMap::value_type(key, &unit));
166             ASSERT(
167                 loc.second, "Found duplicate global functions for %s",
168                 key.c_str());
169         }
170     }
171 
172     for (int i = 0; i < _numCisaObjInfos; i++) {
173         CisaObjInfo& cisaObjInfo = _cisaObjInfos[i];
174 
175         for (int j = 0; j < cisaObjInfo.hdr.num_global_variables; j++) {
176             int k = j + cisaObjInfo.hdr.num_extern_variables;
177             CompiledVarInfo& var = cisaObjInfo.hdr.filescope_variables[k];
178             CompiledVarClosure * varClosure =
179                 (CompiledVarClosure *) _mem.alloc(sizeof(CompiledVarClosure));
180             varClosure->var = &var;
181             varClosure->varObjInfo = &cisaObjInfo;
182             varClosure->linkedVarIndex = -1;
183             CLOSURE(var) = varClosure;
184             std::string key((char *)var.name, var.name_len);
185             std::pair<GlobalVarNameToInfoMap::iterator, bool> loc =
186                 _globalVarNameToInfoMap.insert(
187                     GlobalVarNameToInfoMap::value_type(key, &var));
188             ASSERT(
189                 loc.second, "Found duplicate global variables for %s",
190                 key.c_str());
191         }
192     }
193 
194     return 0;
195 }
196 
197 inline void
ClearGlobalInfoTables()198 CISALinker::ClearGlobalInfoTables()
199 {
200     _globalUnitNameToInfoMap.clear();
201     _globalVarNameToInfoMap.clear();
202 }
203 
204 inline int
GetGlobalUnitInfo(const std::string & unitName,CompiledUnitInfo * & globalUnitInfo)205 CISALinker::GetGlobalUnitInfo(
206     const std::string& unitName, CompiledUnitInfo *& globalUnitInfo)
207 {
208     GlobalUnitNameToInfoMap::iterator loc =
209         _globalUnitNameToInfoMap.find(unitName);
210     ASSERT(
211         loc != _globalUnitNameToInfoMap.end(),
212         "Cannot find global function %s", unitName.c_str());
213     globalUnitInfo = (*loc).second;
214 
215     return 0;
216 }
217 
218 inline int
GetGlobalUnitClosure(const std::string & unitName,CompiledUnitClosure * & globalUnitClosure)219 CISALinker::GetGlobalUnitClosure(
220     const std::string& unitName, CompiledUnitClosure *& globalUnitClosure)
221 {
222     CompiledUnitInfo *globalUnitInfo = NULL;
223     TRY(GetGlobalUnitInfo(unitName, globalUnitInfo));
224     globalUnitClosure = UNITCLOSURE(*globalUnitInfo);
225     INTERNAL_ASSERT(globalUnitClosure);
226 
227     return 0;
228 }
229 
230 inline int
GetGlobalVarInfo(const std::string & unitName,CompiledVarInfo * & globalVarInfo)231 CISALinker::GetGlobalVarInfo(
232     const std::string& unitName, CompiledVarInfo *& globalVarInfo)
233 {
234     GlobalVarNameToInfoMap::iterator loc =
235         _globalVarNameToInfoMap.find(unitName);
236     ASSERT(
237         loc != _globalVarNameToInfoMap.end(),
238         "Cannot find global variable %s", unitName.c_str());
239     globalVarInfo = (*loc).second;
240 
241     return 0;
242 }
243 
244 inline int
GetGlobalVarClosure(const std::string & unitName,CompiledVarClosure * & globalVarClosure)245 CISALinker::GetGlobalVarClosure(
246     const std::string& unitName, CompiledVarClosure *& globalVarClosure)
247 {
248     CompiledVarInfo *globalVarInfo = NULL;
249     TRY(GetGlobalVarInfo(unitName, globalVarInfo));
250     globalVarClosure = VARCLOSURE(*globalVarInfo);
251     INTERNAL_ASSERT(globalVarClosure);
252 
253     return 0;
254 }
255 
256 int
CreateKernelClosures(const std::string & knlName,CompiledUnitClosureList & knlClosureList)257 CISALinker::CreateKernelClosures(
258     const std::string& knlName, CompiledUnitClosureList& knlClosureList)
259 {
260     for (int i = 0; i < _numCisaObjInfos; i++) {
261         CisaObjInfo& cisaObjInfo = _cisaObjInfos[i];
262 
263         for (int j = 0; j < cisaObjInfo.hdr.num_kernels; j++) {
264             CompiledUnitInfo& kernel = cisaObjInfo.hdr.kernels[j];
265 
266             if ((knlName.size() == 0) ||
267                 (knlName.size() == kernel.name_len &&
268                  strncmp(kernel.name, knlName.c_str(), knlName.size()) == 0)) {
269                 CompiledUnitClosure *knlClosure =
270                     (CompiledUnitClosure *)
271                     _mem.alloc(sizeof(CompiledUnitClosure));
272                 ALLOC_ASSERT(knlClosure);
273                 knlClosure->unit = &kernel;
274                 knlClosure->unitObjInfo = &cisaObjInfo;
275                 knlClosure->linkedUnitIndex = 0;
276                 CLOSURE(kernel) = knlClosure;
277                 knlClosureList.push_back(knlClosure);
278 
279                 if (knlName.size() && knlClosureList.size()) {
280                     break;
281                 }
282             }
283 
284             if (knlName.size() && knlClosureList.size()) {
285                 break;
286             }
287         }
288     }
289 
290     if (knlName.size()) {
291         ASSERT(
292             knlClosureList.size() > 0,
293             "Cannot find kernel %s", knlName.c_str());
294     }
295     else {
296         ASSERT(
297             knlClosureList.size() > 0,
298             "Cannot find any kernel in input CISA objects");
299     }
300 
301     return 0;
302 }
303 
304 int
LinkLocalCisaObjInfos(CisaObjInfo & cisaObjInfo,CompiledUnitClosureList & localUnitClosureList)305 CISALinker::LinkLocalCisaObjInfos(
306     CisaObjInfo& cisaObjInfo, CompiledUnitClosureList& localUnitClosureList)
307 {
308     _localUnitMap = cisaObjInfo.hdr.functions;
309     _localVarMap  = cisaObjInfo.hdr.filescope_variables;
310     CompiledUnitClosureList::iterator iter = localUnitClosureList.begin();
311 
312     for ( ; iter != localUnitClosureList.end(); ++iter) {
313         TRY(LinkInDepUnits(**iter));
314         TRY(LinkInDepVars(**iter));
315     }
316 
317     for (iter = _pendingLocalClosures.begin();
318          iter != _pendingLocalClosures.end(); ++iter) {
319         TRY(LinkInDepUnits(**iter));
320         TRY(LinkInDepVars(**iter));
321     }
322 
323     for (iter = _pendingLocalClosures.begin();
324          iter != _pendingLocalClosures.end(); ++iter) {
325         TRY(RelocFunctionSyms(**iter));
326         TRY(RelocVariableSyms(**iter));
327     }
328 
329     for (iter = localUnitClosureList.begin();
330          iter != localUnitClosureList.end(); ++iter) {
331         TRY(RelocFunctionSyms(**iter));
332         TRY(RelocVariableSyms(**iter));
333     }
334 
335     _pendingLocalClosures.clear();
336     _localUnitMap = NULL;
337     _localVarMap = NULL;
338 
339     return 0;
340 }
341 
342 int
LinkExternCisaObjInfos()343 CISALinker::LinkExternCisaObjInfos()
344 {
345     CompiledUnitClosureList::iterator iter = _pendingExternClosures.begin();
346 
347     for ( ; iter != _pendingExternClosures.end(); ++iter) {
348         CompiledUnitClosureList localUnitClosuresList;
349         localUnitClosuresList.push_back(*iter);
350 
351         CompiledUnitClosureList::iterator jter = iter;
352 
353         for ( ++jter; jter != _pendingExternClosures.end(); ) {
354 
355             if ((*jter)->unitObjInfo == (*iter)->unitObjInfo) {
356                 localUnitClosuresList.push_back(*jter);
357                 CompiledUnitClosureList::iterator kter = jter++;
358                 _pendingExternClosures.erase(kter);
359             }
360             else {
361                 ++jter;
362             }
363         }
364 
365         CisaObjInfo& unitObjInfo = *(*iter)->unitObjInfo;
366         TRY(LinkLocalCisaObjInfos(unitObjInfo, localUnitClosuresList));
367     }
368 
369     _pendingExternClosures.clear();
370 
371     return 0;
372 }
373 
374 int
LinkInDepUnits(CompiledUnitClosure & cisaUnitClosure)375 CISALinker::LinkInDepUnits(CompiledUnitClosure& cisaUnitClosure)
376 {
377     CompiledUnitInfo& cisaUnitInfo = *cisaUnitClosure.unit;
378     int globalStartIndex =
379         cisaUnitClosure.unitObjInfo->hdr.num_extern_functions;
380     int staticStartIndex =
381         globalStartIndex +
382         cisaUnitClosure.unitObjInfo->hdr.num_global_functions;
383 
384     for (int i = 0; i < cisaUnitInfo.function_reloc_symtab.num_syms; i++) {
385         int inputRefIndex =
386             cisaUnitInfo.function_reloc_symtab.reloc_syms[i].resolved_index;
387 
388         if (inputRefIndex >= staticStartIndex) {
389 
390             if (CLOSURE(_localUnitMap[inputRefIndex]) == NULL) {
391                 CompiledUnitClosure *depUnitClosure =
392                     (CompiledUnitClosure *)
393                     _mem.alloc(sizeof(CompiledUnitClosure));
394                 CLOSURE(_localUnitMap[inputRefIndex]) = depUnitClosure;
395                 depUnitClosure->unit =
396                     &cisaUnitClosure.unitObjInfo->hdr.functions[inputRefIndex];
397                 depUnitClosure->unitObjInfo = cisaUnitClosure.unitObjInfo;
398                 depUnitClosure->linkedUnitIndex = _countLinkedUnits++;
399                 _linkedUnitIndexToClosureMap.push_back(depUnitClosure);
400                 _pendingLocalClosures.push_back(depUnitClosure);
401             }
402         }
403         else if (inputRefIndex >= globalStartIndex) {
404             CompiledUnitClosure *depUnitClosure =
405                 UNITCLOSURE(_localUnitMap[inputRefIndex]);
406             INTERNAL_ASSERT(depUnitClosure);
407 
408             if (depUnitClosure->linkedUnitIndex == -1) {
409                 depUnitClosure->linkedUnitIndex = _countLinkedUnits++;
410                 _linkedUnitIndexToClosureMap.push_back(depUnitClosure);
411                 _pendingLocalClosures.push_back(depUnitClosure);
412             }
413         }
414         else {
415             CompiledUnitInfo& unit =
416                 cisaUnitClosure.unitObjInfo->hdr.functions[inputRefIndex];
417             CompiledUnitClosure *externUnitClosure = NULL;
418             std::string unitName(unit.name, unit.name_len);
419             TRY(GetGlobalUnitClosure(unitName, externUnitClosure));
420 
421             if (externUnitClosure->linkedUnitIndex == -1) {
422                 externUnitClosure->linkedUnitIndex = _countLinkedUnits++;
423                 _linkedUnitIndexToClosureMap.push_back(externUnitClosure);
424                 _pendingExternClosures.push_back(externUnitClosure);
425             }
426         }
427     }
428 
429     return 0;
430 }
431 
432 int
LinkInDepVars(CompiledUnitClosure & cisaUnitClosure)433 CISALinker::LinkInDepVars(CompiledUnitClosure& cisaUnitClosure)
434 {
435     CompiledVarInfo *vars =
436         cisaUnitClosure.unitObjInfo->hdr.filescope_variables;
437     CompiledUnitInfo& cisaUnitInfo = *cisaUnitClosure.unit;
438     int globalStartIndex =
439         cisaUnitClosure.unitObjInfo->hdr.num_extern_variables;
440     int staticStartIndex =
441         globalStartIndex +
442         cisaUnitClosure.unitObjInfo->hdr.num_global_variables;
443 
444     for (int i = 0; i < cisaUnitInfo.variable_reloc_symtab.num_syms; i++) {
445         int inputRefIndex =
446             cisaUnitInfo.variable_reloc_symtab.reloc_syms[i].resolved_index;
447 
448         if (inputRefIndex >= staticStartIndex) {
449 
450             if (CLOSURE(_localVarMap[inputRefIndex]) == NULL) {
451                 CompiledVarClosure * depVarClosure =
452                     (CompiledVarClosure *)
453                     _mem.alloc(sizeof(CompiledVarClosure));
454                 CLOSURE(_localVarMap[inputRefIndex]) = depVarClosure;
455                 CompiledVarInfo& var = vars[inputRefIndex];
456                 depVarClosure->var =&var;
457                 depVarClosure->varObjInfo = cisaUnitClosure.unitObjInfo;
458                 depVarClosure->linkedVarIndex = _countLinkedVars++;
459                 _linkedVarIndexToClosureMap.push_back(depVarClosure);
460             }
461         }
462         else if (inputRefIndex >= globalStartIndex) {
463             CompiledVarClosure *depVarClosure =
464                 VARCLOSURE(_localVarMap[inputRefIndex]);
465             INTERNAL_ASSERT(depVarClosure);
466 
467             if (depVarClosure->linkedVarIndex == -1) {
468                 depVarClosure->linkedVarIndex = _countLinkedVars++;
469                 _linkedVarIndexToClosureMap.push_back(depVarClosure);
470             }
471         }
472         else {
473             CompiledVarInfo& variable = vars[inputRefIndex];
474             CompiledVarClosure *externVarClosure = NULL;
475             std::string varName((char *) variable.name, variable.name_len);
476             TRY(GetGlobalVarClosure(varName, externVarClosure));
477 
478             if (externVarClosure->linkedVarIndex == -1) {
479                 externVarClosure->linkedVarIndex = _countLinkedVars++;
480                 _linkedVarIndexToClosureMap.push_back(externVarClosure);
481             }
482         }
483     }
484 
485     return 0;
486 }
487 
488 int
RelocFunctionSyms(CompiledUnitClosure & localUnitClosure)489 CISALinker::RelocFunctionSyms(CompiledUnitClosure& localUnitClosure)
490 {
491     CompiledUnitInfo& localUnitInfo = *localUnitClosure.unit;
492 
493     for (int i = 0; i < localUnitInfo.function_reloc_symtab.num_syms; i++) {
494         int inputRefIndex =
495             localUnitInfo.function_reloc_symtab.reloc_syms[i].resolved_index;
496         int offset = localUnitClosure.unitObjInfo->hdr.num_extern_functions;
497 
498         if (inputRefIndex >= offset) {
499             int linkedUnitIndex =
500                 UNITCLOSURE(_localUnitMap[inputRefIndex])->linkedUnitIndex;
501             INTERNAL_ASSERT(linkedUnitIndex >= 0);
502             localUnitInfo.function_reloc_symtab.reloc_syms[i].resolved_index =
503                 linkedUnitIndex;
504         }
505         else {
506             CompiledUnitInfo *units =
507                 localUnitClosure.unitObjInfo->hdr.functions;
508             CompiledUnitInfo& unit = units[inputRefIndex];
509             CompiledUnitClosure *externUnitClosure = NULL;
510             std::string unitName(unit.name, unit.name_len);
511             TRY(GetGlobalUnitClosure(unitName, externUnitClosure));
512             int linkedUnitIndex = externUnitClosure->linkedUnitIndex;
513             INTERNAL_ASSERT(linkedUnitIndex >= 0);
514             localUnitInfo.function_reloc_symtab.reloc_syms[i].resolved_index =
515                 linkedUnitIndex;
516         }
517     }
518 
519     return 0;
520 }
521 
522 int
RelocVariableSyms(CompiledUnitClosure & localUnitClosure)523 CISALinker::RelocVariableSyms(CompiledUnitClosure& localUnitClosure)
524 {
525     CompiledUnitInfo& localUnitInfo = *localUnitClosure.unit;
526     CompiledVarInfo *vars =
527         (CompiledVarInfo *)
528         localUnitClosure.unitObjInfo->hdr.filescope_variables;
529 
530     for (int i = 0; i < localUnitInfo.variable_reloc_symtab.num_syms; i++) {
531         int inputRefIndex =
532             localUnitInfo.variable_reloc_symtab.reloc_syms[i].resolved_index;
533         int offset =
534             localUnitClosure.unitObjInfo->hdr.num_extern_variables;
535 
536         if (inputRefIndex >= offset) {
537             int linkedVarIndex =
538                 VARCLOSURE(_localVarMap[inputRefIndex])->linkedVarIndex;
539             INTERNAL_ASSERT(linkedVarIndex >= 0);
540             localUnitInfo.variable_reloc_symtab.reloc_syms[i].resolved_index =
541                 linkedVarIndex;
542         }
543         else {
544             CompiledVarInfo& variable = vars[inputRefIndex];
545             CompiledVarClosure * externVarClosure = NULL;
546             std::string unitName((char *) variable.name, variable.name_len);
547             TRY(GetGlobalVarClosure(unitName, externVarClosure));
548             int linkedVarIndex = externVarClosure->linkedVarIndex;
549             INTERNAL_ASSERT(linkedVarIndex >= 0);
550             localUnitInfo.variable_reloc_symtab.reloc_syms[i].resolved_index =
551                 externVarClosure->linkedVarIndex;
552         }
553     }
554 
555     return 0;
556 }
557 
558 int
BuildLinkedCisaObj(CompiledUnitClosureList & knlClosureList)559 CISALinker::BuildLinkedCisaObj(CompiledUnitClosureList& knlClosureList)
560 {
561     CisaObjInfo& linkedObjInfo = _cisaObjInfos[_numCisaObjInfos];
562     const CisaHeader& firstKnlHdr = knlClosureList.front()->unitObjInfo->hdr;
563 
564     linkedObjInfo.hdr.magic_number = firstKnlHdr.magic_number;
565     linkedObjInfo.hdr.major_version = firstKnlHdr.major_version;
566     linkedObjInfo.hdr.minor_version = firstKnlHdr.minor_version;
567     linkedObjInfo.hdr.num_kernels = knlClosureList.size();
568     linkedObjInfo.hdr.num_extern_variables = 0;
569     linkedObjInfo.hdr.num_global_variables = 0;
570     linkedObjInfo.hdr.num_static_variables = _countLinkedVars;
571     linkedObjInfo.hdr.num_filescope_variables = _countLinkedVars;
572     linkedObjInfo.hdr.num_extern_functions = 0;
573     linkedObjInfo.hdr.num_global_functions = 0;
574     linkedObjInfo.hdr.num_static_functions = _countLinkedUnits;
575     linkedObjInfo.hdr.num_functions = _countLinkedUnits;
576     linkedObjInfo.hdr.kernels =
577         (CompiledUnitInfo *)
578         _mem.alloc(sizeof(CompiledUnitInfo) * knlClosureList.size());
579     ALLOC_ASSERT(linkedObjInfo.hdr.kernels);
580     linkedObjInfo.hdr.filescope_variables =
581         (CompiledVarInfo *) _mem.alloc(
582             sizeof(CompiledUnitInfo) * _countLinkedVars);
583 
584     if (_countLinkedUnits) {
585         linkedObjInfo.hdr.functions =
586             (CompiledUnitInfo *) _mem.alloc(
587                 sizeof(CompiledUnitInfo) * _countLinkedUnits);
588         ALLOC_ASSERT(_countLinkedUnits == 0 || linkedObjInfo.hdr.functions);
589     }
590     else {
591         linkedObjInfo.hdr.functions = NULL;
592     }
593 
594     TRY(BuildLinkedVarInfo(linkedObjInfo.hdr));
595     CompiledUnitClosureList::iterator iter = knlClosureList.begin();
596 
597     for (int i = 0; iter != knlClosureList.end(); ++iter, ++i) {
598         CompiledUnitClosure& knlClosure = **iter;
599         CompiledUnitInfo& knlInfo = *knlClosure.unit;
600         std::string knlName(knlInfo.name, knlInfo.name_len);
601         TRY(BuildLinkedUnitInfo(
602                 knlName, knlClosure, linkedObjInfo.hdr.kernels[i]));
603     }
604 
605     for (int i = 0; i < _countLinkedUnits; i++) {
606         CompiledUnitClosure& funcClosure = *_linkedUnitIndexToClosureMap[i];
607         CompiledUnitInfo& funcInfo = *funcClosure.unit;
608         std::string unitName(funcInfo.name, funcInfo.name_len);
609         TRY(BuildLinkedUnitInfo(
610                 unitName, funcClosure,linkedObjInfo.hdr.functions[i]));
611     }
612 
613     linkedObjInfo.buf = NULL;
614     linkedObjInfo.size = 0;
615 
616     return 0;
617 }
618 
619 int
BuildLinkedUnitInfo(const std::string & unitName,CompiledUnitClosure & objUnitClosure,CompiledUnitInfo & linkedUnitInfo)620 CISALinker::BuildLinkedUnitInfo(
621     const std::string &unitName, CompiledUnitClosure& objUnitClosure,
622     CompiledUnitInfo& linkedUnitInfo)
623 {
624     CompiledUnitInfo& objUnit = *objUnitClosure.unit;
625 
626     linkedUnitInfo.name_len = unitName.size();
627     strncpy(linkedUnitInfo.name, unitName.c_str(), unitName.size());
628     linkedUnitInfo.offset = objUnit.offset;
629     linkedUnitInfo.size = objUnit.size;
630     linkedUnitInfo.input_offset = objUnit.input_offset;
631     BuildRelocSymTab(
632         linkedUnitInfo.variable_reloc_symtab, objUnit.variable_reloc_symtab);
633     BuildRelocSymTab(
634         linkedUnitInfo.function_reloc_symtab, objUnit.function_reloc_symtab);
635     linkedUnitInfo.num_gen_binaries = 0;
636     linkedUnitInfo.cisa_binary_buffer =
637         (char *) objUnitClosure.unitObjInfo->buf + objUnit.offset;
638 
639     return 0;
640 }
641 
642 int
BuildRelocSymTab(RelocTab & dst,RelocTab & src)643 CISALinker::BuildRelocSymTab(RelocTab& dst, RelocTab& src)
644 {
645     dst.num_syms = src.num_syms;
646 
647     if (dst.num_syms) {
648         dst.reloc_syms =
649             (reloc_sym *) _mem.alloc(sizeof(reloc_sym) * src.num_syms);
650         ALLOC_ASSERT(dst.reloc_syms);
651 
652         for (int i = 0; i < src.num_syms; i++) {
653             dst.reloc_syms[i].symbolic_index =
654                 src.reloc_syms[i].symbolic_index;
655             dst.reloc_syms[i].resolved_index =
656                 src.reloc_syms[i].resolved_index;
657         }
658     }
659     else {
660         dst.reloc_syms = NULL;
661     }
662 
663     return 0;
664 }
665 
666 int
BuildLinkedVarInfo(CisaHeader & linkedUnitHdr)667 CISALinker::BuildLinkedVarInfo(CisaHeader& linkedUnitHdr)
668 {
669     for (int i = 0; i < _countLinkedVars; i++) {
670         CompiledVarInfo& objVariable = *_linkedVarIndexToClosureMap[i]->var;
671         CompiledVarInfo& linkedVariable = linkedUnitHdr.filescope_variables[i];
672         linkedVariable.name_len = objVariable.name_len;
673         linkedVariable.name = objVariable.name;
674         linkedVariable.bit_properties = objVariable.bit_properties;
675         linkedVariable.num_elements = objVariable.num_elements;
676         linkedVariable.attribute_count = objVariable.attribute_count;
677         linkedVariable.attributes = objVariable.attributes;
678     }
679 
680     return 0;
681 }
682 
683 int
UpdateLinkedCisaImageOffsetsAndSize()684 CISALinker::UpdateLinkedCisaImageOffsetsAndSize()
685 {
686     CisaObjInfo& linkedObjInfo    = _cisaObjInfos[_numCisaObjInfos];
687     CisaHeader& linkedObjHdr      = linkedObjInfo.hdr;
688 
689     _linkedCisaImageSize = 0;
690     _linkedCisaImageSize += sizeof(linkedObjHdr.magic_number);
691     _linkedCisaImageSize += sizeof(linkedObjHdr.major_version);
692     _linkedCisaImageSize += sizeof(linkedObjHdr.minor_version);
693     _linkedCisaImageSize += sizeof(linkedObjHdr.num_kernels);
694 
695     for (int i = 0; i < linkedObjHdr.num_kernels; i++) {
696         _linkedCisaImageSize += CalculateSize(linkedObjHdr.kernels[i], false);
697     }
698 
699     _linkedCisaImageSize += sizeof(linkedObjHdr.num_filescope_variables);
700 
701     for (int i = 0; i < linkedObjHdr.num_filescope_variables; i++) {
702         _linkedCisaImageSize +=
703             CalculateSize(linkedObjHdr.filescope_variables[i]);
704     }
705 
706     _linkedCisaImageSize += sizeof(linkedObjHdr.num_functions);
707 
708     for (int i = 0; i < linkedObjHdr.num_functions; i++) {
709         _linkedCisaImageSize += CalculateSize(linkedObjHdr.functions[i], true);
710     }
711 
712     for (int i = 0; i < linkedObjHdr.num_kernels; i++) {
713         CompiledUnitInfo& knlUnitInfo = linkedObjHdr.kernels[i];
714         unsigned knlUnitDataStartOffset = _linkedCisaImageSize;
715         knlUnitInfo.input_offset = knlUnitInfo.input_offset - knlUnitInfo.offset + knlUnitDataStartOffset;
716         knlUnitInfo.offset = knlUnitDataStartOffset;
717         _linkedCisaImageSize += knlUnitInfo.size;
718     }
719 
720     for (int i = 0; i < linkedObjHdr.num_functions; i++) {
721         CompiledUnitInfo& unitInfo = linkedObjHdr.functions[i];
722         unsigned unitDataStartOffset = _linkedCisaImageSize;
723         unitInfo.offset = unitDataStartOffset;
724         _linkedCisaImageSize += unitInfo.size;
725     }
726 
727     linkedObjInfo.size = _linkedCisaImageSize;
728 
729     return 0;
730 }
731 
732 int
CalculateSize(CompiledUnitInfo & unit,bool isFunction)733 CISALinker::CalculateSize(CompiledUnitInfo& unit, bool isFunction)
734 {
735     unsigned size = 0;
736     if( isFunction == true )
737     {
738         size += sizeof(unit.linkage);
739     }
740 
741     size += sizeof(unit.name_len) + unit.name_len;
742     size += sizeof(unit.offset);
743     size += sizeof(unit.size);
744 
745     if( isFunction == false )
746     {
747         size += sizeof(unit.input_offset);
748     }
749 
750     size += CalculateSize(unit.variable_reloc_symtab);
751     size += CalculateSize(unit.function_reloc_symtab);
752 
753     if( isFunction == false )
754     {
755         size += sizeof(unit.num_gen_binaries);
756     }
757 
758     return size;
759 }
760 
761 int
CalculateSize(CompiledVarInfo & var)762 CISALinker::CalculateSize(CompiledVarInfo& var)
763 {
764     unsigned size = 0;
765     size += sizeof(var.linkage);
766     size += sizeof(var.name_len) + var.name_len;
767     size += sizeof(var.bit_properties);
768     size += sizeof(var.num_elements);
769     size += sizeof(var.attribute_count);
770 
771     for (int i = 0; i < var.attribute_count; i++) {
772         size += sizeof(var.attributes[i].nameIndex);
773         size +=
774             sizeof(var.attributes[i].size) + var.attributes[i].size;
775     }
776 
777     return size;
778 }
779 
780 int
CalculateSize(RelocTab & symTab)781 CISALinker::CalculateSize(RelocTab& symTab)
782 {
783     unsigned size = 0;
784     size += sizeof(symTab.num_syms);
785     size += sizeof(reloc_sym) * symTab.num_syms;
786 
787     return size;
788 }
789 
790 int
AllocateCisaObjInfos(int numCisaObjs)791 CISALinker::AllocateCisaObjInfos(int numCisaObjs)
792 {
793     _cisaObjInfos =
794         (CisaObjInfo *)_mem.alloc(sizeof(CisaObjInfo) * (numCisaObjs + 1));
795     ALLOC_ASSERT(_cisaObjInfos);
796     _numCisaObjInfos = numCisaObjs;
797 
798     for (int i = 0; i < numCisaObjs + 1; i++) {
799         _cisaObjInfos[i].index = i;
800     }
801 
802     return 0;
803 }
804 
805 int
ReadCisaMemObj(const CisaObj & cisaObj,CisaObjInfo & cisaObjInfo)806 CISALinker::ReadCisaMemObj(const CisaObj& cisaObj, CisaObjInfo& cisaObjInfo)
807 {
808     unsigned cisaBytePos = 0;
809 
810     if (ExtractCisaMemObjHdr(cisaObjInfo.hdr, cisaBytePos, cisaObj.buf)) {
811         return 1;
812     }
813 
814     ASSERT(cisaBytePos <= cisaObj.size, "Corrupted CISA object");
815     cisaObjInfo.buf = cisaObj.buf;
816     cisaObjInfo.size = cisaObj.size;
817 
818     return 0;
819 }
820 
821 
822 inline int
ExtractCisaMemObjHdr(CisaHeader & cisaHdr,unsigned & cisaBytePos,const void * cisaBuffer)823 CISALinker::ExtractCisaMemObjHdr(
824     CisaHeader& cisaHdr, unsigned& cisaBytePos, const void *cisaBuffer)
825 {
826     TRY(::processCommonISAHeader(cisaHdr, cisaBytePos, cisaBuffer, &_mem));
827     ASSERT(
828         cisaHdr.major_version >= 3, "Linking is supported only for CISA 3.0+");
829 
830     return 0;
831 }
832 
833 int
ReadCisaFileObj(const char * cisaFileName,CisaObjInfo & cisaObjInfo)834 CISALinker::ReadCisaFileObj(const char *cisaFileName, CisaObjInfo& cisaObjInfo)
835 {
836     FILE *cisaFile = fopen(cisaFileName, "rb");
837     ASSERT(cisaFile != NULL, "Cannot open %s", cisaFileName);
838     fseek(cisaFile, 0, SEEK_END);
839     unsigned fileSize = ftell(cisaFile);
840     char *cisaBuffer = (char *) _mem.alloc(fileSize);
841     fseek(cisaFile, 0, SEEK_SET);
842     ALLOC_ASSERT(cisaBuffer);
843     ASSERT(
844         fread(cisaBuffer, 1, fileSize, cisaFile) != 0,
845         "Cannot read CISA object %s", cisaFileName);
846     fclose(cisaFile);
847     CisaObj cisaObj;
848     cisaObj.buf = cisaBuffer;
849     cisaObj.size = fileSize;
850 
851     return ReadCisaMemObj(cisaObj, cisaObjInfo);
852 }
853 
854 int
WriteCisaMemObj(CisaObj & cisaObj)855 CISALinker::WriteCisaMemObj(CisaObj& cisaObj)
856 {
857     TRY(WriteCisaMemObj());
858     cisaObj.size = _linkedCisaImageSize;
859     cisaObj.buf = (char *) (*_allocator)(_linkedCisaImageSize);
860     CisaObjInfo& linkedObjInfo = _cisaObjInfos[_numCisaObjInfos];
861     memcpy((void *) cisaObj.buf, linkedObjInfo.buf, cisaObj.size);
862     ALLOC_ASSERT(cisaObj.buf);
863 
864     return 0;
865 }
866 
867 int
WriteCisaMemObj()868 CISALinker::WriteCisaMemObj()
869 {
870     CisaObjInfo&      linkedObjInfo = _cisaObjInfos[_numCisaObjInfos];
871     CisaHeader&       linkedObjHdr  = linkedObjInfo.hdr;
872     CompiledUnitInfo& knlUnitInfo   = linkedObjHdr.kernels[0];
873 
874     linkedObjInfo.size = _linkedCisaImageSize;
875     linkedObjInfo.buf = (char *) _mem.alloc(_linkedCisaImageSize);
876     ALLOC_ASSERT(linkedObjInfo.buf);
877 
878     BUF_APPEND_SCALAR(linkedObjHdr.magic_number);
879     BUF_APPEND_SCALAR(linkedObjHdr.major_version);
880     BUF_APPEND_SCALAR(linkedObjHdr.minor_version);
881     BUF_APPEND_SCALAR(linkedObjHdr.num_kernels);
882 
883     for (int i = 0; i < linkedObjHdr.num_kernels; i++) {
884         WriteCisaCompiledUnitInfo(linkedObjHdr.kernels[i], false);
885     }
886 
887     BUF_APPEND_SCALAR(linkedObjHdr.num_filescope_variables);
888 
889     for (int i = 0; i < linkedObjHdr.num_filescope_variables; i++) {
890         WriteCisaVarInfo(linkedObjHdr.filescope_variables[i]);
891     }
892 
893     BUF_APPEND_SCALAR(linkedObjHdr.num_functions);
894     for (int i = 0; i < linkedObjHdr.num_functions; i++) {
895         WriteCisaCompiledUnitInfo(linkedObjHdr.functions[i], true);
896     }
897 
898     for (int i = 0; i < linkedObjHdr.num_kernels; i++) {
899         WriteCisaCompiledUnitData(linkedObjHdr.kernels[i]);
900     }
901 
902     for (int i = 0; i < linkedObjHdr.num_functions; i++) {
903         WriteCisaCompiledUnitData(linkedObjHdr.functions[i]);
904     }
905 
906     INTERNAL_ASSERT(linkedObjInfo.size == _linkedCisaImageSize);
907 
908     return 0;
909 }
910 
911 int
WriteCisaCompiledUnitInfo(CompiledUnitInfo & unit,bool isFunction)912 CISALinker::WriteCisaCompiledUnitInfo(CompiledUnitInfo& unit, bool isFunction)
913 {
914     if( isFunction == true )
915     {
916         BUF_APPEND_SCALAR(unit.linkage);
917     }
918 
919     BUF_APPEND_SCALAR(unit.name_len);
920     BUF_APPEND_VECTOR(unit.name, unit.name_len);
921     BUF_APPEND_SCALAR(unit.offset);
922     BUF_APPEND_SCALAR(unit.size);
923 
924     if( isFunction == false )
925     {
926         BUF_APPEND_SCALAR(unit.input_offset);
927     }
928 
929     WriteRelocSymTab(unit.variable_reloc_symtab);
930     WriteRelocSymTab(unit.function_reloc_symtab);
931 
932     if( isFunction == false )
933     {
934         unit.num_gen_binaries = 0;
935         BUF_APPEND_SCALAR(unit.num_gen_binaries);
936     }
937 
938     return 0;
939 }
940 
941 int
WriteCisaVarInfo(CompiledVarInfo & var)942 CISALinker::WriteCisaVarInfo(CompiledVarInfo& var)
943 {
944     BUF_APPEND_SCALAR(var.linkage);
945     BUF_APPEND_SCALAR(var.name_len);
946     BUF_APPEND_VECTOR(var.name, var.name_len);
947     BUF_APPEND_SCALAR(var.bit_properties);
948     BUF_APPEND_SCALAR(var.num_elements);
949     BUF_APPEND_SCALAR(var.attribute_count);
950 
951     for (int i = 0; i < var.attribute_count; i++) {
952         BUF_APPEND_SCALAR(var.attributes[i].nameIndex);
953         BUF_APPEND_SCALAR(var.attributes[i].size);
954         BUF_APPEND_VECTOR(
955             var.attributes[i].value.stringVal, var.attributes[i].size);
956     }
957 
958     return 0;
959 }
960 
961 int
WriteRelocSymTab(RelocTab & symTab)962 CISALinker::WriteRelocSymTab(RelocTab& symTab)
963 {
964     BUF_APPEND_SCALAR(symTab.num_syms);
965 
966     for (int i = 0; i < symTab.num_syms; i++) {
967         BUF_APPEND_SCALAR(symTab.reloc_syms[i].symbolic_index);
968         BUF_APPEND_SCALAR(symTab.reloc_syms[i].resolved_index);
969     }
970 
971     return 0;
972 }
973 
974 int
WriteCisaCompiledUnitData(CompiledUnitInfo & unitInfo)975 CISALinker::WriteCisaCompiledUnitData(CompiledUnitInfo& unitInfo)
976 {
977     if (unitInfo.size) {
978         BUF_APPEND_VECTOR(unitInfo.cisa_binary_buffer, unitInfo.size);
979     }
980 
981     return 0;
982 }
983 
984 int
WriteCisaFileObj(const char * cisaFileName)985 CISALinker::WriteCisaFileObj(const char *cisaFileName)
986 {
987     WriteCisaMemObj();
988     FILE *cisaFile = fopen(cisaFileName, "wb");
989     ASSERT(cisaFile != NULL, "Cannot open %s for write", cisaFileName);
990     CisaObjInfo& cisaObjInfo = _cisaObjInfos[_numCisaObjInfos];
991     ASSERT(
992         fwrite(cisaObjInfo.buf, 1, cisaObjInfo.size, cisaFile) ==
993         cisaObjInfo.size,
994         "Error in writing linked CISA object");
995     fclose(cisaFile);
996 
997     return 0;
998 }
999