blob: 1796989b6b8f52823553b13ec291a9bd53ffbb0a [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
519struct ItaniumParamParser {
520 AMDGPULibFunc::Param Prev;
521 bool parseItaniumParam(StringRef& param, AMDGPULibFunc::Param &res);
522};
523
524bool ItaniumParamParser::parseItaniumParam(StringRef& param,
525 AMDGPULibFunc::Param &res) {
526 res.reset();
527 if (param.empty()) return false;
528
529 // parse pointer prefix
530 if (eatTerm(param, 'P')) {
531 if (eatTerm(param, 'K')) res.PtrKind |= AMDGPULibFunc::CONST;
532 if (eatTerm(param, 'V')) res.PtrKind |= AMDGPULibFunc::VOLATILE;
533 if (!eatTerm(param, "U3AS")) {
534 res.PtrKind |= AMDGPULibFunc::PRIVATE;
535 } else {
536 switch(param.front()) {
537 case '1': res.PtrKind |= AMDGPULibFunc::GLOBAL; break;
538 case '2': res.PtrKind |= AMDGPULibFunc::READONLY;break;
539 case '3': res.PtrKind |= AMDGPULibFunc::LOCAL; break;
540 case '4': res.PtrKind |= AMDGPULibFunc::GENERIC; break;
541 case '5': res.PtrKind |= AMDGPULibFunc::OTHER; break;
542 default: return false;
543 }
544 drop_front(param, 1);
545 }
546 } else {
547 res.PtrKind = AMDGPULibFunc::BYVALUE;
548 }
549
550 // parse vector size
551 if (eatTerm(param,"Dv")) {
552 res.VectorSize = parseVecSize(param);
553 if (res.VectorSize==1 || !eatTerm(param, '_')) return false;
554 }
555
556 // parse type
557 char const TC = param.front();
558 if (::isDigit(TC)) {
559 res.ArgType = StringSwitch<AMDGPULibFunc::EType>
560 (eatLengthPrefixedName(param))
561 .Case("ocl_image1darray" , AMDGPULibFunc::IMG1DA)
562 .Case("ocl_image1dbuffer", AMDGPULibFunc::IMG1DB)
563 .Case("ocl_image2darray" , AMDGPULibFunc::IMG2DA)
564 .Case("ocl_image1d" , AMDGPULibFunc::IMG1D)
565 .Case("ocl_image2d" , AMDGPULibFunc::IMG2D)
566 .Case("ocl_image3d" , AMDGPULibFunc::IMG3D)
567 .Case("ocl_event" , AMDGPULibFunc::DUMMY)
568 .Case("ocl_sampler" , AMDGPULibFunc::DUMMY)
569 .Default(AMDGPULibFunc::DUMMY);
570 } else {
571 drop_front(param);
572 switch (TC) {
573 case 'h': res.ArgType = AMDGPULibFunc::U8; break;
574 case 't': res.ArgType = AMDGPULibFunc::U16; break;
575 case 'j': res.ArgType = AMDGPULibFunc::U32; break;
576 case 'm': res.ArgType = AMDGPULibFunc::U64; break;
577 case 'c': res.ArgType = AMDGPULibFunc::I8; break;
578 case 's': res.ArgType = AMDGPULibFunc::I16; break;
579 case 'i': res.ArgType = AMDGPULibFunc::I32; break;
580 case 'l': res.ArgType = AMDGPULibFunc::I64; break;
581 case 'f': res.ArgType = AMDGPULibFunc::F32; break;
582 case 'd': res.ArgType = AMDGPULibFunc::F64; break;
583 case 'D': if (!eatTerm(param, 'h')) return false;
584 res.ArgType = AMDGPULibFunc::F16; break;
585 case 'S':
586 if (!eatTerm(param, '_')) {
587 eatNumber(param);
588 if (!eatTerm(param, '_')) return false;
589 }
590 res.VectorSize = Prev.VectorSize;
591 res.ArgType = Prev.ArgType;
592 break;
593 default:;
594 }
595 }
596 if (res.ArgType == 0) return false;
597 Prev.VectorSize = res.VectorSize;
598 Prev.ArgType = res.ArgType;
599 return true;
600}
601
602bool AMDGPULibFunc::parseItanuimName(StringRef& mangledName) {
603 StringRef Name = eatLengthPrefixedName(mangledName);
604 FKind = parseNamePrefix(Name);
605 if (!parseName(Name)) return false;
606
607 const ManglingRule& Rule = manglingRules[FuncId];
608 ItaniumParamParser Parser;
609 for (int I=0; I < Rule.maxLeadIndex(); ++I) {
610 Param P;
611 if (!Parser.parseItaniumParam(mangledName, P))
612 return false;
613
614 if ((I + 1) == Rule.Lead[0]) Leads[0] = P;
615 if ((I + 1) == Rule.Lead[1]) Leads[1] = P;
616 }
617 return true;
618}
619
620bool AMDGPULibFunc::parse(StringRef mangledName, AMDGPULibFunc& iInfo) {
621 iInfo.reset();
622 if (mangledName.empty())
623 return false;
624
625 if (eatTerm(mangledName, "_Z")) {
626 return iInfo.parseItanuimName(mangledName);
627 }
628 return false;
629}
630
631StringRef AMDGPULibFunc::getUnmangledName(const StringRef& mangledName) {
632 StringRef S = mangledName;
633 if (eatTerm(S, "_Z"))
634 return eatLengthPrefixedName(S);
635 return StringRef();
636}
637
638
639///////////////////////////////////////////////////////////////////////////////
640// Mangling
641
642template <typename Stream>
643void AMDGPULibFunc::writeName(Stream& OS) const {
644 const char *Pfx = "";
645 switch (FKind) {
646 case NATIVE: Pfx = "native_"; break;
647 case HALF: Pfx = "half_"; break;
648 default: break;
649 }
650 if (!Name.empty()) {
651 OS << Pfx << Name;
652 } else if (FuncId != EI_NONE) {
653 OS << Pfx;
654 const StringRef& S = manglingRules[FuncId].Name;
655 OS.write(S.data(), S.size());
656 }
657}
658
659std::string AMDGPULibFunc::mangle() const {
660 return mangleNameItanium();
661}
662
663///////////////////////////////////////////////////////////////////////////////
664// Itanium Mangling
665
666static const char *getItaniumTypeName(AMDGPULibFunc::EType T) {
667 switch (T) {
668 case AMDGPULibFunc::U8: return "h";
669 case AMDGPULibFunc::U16: return "t";
670 case AMDGPULibFunc::U32: return "j";
671 case AMDGPULibFunc::U64: return "m";
672 case AMDGPULibFunc::I8: return "c";
673 case AMDGPULibFunc::I16: return "s";
674 case AMDGPULibFunc::I32: return "i";
675 case AMDGPULibFunc::I64: return "l";
676 case AMDGPULibFunc::F16: return "Dh";
677 case AMDGPULibFunc::F32: return "f";
678 case AMDGPULibFunc::F64: return "d";
679 case AMDGPULibFunc::IMG1DA: return "16ocl_image1darray";
680 case AMDGPULibFunc::IMG1DB: return "17ocl_image1dbuffer";
681 case AMDGPULibFunc::IMG2DA: return "16ocl_image2darray";
682 case AMDGPULibFunc::IMG1D: return "11ocl_image1d";
683 case AMDGPULibFunc::IMG2D: return "11ocl_image2d";
684 case AMDGPULibFunc::IMG3D: return "11ocl_image3d";
685 case AMDGPULibFunc::SAMPLER: return "11ocl_sampler";
686 case AMDGPULibFunc::EVENT: return "9ocl_event";
687 default: llvm_unreachable("Unhandeled param type");
688 }
689 return nullptr;
690}
691
692
693// Itanium mangling ABI says:
694// "5.1.8. Compression
695// ... Each non-terminal in the grammar for which <substitution> appears on the
696// right-hand side is both a source of future substitutions and a candidate
697// for being substituted. There are two exceptions that appear to be
698// substitution candidates from the grammar, but are explicitly excluded:
699// 1. <builtin-type> other than vendor extended types ..."
700
701// For the purpose of functions the following productions make sence for the
702// substitution:
703// <type> ::= <builtin-type>
704// ::= <class-enum-type>
705// ::= <array-type>
706// ::=<CV-qualifiers> <type>
707// ::= P <type> # pointer-to
708// ::= <substitution>
709//
710// Note that while types like images, samplers and events are by the ABI encoded
711// using <class-enum-type> production rule they're not used for substitution
712// because clang consider them as builtin types.
713//
714// DvNN_ type is GCC extension for vectors and is a subject for the substitution.
715
716
717class ItaniumMangler {
718 SmallVector<AMDGPULibFunc::Param, 10> Str; // list of accumulated substituions
719 bool UseAddrSpace;
720
721 int findSubst(const AMDGPULibFunc::Param& P) const {
722 for(unsigned I = 0; I < Str.size(); ++I) {
723 const AMDGPULibFunc::Param& T = Str[I];
724 if (P.PtrKind == T.PtrKind &&
725 P.VectorSize == T.VectorSize &&
726 P.ArgType == T.ArgType) {
727 return I;
728 }
729 }
730 return -1;
731 }
732
733 template <typename Stream>
734 bool trySubst(Stream& os, const AMDGPULibFunc::Param& p) {
735 int const subst = findSubst(p);
736 if (subst < 0) return false;
737 // Substitutions are mangled as S(XX)?_ where XX is a hexadecimal number
738 // 0 1 2
739 // S_ S0_ S1_
740 if (subst == 0) os << "S_";
741 else os << 'S' << (subst-1) << '_';
742 return true;
743 }
744
745public:
746 ItaniumMangler(bool useAddrSpace)
747 : UseAddrSpace(useAddrSpace) {}
748
749 template <typename Stream>
750 void operator()(Stream& os, AMDGPULibFunc::Param p) {
751
752 // Itanium mangling ABI 5.1.8. Compression:
753 // Logically, the substitutable components of a mangled name are considered
754 // left-to-right, components before the composite structure of which they
755 // are a part. If a component has been encountered before, it is substituted
756 // as described below. This decision is independent of whether its components
757 // have been substituted, so an implementation may optimize by considering
758 // large structures for substitution before their components. If a component
759 // has not been encountered before, its mangling is identified, and it is
760 // added to a dictionary of substitution candidates. No entity is added to
761 // the dictionary twice.
762 AMDGPULibFunc::Param Ptr;
763
764 if (p.PtrKind) {
765 if (trySubst(os, p)) return;
766 os << 'P';
767 if (p.PtrKind & AMDGPULibFunc::CONST) os << 'K';
768 if (p.PtrKind & AMDGPULibFunc::VOLATILE) os << 'V';
769 int AS = UseAddrSpace ? (p.PtrKind & AMDGPULibFunc::ADDR_SPACE)-1 : 0;
770 if (AS != 0) os << "U3AS" << AS;
771 Ptr = p;
772 p.PtrKind = 0;
773 }
774
775 if (p.VectorSize > 1) {
776 if (trySubst(os, p)) goto exit;
777 Str.push_back(p);
778 os << "Dv" << static_cast<unsigned>(p.VectorSize) << '_';
779 }
780
781 os << getItaniumTypeName((AMDGPULibFunc::EType)p.ArgType);
782
783 exit:
784 if (Ptr.ArgType) Str.push_back(Ptr);
785 }
786};
787
788std::string AMDGPULibFunc::mangleNameItanium() const {
789 SmallString<128> Buf;
790 raw_svector_ostream S(Buf);
791 SmallString<128> NameBuf;
792 raw_svector_ostream Name(NameBuf);
793 writeName(Name);
794 const StringRef& NameStr = Name.str();
795 S << "_Z" << static_cast<int>(NameStr.size()) << NameStr;
796
797 ItaniumMangler Mangler(true);
798 ParamIterator I(Leads, manglingRules[FuncId]);
799 Param P;
800 while ((P = I.getNextParam()).ArgType != 0)
801 Mangler(S, P);
802 return S.str();
803}
804
805///////////////////////////////////////////////////////////////////////////////
806// Misc
807
808static Type* getIntrinsicParamType(
809 LLVMContext& C,
810 const AMDGPULibFunc::Param& P,
811 bool useAddrSpace) {
812 Type* T = nullptr;
813 switch (P.ArgType) {
814 case AMDGPULibFunc::U8:
815 case AMDGPULibFunc::I8: T = Type::getInt8Ty(C); break;
816 case AMDGPULibFunc::U16:
817 case AMDGPULibFunc::I16: T = Type::getInt16Ty(C); break;
818 case AMDGPULibFunc::U32:
819 case AMDGPULibFunc::I32: T = Type::getInt32Ty(C); break;
820 case AMDGPULibFunc::U64:
821 case AMDGPULibFunc::I64: T = Type::getInt64Ty(C); break;
822 case AMDGPULibFunc::F16: T = Type::getHalfTy(C); break;
823 case AMDGPULibFunc::F32: T = Type::getFloatTy(C); break;
824 case AMDGPULibFunc::F64: T = Type::getDoubleTy(C); break;
825
826 case AMDGPULibFunc::IMG1DA:
827 case AMDGPULibFunc::IMG1DB:
828 case AMDGPULibFunc::IMG2DA:
829 case AMDGPULibFunc::IMG1D:
830 case AMDGPULibFunc::IMG2D:
831 case AMDGPULibFunc::IMG3D:
832 T = StructType::create(C,"ocl_image")->getPointerTo(); break;
833 case AMDGPULibFunc::SAMPLER:
834 T = StructType::create(C,"ocl_sampler")->getPointerTo(); break;
835 case AMDGPULibFunc::EVENT:
836 T = StructType::create(C,"ocl_event")->getPointerTo(); break;
837 default:
838 llvm_unreachable("Unhandeled param type");
839 return nullptr;
840 }
841 if (P.VectorSize > 1)
842 T = VectorType::get(T, P.VectorSize);
843 if (P.PtrKind != AMDGPULibFunc::BYVALUE)
844 T = useAddrSpace ? T->getPointerTo((P.PtrKind & AMDGPULibFunc::ADDR_SPACE)
845 - 1)
846 : T->getPointerTo();
847 return T;
848}
849
850FunctionType* AMDGPULibFunc::getFunctionType(Module& M) const {
851 LLVMContext& C = M.getContext();
852 std::vector<Type*> Args;
853 ParamIterator I(Leads, manglingRules[FuncId]);
854 Param P;
855 while ((P=I.getNextParam()).ArgType != 0)
856 Args.push_back(getIntrinsicParamType(C, P, true));
857
858 return FunctionType::get(
859 getIntrinsicParamType(C, getRetType(FuncId, Leads), true),
860 Args, false);
861}
862
863unsigned AMDGPULibFunc::getNumArgs() const {
864 return manglingRules[FuncId].getNumArgs();
865}
866
867std::string AMDGPULibFunc::getName() const {
868 SmallString<128> Buf;
869 raw_svector_ostream OS(Buf);
870 writeName(OS);
871 return OS.str();
872}
873
874Function *AMDGPULibFunc::getFunction(Module *M, const AMDGPULibFunc& fInfo) {
875 std::string FuncName = fInfo.mangle();
876 Function *F = dyn_cast_or_null<Function>(
877 M->getValueSymbolTable().lookup(FuncName));
878
879 // check formal with actual types conformance
880 if (F && !F->isDeclaration()
881 && !F->isVarArg()
882 && F->arg_size() == fInfo.getNumArgs()) {
883 return F;
884 }
885 return nullptr;
886}
887
888Function *AMDGPULibFunc::getOrInsertFunction(Module *M,
889 const AMDGPULibFunc& fInfo) {
890 std::string const FuncName = fInfo.mangle();
891 Function *F = dyn_cast_or_null<Function>(
892 M->getValueSymbolTable().lookup(FuncName));
893
894 // check formal with actual types conformance
895 if (F && !F->isDeclaration()
896 && !F->isVarArg()
897 && F->arg_size() == fInfo.getNumArgs()) {
898 return F;
899 }
900
901 FunctionType *FuncTy = fInfo.getFunctionType(*M);
902
903 bool hasPtr = false;
904 for (FunctionType::param_iterator
905 PI = FuncTy->param_begin(),
906 PE = FuncTy->param_end();
907 PI != PE; ++PI) {
908 const Type* argTy = static_cast<const Type*>(*PI);
909 if (argTy->isPointerTy()) {
910 hasPtr = true;
911 break;
912 }
913 }
914
915 Constant *C = nullptr;
916 if (hasPtr) {
917 // Do not set extra attributes for functions with pointer arguments.
918 C = M->getOrInsertFunction(FuncName, FuncTy);
919 } else {
920 AttributeList Attr;
921 LLVMContext &Ctx = M->getContext();
922 Attr.addAttribute(Ctx, AttributeList::FunctionIndex, Attribute::ReadOnly);
923 Attr.addAttribute(Ctx, AttributeList::FunctionIndex, Attribute::NoUnwind);
924 C = M->getOrInsertFunction(FuncName, FuncTy, Attr);
925 }
926
927 return cast<Function>(C);
928}