blob: 55ff10fc9b3030e348df73412f595ca0ae01480b [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
15#include "Builtins.h"
16
SJW173c7e92020-03-16 08:44:47 -050017#include <cstdlib>
18#include <unordered_map>
19
alan-bakerf67468c2019-11-25 15:51:49 -050020using namespace llvm;
SJW173c7e92020-03-16 08:44:47 -050021using namespace clspv;
alan-bakerf67468c2019-11-25 15:51:49 -050022
SJW173c7e92020-03-16 08:44:47 -050023namespace {
24////////////////////////////////////////////////////////////////////////////////
25//// Convert Builtin function name to a Type enum
26////////////////////////////////////////////////////////////////////////////////
27Builtins::BuiltinType LookupBuiltinType(const std::string &name) {
28
29// Build static map of builtin function names
30#include "BuiltinsMap.inc"
31
32 auto ii = s_func_map.find(name.c_str());
33 if (ii != s_func_map.end()) {
34 return (*ii).second;
35 }
36 return Builtins::kBuiltinNone;
alan-bakerf67468c2019-11-25 15:51:49 -050037}
38
SJW173c7e92020-03-16 08:44:47 -050039////////////////////////////////////////////////////////////////////////////////
40// Mangled name parsing utilities
41// - We only handle Itanium-style C++ mangling, plus modifications for OpenCL.
42////////////////////////////////////////////////////////////////////////////////
43
44// Given a mangled name starting at character position |pos| in |str|, extracts
45// the original name (without mangling) and updates |pos| so it will index the
46// character just past that original name (which might be just past the end of
47// the string). If the mangling is invalid, then an empty string is returned,
48// and |pos| is not updated. Example: if str = "_Z3fooi", and *pos = 2, then
49// returns "foo" and adds 4 to *pos.
50std::string GetUnmangledName(const std::string &str, size_t *pos) {
51 char *end = nullptr;
52 assert(*pos < str.size());
53 auto name_len = strtol(&str[*pos], &end, 10);
54 if (!name_len) {
55 return "";
56 }
57 ptrdiff_t name_pos = end - str.data();
58 if (name_pos + name_len > str.size()) {
59 // Protect against maliciously large number.
60 return "";
61 }
62
63 *pos = name_pos + name_len;
64 return str.substr(size_t(name_pos), name_len);
alan-bakerf67468c2019-11-25 15:51:49 -050065}
66
SJW173c7e92020-03-16 08:44:47 -050067// Capture parameter type and qualifiers starting at |pos|
68// - return new parsing position pos, or zero for error
69size_t GetParameterType(const std::string &mangled_name,
70 clspv::Builtins::ParamTypeInfo *type_info, size_t pos) {
71 // Parse a parameter type encoding
72 char type_code = mangled_name[pos++];
73
74 switch (type_code) {
75 // qualifiers
76 case 'P': // Pointer
77 case 'R': // Reference
78 return GetParameterType(mangled_name, type_info, pos);
79 case 'k': // ??? not part of cxxabi
80 case 'K': // const
81 case 'V': // volatile
82 return GetParameterType(mangled_name, type_info, pos);
83 case 'U': { // Address space
84 // address_space name not captured
85 (void)GetUnmangledName(mangled_name, &pos);
86 return GetParameterType(mangled_name, type_info, pos);
87 }
88 // OCL types
89 case 'D':
90 type_code = mangled_name[pos++];
91 if (type_code == 'v') { // OCL vector
92 char *end = nullptr;
93 int numElems = strtol(&mangled_name[pos], &end, 10);
94 if (!numElems) {
95 return 0;
96 }
97 type_info->vector_size = numElems;
98 pos = end - mangled_name.data();
99 if (pos > mangled_name.size()) {
100 // Protect against maliciously large number.
101 return 0;
102 }
103
104 if (mangled_name[pos++] != '_') {
105 return 0;
106 }
107 return GetParameterType(mangled_name, type_info, pos);
108 } else if (type_code == 'h') { // OCL half
109 type_info->type_id = Type::FloatTyID;
110 type_info->is_signed = true;
111 type_info->byte_len = 2;
SJW2c317da2020-03-23 07:39:13 -0500112 return pos;
SJW173c7e92020-03-16 08:44:47 -0500113 } else {
114#ifdef DEBUG
115 llvm::outs() << "Func: " << mangled_name << "\n";
116 llvm_unreachable("failed to demangle name");
117#endif
118 return 0;
119 }
120 break;
121
122 // element types
123 case 'l': // long
124 case 'i': // int
125 case 's': // short
126 case 'c': // char
127 case 'a': // signed char
128 type_info->type_id = Type::IntegerTyID;
129 type_info->is_signed = true;
130 break;
131 case 'm': // unsigned long
132 case 'j': // unsigned int
133 case 't': // unsigned short
134 case 'h': // unsigned char
135 type_info->type_id = Type::IntegerTyID;
136 type_info->is_signed = false;
137 break;
138 case 'd': // double float
139 case 'f': // single float
140 type_info->type_id = Type::FloatTyID;
141 type_info->is_signed = true;
142 break;
143 case 'v': // void
144 break;
145 case '1': // struct name
146 case '2': // - a <positive length number> for size of the following name
147 case '3': // - e.g. struct Foobar {} - would be encoded as '6Foobar'
148 case '4': // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.unqualified-name
149 case '5':
150 case '6':
151 case '7':
152 case '8':
153 case '9':
154 type_info->type_id = Type::StructTyID;
155 pos--;
156 type_info->name = GetUnmangledName(mangled_name, &pos);
157 break;
158 case '.':
159 return 0;
160 default:
161#ifdef DEBUG
162 llvm::outs() << "Func: " << mangled_name << "\n";
163 llvm_unreachable("failed to demangle name");
164#endif
165 return 0;
166 }
167
168 switch (type_code) {
169 // element types
170 case 'l': // long
171 case 'm': // unsigned long
172 case 'd': // double float
173 type_info->byte_len = 8;
174 break;
175 case 'i': // int
176 case 'j': // unsigned int
177 case 'f': // single float
178 type_info->byte_len = 4;
179 break;
180 case 's': // short
181 case 't': // unsigned short
182 type_info->byte_len = 2;
183 break;
184 case 'c': // char
185 case 'a': // signed char
186 case 'h': // unsigned char
187 type_info->byte_len = 1;
188 break;
189 default:
190 break;
191 }
192 return pos;
193}
194} // namespace
195
196////////////////////////////////////////////////////////////////////////////////
197// FunctionInfo::GetFromMangledNameCheck
198// - parse mangled name as far as possible. Some names are an aggregate of
199// fields separated by '.'
200// - extract name and parameter types, and return type for 'convert' functions
201// - return true if the mangled name can be fully parsed
202bool Builtins::FunctionInfo::GetFromMangledNameCheck(
203 const std::string &mangled_name) {
204 size_t pos = 0;
205 if (!(mangled_name[pos++] == '_' && mangled_name[pos++] == 'Z')) {
206 name_ = mangled_name;
207 return false;
208 }
209
210 name_ = GetUnmangledName(mangled_name, &pos);
211 if (name_.empty()) {
212 return false;
213 }
214
SJW173c7e92020-03-16 08:44:47 -0500215 auto mangled_name_len = mangled_name.size();
216 while (pos < mangled_name_len) {
217 ParamTypeInfo type_info;
218 if (mangled_name[pos] == 'S') {
219 // handle duplicate param_type
220 if (mangled_name[pos + 1] != '_') {
221 return false;
222 }
223 pos += 2;
224 if (params_.empty()) {
225 return false;
226 }
227 params_.push_back(params_.back());
alan-bakeradf44262020-03-16 11:17:21 -0400228 } else if ((pos = GetParameterType(mangled_name, &type_info, pos))) {
SJW173c7e92020-03-16 08:44:47 -0500229 params_.push_back(type_info);
230 } else {
231 return false;
232 }
233 }
234
235 return true;
alan-bakerf67468c2019-11-25 15:51:49 -0500236}
237
SJW173c7e92020-03-16 08:44:47 -0500238////////////////////////////////////////////////////////////////////////////////
239// FunctionInfo ctor - parses mangled name
240Builtins::FunctionInfo::FunctionInfo(const std::string &mangled_name) {
241 is_valid_ = GetFromMangledNameCheck(mangled_name);
242 type_ = LookupBuiltinType(name_);
SJW61531372020-06-09 07:31:08 -0500243 if (type_ == kConvert) {
244 // deduce return type from name, only for convert
245 char tok = name_[8];
246 return_type_.is_signed = tok != 'u'; // unsigned
247 return_type_.type_id = tok == 'f' ? Type::FloatTyID : Type::IntegerTyID;
248 }
alan-bakerf67468c2019-11-25 15:51:49 -0500249}
250
SJW173c7e92020-03-16 08:44:47 -0500251// get const ParamTypeInfo for nth parameter
252const Builtins::ParamTypeInfo &
253Builtins::FunctionInfo::getParameter(size_t _arg) const {
254 assert(params_.size() > _arg);
255 return params_[_arg];
alan-bakerf67468c2019-11-25 15:51:49 -0500256}
257
SJW2c317da2020-03-23 07:39:13 -0500258// Test for OCL Sampler parameter type
259bool Builtins::ParamTypeInfo::isSampler() const {
SJW61531372020-06-09 07:31:08 -0500260 return type_id == Type::StructTyID &&
261 (name == "ocl_sampler" || name == "opencl.sampler_t");
SJW2c317da2020-03-23 07:39:13 -0500262}
263
SJW173c7e92020-03-16 08:44:47 -0500264////////////////////////////////////////////////////////////////////////////////
265//// Lookup interface
266//// - only demangle once for any name encountered
267////////////////////////////////////////////////////////////////////////////////
268const Builtins::FunctionInfo &
269Builtins::Lookup(const std::string &mangled_name) {
270 static std::unordered_map<std::string, FunctionInfo> s_mangled_map;
271 auto fi = s_mangled_map.emplace(mangled_name, mangled_name);
272 return (*fi.first).second;
alan-baker75090e42020-02-20 11:21:04 -0500273}
274
SJW173c7e92020-03-16 08:44:47 -0500275////////////////////////////////////////////////////////////////////////////////
SJW61531372020-06-09 07:31:08 -0500276// Generate a mangled name loosely based on Itanium mangling
277std::string Builtins::GetMangledFunctionName(const char *name, Type *type) {
278 assert(name);
279 std::string mangled_name =
280 std::string("_Z") + std::to_string(strlen(name)) + name;
281 if (auto *func_type = dyn_cast<FunctionType>(type)) {
282 Type *last_arg_type = nullptr;
283 for (auto *arg_type : func_type->params()) {
284 if (arg_type == last_arg_type) {
285 mangled_name += "S_";
286 } else {
287 mangled_name += GetMangledTypeName(arg_type);
288 last_arg_type = arg_type;
289 }
290 }
291 } else {
292 mangled_name += GetMangledTypeName(type);
SJW173c7e92020-03-16 08:44:47 -0500293 }
SJW61531372020-06-09 07:31:08 -0500294 return mangled_name;
alan-baker75090e42020-02-20 11:21:04 -0500295}
296
SJW61531372020-06-09 07:31:08 -0500297// The mangling follows the Itanium convention.
298std::string Builtins::GetMangledFunctionName(const char *name) {
299 assert(name);
300 return std::string("_Z") + std::to_string(strlen(name)) + name;
301}
302
303// The mangling loosely follows the Itanium convention.
304// Its purpose is solely to ensure uniqueness of names, it is not
305// meant to convey type information.
306std::string Builtins::GetMangledTypeName(Type *Ty) {
307 std::string mangled_type_str;
308
309 switch (Ty->getTypeID()) {
310 case Type::VoidTyID:
311 return "v";
312 case Type::HalfTyID:
313 return "Dh";
314 case Type::FloatTyID:
315 return "f";
316 case Type::DoubleTyID:
317 return "d";
318
319 case Type::IntegerTyID:
320 switch (Ty->getIntegerBitWidth()) {
321 case 1:
322 return "b";
323 case 8:
324 return "h";
325 case 16:
326 return "t";
327 case 32:
328 return "j";
329 case 64:
330 return "m";
331 default:
332 assert(0);
333 break;
334 }
335 break;
336
337 case Type::StructTyID: {
338 auto *StrTy = cast<StructType>(Ty);
339 if (StrTy->isLiteral()) {
340 assert(StrTy->getNumElements() == 1);
341 return GetMangledTypeName(StrTy->getElementType(0));
342 }
343 mangled_type_str =
344 std::to_string(Ty->getStructName().size()) + Ty->getStructName().str();
345 break;
SJW173c7e92020-03-16 08:44:47 -0500346 }
SJW61531372020-06-09 07:31:08 -0500347 case Type::ArrayTyID:
348 mangled_type_str = "P" + GetMangledTypeName(Ty->getArrayElementType());
349 break;
350 case Type::PointerTyID: {
351 mangled_type_str = "P";
352 auto AS = Ty->getPointerAddressSpace();
353 if (AS != 0) {
354 std::string AS_name = "AS" + std::to_string(AS);
355 mangled_type_str += "U" + std::to_string(AS_name.size()) + AS_name;
356 }
357 mangled_type_str += GetMangledTypeName(Ty->getPointerElementType());
358 break;
SJW173c7e92020-03-16 08:44:47 -0500359 }
SJW61531372020-06-09 07:31:08 -0500360 case Type::FixedVectorTyID: {
361 auto VecTy = cast<VectorType>(Ty);
alan-baker5a8c3be2020-09-09 13:44:26 -0400362 mangled_type_str =
363 "Dv" + std::to_string(VecTy->getElementCount().getKnownMinValue()) +
364 "_" + GetMangledTypeName(VecTy->getElementType());
SJW61531372020-06-09 07:31:08 -0500365 break;
SJW173c7e92020-03-16 08:44:47 -0500366 }
alan-bakerf67468c2019-11-25 15:51:49 -0500367
SJW61531372020-06-09 07:31:08 -0500368 case Type::FunctionTyID:
369 case Type::X86_FP80TyID:
370 case Type::FP128TyID:
371 case Type::PPC_FP128TyID:
372 case Type::LabelTyID:
373 case Type::MetadataTyID:
374 case Type::X86_MMXTyID:
375 case Type::TokenTyID:
376 default:
377 assert(0);
378 break;
SJW173c7e92020-03-16 08:44:47 -0500379 }
SJW61531372020-06-09 07:31:08 -0500380 return mangled_type_str;
alan-bakerf67468c2019-11-25 15:51:49 -0500381}