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 struct ItaniumParamParser {
520   AMDGPULibFunc::Param Prev;
521   bool parseItaniumParam(StringRef& param, AMDGPULibFunc::Param &res);
522 };
523 
524 bool 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 
602 bool 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 
620 bool 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 
631 StringRef 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 
642 template <typename Stream>
643 void 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 
659 std::string AMDGPULibFunc::mangle() const {
660   return mangleNameItanium();
661 }
662 
663 ///////////////////////////////////////////////////////////////////////////////
664 // Itanium Mangling
665 
666 static 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 
717 class 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 
745 public:
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 
788 std::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 
808 static 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 
850 FunctionType* 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 
863 unsigned AMDGPULibFunc::getNumArgs() const {
864   return manglingRules[FuncId].getNumArgs();
865 }
866 
867 std::string AMDGPULibFunc::getName() const {
868   SmallString<128> Buf;
869   raw_svector_ostream OS(Buf);
870   writeName(OS);
871   return OS.str();
872 }
873 
874 Function *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 
888 Function *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 }
929