1 //===-- 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 
26 using namespace llvm;
27 
28 namespace {
29 
30 enum 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 
57 struct 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 
68 unsigned 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 
98 static 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 
301 static 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 
310 static 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 
324 class ParamIterator {
325   const AMDGPULibFunc::Param (&Leads)[2];
326   const ManglingRule& Rule;
327   int Index;
328 public:
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 
336 AMDGPULibFunc::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 
420 inline static void drop_front(StringRef& str, size_t n = 1) {
421   str = str.drop_front(n);
422 }
423 
424 static 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 
432 template <size_t N>
433 static 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 
441 static inline bool isDigit(char c) { return c >= '0' && c <= '9'; }
442 
443 static 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 
453 static 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 
464 AMDGPULibFunc::AMDGPULibFunc() {
465   reset();
466 }
467 
468 AMDGPULibFunc::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 
475 void 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 
486 static 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 
497 static 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 
511 bool 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 
519 namespace {
520 struct ItaniumParamParser {
521   AMDGPULibFunc::Param Prev;
522   bool parseItaniumParam(StringRef& param, AMDGPULibFunc::Param &res);
523 };
524 } // namespace
525 
526 bool 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 
604 bool 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 
622 bool 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 
633 StringRef 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 
644 template <typename Stream>
645 void 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 
661 std::string AMDGPULibFunc::mangle() const {
662   return mangleNameItanium();
663 }
664 
665 ///////////////////////////////////////////////////////////////////////////////
666 // Itanium Mangling
667 
668 static 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 
694 namespace {
695 // 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 
719 class 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 
747 public:
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 };
789 } // namespace
790 
791 std::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 
811 static 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 
853 FunctionType* 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 
866 unsigned AMDGPULibFunc::getNumArgs() const {
867   return manglingRules[FuncId].getNumArgs();
868 }
869 
870 std::string AMDGPULibFunc::getName() const {
871   SmallString<128> Buf;
872   raw_svector_ostream OS(Buf);
873   writeName(OS);
874   return OS.str();
875 }
876 
877 Function *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 
891 Function *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 }
932