blob: ee36cf6eb3ef4ba44b1757047d62e10df5727df0 [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;
112 } else {
113#ifdef DEBUG
114 llvm::outs() << "Func: " << mangled_name << "\n";
115 llvm_unreachable("failed to demangle name");
116#endif
117 return 0;
118 }
119 break;
120
121 // element types
122 case 'l': // long
123 case 'i': // int
124 case 's': // short
125 case 'c': // char
126 case 'a': // signed char
127 type_info->type_id = Type::IntegerTyID;
128 type_info->is_signed = true;
129 break;
130 case 'm': // unsigned long
131 case 'j': // unsigned int
132 case 't': // unsigned short
133 case 'h': // unsigned char
134 type_info->type_id = Type::IntegerTyID;
135 type_info->is_signed = false;
136 break;
137 case 'd': // double float
138 case 'f': // single float
139 type_info->type_id = Type::FloatTyID;
140 type_info->is_signed = true;
141 break;
142 case 'v': // void
143 break;
144 case '1': // struct name
145 case '2': // - a <positive length number> for size of the following name
146 case '3': // - e.g. struct Foobar {} - would be encoded as '6Foobar'
147 case '4': // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.unqualified-name
148 case '5':
149 case '6':
150 case '7':
151 case '8':
152 case '9':
153 type_info->type_id = Type::StructTyID;
154 pos--;
155 type_info->name = GetUnmangledName(mangled_name, &pos);
156 break;
157 case '.':
158 return 0;
159 default:
160#ifdef DEBUG
161 llvm::outs() << "Func: " << mangled_name << "\n";
162 llvm_unreachable("failed to demangle name");
163#endif
164 return 0;
165 }
166
167 switch (type_code) {
168 // element types
169 case 'l': // long
170 case 'm': // unsigned long
171 case 'd': // double float
172 type_info->byte_len = 8;
173 break;
174 case 'i': // int
175 case 'j': // unsigned int
176 case 'f': // single float
177 type_info->byte_len = 4;
178 break;
179 case 's': // short
180 case 't': // unsigned short
181 type_info->byte_len = 2;
182 break;
183 case 'c': // char
184 case 'a': // signed char
185 case 'h': // unsigned char
186 type_info->byte_len = 1;
187 break;
188 default:
189 break;
190 }
191 return pos;
192}
193} // namespace
194
195////////////////////////////////////////////////////////////////////////////////
196// FunctionInfo::GetFromMangledNameCheck
197// - parse mangled name as far as possible. Some names are an aggregate of
198// fields separated by '.'
199// - extract name and parameter types, and return type for 'convert' functions
200// - return true if the mangled name can be fully parsed
201bool Builtins::FunctionInfo::GetFromMangledNameCheck(
202 const std::string &mangled_name) {
203 size_t pos = 0;
204 if (!(mangled_name[pos++] == '_' && mangled_name[pos++] == 'Z')) {
205 name_ = mangled_name;
206 return false;
207 }
208
209 name_ = GetUnmangledName(mangled_name, &pos);
210 if (name_.empty()) {
211 return false;
212 }
213
214 if (!name_.compare(0, 8, "convert_")) {
215 // deduce return type from name, only for convert
216 char tok = name_[8];
217 return_type_.is_signed = tok != 'u'; // unsigned
218 return_type_.type_id = tok == 'f' ? Type::FloatTyID : Type::IntegerTyID;
219 }
220
221 auto mangled_name_len = mangled_name.size();
222 while (pos < mangled_name_len) {
223 ParamTypeInfo type_info;
224 if (mangled_name[pos] == 'S') {
225 // handle duplicate param_type
226 if (mangled_name[pos + 1] != '_') {
227 return false;
228 }
229 pos += 2;
230 if (params_.empty()) {
231 return false;
232 }
233 params_.push_back(params_.back());
alan-bakeradf44262020-03-16 11:17:21 -0400234 } else if ((pos = GetParameterType(mangled_name, &type_info, pos))) {
SJW173c7e92020-03-16 08:44:47 -0500235 params_.push_back(type_info);
236 } else {
237 return false;
238 }
239 }
240
241 return true;
alan-bakerf67468c2019-11-25 15:51:49 -0500242}
243
SJW173c7e92020-03-16 08:44:47 -0500244////////////////////////////////////////////////////////////////////////////////
245// FunctionInfo ctor - parses mangled name
246Builtins::FunctionInfo::FunctionInfo(const std::string &mangled_name) {
247 is_valid_ = GetFromMangledNameCheck(mangled_name);
248 type_ = LookupBuiltinType(name_);
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
SJW173c7e92020-03-16 08:44:47 -0500258////////////////////////////////////////////////////////////////////////////////
259//// Lookup interface
260//// - only demangle once for any name encountered
261////////////////////////////////////////////////////////////////////////////////
262const Builtins::FunctionInfo &
263Builtins::Lookup(const std::string &mangled_name) {
264 static std::unordered_map<std::string, FunctionInfo> s_mangled_map;
265 auto fi = s_mangled_map.emplace(mangled_name, mangled_name);
266 return (*fi.first).second;
alan-baker75090e42020-02-20 11:21:04 -0500267}
268
SJW173c7e92020-03-16 08:44:47 -0500269////////////////////////////////////////////////////////////////////////////////
270//// Legacy interface
271////////////////////////////////////////////////////////////////////////////////
272bool Builtins::IsImageBuiltin(StringRef name) {
273 auto func_type = Lookup(name).getType();
274 return func_type > kType_Image_Start && func_type < kType_Image_End;
alan-baker75090e42020-02-20 11:21:04 -0500275}
276
SJW173c7e92020-03-16 08:44:47 -0500277bool Builtins::IsSampledImageRead(StringRef name) {
278 return IsFloatSampledImageRead(name) || IsUintSampledImageRead(name) ||
279 IsIntSampledImageRead(name);
alan-baker75090e42020-02-20 11:21:04 -0500280}
281
SJW173c7e92020-03-16 08:44:47 -0500282bool Builtins::IsFloatSampledImageRead(StringRef _name) {
283 const auto &fi = Lookup(_name);
284 if (fi.getType() == kReadImagef) {
285 const auto &pi = fi.getParameter(1);
286 return pi.name == "ocl_sampler";
287 }
288 return false;
alan-baker75090e42020-02-20 11:21:04 -0500289}
290
SJW173c7e92020-03-16 08:44:47 -0500291bool Builtins::IsUintSampledImageRead(StringRef _name) {
292 const auto &fi = Lookup(_name);
293 if (fi.getType() == kReadImageui) {
294 const auto &pi = fi.getParameter(1);
295 return pi.name == "ocl_sampler";
296 }
297 return false;
alan-bakerf67468c2019-11-25 15:51:49 -0500298}
299
SJW173c7e92020-03-16 08:44:47 -0500300bool Builtins::IsIntSampledImageRead(StringRef _name) {
301 const auto &fi = Lookup(_name);
302 if (fi.getType() == kReadImagei) {
303 const auto &pi = fi.getParameter(1);
304 return pi.name == "ocl_sampler";
305 }
306 return false;
alan-bakerf67468c2019-11-25 15:51:49 -0500307}
308
SJW173c7e92020-03-16 08:44:47 -0500309bool Builtins::IsUnsampledImageRead(StringRef name) {
310 return IsFloatUnsampledImageRead(name) || IsUintUnsampledImageRead(name) ||
311 IsIntUnsampledImageRead(name);
alan-bakerf67468c2019-11-25 15:51:49 -0500312}
313
SJW173c7e92020-03-16 08:44:47 -0500314bool Builtins::IsFloatUnsampledImageRead(StringRef _name) {
315 const auto &fi = Lookup(_name);
316 if (fi.getType() == kReadImagef) {
317 const auto &pi = fi.getParameter(1);
318 return pi.name != "ocl_sampler";
319 }
320 return false;
alan-bakerf67468c2019-11-25 15:51:49 -0500321}
322
SJW173c7e92020-03-16 08:44:47 -0500323bool Builtins::IsUintUnsampledImageRead(StringRef _name) {
324 const auto &fi = Lookup(_name);
325 if (fi.getType() == kReadImageui) {
326 const auto &pi = fi.getParameter(1);
327 return pi.name != "ocl_sampler";
328 }
329 return false;
alan-bakerf67468c2019-11-25 15:51:49 -0500330}
331
SJW173c7e92020-03-16 08:44:47 -0500332bool Builtins::IsIntUnsampledImageRead(StringRef _name) {
333 const auto &fi = Lookup(_name);
334 if (fi.getType() == kReadImagei) {
335 const auto &pi = fi.getParameter(1);
336 return pi.name != "ocl_sampler";
337 }
338 return false;
alan-bakerce179f12019-12-06 19:02:22 -0500339}
340
SJW173c7e92020-03-16 08:44:47 -0500341bool Builtins::IsImageWrite(StringRef name) {
342 auto func_code = Lookup(name).getType();
343 return func_code == kWriteImagef || func_code == kWriteImageui ||
344 func_code == kWriteImagei || func_code == kWriteImageh;
alan-bakerce179f12019-12-06 19:02:22 -0500345}
346
SJW173c7e92020-03-16 08:44:47 -0500347bool Builtins::IsFloatImageWrite(StringRef name) {
348 return Lookup(name) == kWriteImagef;
alan-bakerce179f12019-12-06 19:02:22 -0500349}
350
SJW173c7e92020-03-16 08:44:47 -0500351bool Builtins::IsUintImageWrite(StringRef name) {
352 return Lookup(name) == kWriteImageui;
353}
354
355bool Builtins::IsIntImageWrite(StringRef name) {
356 return Lookup(name) == kWriteImagei;
357}
358
359bool Builtins::IsGetImageHeight(StringRef name) {
360 return Lookup(name) == kGetImageHeight;
361}
362
363bool Builtins::IsGetImageWidth(StringRef name) {
364 return Lookup(name) == kGetImageWidth;
365}
366
367bool Builtins::IsGetImageDepth(StringRef name) {
368 return Lookup(name) == kGetImageDepth;
369}
370
371bool Builtins::IsGetImageDim(StringRef name) {
372 return Lookup(name) == kGetImageDim;
373}
374
375bool Builtins::IsImageQuery(StringRef name) {
376 auto func_code = Lookup(name).getType();
377 return func_code == kGetImageHeight || func_code == kGetImageWidth ||
378 func_code == kGetImageDepth || func_code == kGetImageDim;
alan-bakerf67468c2019-11-25 15:51:49 -0500379}