blob: 5871d7d07dbf5ec1305c5b029efbf4af1158f41c [file] [log] [blame]
alan-bakerf67468c2019-11-25 15:51:49 -05001// Copyright 2019 The Clspv Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Marco Antogninid9ccec72020-12-01 16:52:34 +000015#include "llvm/Support/raw_ostream.h"
16
alan-bakerf67468c2019-11-25 15:51:49 -050017#include "Builtins.h"
18
SJW173c7e92020-03-16 08:44:47 -050019#include <cstdlib>
20#include <unordered_map>
21
alan-bakerf67468c2019-11-25 15:51:49 -050022using namespace llvm;
SJW173c7e92020-03-16 08:44:47 -050023using namespace clspv;
alan-bakerf67468c2019-11-25 15:51:49 -050024
SJW173c7e92020-03-16 08:44:47 -050025namespace {
alan-bakerc7a4c642022-06-02 14:35:46 -040026
27const std::string kPreviousParam = "__clspv_previous_param";
28
SJW173c7e92020-03-16 08:44:47 -050029////////////////////////////////////////////////////////////////////////////////
30//// Convert Builtin function name to a Type enum
31////////////////////////////////////////////////////////////////////////////////
32Builtins::BuiltinType LookupBuiltinType(const std::string &name) {
33
34// Build static map of builtin function names
35#include "BuiltinsMap.inc"
36
37 auto ii = s_func_map.find(name.c_str());
38 if (ii != s_func_map.end()) {
39 return (*ii).second;
40 }
41 return Builtins::kBuiltinNone;
alan-bakerf67468c2019-11-25 15:51:49 -050042}
43
SJW173c7e92020-03-16 08:44:47 -050044////////////////////////////////////////////////////////////////////////////////
45// Mangled name parsing utilities
46// - We only handle Itanium-style C++ mangling, plus modifications for OpenCL.
47////////////////////////////////////////////////////////////////////////////////
48
49// Given a mangled name starting at character position |pos| in |str|, extracts
50// the original name (without mangling) and updates |pos| so it will index the
51// character just past that original name (which might be just past the end of
52// the string). If the mangling is invalid, then an empty string is returned,
53// and |pos| is not updated. Example: if str = "_Z3fooi", and *pos = 2, then
54// returns "foo" and adds 4 to *pos.
55std::string GetUnmangledName(const std::string &str, size_t *pos) {
56 char *end = nullptr;
57 assert(*pos < str.size());
58 auto name_len = strtol(&str[*pos], &end, 10);
59 if (!name_len) {
60 return "";
61 }
62 ptrdiff_t name_pos = end - str.data();
Marco Antognini7e338402021-03-15 12:48:37 +000063 if (static_cast<std::size_t>(name_pos + name_len) > str.size()) {
SJW173c7e92020-03-16 08:44:47 -050064 // Protect against maliciously large number.
65 return "";
66 }
67
68 *pos = name_pos + name_len;
69 return str.substr(size_t(name_pos), name_len);
alan-bakerf67468c2019-11-25 15:51:49 -050070}
71
SJW173c7e92020-03-16 08:44:47 -050072// Capture parameter type and qualifiers starting at |pos|
73// - return new parsing position pos, or zero for error
74size_t GetParameterType(const std::string &mangled_name,
75 clspv::Builtins::ParamTypeInfo *type_info, size_t pos) {
76 // Parse a parameter type encoding
77 char type_code = mangled_name[pos++];
78
79 switch (type_code) {
80 // qualifiers
81 case 'P': // Pointer
82 case 'R': // Reference
83 return GetParameterType(mangled_name, type_info, pos);
84 case 'k': // ??? not part of cxxabi
85 case 'K': // const
86 case 'V': // volatile
87 return GetParameterType(mangled_name, type_info, pos);
88 case 'U': { // Address space
89 // address_space name not captured
90 (void)GetUnmangledName(mangled_name, &pos);
91 return GetParameterType(mangled_name, type_info, pos);
92 }
alan-bakerc7a4c642022-06-02 14:35:46 -040093 case 'A': { // Atomic type
94 if (mangled_name.substr(pos, 5) == "tomic")
95 return GetParameterType(mangled_name, type_info, pos + 5);
96 return 0;
97 }
98 case 'S':
99 // same as previous parameter
100 if (mangled_name[pos] != '_') {
101 return 0;
102 }
103 type_info->name = kPreviousParam;
104 return pos + 1;
SJW173c7e92020-03-16 08:44:47 -0500105 // OCL types
106 case 'D':
107 type_code = mangled_name[pos++];
108 if (type_code == 'v') { // OCL vector
109 char *end = nullptr;
110 int numElems = strtol(&mangled_name[pos], &end, 10);
111 if (!numElems) {
112 return 0;
113 }
114 type_info->vector_size = numElems;
115 pos = end - mangled_name.data();
116 if (pos > mangled_name.size()) {
117 // Protect against maliciously large number.
118 return 0;
119 }
120
121 if (mangled_name[pos++] != '_') {
122 return 0;
123 }
124 return GetParameterType(mangled_name, type_info, pos);
125 } else if (type_code == 'h') { // OCL half
126 type_info->type_id = Type::FloatTyID;
127 type_info->is_signed = true;
128 type_info->byte_len = 2;
SJW2c317da2020-03-23 07:39:13 -0500129 return pos;
SJW173c7e92020-03-16 08:44:47 -0500130 } else {
131#ifdef DEBUG
132 llvm::outs() << "Func: " << mangled_name << "\n";
133 llvm_unreachable("failed to demangle name");
134#endif
135 return 0;
136 }
137 break;
138
139 // element types
140 case 'l': // long
141 case 'i': // int
142 case 's': // short
143 case 'c': // char
144 case 'a': // signed char
145 type_info->type_id = Type::IntegerTyID;
146 type_info->is_signed = true;
147 break;
148 case 'm': // unsigned long
149 case 'j': // unsigned int
150 case 't': // unsigned short
151 case 'h': // unsigned char
152 type_info->type_id = Type::IntegerTyID;
153 type_info->is_signed = false;
154 break;
155 case 'd': // double float
156 case 'f': // single float
157 type_info->type_id = Type::FloatTyID;
158 type_info->is_signed = true;
159 break;
160 case 'v': // void
161 break;
162 case '1': // struct name
163 case '2': // - a <positive length number> for size of the following name
164 case '3': // - e.g. struct Foobar {} - would be encoded as '6Foobar'
165 case '4': // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.unqualified-name
166 case '5':
167 case '6':
168 case '7':
169 case '8':
170 case '9':
171 type_info->type_id = Type::StructTyID;
172 pos--;
173 type_info->name = GetUnmangledName(mangled_name, &pos);
174 break;
175 case '.':
176 return 0;
177 default:
178#ifdef DEBUG
179 llvm::outs() << "Func: " << mangled_name << "\n";
180 llvm_unreachable("failed to demangle name");
181#endif
182 return 0;
183 }
184
185 switch (type_code) {
186 // element types
187 case 'l': // long
188 case 'm': // unsigned long
189 case 'd': // double float
190 type_info->byte_len = 8;
191 break;
192 case 'i': // int
193 case 'j': // unsigned int
194 case 'f': // single float
195 type_info->byte_len = 4;
196 break;
197 case 's': // short
198 case 't': // unsigned short
199 type_info->byte_len = 2;
200 break;
201 case 'c': // char
202 case 'a': // signed char
203 case 'h': // unsigned char
204 type_info->byte_len = 1;
205 break;
206 default:
207 break;
208 }
209 return pos;
210}
211} // namespace
212
213////////////////////////////////////////////////////////////////////////////////
214// FunctionInfo::GetFromMangledNameCheck
215// - parse mangled name as far as possible. Some names are an aggregate of
216// fields separated by '.'
217// - extract name and parameter types, and return type for 'convert' functions
218// - return true if the mangled name can be fully parsed
219bool Builtins::FunctionInfo::GetFromMangledNameCheck(
220 const std::string &mangled_name) {
221 size_t pos = 0;
222 if (!(mangled_name[pos++] == '_' && mangled_name[pos++] == 'Z')) {
223 name_ = mangled_name;
224 return false;
225 }
226
227 name_ = GetUnmangledName(mangled_name, &pos);
228 if (name_.empty()) {
229 return false;
230 }
231
SJW173c7e92020-03-16 08:44:47 -0500232 auto mangled_name_len = mangled_name.size();
233 while (pos < mangled_name_len) {
234 ParamTypeInfo type_info;
235 if (mangled_name[pos] == 'S') {
alan-baker2ceb6592022-06-07 09:41:35 -0400236 // handle duplicate param_type. Comes in two flavours:
237 // S_ and S#_.
238 char p1 = mangled_name[pos + 1];
239 if (p1 != '_' && (mangled_name[pos + 2] != '_')) {
SJW173c7e92020-03-16 08:44:47 -0500240 return false;
241 }
alan-baker2ceb6592022-06-07 09:41:35 -0400242 pos += p1 == '_' ? 2 : 3;
SJW173c7e92020-03-16 08:44:47 -0500243 if (params_.empty()) {
244 return false;
245 }
246 params_.push_back(params_.back());
alan-bakeradf44262020-03-16 11:17:21 -0400247 } else if ((pos = GetParameterType(mangled_name, &type_info, pos))) {
alan-bakerc7a4c642022-06-02 14:35:46 -0400248 if (type_info.type_id == llvm::Type::VoidTyID &&
249 type_info.name == kPreviousParam) {
250 // After additional demangling, the underlying data type is the same as
251 // the previous parameter.
252 if (!params_.empty()) {
253 params_.push_back(params_.back());
254 } else {
255 return false;
256 }
257 } else {
258 params_.push_back(type_info);
259 }
SJW173c7e92020-03-16 08:44:47 -0500260 } else {
261 return false;
262 }
263 }
264
265 return true;
alan-bakerf67468c2019-11-25 15:51:49 -0500266}
267
SJW173c7e92020-03-16 08:44:47 -0500268////////////////////////////////////////////////////////////////////////////////
269// FunctionInfo ctor - parses mangled name
270Builtins::FunctionInfo::FunctionInfo(const std::string &mangled_name) {
271 is_valid_ = GetFromMangledNameCheck(mangled_name);
272 type_ = LookupBuiltinType(name_);
SJW61531372020-06-09 07:31:08 -0500273 if (type_ == kConvert) {
274 // deduce return type from name, only for convert
275 char tok = name_[8];
276 return_type_.is_signed = tok != 'u'; // unsigned
277 return_type_.type_id = tok == 'f' ? Type::FloatTyID : Type::IntegerTyID;
278 }
alan-bakerf67468c2019-11-25 15:51:49 -0500279}
280
SJW173c7e92020-03-16 08:44:47 -0500281// get const ParamTypeInfo for nth parameter
282const Builtins::ParamTypeInfo &
283Builtins::FunctionInfo::getParameter(size_t _arg) const {
284 assert(params_.size() > _arg);
285 return params_[_arg];
alan-bakerf67468c2019-11-25 15:51:49 -0500286}
287
Marco Antogninid9ccec72020-12-01 16:52:34 +0000288Builtins::ParamTypeInfo &Builtins::FunctionInfo::getParameter(size_t _arg) {
289 assert(params_.size() > _arg);
290 return params_[_arg];
291}
292
SJW2c317da2020-03-23 07:39:13 -0500293// Test for OCL Sampler parameter type
294bool Builtins::ParamTypeInfo::isSampler() const {
SJW61531372020-06-09 07:31:08 -0500295 return type_id == Type::StructTyID &&
296 (name == "ocl_sampler" || name == "opencl.sampler_t");
SJW2c317da2020-03-23 07:39:13 -0500297}
298
alan-baker67d639b2022-05-09 11:23:31 -0400299llvm::Type *Builtins::ParamTypeInfo::DataType(LLVMContext &context) const {
300 if (isSampler()) {
301 llvm_unreachable("sampler is unhandled");
302 }
303
304 Type *ty = nullptr;
305 switch (type_id) {
306 case llvm::Type::IntegerTyID:
307 ty = llvm::IntegerType::get(context, byte_len * 8);
308 break;
309 case llvm::Type::HalfTyID:
310 ty = llvm::Type::getHalfTy(context);
311 break;
312 case llvm::Type::FloatTyID:
313 ty = llvm::Type::getFloatTy(context);
314 break;
315 case llvm::Type::DoubleTyID:
316 ty = llvm::Type::getDoubleTy(context);
317 break;
318 default:
319 llvm_unreachable("unsupported type");
320 break;
321 }
322
323 if (vector_size > 0) {
324 ty = FixedVectorType::get(ty, vector_size);
325 }
326
327 return ty;
328}
329
SJW173c7e92020-03-16 08:44:47 -0500330////////////////////////////////////////////////////////////////////////////////
331//// Lookup interface
332//// - only demangle once for any name encountered
333////////////////////////////////////////////////////////////////////////////////
334const Builtins::FunctionInfo &
335Builtins::Lookup(const std::string &mangled_name) {
336 static std::unordered_map<std::string, FunctionInfo> s_mangled_map;
337 auto fi = s_mangled_map.emplace(mangled_name, mangled_name);
338 return (*fi.first).second;
alan-baker75090e42020-02-20 11:21:04 -0500339}
340
SJW173c7e92020-03-16 08:44:47 -0500341////////////////////////////////////////////////////////////////////////////////
SJW61531372020-06-09 07:31:08 -0500342// Generate a mangled name loosely based on Itanium mangling
343std::string Builtins::GetMangledFunctionName(const char *name, Type *type) {
344 assert(name);
345 std::string mangled_name =
346 std::string("_Z") + std::to_string(strlen(name)) + name;
347 if (auto *func_type = dyn_cast<FunctionType>(type)) {
348 Type *last_arg_type = nullptr;
349 for (auto *arg_type : func_type->params()) {
alan-baker5f2e88e2020-12-07 15:24:04 -0500350 std::string arg_name = GetMangledTypeName(arg_type);
351 if (arg_name.size() > 1 && arg_type == last_arg_type) {
SJW61531372020-06-09 07:31:08 -0500352 mangled_name += "S_";
353 } else {
354 mangled_name += GetMangledTypeName(arg_type);
355 last_arg_type = arg_type;
356 }
357 }
358 } else {
359 mangled_name += GetMangledTypeName(type);
SJW173c7e92020-03-16 08:44:47 -0500360 }
SJW61531372020-06-09 07:31:08 -0500361 return mangled_name;
alan-baker75090e42020-02-20 11:21:04 -0500362}
363
SJW61531372020-06-09 07:31:08 -0500364// The mangling follows the Itanium convention.
365std::string Builtins::GetMangledFunctionName(const char *name) {
366 assert(name);
367 return std::string("_Z") + std::to_string(strlen(name)) + name;
368}
369
Marco Antogninid9ccec72020-12-01 16:52:34 +0000370std::string
371Builtins::GetMangledFunctionName(const Builtins::FunctionInfo &info) {
372 // This is a best-effort attempt at reconstructing the mangled name for the
373 // given function. Because demangling is a lossy process some information may
374 // be lost and is therefore no longer available.
375 std::string name;
376 raw_string_ostream out(name);
377
378 StringRef function_name = info.getName();
379 out << "_Z" << function_name.size() << function_name;
380
381 for (size_t i = 0; i < info.getParameterCount(); ++i) {
382 const auto &param = info.getParameter(i);
383
384 if (param.vector_size != 0) {
385 out << "Dv" << param.vector_size << '_';
386 }
387
388 switch (param.type_id) {
389 case Type::FloatTyID:
390 switch (param.byte_len) {
391 case 2:
392 out << "Dh";
393 break;
394 case 4:
395 out << "f";
396 break;
397 case 8:
398 out << "d";
399 break;
400 default:
401 llvm_unreachable("Invalid byte_len for floating point type.");
402 break;
403 }
404 break;
405
406 case Type::IntegerTyID:
407 if (param.is_signed) {
408 switch (param.byte_len) {
409 case 1:
410 // Not enough information to distinguish between char (c) and signed
411 // char (a).
412 out << 'c';
413 break;
414 case 2:
415 out << "s";
416 break;
417 case 4:
418 out << "i";
419 break;
420 case 8:
421 out << "l";
422 break;
423 default:
424 llvm_unreachable("Invalid byte_len for signed integer type.");
425 break;
426 }
427 } else {
428 switch (param.byte_len) {
429 case 1:
430 out << 'h';
431 break;
432 case 2:
433 out << "t";
434 break;
435 case 4:
436 out << "j";
437 break;
438 case 8:
439 out << "m";
440 break;
441 default:
442 llvm_unreachable("Invalid byte_len for unsigned integer type.");
443 break;
444 }
445 }
446 break;
447
448 case Type::StructTyID:
449 out << param.name.size() << param.name;
450 break;
451
452 default:
453 llvm_unreachable("Unsupported type id");
454 break;
455 }
456 }
457
458 out.flush();
459 return name;
460}
461
SJW61531372020-06-09 07:31:08 -0500462// The mangling loosely follows the Itanium convention.
463// Its purpose is solely to ensure uniqueness of names, it is not
464// meant to convey type information.
465std::string Builtins::GetMangledTypeName(Type *Ty) {
466 std::string mangled_type_str;
467
468 switch (Ty->getTypeID()) {
469 case Type::VoidTyID:
470 return "v";
471 case Type::HalfTyID:
472 return "Dh";
473 case Type::FloatTyID:
474 return "f";
475 case Type::DoubleTyID:
476 return "d";
477
478 case Type::IntegerTyID:
479 switch (Ty->getIntegerBitWidth()) {
480 case 1:
481 return "b";
482 case 8:
483 return "h";
484 case 16:
485 return "t";
486 case 32:
487 return "j";
488 case 64:
489 return "m";
490 default:
491 assert(0);
492 break;
493 }
494 break;
495
496 case Type::StructTyID: {
497 auto *StrTy = cast<StructType>(Ty);
498 if (StrTy->isLiteral()) {
499 assert(StrTy->getNumElements() == 1);
500 return GetMangledTypeName(StrTy->getElementType(0));
501 }
502 mangled_type_str =
503 std::to_string(Ty->getStructName().size()) + Ty->getStructName().str();
504 break;
SJW173c7e92020-03-16 08:44:47 -0500505 }
SJW61531372020-06-09 07:31:08 -0500506 case Type::ArrayTyID:
507 mangled_type_str = "P" + GetMangledTypeName(Ty->getArrayElementType());
508 break;
509 case Type::PointerTyID: {
510 mangled_type_str = "P";
511 auto AS = Ty->getPointerAddressSpace();
512 if (AS != 0) {
513 std::string AS_name = "AS" + std::to_string(AS);
514 mangled_type_str += "U" + std::to_string(AS_name.size()) + AS_name;
515 }
516 mangled_type_str += GetMangledTypeName(Ty->getPointerElementType());
517 break;
SJW173c7e92020-03-16 08:44:47 -0500518 }
SJW61531372020-06-09 07:31:08 -0500519 case Type::FixedVectorTyID: {
520 auto VecTy = cast<VectorType>(Ty);
alan-baker5a8c3be2020-09-09 13:44:26 -0400521 mangled_type_str =
522 "Dv" + std::to_string(VecTy->getElementCount().getKnownMinValue()) +
523 "_" + GetMangledTypeName(VecTy->getElementType());
SJW61531372020-06-09 07:31:08 -0500524 break;
SJW173c7e92020-03-16 08:44:47 -0500525 }
alan-bakerf67468c2019-11-25 15:51:49 -0500526
SJW61531372020-06-09 07:31:08 -0500527 case Type::FunctionTyID:
528 case Type::X86_FP80TyID:
529 case Type::FP128TyID:
530 case Type::PPC_FP128TyID:
531 case Type::LabelTyID:
532 case Type::MetadataTyID:
533 case Type::X86_MMXTyID:
534 case Type::TokenTyID:
535 default:
536 assert(0);
537 break;
SJW173c7e92020-03-16 08:44:47 -0500538 }
SJW61531372020-06-09 07:31:08 -0500539 return mangled_type_str;
alan-bakerf67468c2019-11-25 15:51:49 -0500540}