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