blob: 455f33a9cda5986fe9ea15faf472e667817656ff [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
215 if (!name_.compare(0, 8, "convert_")) {
216 // deduce return type from name, only for convert
217 char tok = name_[8];
218 return_type_.is_signed = tok != 'u'; // unsigned
219 return_type_.type_id = tok == 'f' ? Type::FloatTyID : Type::IntegerTyID;
220 }
221
222 auto mangled_name_len = mangled_name.size();
223 while (pos < mangled_name_len) {
224 ParamTypeInfo type_info;
225 if (mangled_name[pos] == 'S') {
226 // handle duplicate param_type
227 if (mangled_name[pos + 1] != '_') {
228 return false;
229 }
230 pos += 2;
231 if (params_.empty()) {
232 return false;
233 }
234 params_.push_back(params_.back());
alan-bakeradf44262020-03-16 11:17:21 -0400235 } else if ((pos = GetParameterType(mangled_name, &type_info, pos))) {
SJW173c7e92020-03-16 08:44:47 -0500236 params_.push_back(type_info);
237 } else {
238 return false;
239 }
240 }
241
242 return true;
alan-bakerf67468c2019-11-25 15:51:49 -0500243}
244
SJW173c7e92020-03-16 08:44:47 -0500245////////////////////////////////////////////////////////////////////////////////
246// FunctionInfo ctor - parses mangled name
247Builtins::FunctionInfo::FunctionInfo(const std::string &mangled_name) {
248 is_valid_ = GetFromMangledNameCheck(mangled_name);
249 type_ = LookupBuiltinType(name_);
alan-bakerf67468c2019-11-25 15:51:49 -0500250}
251
SJW173c7e92020-03-16 08:44:47 -0500252// get const ParamTypeInfo for nth parameter
253const Builtins::ParamTypeInfo &
254Builtins::FunctionInfo::getParameter(size_t _arg) const {
255 assert(params_.size() > _arg);
256 return params_[_arg];
alan-bakerf67468c2019-11-25 15:51:49 -0500257}
258
SJW2c317da2020-03-23 07:39:13 -0500259// Test for OCL Sampler parameter type
260bool Builtins::ParamTypeInfo::isSampler() const {
261 return type_id == Type::StructTyID && name == "ocl_sampler";
262}
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////////////////////////////////////////////////////////////////////////////////
276//// Legacy interface
277////////////////////////////////////////////////////////////////////////////////
278bool Builtins::IsImageBuiltin(StringRef name) {
279 auto func_type = Lookup(name).getType();
280 return func_type > kType_Image_Start && func_type < kType_Image_End;
alan-baker75090e42020-02-20 11:21:04 -0500281}
282
SJW173c7e92020-03-16 08:44:47 -0500283bool Builtins::IsSampledImageRead(StringRef name) {
284 return IsFloatSampledImageRead(name) || IsUintSampledImageRead(name) ||
285 IsIntSampledImageRead(name);
alan-baker75090e42020-02-20 11:21:04 -0500286}
287
SJW173c7e92020-03-16 08:44:47 -0500288bool Builtins::IsFloatSampledImageRead(StringRef _name) {
289 const auto &fi = Lookup(_name);
290 if (fi.getType() == kReadImagef) {
291 const auto &pi = fi.getParameter(1);
SJW2c317da2020-03-23 07:39:13 -0500292 return pi.isSampler();
SJW173c7e92020-03-16 08:44:47 -0500293 }
294 return false;
alan-baker75090e42020-02-20 11:21:04 -0500295}
296
SJW173c7e92020-03-16 08:44:47 -0500297bool Builtins::IsUintSampledImageRead(StringRef _name) {
298 const auto &fi = Lookup(_name);
299 if (fi.getType() == kReadImageui) {
300 const auto &pi = fi.getParameter(1);
SJW2c317da2020-03-23 07:39:13 -0500301 return pi.isSampler();
SJW173c7e92020-03-16 08:44:47 -0500302 }
303 return false;
alan-bakerf67468c2019-11-25 15:51:49 -0500304}
305
SJW173c7e92020-03-16 08:44:47 -0500306bool Builtins::IsIntSampledImageRead(StringRef _name) {
307 const auto &fi = Lookup(_name);
308 if (fi.getType() == kReadImagei) {
309 const auto &pi = fi.getParameter(1);
SJW2c317da2020-03-23 07:39:13 -0500310 return pi.isSampler();
SJW173c7e92020-03-16 08:44:47 -0500311 }
312 return false;
alan-bakerf67468c2019-11-25 15:51:49 -0500313}
314
SJW173c7e92020-03-16 08:44:47 -0500315bool Builtins::IsUnsampledImageRead(StringRef name) {
316 return IsFloatUnsampledImageRead(name) || IsUintUnsampledImageRead(name) ||
317 IsIntUnsampledImageRead(name);
alan-bakerf67468c2019-11-25 15:51:49 -0500318}
319
SJW173c7e92020-03-16 08:44:47 -0500320bool Builtins::IsFloatUnsampledImageRead(StringRef _name) {
321 const auto &fi = Lookup(_name);
322 if (fi.getType() == kReadImagef) {
323 const auto &pi = fi.getParameter(1);
SJW2c317da2020-03-23 07:39:13 -0500324 return !pi.isSampler();
SJW173c7e92020-03-16 08:44:47 -0500325 }
326 return false;
alan-bakerf67468c2019-11-25 15:51:49 -0500327}
328
SJW173c7e92020-03-16 08:44:47 -0500329bool Builtins::IsUintUnsampledImageRead(StringRef _name) {
330 const auto &fi = Lookup(_name);
331 if (fi.getType() == kReadImageui) {
332 const auto &pi = fi.getParameter(1);
SJW2c317da2020-03-23 07:39:13 -0500333 return !pi.isSampler();
SJW173c7e92020-03-16 08:44:47 -0500334 }
335 return false;
alan-bakerf67468c2019-11-25 15:51:49 -0500336}
337
SJW173c7e92020-03-16 08:44:47 -0500338bool Builtins::IsIntUnsampledImageRead(StringRef _name) {
339 const auto &fi = Lookup(_name);
340 if (fi.getType() == kReadImagei) {
341 const auto &pi = fi.getParameter(1);
SJW2c317da2020-03-23 07:39:13 -0500342 return !pi.isSampler();
SJW173c7e92020-03-16 08:44:47 -0500343 }
344 return false;
alan-bakerce179f12019-12-06 19:02:22 -0500345}
346
SJW173c7e92020-03-16 08:44:47 -0500347bool Builtins::IsImageWrite(StringRef name) {
348 auto func_code = Lookup(name).getType();
349 return func_code == kWriteImagef || func_code == kWriteImageui ||
350 func_code == kWriteImagei || func_code == kWriteImageh;
alan-bakerce179f12019-12-06 19:02:22 -0500351}
352
SJW173c7e92020-03-16 08:44:47 -0500353bool Builtins::IsFloatImageWrite(StringRef name) {
354 return Lookup(name) == kWriteImagef;
alan-bakerce179f12019-12-06 19:02:22 -0500355}
356
SJW173c7e92020-03-16 08:44:47 -0500357bool Builtins::IsUintImageWrite(StringRef name) {
358 return Lookup(name) == kWriteImageui;
359}
360
361bool Builtins::IsIntImageWrite(StringRef name) {
362 return Lookup(name) == kWriteImagei;
363}
364
365bool Builtins::IsGetImageHeight(StringRef name) {
366 return Lookup(name) == kGetImageHeight;
367}
368
369bool Builtins::IsGetImageWidth(StringRef name) {
370 return Lookup(name) == kGetImageWidth;
371}
372
373bool Builtins::IsGetImageDepth(StringRef name) {
374 return Lookup(name) == kGetImageDepth;
375}
376
377bool Builtins::IsGetImageDim(StringRef name) {
378 return Lookup(name) == kGetImageDim;
379}
380
381bool Builtins::IsImageQuery(StringRef name) {
382 auto func_code = Lookup(name).getType();
383 return func_code == kGetImageHeight || func_code == kGetImageWidth ||
384 func_code == kGetImageDepth || func_code == kGetImageDim;
alan-bakerf67468c2019-11-25 15:51:49 -0500385}