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 "AMDGPU.h" 15 #include "AMDGPULibFunc.h" 16 #include <llvm/ADT/SmallString.h> 17 #include <llvm/ADT/SmallVector.h> 18 #include <llvm/ADT/StringSwitch.h> 19 #include "llvm/IR/Attributes.h" 20 #include "llvm/IR/DerivedTypes.h" 21 #include "llvm/IR/Function.h" 22 #include "llvm/IR/Module.h" 23 #include "llvm/IR/ValueSymbolTable.h" 24 #include <llvm/Support/raw_ostream.h> 25 #include <string> 26 27 using namespace llvm; 28 29 namespace { 30 31 enum EManglingParam { 32 E_NONE, 33 EX_EVENT, 34 EX_FLOAT4, 35 EX_INTV4, 36 EX_RESERVEDID, 37 EX_SAMPLER, 38 EX_SIZET, 39 EX_UINT, 40 EX_UINTV4, 41 E_ANY, 42 E_CONSTPTR_ANY, 43 E_CONSTPTR_SWAPGL, 44 E_COPY, 45 E_IMAGECOORDS, 46 E_POINTEE, 47 E_SETBASE_I32, 48 E_SETBASE_U32, 49 E_MAKEBASE_UNS, 50 E_V16_OF_POINTEE, 51 E_V2_OF_POINTEE, 52 E_V3_OF_POINTEE, 53 E_V4_OF_POINTEE, 54 E_V8_OF_POINTEE, 55 E_VLTLPTR_ANY, 56 }; 57 58 struct ManglingRule { 59 StringRef const Name; 60 unsigned char Lead[2]; 61 unsigned char Param[5]; 62 63 int maxLeadIndex() const { return (std::max)(Lead[0], Lead[1]); } 64 int getNumLeads() const { return (Lead[0] ? 1 : 0) + (Lead[1] ? 1 : 0); } 65 66 unsigned getNumArgs() const; 67 }; 68 69 // Information about library functions with unmangled names. 70 class UnmangledFuncInfo { 71 StringRef const Name; 72 unsigned NumArgs; 73 74 // Table for all lib functions with unmangled names. 75 static const UnmangledFuncInfo Table[]; 76 77 // Number of entries in Table. 78 static const unsigned TableSize; 79 80 // Map function name to index. 81 class NameMap : public StringMap<unsigned> { 82 public: 83 NameMap() { 84 for (unsigned I = 0; I != TableSize; ++I) 85 (*this)[Table[I].Name] = I; 86 } 87 }; 88 friend class NameMap; 89 static NameMap Map; 90 91 public: 92 using ID = AMDGPULibFunc::EFuncId; 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 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}}, 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}}, 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 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 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 unsigned AS = AMDGPULibFunc::getAddrSpaceFromEPtrKind(P.PtrKind); 463 switch (AS) { 464 case AMDGPUAS::GLOBAL_ADDRESS: AS = AMDGPUAS::LOCAL_ADDRESS; break; 465 case AMDGPUAS::LOCAL_ADDRESS: AS = AMDGPUAS::GLOBAL_ADDRESS; break; 466 } 467 P.PtrKind = AMDGPULibFunc::getEPtrKindFromAddrSpace(AS); 468 P.PtrKind |= AMDGPULibFunc::CONST; 469 break; 470 } 471 472 default: llvm_unreachable("Unhandeled param rule"); 473 } 474 } 475 ++Index; 476 return P; 477 } 478 479 inline static void drop_front(StringRef& str, size_t n = 1) { 480 str = str.drop_front(n); 481 } 482 483 static bool eatTerm(StringRef& mangledName, const char c) { 484 if (mangledName.front() == c) { 485 drop_front(mangledName); 486 return true; 487 } 488 return false; 489 } 490 491 template <size_t N> 492 static bool eatTerm(StringRef& mangledName, const char (&str)[N]) { 493 if (mangledName.startswith(StringRef(str, N-1))) { 494 drop_front(mangledName, N-1); 495 return true; 496 } 497 return false; 498 } 499 500 static inline bool isDigit(char c) { return c >= '0' && c <= '9'; } 501 502 static int eatNumber(StringRef& s) { 503 size_t const savedSize = s.size(); 504 int n = 0; 505 while (!s.empty() && isDigit(s.front())) { 506 n = n*10 + s.front() - '0'; 507 drop_front(s); 508 } 509 return s.size() < savedSize ? n : -1; 510 } 511 512 static StringRef eatLengthPrefixedName(StringRef& mangledName) { 513 int const Len = eatNumber(mangledName); 514 if (Len <= 0 || static_cast<size_t>(Len) > mangledName.size()) 515 return StringRef(); 516 StringRef Res = mangledName.substr(0, Len); 517 drop_front(mangledName, Len); 518 return Res; 519 } 520 521 } // end anonymous namespace 522 523 AMDGPUMangledLibFunc::AMDGPUMangledLibFunc() { 524 FuncId = EI_NONE; 525 FKind = NOPFX; 526 Leads[0].reset(); 527 Leads[1].reset(); 528 Name.clear(); 529 } 530 531 AMDGPUUnmangledLibFunc::AMDGPUUnmangledLibFunc() { 532 FuncId = EI_NONE; 533 FuncTy = nullptr; 534 } 535 536 AMDGPUMangledLibFunc::AMDGPUMangledLibFunc( 537 EFuncId id, const AMDGPUMangledLibFunc ©From) { 538 FuncId = id; 539 FKind = copyFrom.FKind; 540 Leads[0] = copyFrom.Leads[0]; 541 Leads[1] = copyFrom.Leads[1]; 542 } 543 544 /////////////////////////////////////////////////////////////////////////////// 545 // Demangling 546 547 static int parseVecSize(StringRef& mangledName) { 548 size_t const Len = eatNumber(mangledName); 549 switch (Len) { 550 case 2: case 3: case 4: case 8: case 16: 551 return Len; 552 default: 553 break; 554 } 555 return 1; 556 } 557 558 static AMDGPULibFunc::ENamePrefix parseNamePrefix(StringRef& mangledName) { 559 std::pair<StringRef, StringRef> const P = mangledName.split('_'); 560 AMDGPULibFunc::ENamePrefix Pfx = 561 StringSwitch<AMDGPULibFunc::ENamePrefix>(P.first) 562 .Case("native", AMDGPULibFunc::NATIVE) 563 .Case("half" , AMDGPULibFunc::HALF) 564 .Default(AMDGPULibFunc::NOPFX); 565 566 if (Pfx != AMDGPULibFunc::NOPFX) 567 mangledName = P.second; 568 569 return Pfx; 570 } 571 572 bool AMDGPUMangledLibFunc::parseUnmangledName(StringRef FullName) { 573 FuncId = static_cast<EFuncId>(manglingRulesMap.lookup(FullName)); 574 return FuncId != EI_NONE; 575 } 576 577 /////////////////////////////////////////////////////////////////////////////// 578 // Itanium Demangling 579 580 namespace { 581 struct ItaniumParamParser { 582 AMDGPULibFunc::Param Prev; 583 bool parseItaniumParam(StringRef& param, AMDGPULibFunc::Param &res); 584 }; 585 } // namespace 586 587 bool ItaniumParamParser::parseItaniumParam(StringRef& param, 588 AMDGPULibFunc::Param &res) { 589 res.reset(); 590 if (param.empty()) return false; 591 592 // parse pointer prefix 593 if (eatTerm(param, 'P')) { 594 if (eatTerm(param, 'K')) res.PtrKind |= AMDGPULibFunc::CONST; 595 if (eatTerm(param, 'V')) res.PtrKind |= AMDGPULibFunc::VOLATILE; 596 unsigned AS; 597 if (!eatTerm(param, "U3AS")) { 598 AS = 0; 599 } else { 600 AS = param.front() - '0'; 601 drop_front(param, 1); 602 } 603 res.PtrKind |= AMDGPULibFuncBase::getEPtrKindFromAddrSpace(AS); 604 } else { 605 res.PtrKind = AMDGPULibFunc::BYVALUE; 606 } 607 608 // parse vector size 609 if (eatTerm(param,"Dv")) { 610 res.VectorSize = parseVecSize(param); 611 if (res.VectorSize==1 || !eatTerm(param, '_')) return false; 612 } 613 614 // parse type 615 char const TC = param.front(); 616 if (::isDigit(TC)) { 617 res.ArgType = StringSwitch<AMDGPULibFunc::EType> 618 (eatLengthPrefixedName(param)) 619 .Case("ocl_image1darray" , AMDGPULibFunc::IMG1DA) 620 .Case("ocl_image1dbuffer", AMDGPULibFunc::IMG1DB) 621 .Case("ocl_image2darray" , AMDGPULibFunc::IMG2DA) 622 .Case("ocl_image1d" , AMDGPULibFunc::IMG1D) 623 .Case("ocl_image2d" , AMDGPULibFunc::IMG2D) 624 .Case("ocl_image3d" , AMDGPULibFunc::IMG3D) 625 .Case("ocl_event" , AMDGPULibFunc::DUMMY) 626 .Case("ocl_sampler" , AMDGPULibFunc::DUMMY) 627 .Default(AMDGPULibFunc::DUMMY); 628 } else { 629 drop_front(param); 630 switch (TC) { 631 case 'h': res.ArgType = AMDGPULibFunc::U8; break; 632 case 't': res.ArgType = AMDGPULibFunc::U16; break; 633 case 'j': res.ArgType = AMDGPULibFunc::U32; break; 634 case 'm': res.ArgType = AMDGPULibFunc::U64; break; 635 case 'c': res.ArgType = AMDGPULibFunc::I8; break; 636 case 's': res.ArgType = AMDGPULibFunc::I16; break; 637 case 'i': res.ArgType = AMDGPULibFunc::I32; break; 638 case 'l': res.ArgType = AMDGPULibFunc::I64; break; 639 case 'f': res.ArgType = AMDGPULibFunc::F32; break; 640 case 'd': res.ArgType = AMDGPULibFunc::F64; break; 641 case 'D': if (!eatTerm(param, 'h')) return false; 642 res.ArgType = AMDGPULibFunc::F16; break; 643 case 'S': 644 if (!eatTerm(param, '_')) { 645 eatNumber(param); 646 if (!eatTerm(param, '_')) return false; 647 } 648 res.VectorSize = Prev.VectorSize; 649 res.ArgType = Prev.ArgType; 650 break; 651 default:; 652 } 653 } 654 if (res.ArgType == 0) return false; 655 Prev.VectorSize = res.VectorSize; 656 Prev.ArgType = res.ArgType; 657 return true; 658 } 659 660 bool AMDGPUMangledLibFunc::parseFuncName(StringRef &mangledName) { 661 StringRef Name = eatLengthPrefixedName(mangledName); 662 FKind = parseNamePrefix(Name); 663 if (!parseUnmangledName(Name)) 664 return false; 665 666 const ManglingRule& Rule = manglingRules[FuncId]; 667 ItaniumParamParser Parser; 668 for (int I=0; I < Rule.maxLeadIndex(); ++I) { 669 Param P; 670 if (!Parser.parseItaniumParam(mangledName, P)) 671 return false; 672 673 if ((I + 1) == Rule.Lead[0]) Leads[0] = P; 674 if ((I + 1) == Rule.Lead[1]) Leads[1] = P; 675 } 676 return true; 677 } 678 679 bool AMDGPUUnmangledLibFunc::parseFuncName(StringRef &Name) { 680 if (!UnmangledFuncInfo::lookup(Name, FuncId)) 681 return false; 682 setName(Name); 683 return true; 684 } 685 686 bool AMDGPULibFunc::parse(StringRef FuncName, AMDGPULibFunc &F) { 687 if (FuncName.empty()) { 688 F.Impl = std::unique_ptr<AMDGPULibFuncImpl>(); 689 return false; 690 } 691 692 if (eatTerm(FuncName, "_Z")) 693 F.Impl = make_unique<AMDGPUMangledLibFunc>(); 694 else 695 F.Impl = make_unique<AMDGPUUnmangledLibFunc>(); 696 if (F.Impl->parseFuncName(FuncName)) 697 return true; 698 699 F.Impl = std::unique_ptr<AMDGPULibFuncImpl>(); 700 return false; 701 } 702 703 StringRef AMDGPUMangledLibFunc::getUnmangledName(StringRef mangledName) { 704 StringRef S = mangledName; 705 if (eatTerm(S, "_Z")) 706 return eatLengthPrefixedName(S); 707 return StringRef(); 708 } 709 710 /////////////////////////////////////////////////////////////////////////////// 711 // Mangling 712 713 template <typename Stream> 714 void AMDGPUMangledLibFunc::writeName(Stream &OS) const { 715 const char *Pfx = ""; 716 switch (FKind) { 717 case NATIVE: Pfx = "native_"; break; 718 case HALF: Pfx = "half_"; break; 719 default: break; 720 } 721 if (!Name.empty()) { 722 OS << Pfx << Name; 723 } else if (FuncId != EI_NONE) { 724 OS << Pfx; 725 const StringRef& S = manglingRules[FuncId].Name; 726 OS.write(S.data(), S.size()); 727 } 728 } 729 730 std::string AMDGPUMangledLibFunc::mangle() const { return mangleNameItanium(); } 731 732 /////////////////////////////////////////////////////////////////////////////// 733 // Itanium Mangling 734 735 static const char *getItaniumTypeName(AMDGPULibFunc::EType T) { 736 switch (T) { 737 case AMDGPULibFunc::U8: return "h"; 738 case AMDGPULibFunc::U16: return "t"; 739 case AMDGPULibFunc::U32: return "j"; 740 case AMDGPULibFunc::U64: return "m"; 741 case AMDGPULibFunc::I8: return "c"; 742 case AMDGPULibFunc::I16: return "s"; 743 case AMDGPULibFunc::I32: return "i"; 744 case AMDGPULibFunc::I64: return "l"; 745 case AMDGPULibFunc::F16: return "Dh"; 746 case AMDGPULibFunc::F32: return "f"; 747 case AMDGPULibFunc::F64: return "d"; 748 case AMDGPULibFunc::IMG1DA: return "16ocl_image1darray"; 749 case AMDGPULibFunc::IMG1DB: return "17ocl_image1dbuffer"; 750 case AMDGPULibFunc::IMG2DA: return "16ocl_image2darray"; 751 case AMDGPULibFunc::IMG1D: return "11ocl_image1d"; 752 case AMDGPULibFunc::IMG2D: return "11ocl_image2d"; 753 case AMDGPULibFunc::IMG3D: return "11ocl_image3d"; 754 case AMDGPULibFunc::SAMPLER: return "11ocl_sampler"; 755 case AMDGPULibFunc::EVENT: return "9ocl_event"; 756 default: llvm_unreachable("Unhandeled param type"); 757 } 758 return nullptr; 759 } 760 761 namespace { 762 // Itanium mangling ABI says: 763 // "5.1.8. Compression 764 // ... Each non-terminal in the grammar for which <substitution> appears on the 765 // right-hand side is both a source of future substitutions and a candidate 766 // for being substituted. There are two exceptions that appear to be 767 // substitution candidates from the grammar, but are explicitly excluded: 768 // 1. <builtin-type> other than vendor extended types ..." 769 770 // For the purpose of functions the following productions make sence for the 771 // substitution: 772 // <type> ::= <builtin-type> 773 // ::= <class-enum-type> 774 // ::= <array-type> 775 // ::=<CV-qualifiers> <type> 776 // ::= P <type> # pointer-to 777 // ::= <substitution> 778 // 779 // Note that while types like images, samplers and events are by the ABI encoded 780 // using <class-enum-type> production rule they're not used for substitution 781 // because clang consider them as builtin types. 782 // 783 // DvNN_ type is GCC extension for vectors and is a subject for the substitution. 784 785 786 class ItaniumMangler { 787 SmallVector<AMDGPULibFunc::Param, 10> Str; // list of accumulated substituions 788 bool UseAddrSpace; 789 790 int findSubst(const AMDGPULibFunc::Param& P) const { 791 for(unsigned I = 0; I < Str.size(); ++I) { 792 const AMDGPULibFunc::Param& T = Str[I]; 793 if (P.PtrKind == T.PtrKind && 794 P.VectorSize == T.VectorSize && 795 P.ArgType == T.ArgType) { 796 return I; 797 } 798 } 799 return -1; 800 } 801 802 template <typename Stream> 803 bool trySubst(Stream& os, const AMDGPULibFunc::Param& p) { 804 int const subst = findSubst(p); 805 if (subst < 0) return false; 806 // Substitutions are mangled as S(XX)?_ where XX is a hexadecimal number 807 // 0 1 2 808 // S_ S0_ S1_ 809 if (subst == 0) os << "S_"; 810 else os << 'S' << (subst-1) << '_'; 811 return true; 812 } 813 814 public: 815 ItaniumMangler(bool useAddrSpace) 816 : UseAddrSpace(useAddrSpace) {} 817 818 template <typename Stream> 819 void operator()(Stream& os, AMDGPULibFunc::Param p) { 820 821 // Itanium mangling ABI 5.1.8. Compression: 822 // Logically, the substitutable components of a mangled name are considered 823 // left-to-right, components before the composite structure of which they 824 // are a part. If a component has been encountered before, it is substituted 825 // as described below. This decision is independent of whether its components 826 // have been substituted, so an implementation may optimize by considering 827 // large structures for substitution before their components. If a component 828 // has not been encountered before, its mangling is identified, and it is 829 // added to a dictionary of substitution candidates. No entity is added to 830 // the dictionary twice. 831 AMDGPULibFunc::Param Ptr; 832 833 if (p.PtrKind) { 834 if (trySubst(os, p)) return; 835 os << 'P'; 836 if (p.PtrKind & AMDGPULibFunc::CONST) os << 'K'; 837 if (p.PtrKind & AMDGPULibFunc::VOLATILE) os << 'V'; 838 unsigned AS = UseAddrSpace 839 ? AMDGPULibFuncBase::getAddrSpaceFromEPtrKind(p.PtrKind) 840 : 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 }; 858 } // namespace 859 860 std::string AMDGPUMangledLibFunc::mangleNameItanium() const { 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 922 FunctionType *AMDGPUMangledLibFunc::getFunctionType(Module &M) const { 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 935 unsigned AMDGPUMangledLibFunc::getNumArgs() const { 936 return manglingRules[FuncId].getNumArgs(); 937 } 938 939 unsigned AMDGPUUnmangledLibFunc::getNumArgs() const { 940 return UnmangledFuncInfo::getNumArgs(FuncId); 941 } 942 943 std::string AMDGPUMangledLibFunc::getName() const { 944 SmallString<128> Buf; 945 raw_svector_ostream OS(Buf); 946 writeName(OS); 947 return OS.str(); 948 } 949 950 Function *AMDGPULibFunc::getFunction(Module *M, const AMDGPULibFunc &fInfo) { 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, 965 const AMDGPULibFunc &fInfo) { 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 } 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 } 1054