blob: 96addc01edae87d824d9bf0c72fdffede48d002d [file] [log] [blame]
Stanislav Mekhanoshin7f377942017-08-11 16:42:09 +00001//===-- AMDGPULibFunc.cpp -------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains utility functions to work with Itanium mangled names
11//
12//===----------------------------------------------------------------------===//
13
14#include "AMDGPULibFunc.h"
15#include <llvm/ADT/SmallString.h>
16#include <llvm/ADT/SmallVector.h>
17#include <llvm/ADT/StringSwitch.h>
18#include "llvm/IR/Attributes.h"
19#include "llvm/IR/DerivedTypes.h"
20#include "llvm/IR/Function.h"
21#include "llvm/IR/Module.h"
22#include "llvm/IR/ValueSymbolTable.h"
23#include <llvm/Support/raw_ostream.h>
24#include <string>
25
26using namespace llvm;
27
28namespace {
29
30enum EManglingParam {
31 E_NONE,
32 EX_EVENT,
33 EX_FLOAT4,
34 EX_INTV4,
35 EX_RESERVEDID,
36 EX_SAMPLER,
37 EX_SIZET,
38 EX_UINT,
39 EX_UINTV4,
40 E_ANY,
41 E_CONSTPTR_ANY,
42 E_CONSTPTR_SWAPGL,
43 E_COPY,
44 E_IMAGECOORDS,
45 E_POINTEE,
46 E_SETBASE_I32,
47 E_SETBASE_U32,
48 E_MAKEBASE_UNS,
49 E_V16_OF_POINTEE,
50 E_V2_OF_POINTEE,
51 E_V3_OF_POINTEE,
52 E_V4_OF_POINTEE,
53 E_V8_OF_POINTEE,
54 E_VLTLPTR_ANY,
55};
56
57struct ManglingRule {
58 StringRef const Name;
59 unsigned char Lead[2];
60 unsigned char Param[5];
61
62 int maxLeadIndex() const { return (std::max)(Lead[0], Lead[1]); }
63 int getNumLeads() const { return (Lead[0] ? 1 : 0) + (Lead[1] ? 1 : 0); }
64
65 unsigned getNumArgs() const;
66};
67
68unsigned ManglingRule::getNumArgs() const {
69 unsigned I=0;
70 while (I < (sizeof Param/sizeof Param[0]) && Param[I]) ++I;
71 return I;
72}
73
74// This table describes function formal argument type rules. The order of rules
75// corresponds to the EFuncId enum at AMDGPULibFunc.h
76//
77// "<func name>", { <leads> }, { <param rules> }
78// where:
79// <leads> - list of integers that are one-based indexes of formal argument
80// used to mangle a function name. Other argument types are derived from types
81// of these 'leads'. The order of integers in this list correspond to the
82// order in which these arguments are mangled in the EDG mangling scheme. The
83// same order should be preserved for arguments in the AMDGPULibFunc structure
84// when it is used for mangling. For example:
85// { "vstorea_half", {3,1}, {E_ANY,EX_SIZET,E_ANY}},
86// will be mangled in EDG scheme as vstorea_half_<3dparam>_<1stparam>
87// When mangling from code use:
88// AMDGPULibFunc insc;
89// insc.param[0] = ... // describe 3rd parameter
90// insc.param[1] = ... // describe 1rd parameter
91//
92// <param rules> - list of rules used to derive all of the function formal
93// argument types. EX_ prefixed are simple types, other derived from the
94// latest 'lead' argument type in the order of encoding from first to last.
95// E_ANY - use prev lead type, E_CONSTPTR_ANY - make const pointer out of
96// prev lead type, etc. see ParamIterator::getNextParam() for details.
97
98static const ManglingRule manglingRules[] = {
99{ StringRef(), {0}, {0} },
100{ "abs" , {1}, {E_ANY}},
101{ "abs_diff" , {1}, {E_ANY,E_COPY}},
102{ "acos" , {1}, {E_ANY}},
103{ "acosh" , {1}, {E_ANY}},
104{ "acospi" , {1}, {E_ANY}},
105{ "add_sat" , {1}, {E_ANY,E_COPY}},
106{ "all" , {1}, {E_ANY}},
107{ "any" , {1}, {E_ANY}},
108{ "asin" , {1}, {E_ANY}},
109{ "asinh" , {1}, {E_ANY}},
110{ "asinpi" , {1}, {E_ANY}},
111{ "async_work_group_copy" , {1}, {E_ANY,E_CONSTPTR_SWAPGL,EX_SIZET,EX_EVENT}},
112{ "async_work_group_strided_copy" , {1}, {E_ANY,E_CONSTPTR_SWAPGL,EX_SIZET,EX_SIZET,EX_EVENT}},
113{ "atan" , {1}, {E_ANY}},
114{ "atan2" , {1}, {E_ANY,E_COPY}},
115{ "atan2pi" , {1}, {E_ANY,E_COPY}},
116{ "atanh" , {1}, {E_ANY}},
117{ "atanpi" , {1}, {E_ANY}},
118{ "atomic_add" , {1}, {E_VLTLPTR_ANY,E_POINTEE}},
119{ "atomic_and" , {1}, {E_VLTLPTR_ANY,E_POINTEE}},
120{ "atomic_cmpxchg" , {1}, {E_VLTLPTR_ANY,E_POINTEE,E_POINTEE}},
121{ "atomic_dec" , {1}, {E_VLTLPTR_ANY}},
122{ "atomic_inc" , {1}, {E_VLTLPTR_ANY}},
123{ "atomic_max" , {1}, {E_VLTLPTR_ANY,E_POINTEE}},
124{ "atomic_min" , {1}, {E_VLTLPTR_ANY,E_POINTEE}},
125{ "atomic_or" , {1}, {E_VLTLPTR_ANY,E_POINTEE}},
126{ "atomic_sub" , {1}, {E_VLTLPTR_ANY,E_POINTEE}},
127{ "atomic_xchg" , {1}, {E_VLTLPTR_ANY,E_POINTEE}},
128{ "atomic_xor" , {1}, {E_VLTLPTR_ANY,E_POINTEE}},
129{ "bitselect" , {1}, {E_ANY,E_COPY,E_COPY}},
130{ "cbrt" , {1}, {E_ANY}},
131{ "ceil" , {1}, {E_ANY}},
132{ "clamp" , {1}, {E_ANY,E_COPY,E_COPY}},
133{ "clz" , {1}, {E_ANY}},
134{ "commit_read_pipe" , {1}, {E_ANY,EX_RESERVEDID}},
135{ "commit_write_pipe" , {1}, {E_ANY,EX_RESERVEDID}},
136{ "copysign" , {1}, {E_ANY,E_COPY}},
137{ "cos" , {1}, {E_ANY}},
138{ "cosh" , {1}, {E_ANY}},
139{ "cospi" , {1}, {E_ANY}},
140{ "cross" , {1}, {E_ANY,E_COPY}},
141{ "ctz" , {1}, {E_ANY}},
142{ "degrees" , {1}, {E_ANY}},
143{ "distance" , {1}, {E_ANY,E_COPY}},
144{ "divide" , {1}, {E_ANY,E_COPY}},
145{ "dot" , {1}, {E_ANY,E_COPY}},
146{ "erf" , {1}, {E_ANY}},
147{ "erfc" , {1}, {E_ANY}},
148{ "exp" , {1}, {E_ANY}},
149{ "exp10" , {1}, {E_ANY}},
150{ "exp2" , {1}, {E_ANY}},
151{ "expm1" , {1}, {E_ANY}},
152{ "fabs" , {1}, {E_ANY}},
153{ "fast_distance" , {1}, {E_ANY,E_COPY}},
154{ "fast_length" , {1}, {E_ANY}},
155{ "fast_normalize" , {1}, {E_ANY}},
156{ "fdim" , {1}, {E_ANY,E_COPY}},
157{ "floor" , {1}, {E_ANY}},
158{ "fma" , {1}, {E_ANY,E_COPY,E_COPY}},
159{ "fmax" , {1}, {E_ANY,E_COPY}},
160{ "fmin" , {1}, {E_ANY,E_COPY}},
161{ "fmod" , {1}, {E_ANY,E_COPY}},
162{ "fract" , {2}, {E_POINTEE,E_ANY}},
163{ "frexp" , {1,2}, {E_ANY,E_ANY}},
164{ "get_image_array_size" , {1}, {E_ANY}},
165{ "get_image_channel_data_type" , {1}, {E_ANY}},
166{ "get_image_channel_order" , {1}, {E_ANY}},
167{ "get_image_dim" , {1}, {E_ANY}},
168{ "get_image_height" , {1}, {E_ANY}},
169{ "get_image_width" , {1}, {E_ANY}},
170{ "get_pipe_max_packets" , {1}, {E_ANY}},
171{ "get_pipe_num_packets" , {1}, {E_ANY}},
172{ "hadd" , {1}, {E_ANY,E_COPY}},
173{ "hypot" , {1}, {E_ANY,E_COPY}},
174{ "ilogb" , {1}, {E_ANY}},
175{ "isequal" , {1}, {E_ANY,E_COPY}},
176{ "isfinite" , {1}, {E_ANY}},
177{ "isgreater" , {1}, {E_ANY,E_COPY}},
178{ "isgreaterequal" , {1}, {E_ANY,E_COPY}},
179{ "isinf" , {1}, {E_ANY}},
180{ "isless" , {1}, {E_ANY,E_COPY}},
181{ "islessequal" , {1}, {E_ANY,E_COPY}},
182{ "islessgreater" , {1}, {E_ANY,E_COPY}},
183{ "isnan" , {1}, {E_ANY}},
184{ "isnormal" , {1}, {E_ANY}},
185{ "isnotequal" , {1}, {E_ANY,E_COPY}},
186{ "isordered" , {1}, {E_ANY,E_COPY}},
187{ "isunordered" , {1}, {E_ANY,E_COPY}},
188{ "ldexp" , {1}, {E_ANY,E_SETBASE_I32}},
189{ "length" , {1}, {E_ANY}},
190{ "lgamma" , {1}, {E_ANY}},
191{ "lgamma_r" , {1,2}, {E_ANY,E_ANY}},
192{ "log" , {1}, {E_ANY}},
193{ "log10" , {1}, {E_ANY}},
194{ "log1p" , {1}, {E_ANY}},
195{ "log2" , {1}, {E_ANY}},
196{ "logb" , {1}, {E_ANY}},
197{ "mad" , {1}, {E_ANY,E_COPY,E_COPY}},
198{ "mad24" , {1}, {E_ANY,E_COPY,E_COPY}},
199{ "mad_hi" , {1}, {E_ANY,E_COPY,E_COPY}},
200{ "mad_sat" , {1}, {E_ANY,E_COPY,E_COPY}},
201{ "max" , {1}, {E_ANY,E_COPY}},
202{ "maxmag" , {1}, {E_ANY,E_COPY}},
203{ "min" , {1}, {E_ANY,E_COPY}},
204{ "minmag" , {1}, {E_ANY,E_COPY}},
205{ "mix" , {1}, {E_ANY,E_COPY,E_COPY}},
206{ "modf" , {2}, {E_POINTEE,E_ANY}},
207{ "mul24" , {1}, {E_ANY,E_COPY}},
208{ "mul_hi" , {1}, {E_ANY,E_COPY}},
209{ "nan" , {1}, {E_ANY}},
210{ "nextafter" , {1}, {E_ANY,E_COPY}},
211{ "normalize" , {1}, {E_ANY}},
212{ "popcount" , {1}, {E_ANY}},
213{ "pow" , {1}, {E_ANY,E_COPY}},
214{ "pown" , {1}, {E_ANY,E_SETBASE_I32}},
215{ "powr" , {1}, {E_ANY,E_COPY}},
216{ "prefetch" , {1}, {E_CONSTPTR_ANY,EX_SIZET}},
217{ "radians" , {1}, {E_ANY}},
218{ "read_pipe" , {4}, {E_COPY,EX_RESERVEDID,EX_UINT,E_ANY}},
219{ "recip" , {1}, {E_ANY}},
220{ "remainder" , {1}, {E_ANY,E_COPY}},
221{ "remquo" , {1,3}, {E_ANY,E_COPY,E_ANY}},
222{ "reserve_read_pipe" , {1}, {E_ANY,EX_UINT}},
223{ "reserve_write_pipe" , {1}, {E_ANY,EX_UINT}},
224{ "rhadd" , {1}, {E_ANY,E_COPY}},
225{ "rint" , {1}, {E_ANY}},
226{ "rootn" , {1}, {E_ANY,E_SETBASE_I32}},
227{ "rotate" , {1}, {E_ANY,E_COPY}},
228{ "round" , {1}, {E_ANY}},
229{ "rsqrt" , {1}, {E_ANY}},
230{ "select" , {1,3}, {E_ANY,E_COPY,E_ANY}},
231{ "shuffle" , {1,2}, {E_ANY,E_ANY}},
232{ "shuffle2" , {1,3}, {E_ANY,E_COPY,E_ANY}},
233{ "sign" , {1}, {E_ANY}},
234{ "signbit" , {1}, {E_ANY}},
235{ "sin" , {1}, {E_ANY}},
236{ "sincos" , {2}, {E_POINTEE,E_ANY}},
237{ "sinh" , {1}, {E_ANY}},
238{ "sinpi" , {1}, {E_ANY}},
239{ "smoothstep" , {1}, {E_ANY,E_COPY,E_COPY}},
240{ "sqrt" , {1}, {E_ANY}},
241{ "step" , {1}, {E_ANY,E_COPY}},
242{ "sub_group_broadcast" , {1}, {E_ANY,EX_UINT}},
243{ "sub_group_commit_read_pipe" , {1}, {E_ANY,EX_RESERVEDID}},
244{ "sub_group_commit_write_pipe" , {1}, {E_ANY,EX_RESERVEDID}},
245{ "sub_group_reduce_add" , {1}, {E_ANY}},
246{ "sub_group_reduce_max" , {1}, {E_ANY}},
247{ "sub_group_reduce_min" , {1}, {E_ANY}},
248{ "sub_group_reserve_read_pipe" , {1}, {E_ANY,EX_UINT}},
249{ "sub_group_reserve_write_pipe" , {1}, {E_ANY,EX_UINT}},
250{ "sub_group_scan_exclusive_add" , {1}, {E_ANY}},
251{ "sub_group_scan_exclusive_max" , {1}, {E_ANY}},
252{ "sub_group_scan_exclusive_min" , {1}, {E_ANY}},
253{ "sub_group_scan_inclusive_add" , {1}, {E_ANY}},
254{ "sub_group_scan_inclusive_max" , {1}, {E_ANY}},
255{ "sub_group_scan_inclusive_min" , {1}, {E_ANY}},
256{ "sub_sat" , {1}, {E_ANY,E_COPY}},
257{ "tan" , {1}, {E_ANY}},
258{ "tanh" , {1}, {E_ANY}},
259{ "tanpi" , {1}, {E_ANY}},
260{ "tgamma" , {1}, {E_ANY}},
261{ "trunc" , {1}, {E_ANY}},
262{ "upsample" , {1}, {E_ANY,E_MAKEBASE_UNS}},
263{ "vec_step" , {1}, {E_ANY}},
264{ "vstore" , {3}, {E_POINTEE,EX_SIZET,E_ANY}},
265{ "vstore16" , {3}, {E_V16_OF_POINTEE,EX_SIZET,E_ANY}},
266{ "vstore2" , {3}, {E_V2_OF_POINTEE,EX_SIZET,E_ANY}},
267{ "vstore3" , {3}, {E_V3_OF_POINTEE,EX_SIZET,E_ANY}},
268{ "vstore4" , {3}, {E_V4_OF_POINTEE,EX_SIZET,E_ANY}},
269{ "vstore8" , {3}, {E_V8_OF_POINTEE,EX_SIZET,E_ANY}},
270{ "work_group_commit_read_pipe" , {1}, {E_ANY,EX_RESERVEDID}},
271{ "work_group_commit_write_pipe" , {1}, {E_ANY,EX_RESERVEDID}},
272{ "work_group_reduce_add" , {1}, {E_ANY}},
273{ "work_group_reduce_max" , {1}, {E_ANY}},
274{ "work_group_reduce_min" , {1}, {E_ANY}},
275{ "work_group_reserve_read_pipe" , {1}, {E_ANY,EX_UINT}},
276{ "work_group_reserve_write_pipe" , {1}, {E_ANY,EX_UINT}},
277{ "work_group_scan_exclusive_add" , {1}, {E_ANY}},
278{ "work_group_scan_exclusive_max" , {1}, {E_ANY}},
279{ "work_group_scan_exclusive_min" , {1}, {E_ANY}},
280{ "work_group_scan_inclusive_add" , {1}, {E_ANY}},
281{ "work_group_scan_inclusive_max" , {1}, {E_ANY}},
282{ "work_group_scan_inclusive_min" , {1}, {E_ANY}},
283{ "write_imagef" , {1}, {E_ANY,E_IMAGECOORDS,EX_FLOAT4}},
284{ "write_imagei" , {1}, {E_ANY,E_IMAGECOORDS,EX_INTV4}},
285{ "write_imageui" , {1}, {E_ANY,E_IMAGECOORDS,EX_UINTV4}},
286{ "write_pipe" , {4}, {E_COPY,EX_RESERVEDID,EX_UINT,E_ANY}},
287{ "ncos" , {1}, {E_ANY} },
288{ "nexp2" , {1}, {E_ANY} },
289{ "nfma" , {1}, {E_ANY, E_COPY, E_COPY} },
290{ "nlog2" , {1}, {E_ANY} },
291{ "nrcp" , {1}, {E_ANY} },
292{ "nrsqrt" , {1}, {E_ANY} },
293{ "nsin" , {1}, {E_ANY} },
294{ "nsqrt" , {1}, {E_ANY} },
295{ "ftz" , {1}, {E_ANY} },
296{ "fldexp" , {1}, {E_ANY, EX_UINT} },
297{ "class" , {1}, {E_ANY, EX_UINT} },
298{ "rcbrt" , {1}, {E_ANY} },
299};
300
301static const struct ManglingRulesMap : public StringMap<int> {
302 ManglingRulesMap()
303 : StringMap<int>(sizeof(manglingRules)/sizeof(manglingRules[0])) {
304 int Id = 0;
305 for (auto Rule : manglingRules)
306 insert({ Rule.Name, Id++ });
307 }
308} manglingRulesMap;
309
310static AMDGPULibFunc::Param getRetType(AMDGPULibFunc::EFuncId id,
311 const AMDGPULibFunc::Param (&Leads)[2]) {
312 AMDGPULibFunc::Param Res = Leads[0];
313 // TBD - This switch may require to be extended for other intriniscs
314 switch (id) {
315 case AMDGPULibFunc::EI_SINCOS:
316 Res.PtrKind = AMDGPULibFunc::BYVALUE;
317 break;
318 default:
319 break;
320 }
321 return Res;
322}
323
324class ParamIterator {
325 const AMDGPULibFunc::Param (&Leads)[2];
326 const ManglingRule& Rule;
327 int Index;
328public:
329 ParamIterator(const AMDGPULibFunc::Param (&leads)[2],
330 const ManglingRule& rule)
331 : Leads(leads), Rule(rule), Index(0) {}
332
333 AMDGPULibFunc::Param getNextParam();
334};
335
336AMDGPULibFunc::Param ParamIterator::getNextParam() {
337 AMDGPULibFunc::Param P;
338 if (Index >= int(sizeof Rule.Param/sizeof Rule.Param[0])) return P;
339
340 const char R = Rule.Param[Index];
341 switch (R) {
342 case E_NONE: break;
343 case EX_UINT:
344 P.ArgType = AMDGPULibFunc::U32; break;
345 case EX_INTV4:
346 P.ArgType = AMDGPULibFunc::I32; P.VectorSize = 4; break;
347 case EX_UINTV4:
348 P.ArgType = AMDGPULibFunc::U32; P.VectorSize = 4; break;
349 case EX_FLOAT4:
350 P.ArgType = AMDGPULibFunc::F32; P.VectorSize = 4; break;
351 case EX_SIZET:
352 P.ArgType = AMDGPULibFunc::U64; break;
353 case EX_EVENT:
354 P.ArgType = AMDGPULibFunc::EVENT; break;
355 case EX_SAMPLER:
356 P.ArgType = AMDGPULibFunc::SAMPLER; break;
357 case EX_RESERVEDID: break; // TBD
358 default:
359 if (Index == (Rule.Lead[1] - 1)) P = Leads[1];
360 else P = Leads[0];
361
362 switch (R) {
363 case E_ANY:
364 case E_COPY: break;
365
366 case E_POINTEE:
367 P.PtrKind = AMDGPULibFunc::BYVALUE; break;
368 case E_V2_OF_POINTEE:
369 P.VectorSize = 2; P.PtrKind = AMDGPULibFunc::BYVALUE; break;
370 case E_V3_OF_POINTEE:
371 P.VectorSize = 3; P.PtrKind = AMDGPULibFunc::BYVALUE; break;
372 case E_V4_OF_POINTEE:
373 P.VectorSize = 4; P.PtrKind = AMDGPULibFunc::BYVALUE; break;
374 case E_V8_OF_POINTEE:
375 P.VectorSize = 8; P.PtrKind = AMDGPULibFunc::BYVALUE; break;
376 case E_V16_OF_POINTEE:
377 P.VectorSize = 16; P.PtrKind = AMDGPULibFunc::BYVALUE; break;
378 case E_CONSTPTR_ANY:
379 P.PtrKind |= AMDGPULibFunc::CONST; break;
380 case E_VLTLPTR_ANY:
381 P.PtrKind |= AMDGPULibFunc::VOLATILE; break;
382 case E_SETBASE_I32:
383 P.ArgType = AMDGPULibFunc::I32; break;
384 case E_SETBASE_U32:
385 P.ArgType = AMDGPULibFunc::U32; break;
386
387 case E_MAKEBASE_UNS:
388 P.ArgType &= ~AMDGPULibFunc::BASE_TYPE_MASK;
389 P.ArgType |= AMDGPULibFunc::UINT;
390 break;
391
392 case E_IMAGECOORDS:
393 switch (P.ArgType) {
394 case AMDGPULibFunc::IMG1DA: P.VectorSize = 2; break;
395 case AMDGPULibFunc::IMG1DB: P.VectorSize = 1; break;
396 case AMDGPULibFunc::IMG2DA: P.VectorSize = 4; break;
397 case AMDGPULibFunc::IMG1D: P.VectorSize = 1; break;
398 case AMDGPULibFunc::IMG2D: P.VectorSize = 2; break;
399 case AMDGPULibFunc::IMG3D: P.VectorSize = 4; break;
400 }
401 P.PtrKind = AMDGPULibFunc::BYVALUE;
402 P.ArgType = AMDGPULibFunc::I32;
403 break;
404
405 case E_CONSTPTR_SWAPGL:
406 switch (P.PtrKind & AMDGPULibFunc::ADDR_SPACE) {
407 case AMDGPULibFunc::GLOBAL: P.PtrKind = AMDGPULibFunc::LOCAL; break;
408 case AMDGPULibFunc::LOCAL: P.PtrKind = AMDGPULibFunc::GLOBAL; break;
409 }
410 P.PtrKind |= AMDGPULibFunc::CONST;
411 break;
412
413 default: llvm_unreachable("Unhandeled param rule");
414 }
415 }
416 ++Index;
417 return P;
418}
419
420inline static void drop_front(StringRef& str, size_t n = 1) {
421 str = str.drop_front(n);
422}
423
424static bool eatTerm(StringRef& mangledName, const char c) {
425 if (mangledName.front() == c) {
426 drop_front(mangledName);
427 return true;
428 }
429 return false;
430}
431
432template <size_t N>
433static bool eatTerm(StringRef& mangledName, const char (&str)[N]) {
434 if (mangledName.startswith(StringRef(str, N-1))) {
435 drop_front(mangledName, N-1);
436 return true;
437 }
438 return false;
439}
440
441static inline bool isDigit(char c) { return c >= '0' && c <= '9'; }
442
443static int eatNumber(StringRef& s) {
444 size_t const savedSize = s.size();
445 int n = 0;
446 while (!s.empty() && isDigit(s.front())) {
447 n = n*10 + s.front() - '0';
448 drop_front(s);
449 }
450 return s.size() < savedSize ? n : -1;
451}
452
453static StringRef eatLengthPrefixedName(StringRef& mangledName) {
454 int const Len = eatNumber(mangledName);
455 if (Len <= 0 || static_cast<size_t>(Len) > mangledName.size())
456 return StringRef();
457 StringRef Res = mangledName.substr(0, Len);
458 drop_front(mangledName, Len);
459 return Res;
460}
461
462} // end anonymous namespace
463
464AMDGPULibFunc::AMDGPULibFunc() {
465 reset();
466}
467
468AMDGPULibFunc::AMDGPULibFunc(EFuncId id, const AMDGPULibFunc& copyFrom)
469 : FuncId(id) {
470 FKind = copyFrom.FKind;
471 Leads[0] = copyFrom.Leads[0];
472 Leads[1] = copyFrom.Leads[1];
473}
474
475void AMDGPULibFunc::reset() {
476 FuncId = EI_NONE;
477 FKind = NOPFX;
478 Leads[0].reset();
479 Leads[1].reset();
480 Name.clear();
481}
482
483///////////////////////////////////////////////////////////////////////////////
484// Demangling
485
486static int parseVecSize(StringRef& mangledName) {
487 size_t const Len = eatNumber(mangledName);
488 switch (Len) {
489 case 2: case 3: case 4: case 8: case 16:
490 return Len;
491 default:
492 break;
493 }
494 return 1;
495}
496
497static AMDGPULibFunc::ENamePrefix parseNamePrefix(StringRef& mangledName) {
498 std::pair<StringRef, StringRef> const P = mangledName.split('_');
499 AMDGPULibFunc::ENamePrefix Pfx =
500 StringSwitch<AMDGPULibFunc::ENamePrefix>(P.first)
501 .Case("native", AMDGPULibFunc::NATIVE)
502 .Case("half" , AMDGPULibFunc::HALF)
503 .Default(AMDGPULibFunc::NOPFX);
504
505 if (Pfx != AMDGPULibFunc::NOPFX)
506 mangledName = P.second;
507
508 return Pfx;
509}
510
511bool AMDGPULibFunc::parseName(const StringRef& fullName) {
512 FuncId = static_cast<EFuncId>(manglingRulesMap.lookup(fullName));
513 return FuncId != EI_NONE;
514}
515
516///////////////////////////////////////////////////////////////////////////////
517// Itanium Demangling
518
Benjamin Kramer49a49fe2017-08-20 13:03:48 +0000519namespace {
Stanislav Mekhanoshin7f377942017-08-11 16:42:09 +0000520struct ItaniumParamParser {
521 AMDGPULibFunc::Param Prev;
522 bool parseItaniumParam(StringRef& param, AMDGPULibFunc::Param &res);
523};
Benjamin Kramer49a49fe2017-08-20 13:03:48 +0000524} // namespace
Stanislav Mekhanoshin7f377942017-08-11 16:42:09 +0000525
526bool ItaniumParamParser::parseItaniumParam(StringRef& param,
527 AMDGPULibFunc::Param &res) {
528 res.reset();
529 if (param.empty()) return false;
530
531 // parse pointer prefix
532 if (eatTerm(param, 'P')) {
533 if (eatTerm(param, 'K')) res.PtrKind |= AMDGPULibFunc::CONST;
534 if (eatTerm(param, 'V')) res.PtrKind |= AMDGPULibFunc::VOLATILE;
535 if (!eatTerm(param, "U3AS")) {
536 res.PtrKind |= AMDGPULibFunc::PRIVATE;
537 } else {
538 switch(param.front()) {
539 case '1': res.PtrKind |= AMDGPULibFunc::GLOBAL; break;
540 case '2': res.PtrKind |= AMDGPULibFunc::READONLY;break;
541 case '3': res.PtrKind |= AMDGPULibFunc::LOCAL; break;
542 case '4': res.PtrKind |= AMDGPULibFunc::GENERIC; break;
543 case '5': res.PtrKind |= AMDGPULibFunc::OTHER; break;
544 default: return false;
545 }
546 drop_front(param, 1);
547 }
548 } else {
549 res.PtrKind = AMDGPULibFunc::BYVALUE;
550 }
551
552 // parse vector size
553 if (eatTerm(param,"Dv")) {
554 res.VectorSize = parseVecSize(param);
555 if (res.VectorSize==1 || !eatTerm(param, '_')) return false;
556 }
557
558 // parse type
559 char const TC = param.front();
560 if (::isDigit(TC)) {
561 res.ArgType = StringSwitch<AMDGPULibFunc::EType>
562 (eatLengthPrefixedName(param))
563 .Case("ocl_image1darray" , AMDGPULibFunc::IMG1DA)
564 .Case("ocl_image1dbuffer", AMDGPULibFunc::IMG1DB)
565 .Case("ocl_image2darray" , AMDGPULibFunc::IMG2DA)
566 .Case("ocl_image1d" , AMDGPULibFunc::IMG1D)
567 .Case("ocl_image2d" , AMDGPULibFunc::IMG2D)
568 .Case("ocl_image3d" , AMDGPULibFunc::IMG3D)
569 .Case("ocl_event" , AMDGPULibFunc::DUMMY)
570 .Case("ocl_sampler" , AMDGPULibFunc::DUMMY)
571 .Default(AMDGPULibFunc::DUMMY);
572 } else {
573 drop_front(param);
574 switch (TC) {
575 case 'h': res.ArgType = AMDGPULibFunc::U8; break;
576 case 't': res.ArgType = AMDGPULibFunc::U16; break;
577 case 'j': res.ArgType = AMDGPULibFunc::U32; break;
578 case 'm': res.ArgType = AMDGPULibFunc::U64; break;
579 case 'c': res.ArgType = AMDGPULibFunc::I8; break;
580 case 's': res.ArgType = AMDGPULibFunc::I16; break;
581 case 'i': res.ArgType = AMDGPULibFunc::I32; break;
582 case 'l': res.ArgType = AMDGPULibFunc::I64; break;
583 case 'f': res.ArgType = AMDGPULibFunc::F32; break;
584 case 'd': res.ArgType = AMDGPULibFunc::F64; break;
585 case 'D': if (!eatTerm(param, 'h')) return false;
586 res.ArgType = AMDGPULibFunc::F16; break;
587 case 'S':
588 if (!eatTerm(param, '_')) {
589 eatNumber(param);
590 if (!eatTerm(param, '_')) return false;
591 }
592 res.VectorSize = Prev.VectorSize;
593 res.ArgType = Prev.ArgType;
594 break;
595 default:;
596 }
597 }
598 if (res.ArgType == 0) return false;
599 Prev.VectorSize = res.VectorSize;
600 Prev.ArgType = res.ArgType;
601 return true;
602}
603
604bool AMDGPULibFunc::parseItanuimName(StringRef& mangledName) {
605 StringRef Name = eatLengthPrefixedName(mangledName);
606 FKind = parseNamePrefix(Name);
607 if (!parseName(Name)) return false;
608
609 const ManglingRule& Rule = manglingRules[FuncId];
610 ItaniumParamParser Parser;
611 for (int I=0; I < Rule.maxLeadIndex(); ++I) {
612 Param P;
613 if (!Parser.parseItaniumParam(mangledName, P))
614 return false;
615
616 if ((I + 1) == Rule.Lead[0]) Leads[0] = P;
617 if ((I + 1) == Rule.Lead[1]) Leads[1] = P;
618 }
619 return true;
620}
621
622bool AMDGPULibFunc::parse(StringRef mangledName, AMDGPULibFunc& iInfo) {
623 iInfo.reset();
624 if (mangledName.empty())
625 return false;
626
627 if (eatTerm(mangledName, "_Z")) {
628 return iInfo.parseItanuimName(mangledName);
629 }
630 return false;
631}
632
633StringRef AMDGPULibFunc::getUnmangledName(const StringRef& mangledName) {
634 StringRef S = mangledName;
635 if (eatTerm(S, "_Z"))
636 return eatLengthPrefixedName(S);
637 return StringRef();
638}
639
640
641///////////////////////////////////////////////////////////////////////////////
642// Mangling
643
644template <typename Stream>
645void AMDGPULibFunc::writeName(Stream& OS) const {
646 const char *Pfx = "";
647 switch (FKind) {
648 case NATIVE: Pfx = "native_"; break;
649 case HALF: Pfx = "half_"; break;
650 default: break;
651 }
652 if (!Name.empty()) {
653 OS << Pfx << Name;
654 } else if (FuncId != EI_NONE) {
655 OS << Pfx;
656 const StringRef& S = manglingRules[FuncId].Name;
657 OS.write(S.data(), S.size());
658 }
659}
660
661std::string AMDGPULibFunc::mangle() const {
662 return mangleNameItanium();
663}
664
665///////////////////////////////////////////////////////////////////////////////
666// Itanium Mangling
667
668static const char *getItaniumTypeName(AMDGPULibFunc::EType T) {
669 switch (T) {
670 case AMDGPULibFunc::U8: return "h";
671 case AMDGPULibFunc::U16: return "t";
672 case AMDGPULibFunc::U32: return "j";
673 case AMDGPULibFunc::U64: return "m";
674 case AMDGPULibFunc::I8: return "c";
675 case AMDGPULibFunc::I16: return "s";
676 case AMDGPULibFunc::I32: return "i";
677 case AMDGPULibFunc::I64: return "l";
678 case AMDGPULibFunc::F16: return "Dh";
679 case AMDGPULibFunc::F32: return "f";
680 case AMDGPULibFunc::F64: return "d";
681 case AMDGPULibFunc::IMG1DA: return "16ocl_image1darray";
682 case AMDGPULibFunc::IMG1DB: return "17ocl_image1dbuffer";
683 case AMDGPULibFunc::IMG2DA: return "16ocl_image2darray";
684 case AMDGPULibFunc::IMG1D: return "11ocl_image1d";
685 case AMDGPULibFunc::IMG2D: return "11ocl_image2d";
686 case AMDGPULibFunc::IMG3D: return "11ocl_image3d";
687 case AMDGPULibFunc::SAMPLER: return "11ocl_sampler";
688 case AMDGPULibFunc::EVENT: return "9ocl_event";
689 default: llvm_unreachable("Unhandeled param type");
690 }
691 return nullptr;
692}
693
Benjamin Kramer49a49fe2017-08-20 13:03:48 +0000694namespace {
Stanislav Mekhanoshin7f377942017-08-11 16:42:09 +0000695// Itanium mangling ABI says:
696// "5.1.8. Compression
697// ... Each non-terminal in the grammar for which <substitution> appears on the
698// right-hand side is both a source of future substitutions and a candidate
699// for being substituted. There are two exceptions that appear to be
700// substitution candidates from the grammar, but are explicitly excluded:
701// 1. <builtin-type> other than vendor extended types ..."
702
703// For the purpose of functions the following productions make sence for the
704// substitution:
705// <type> ::= <builtin-type>
706// ::= <class-enum-type>
707// ::= <array-type>
708// ::=<CV-qualifiers> <type>
709// ::= P <type> # pointer-to
710// ::= <substitution>
711//
712// Note that while types like images, samplers and events are by the ABI encoded
713// using <class-enum-type> production rule they're not used for substitution
714// because clang consider them as builtin types.
715//
716// DvNN_ type is GCC extension for vectors and is a subject for the substitution.
717
718
719class ItaniumMangler {
720 SmallVector<AMDGPULibFunc::Param, 10> Str; // list of accumulated substituions
721 bool UseAddrSpace;
722
723 int findSubst(const AMDGPULibFunc::Param& P) const {
724 for(unsigned I = 0; I < Str.size(); ++I) {
725 const AMDGPULibFunc::Param& T = Str[I];
726 if (P.PtrKind == T.PtrKind &&
727 P.VectorSize == T.VectorSize &&
728 P.ArgType == T.ArgType) {
729 return I;
730 }
731 }
732 return -1;
733 }
734
735 template <typename Stream>
736 bool trySubst(Stream& os, const AMDGPULibFunc::Param& p) {
737 int const subst = findSubst(p);
738 if (subst < 0) return false;
739 // Substitutions are mangled as S(XX)?_ where XX is a hexadecimal number
740 // 0 1 2
741 // S_ S0_ S1_
742 if (subst == 0) os << "S_";
743 else os << 'S' << (subst-1) << '_';
744 return true;
745 }
746
747public:
748 ItaniumMangler(bool useAddrSpace)
749 : UseAddrSpace(useAddrSpace) {}
750
751 template <typename Stream>
752 void operator()(Stream& os, AMDGPULibFunc::Param p) {
753
754 // Itanium mangling ABI 5.1.8. Compression:
755 // Logically, the substitutable components of a mangled name are considered
756 // left-to-right, components before the composite structure of which they
757 // are a part. If a component has been encountered before, it is substituted
758 // as described below. This decision is independent of whether its components
759 // have been substituted, so an implementation may optimize by considering
760 // large structures for substitution before their components. If a component
761 // has not been encountered before, its mangling is identified, and it is
762 // added to a dictionary of substitution candidates. No entity is added to
763 // the dictionary twice.
764 AMDGPULibFunc::Param Ptr;
765
766 if (p.PtrKind) {
767 if (trySubst(os, p)) return;
768 os << 'P';
769 if (p.PtrKind & AMDGPULibFunc::CONST) os << 'K';
770 if (p.PtrKind & AMDGPULibFunc::VOLATILE) os << 'V';
771 int AS = UseAddrSpace ? (p.PtrKind & AMDGPULibFunc::ADDR_SPACE)-1 : 0;
772 if (AS != 0) os << "U3AS" << AS;
773 Ptr = p;
774 p.PtrKind = 0;
775 }
776
777 if (p.VectorSize > 1) {
778 if (trySubst(os, p)) goto exit;
779 Str.push_back(p);
780 os << "Dv" << static_cast<unsigned>(p.VectorSize) << '_';
781 }
782
783 os << getItaniumTypeName((AMDGPULibFunc::EType)p.ArgType);
784
785 exit:
786 if (Ptr.ArgType) Str.push_back(Ptr);
787 }
788};
Benjamin Kramer49a49fe2017-08-20 13:03:48 +0000789} // namespace
Stanislav Mekhanoshin7f377942017-08-11 16:42:09 +0000790
791std::string AMDGPULibFunc::mangleNameItanium() const {
792 SmallString<128> Buf;
793 raw_svector_ostream S(Buf);
794 SmallString<128> NameBuf;
795 raw_svector_ostream Name(NameBuf);
796 writeName(Name);
797 const StringRef& NameStr = Name.str();
798 S << "_Z" << static_cast<int>(NameStr.size()) << NameStr;
799
800 ItaniumMangler Mangler(true);
801 ParamIterator I(Leads, manglingRules[FuncId]);
802 Param P;
803 while ((P = I.getNextParam()).ArgType != 0)
804 Mangler(S, P);
805 return S.str();
806}
807
808///////////////////////////////////////////////////////////////////////////////
809// Misc
810
811static Type* getIntrinsicParamType(
812 LLVMContext& C,
813 const AMDGPULibFunc::Param& P,
814 bool useAddrSpace) {
815 Type* T = nullptr;
816 switch (P.ArgType) {
817 case AMDGPULibFunc::U8:
818 case AMDGPULibFunc::I8: T = Type::getInt8Ty(C); break;
819 case AMDGPULibFunc::U16:
820 case AMDGPULibFunc::I16: T = Type::getInt16Ty(C); break;
821 case AMDGPULibFunc::U32:
822 case AMDGPULibFunc::I32: T = Type::getInt32Ty(C); break;
823 case AMDGPULibFunc::U64:
824 case AMDGPULibFunc::I64: T = Type::getInt64Ty(C); break;
825 case AMDGPULibFunc::F16: T = Type::getHalfTy(C); break;
826 case AMDGPULibFunc::F32: T = Type::getFloatTy(C); break;
827 case AMDGPULibFunc::F64: T = Type::getDoubleTy(C); break;
828
829 case AMDGPULibFunc::IMG1DA:
830 case AMDGPULibFunc::IMG1DB:
831 case AMDGPULibFunc::IMG2DA:
832 case AMDGPULibFunc::IMG1D:
833 case AMDGPULibFunc::IMG2D:
834 case AMDGPULibFunc::IMG3D:
835 T = StructType::create(C,"ocl_image")->getPointerTo(); break;
836 case AMDGPULibFunc::SAMPLER:
837 T = StructType::create(C,"ocl_sampler")->getPointerTo(); break;
838 case AMDGPULibFunc::EVENT:
839 T = StructType::create(C,"ocl_event")->getPointerTo(); break;
840 default:
841 llvm_unreachable("Unhandeled param type");
842 return nullptr;
843 }
844 if (P.VectorSize > 1)
845 T = VectorType::get(T, P.VectorSize);
846 if (P.PtrKind != AMDGPULibFunc::BYVALUE)
847 T = useAddrSpace ? T->getPointerTo((P.PtrKind & AMDGPULibFunc::ADDR_SPACE)
848 - 1)
849 : T->getPointerTo();
850 return T;
851}
852
853FunctionType* AMDGPULibFunc::getFunctionType(Module& M) const {
854 LLVMContext& C = M.getContext();
855 std::vector<Type*> Args;
856 ParamIterator I(Leads, manglingRules[FuncId]);
857 Param P;
858 while ((P=I.getNextParam()).ArgType != 0)
859 Args.push_back(getIntrinsicParamType(C, P, true));
860
861 return FunctionType::get(
862 getIntrinsicParamType(C, getRetType(FuncId, Leads), true),
863 Args, false);
864}
865
866unsigned AMDGPULibFunc::getNumArgs() const {
867 return manglingRules[FuncId].getNumArgs();
868}
869
870std::string AMDGPULibFunc::getName() const {
871 SmallString<128> Buf;
872 raw_svector_ostream OS(Buf);
873 writeName(OS);
874 return OS.str();
875}
876
877Function *AMDGPULibFunc::getFunction(Module *M, const AMDGPULibFunc& fInfo) {
878 std::string FuncName = fInfo.mangle();
879 Function *F = dyn_cast_or_null<Function>(
880 M->getValueSymbolTable().lookup(FuncName));
881
882 // check formal with actual types conformance
883 if (F && !F->isDeclaration()
884 && !F->isVarArg()
885 && F->arg_size() == fInfo.getNumArgs()) {
886 return F;
887 }
888 return nullptr;
889}
890
891Function *AMDGPULibFunc::getOrInsertFunction(Module *M,
892 const AMDGPULibFunc& fInfo) {
893 std::string const FuncName = fInfo.mangle();
894 Function *F = dyn_cast_or_null<Function>(
895 M->getValueSymbolTable().lookup(FuncName));
896
897 // check formal with actual types conformance
898 if (F && !F->isDeclaration()
899 && !F->isVarArg()
900 && F->arg_size() == fInfo.getNumArgs()) {
901 return F;
902 }
903
904 FunctionType *FuncTy = fInfo.getFunctionType(*M);
905
906 bool hasPtr = false;
907 for (FunctionType::param_iterator
908 PI = FuncTy->param_begin(),
909 PE = FuncTy->param_end();
910 PI != PE; ++PI) {
911 const Type* argTy = static_cast<const Type*>(*PI);
912 if (argTy->isPointerTy()) {
913 hasPtr = true;
914 break;
915 }
916 }
917
918 Constant *C = nullptr;
919 if (hasPtr) {
920 // Do not set extra attributes for functions with pointer arguments.
921 C = M->getOrInsertFunction(FuncName, FuncTy);
922 } else {
923 AttributeList Attr;
924 LLVMContext &Ctx = M->getContext();
925 Attr.addAttribute(Ctx, AttributeList::FunctionIndex, Attribute::ReadOnly);
926 Attr.addAttribute(Ctx, AttributeList::FunctionIndex, Attribute::NoUnwind);
927 C = M->getOrInsertFunction(FuncName, FuncTy, Attr);
928 }
929
930 return cast<Function>(C);
931}