1 /*========================== begin_copyright_notice ============================
2
3 Copyright (C) 2019-2021 Intel Corporation
4
5 SPDX-License-Identifier: MIT
6
7 ============================= end_copyright_notice ===========================*/
8
9 /*========================== begin_copyright_notice ============================
10
11 This file is distributed under the University of Illinois Open Source License.
12 See LICENSE.TXT for details.
13
14 ============================= end_copyright_notice ===========================*/
15
16 // Originated from llvm source lib/IR/Function.cpp
17 // Function.cpp - Implement the Global object classes
18
19 // Implementation of methods declared in llvm/GenXIntrinsics/GenXIntrinsics.h
20
21 #include "llvm/GenXIntrinsics/GenXIntrinsics.h"
22
23 #include "llvm/IR/Constants.h"
24 #include "llvm/IR/Function.h"
25 #include "llvm/IR/Intrinsics.h"
26 #include "llvm/IR/Instructions.h"
27 #include "llvm/IR/Module.h"
28 #include "llvm/IR/Type.h"
29 #include "llvm/Support/CommandLine.h"
30 #include <llvm/ADT/StringExtras.h>
31 #include <llvm/ADT/StringMap.h>
32 #include <llvm/CodeGen/ValueTypes.h>
33
34 #include "llvmVCWrapper/IR/DerivedTypes.h"
35 #include "llvmVCWrapper/IR/Intrinsics.h"
36
37 #include <cstring>
38
39 using namespace llvm;
40
41 static cl::opt<bool> EnableGenXIntrinsicsCache(
42 "enable-genx-intrinsics-cache", cl::init(true), cl::Hidden,
43 cl::desc("Enable metadata caching of genx intrinsics"));
44
45 #define MANGLE(STR) (STR)
46
47 /// Intrinsic::isOverloaded(ID) - Returns true if the intrinsic can be
48 /// overloaded.
49 static bool isOverloaded(GenXIntrinsic::ID id);
50
51 /// getIntrinsicInfoTableEntries - Return the IIT table descriptor for the
52 /// specified intrinsic into an array of IITDescriptors.
53 ///
54 void
55 getIntrinsicInfoTableEntries(GenXIntrinsic::ID id,
56 SmallVectorImpl<Intrinsic::IITDescriptor> &T);
57
58 /// IIT_Info - These are enumerators that describe the entries returned by the
59 /// getIntrinsicInfoTableEntries function.
60 ///
61 /// NOTE: This must be kept in synch with the copy in TblGen/IntrinsicEmitter!
62 enum IIT_Info {
63 // Common values should be encoded with 0-15.
64 IIT_Done = 0,
65 IIT_I1 = 1,
66 IIT_I8 = 2,
67 IIT_I16 = 3,
68 IIT_I32 = 4,
69 IIT_I64 = 5,
70 IIT_F16 = 6,
71 IIT_F32 = 7,
72 IIT_F64 = 8,
73 IIT_V2 = 9,
74 IIT_V4 = 10,
75 IIT_V8 = 11,
76 IIT_V16 = 12,
77 IIT_V32 = 13,
78 IIT_PTR = 14,
79 IIT_ARG = 15,
80
81 // Values from 16+ are only encodable with the inefficient encoding.
82 IIT_V64 = 16,
83 IIT_MMX = 17,
84 IIT_TOKEN = 18,
85 IIT_METADATA = 19,
86 IIT_EMPTYSTRUCT = 20,
87 IIT_STRUCT2 = 21,
88 IIT_STRUCT3 = 22,
89 IIT_STRUCT4 = 23,
90 IIT_STRUCT5 = 24,
91 IIT_EXTEND_ARG = 25,
92 IIT_TRUNC_ARG = 26,
93 IIT_ANYPTR = 27,
94 IIT_V1 = 28,
95 IIT_VARARG = 29,
96 IIT_HALF_VEC_ARG = 30,
97 IIT_SAME_VEC_WIDTH_ARG = 31,
98 IIT_PTR_TO_ARG = 32,
99 IIT_PTR_TO_ELT = 33,
100 IIT_VEC_OF_ANYPTRS_TO_ELT = 34,
101 IIT_I128 = 35,
102 IIT_V512 = 36,
103 IIT_V1024 = 37,
104 IIT_STRUCT6 = 38,
105 IIT_STRUCT7 = 39,
106 IIT_STRUCT8 = 40,
107 IIT_F128 = 41
108 };
109
110 static void
DecodeIITType(unsigned & NextElt,ArrayRef<unsigned char> Infos,SmallVectorImpl<Intrinsic::IITDescriptor> & OutputTable)111 DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
112 SmallVectorImpl<Intrinsic::IITDescriptor> &OutputTable) {
113 using namespace Intrinsic;
114
115 IIT_Info Info = IIT_Info(Infos[NextElt++]);
116 unsigned StructElts = 2;
117
118 switch (Info) {
119 case IIT_Done:
120 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Void, 0));
121 return;
122 case IIT_VARARG:
123 OutputTable.push_back(IITDescriptor::get(IITDescriptor::VarArg, 0));
124 return;
125 case IIT_MMX:
126 OutputTable.push_back(IITDescriptor::get(IITDescriptor::MMX, 0));
127 return;
128 case IIT_TOKEN:
129 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Token, 0));
130 return;
131 case IIT_METADATA:
132 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Metadata, 0));
133 return;
134 case IIT_F16:
135 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Half, 0));
136 return;
137 case IIT_F32:
138 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Float, 0));
139 return;
140 case IIT_F64:
141 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Double, 0));
142 return;
143 case IIT_F128:
144 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Quad, 0));
145 return;
146 case IIT_I1:
147 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Integer, 1));
148 return;
149 case IIT_I8:
150 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Integer, 8));
151 return;
152 case IIT_I16:
153 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Integer,16));
154 return;
155 case IIT_I32:
156 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Integer, 32));
157 return;
158 case IIT_I64:
159 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Integer, 64));
160 return;
161 case IIT_I128:
162 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Integer, 128));
163 return;
164 case IIT_V1:
165 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Vector, 1));
166 DecodeIITType(NextElt, Infos, OutputTable);
167 return;
168 case IIT_V2:
169 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Vector, 2));
170 DecodeIITType(NextElt, Infos, OutputTable);
171 return;
172 case IIT_V4:
173 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Vector, 4));
174 DecodeIITType(NextElt, Infos, OutputTable);
175 return;
176 case IIT_V8:
177 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Vector, 8));
178 DecodeIITType(NextElt, Infos, OutputTable);
179 return;
180 case IIT_V16:
181 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Vector, 16));
182 DecodeIITType(NextElt, Infos, OutputTable);
183 return;
184 case IIT_V32:
185 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Vector, 32));
186 DecodeIITType(NextElt, Infos, OutputTable);
187 return;
188 case IIT_V64:
189 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Vector, 64));
190 DecodeIITType(NextElt, Infos, OutputTable);
191 return;
192 case IIT_V512:
193 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Vector, 512));
194 DecodeIITType(NextElt, Infos, OutputTable);
195 return;
196 case IIT_V1024:
197 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Vector, 1024));
198 DecodeIITType(NextElt, Infos, OutputTable);
199 return;
200 case IIT_PTR:
201 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Pointer, 0));
202 DecodeIITType(NextElt, Infos, OutputTable);
203 return;
204 case IIT_ANYPTR: { // [ANYPTR addrspace, subtype]
205 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Pointer,
206 Infos[NextElt++]));
207 DecodeIITType(NextElt, Infos, OutputTable);
208 return;
209 }
210 case IIT_ARG: {
211 unsigned ArgInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
212 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Argument, ArgInfo));
213 return;
214 }
215 case IIT_EXTEND_ARG: {
216 unsigned ArgInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
217 OutputTable.push_back(IITDescriptor::get(IITDescriptor::ExtendArgument,
218 ArgInfo));
219 return;
220 }
221 case IIT_TRUNC_ARG: {
222 unsigned ArgInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
223 OutputTable.push_back(IITDescriptor::get(IITDescriptor::TruncArgument,
224 ArgInfo));
225 return;
226 }
227 case IIT_HALF_VEC_ARG: {
228 unsigned ArgInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
229 OutputTable.push_back(IITDescriptor::get(IITDescriptor::HalfVecArgument,
230 ArgInfo));
231 return;
232 }
233 case IIT_SAME_VEC_WIDTH_ARG: {
234 unsigned ArgInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
235 OutputTable.push_back(IITDescriptor::get(IITDescriptor::SameVecWidthArgument,
236 ArgInfo));
237 return;
238 }
239 case IIT_PTR_TO_ARG: {
240 unsigned ArgInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
241 OutputTable.push_back(IITDescriptor::get(IITDescriptor::PtrToArgument,
242 ArgInfo));
243 return;
244 }
245 case IIT_PTR_TO_ELT: {
246 unsigned ArgInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
247 OutputTable.push_back(IITDescriptor::get(IITDescriptor::PtrToElt, ArgInfo));
248 return;
249 }
250 case IIT_VEC_OF_ANYPTRS_TO_ELT: {
251 unsigned short ArgNo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
252 unsigned short RefNo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
253 OutputTable.push_back(
254 IITDescriptor::get(IITDescriptor::VecOfAnyPtrsToElt, ArgNo, RefNo));
255 return;
256 }
257 case IIT_EMPTYSTRUCT:
258 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Struct, 0));
259 return;
260 case IIT_STRUCT8: ++StructElts; LLVM_FALLTHROUGH;
261 case IIT_STRUCT7: ++StructElts; LLVM_FALLTHROUGH;
262 case IIT_STRUCT6: ++StructElts; LLVM_FALLTHROUGH;
263 case IIT_STRUCT5: ++StructElts; LLVM_FALLTHROUGH;
264 case IIT_STRUCT4: ++StructElts; LLVM_FALLTHROUGH;
265 case IIT_STRUCT3: ++StructElts; LLVM_FALLTHROUGH;
266 case IIT_STRUCT2: {
267 OutputTable.push_back(IITDescriptor::get(IITDescriptor::Struct,StructElts));
268
269 for (unsigned i = 0; i != StructElts; ++i)
270 DecodeIITType(NextElt, Infos, OutputTable);
271 return;
272 }
273 }
274 llvm_unreachable("unhandled");
275 }
276
DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> & Infos,ArrayRef<Type * > Tys,LLVMContext & Context)277 static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos,
278 ArrayRef<Type*> Tys, LLVMContext &Context) {
279 using namespace Intrinsic;
280
281 IITDescriptor D = Infos.front();
282 Infos = Infos.slice(1);
283
284 switch (D.Kind) {
285 case IITDescriptor::Void: return Type::getVoidTy(Context);
286 case IITDescriptor::VarArg: return Type::getVoidTy(Context);
287 case IITDescriptor::MMX: return Type::getX86_MMXTy(Context);
288 case IITDescriptor::Token: return Type::getTokenTy(Context);
289 case IITDescriptor::Metadata: return Type::getMetadataTy(Context);
290 case IITDescriptor::Half: return Type::getHalfTy(Context);
291 case IITDescriptor::Float: return Type::getFloatTy(Context);
292 case IITDescriptor::Double: return Type::getDoubleTy(Context);
293 case IITDescriptor::Quad: return Type::getFP128Ty(Context);
294
295 case IITDescriptor::Integer:
296 return IntegerType::get(Context, D.Integer_Width);
297 case IITDescriptor::Vector:
298 return VCINTR::getVectorType(DecodeFixedType(Infos, Tys, Context),D.Vector_Width);
299 case IITDescriptor::Pointer:
300 return PointerType::get(DecodeFixedType(Infos, Tys, Context),
301 D.Pointer_AddressSpace);
302 case IITDescriptor::Struct: {
303 SmallVector<Type *, 8> Elts;
304 for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i)
305 Elts.push_back(DecodeFixedType(Infos, Tys, Context));
306 return StructType::get(Context, Elts);
307 }
308 case IITDescriptor::Argument:
309 return Tys[D.getArgumentNumber()];
310 case IITDescriptor::ExtendArgument: {
311 Type *Ty = Tys[D.getArgumentNumber()];
312 if (VectorType *VTy = dyn_cast<VectorType>(Ty))
313 return VectorType::getExtendedElementVectorType(VTy);
314
315 return IntegerType::get(Context, 2 * cast<IntegerType>(Ty)->getBitWidth());
316 }
317 case IITDescriptor::TruncArgument: {
318 Type *Ty = Tys[D.getArgumentNumber()];
319 if (VectorType *VTy = dyn_cast<VectorType>(Ty))
320 return VectorType::getTruncatedElementVectorType(VTy);
321
322 IntegerType *ITy = cast<IntegerType>(Ty);
323 assert(ITy->getBitWidth() % 2 == 0);
324 return IntegerType::get(Context, ITy->getBitWidth() / 2);
325 }
326 case IITDescriptor::HalfVecArgument:
327 return VectorType::getHalfElementsVectorType(cast<VectorType>(
328 Tys[D.getArgumentNumber()]));
329 case IITDescriptor::SameVecWidthArgument: {
330 Type *EltTy = DecodeFixedType(Infos, Tys, Context);
331 Type *Ty = Tys[D.getArgumentNumber()];
332 if (VectorType *VTy = dyn_cast<VectorType>(Ty)) {
333 return VCINTR::getVectorType(EltTy,
334 VCINTR::VectorType::getNumElements(VTy));
335 }
336 llvm_unreachable("unhandled");
337 }
338 case IITDescriptor::PtrToArgument: {
339 Type *Ty = Tys[D.getArgumentNumber()];
340 return PointerType::getUnqual(Ty);
341 }
342 case IITDescriptor::PtrToElt: {
343 Type *Ty = Tys[D.getArgumentNumber()];
344 VectorType *VTy = dyn_cast<VectorType>(Ty);
345 if (!VTy)
346 llvm_unreachable("Expected an argument of Vector Type");
347 Type *EltTy = cast<VectorType>(VTy)->getElementType();
348 return PointerType::getUnqual(EltTy);
349 }
350 case IITDescriptor::VecOfAnyPtrsToElt:
351 // Return the overloaded type (which determines the pointers address space)
352 return Tys[D.getOverloadArgNumber()];
353 default:
354 break;
355 }
356 llvm_unreachable("unhandled");
357 }
358
359 #define GET_INTRINSIC_GENERATOR_GLOBAL
360 #include "llvm/GenXIntrinsics/GenXIntrinsicDescription.gen"
361 #undef GET_INTRINSIC_GENERATOR_GLOBAL
362
getIntrinsicInfoTableEntries(GenXIntrinsic::ID id,SmallVectorImpl<Intrinsic::IITDescriptor> & T)363 void GenXIntrinsic::getIntrinsicInfoTableEntries(
364 GenXIntrinsic::ID id, SmallVectorImpl<Intrinsic::IITDescriptor> &T) {
365 assert(id > GenXIntrinsic::not_genx_intrinsic);
366 id = static_cast<GenXIntrinsic::ID>(id - GenXIntrinsic::not_genx_intrinsic);
367 assert(id < sizeof(IIT_Table) / sizeof(*IIT_Table));
368
369 // Check to see if the intrinsic's type was expressible by the table.
370 unsigned TableVal = IIT_Table[id - 1];
371
372 // Decode the TableVal into an array of IITValues.
373 SmallVector<unsigned char, 8> IITValues;
374 ArrayRef<unsigned char> IITEntries;
375 unsigned NextElt = 0;
376 if ((TableVal >> 31) != 0) {
377 // This is an offset into the IIT_LongEncodingTable.
378 IITEntries = IIT_LongEncodingTable;
379
380 // Strip sentinel bit.
381 NextElt = (TableVal << 1) >> 1;
382 } else {
383 // Decode the TableVal into an array of IITValues. If the entry was encoded
384 // into a single word in the table itself, decode it now.
385 do {
386 IITValues.push_back(TableVal & 0xF);
387 TableVal >>= 4;
388 } while (TableVal);
389
390 IITEntries = IITValues;
391 NextElt = 0;
392 }
393
394 // Okay, decode the table into the output vector of IITDescriptors.
395 DecodeIITType(NextElt, IITEntries, T);
396 while (NextElt != IITEntries.size() && IITEntries[NextElt] != 0)
397 DecodeIITType(NextElt, IITEntries, T);
398 }
399
400 /// Returns a stable mangling for the type specified for use in the name
401 /// mangling scheme used by 'any' types in intrinsic signatures. The mangling
402 /// of named types is simply their name. Manglings for unnamed types consist
403 /// of a prefix ('p' for pointers, 'a' for arrays, 'f_' for functions)
404 /// combined with the mangling of their component types. A vararg function
405 /// type will have a suffix of 'vararg'. Since function types can contain
406 /// other function types, we close a function type mangling with suffix 'f'
407 /// which can't be confused with it's prefix. This ensures we don't have
408 /// collisions between two unrelated function types. Otherwise, you might
409 /// parse ffXX as f(fXX) or f(fX)X. (X is a placeholder for any other type.)
getMangledTypeStr(Type * Ty)410 static std::string getMangledTypeStr(Type* Ty) {
411 std::string Result;
412 if (PointerType* PTyp = dyn_cast<PointerType>(Ty)) {
413 Result += "p" + llvm::utostr(PTyp->getAddressSpace()) +
414 getMangledTypeStr(PTyp->getElementType());
415 } else if (ArrayType* ATyp = dyn_cast<ArrayType>(Ty)) {
416 Result += "a" + llvm::utostr(ATyp->getNumElements()) +
417 getMangledTypeStr(ATyp->getElementType());
418 } else if (StructType* STyp = dyn_cast<StructType>(Ty)) {
419 if(!STyp->isLiteral())
420 Result += STyp->getName();
421 else {
422 Result += "s" + llvm::utostr(STyp->getNumElements());
423 for(unsigned int i = 0; i < STyp->getNumElements(); i++)
424 Result += getMangledTypeStr(STyp->getElementType(i));
425 }
426 } else if (FunctionType* FT = dyn_cast<FunctionType>(Ty)) {
427 Result += "f_" + getMangledTypeStr(FT->getReturnType());
428 for (size_t i = 0; i < FT->getNumParams(); i++)
429 Result += getMangledTypeStr(FT->getParamType(i));
430 if (FT->isVarArg())
431 Result += "vararg";
432 // Ensure nested function types are distinguishable.
433 Result += "f";
434 } else if (isa<VectorType>(Ty))
435 Result += "v" +
436 utostr(VCINTR::VectorType::getNumElements(cast<VectorType>(Ty))) +
437 getMangledTypeStr(cast<VectorType>(Ty)->getElementType());
438 else if (Ty)
439 Result += EVT::getEVT(Ty).getEVTString();
440 return Result;
441 }
442
443 static const char * const GenXIntrinsicNameTable[] = {
444 "not_genx_intrinsic",
445 #define GET_INTRINSIC_NAME_TABLE
446 #include "llvm/GenXIntrinsics/GenXIntrinsicDescription.gen"
447 #undef GET_INTRINSIC_NAME_TABLE
448 };
449
isOverloaded(GenXIntrinsic::ID id)450 bool isOverloaded(GenXIntrinsic::ID id) {
451 assert(isGenXIntrinsic(id) && "Invalid intrinsic ID!");
452 id = static_cast<GenXIntrinsic::ID>(id - GenXIntrinsic::not_genx_intrinsic);
453 #define GET_INTRINSIC_OVERLOAD_TABLE
454 #include "llvm/GenXIntrinsics/GenXIntrinsicDescription.gen"
455 #undef GET_INTRINSIC_OVERLOAD_TABLE
456 }
457
458 /// This defines the "getAttributes(ID id)" method.
459 #define GET_INTRINSIC_ATTRIBUTES
460 #include "llvm/GenXIntrinsics/GenXIntrinsicDescription.gen"
461 #undef GET_INTRINSIC_ATTRIBUTES
462
463 static StringRef GenXIntrinsicMDName{ "genx_intrinsic_id" };
464
isSupportedPlatform(const std::string & CPU,unsigned id)465 bool GenXIntrinsic::isSupportedPlatform(const std::string &CPU, unsigned id) {
466 #define GET_INTRINSIC_PLATFORMS
467 #include "llvm/GenXIntrinsics/GenXIntrinsicDescription.gen"
468 #undef GET_INTRINSIC_PLATFORMS
469 assert(SupportedIntrinsics.find(CPU) != SupportedIntrinsics.end() &&
470 "Unknown Platform");
471 assert(GenXIntrinsic::isGenXIntrinsic(id) &&
472 "this function should be used only for GenXIntrinsics");
473 auto PlatformInfoIt = SupportedIntrinsics.find(CPU);
474 if (PlatformInfoIt == SupportedIntrinsics.end())
475 return false;
476 const auto &IntrinsicInfo = PlatformInfoIt->second;
477 size_t IntrinsicIdx = id - GenXIntrinsic::ID::not_genx_intrinsic - 1;
478 if (IntrinsicIdx < IntrinsicInfo.size())
479 return IntrinsicInfo[IntrinsicIdx];
480 return false;
481 }
482
483 /// Table of per-target intrinsic name tables.
484 #define GET_INTRINSIC_TARGET_DATA
485 #include "llvm/GenXIntrinsics/GenXIntrinsicDescription.gen"
486 #undef GET_INTRINSIC_TARGET_DATA
487
isOverloadedArg(unsigned IntrinID,unsigned ArgNum)488 bool GenXIntrinsic::isOverloadedArg(unsigned IntrinID, unsigned ArgNum) {
489 #define GET_INTRINSIC_OVERLOAD_ARGS_TABLE
490 #include "llvm/GenXIntrinsics/GenXIntrinsicDescription.gen"
491 #undef GET_INTRINSIC_OVERLOAD_ARGS_TABLE
492 }
493
isOverloadedRet(unsigned IntrinID)494 bool GenXIntrinsic::isOverloadedRet(unsigned IntrinID) {
495 #define GET_INTRINSIC_OVERLOAD_RET_TABLE
496 #include "llvm/GenXIntrinsics/GenXIntrinsicDescription.gen"
497 #undef GET_INTRINSIC_OVERLOAD_RET_TABLE
498 }
499
500 /// Find the segment of \c IntrinsicNameTable for intrinsics with the same
501 /// target as \c Name, or the generic table if \c Name is not target specific.
502 ///
503 /// Returns the relevant slice of \c IntrinsicNameTable
findTargetSubtable(StringRef Name)504 static ArrayRef<const char *> findTargetSubtable(StringRef Name) {
505 assert(Name.startswith("llvm.genx."));
506
507 ArrayRef<IntrinsicTargetInfo> Targets(TargetInfos);
508 // Drop "llvm." and take the first dotted component. That will be the target
509 // if this is target specific.
510 StringRef Target = Name.drop_front(5).split('.').first;
511 auto It = std::lower_bound(Targets.begin(), Targets.end(), Target,
512 [](const IntrinsicTargetInfo &TI,
513 StringRef Target) { return TI.Name < Target; });
514 // We've either found the target or just fall back to the generic set, which
515 // is always first.
516 const auto &TI = It != Targets.end() && It->Name == Target ? *It : Targets[0];
517 return makeArrayRef(&GenXIntrinsicNameTable[1] + TI.Offset, TI.Count);
518 }
519
getGenXIntrinsicID(const Function * F)520 GenXIntrinsic::ID GenXIntrinsic::getGenXIntrinsicID(const Function *F) {
521 assert(F);
522 llvm::StringRef Name = F->getName();
523 if (!Name.startswith(getGenXIntrinsicPrefix()))
524 return GenXIntrinsic::not_genx_intrinsic;
525
526 // Check metadata cache.
527 if (auto *MD = F->getMetadata(GenXIntrinsicMDName)) {
528 assert(MD->getNumOperands() == 1 && "Invalid intrinsic metadata");
529 auto Val = cast<ValueAsMetadata>(MD->getOperand(0))->getValue();
530 GenXIntrinsic::ID Id =
531 static_cast<GenXIntrinsic::ID>(cast<ConstantInt>(Val)->getZExtValue());
532
533 // we need to check that metadata is correct and can be actually used
534 if (isGenXIntrinsic(Id)) {
535 const char *NamePrefix =
536 GenXIntrinsicNameTable[Id - GenXIntrinsic::not_genx_intrinsic];
537 if (Name.startswith(NamePrefix))
538 return Id;
539 }
540 }
541
542 // Fallback to string lookup.
543 auto ID = lookupGenXIntrinsicID(Name);
544 assert(ID != GenXIntrinsic::not_genx_intrinsic && "Intrinsic not found!");
545 return ID;
546 }
547
getGenXName(GenXIntrinsic::ID id,ArrayRef<Type * > Tys)548 std::string GenXIntrinsic::getGenXName(GenXIntrinsic::ID id,
549 ArrayRef<Type *> Tys) {
550 assert(isGenXIntrinsic(id) && "Invalid intrinsic ID!");
551 assert(Tys.empty() ||
552 (isOverloaded(id) && "Non-overloadable intrinsic was overloaded!"));
553 id = static_cast<GenXIntrinsic::ID>(id - GenXIntrinsic::not_genx_intrinsic);
554 std::string Result(GenXIntrinsicNameTable[id]);
555 for (Type *Ty : Tys) {
556 Result += "." + getMangledTypeStr(Ty);
557 }
558 return Result;
559 }
560
lookupGenXIntrinsicID(StringRef Name)561 GenXIntrinsic::ID GenXIntrinsic::lookupGenXIntrinsicID(StringRef Name) {
562 ArrayRef<const char *> NameTable = findTargetSubtable(Name);
563 int Idx = Intrinsic::lookupLLVMIntrinsicByName(NameTable, Name);
564 if (Idx == -1)
565 return GenXIntrinsic::not_genx_intrinsic;
566
567 // Intrinsic IDs correspond to the location in IntrinsicNameTable, but we have
568 // an index into a sub-table.
569 int Adjust = NameTable.data() - GenXIntrinsicNameTable;
570 auto ID = static_cast<GenXIntrinsic::ID>(Idx + Adjust + GenXIntrinsic::not_genx_intrinsic);
571
572 // If the intrinsic is not overloaded, require an exact match. If it is
573 // overloaded, require either exact or prefix match.
574 assert(Name.size() >= strlen(NameTable[Idx]) &&
575 "Expected either exact or prefix match");
576 assert((Name.size() == strlen(NameTable[Idx])) ||
577 (isOverloaded(ID) && "Non-overloadable intrinsic was overloaded!"));
578 return ID;
579 }
580
getGenXType(LLVMContext & Context,GenXIntrinsic::ID id,ArrayRef<Type * > Tys)581 FunctionType *GenXIntrinsic::getGenXType(LLVMContext &Context,
582 GenXIntrinsic::ID id,
583 ArrayRef<Type *> Tys) {
584 SmallVector<Intrinsic::IITDescriptor, 8> Table;
585 getIntrinsicInfoTableEntries(id, Table);
586
587 ArrayRef<Intrinsic::IITDescriptor> TableRef = Table;
588 Type *ResultTy = DecodeFixedType(TableRef, Tys, Context);
589
590 SmallVector<Type *, 8> ArgTys;
591 while (!TableRef.empty())
592 ArgTys.push_back(DecodeFixedType(TableRef, Tys, Context));
593
594 // DecodeFixedType returns Void for IITDescriptor::Void and
595 // IITDescriptor::VarArg If we see void type as the type of the last argument,
596 // it is vararg intrinsic
597 if (!ArgTys.empty() && ArgTys.back()->isVoidTy()) {
598 ArgTys.pop_back();
599 return FunctionType::get(ResultTy, ArgTys, true);
600 }
601 return FunctionType::get(ResultTy, ArgTys, false);
602 }
603
604 #ifndef NDEBUG
605 // Sanity check for intrinsic types.
606 // After translation from SPIRV literal structures become identified.
607 // However, if intrinsic returns multiple values, then it returns
608 // literal structure.
609 // Having this, compatible intrinsics will have same argument types
610 // and either same return types or layout identical structure types.
isCompatibleIntrinsicSignature(FunctionType * DecodedType,FunctionType * FoundType)611 static bool isCompatibleIntrinsicSignature(FunctionType *DecodedType,
612 FunctionType *FoundType) {
613 if (DecodedType == FoundType)
614 return true;
615
616 if (DecodedType->params() != FoundType->params())
617 return false;
618
619 // Return types are different. Check for structures.
620 auto *DecStrTy = dyn_cast<StructType>(DecodedType->getReturnType());
621 auto *FoundStrTy = dyn_cast<StructType>(FoundType->getReturnType());
622 if (!DecStrTy || !FoundStrTy)
623 return false;
624
625 return DecStrTy->isLayoutIdentical(FoundStrTy);
626 }
627 #endif
628
getGenXDeclaration(Module * M,GenXIntrinsic::ID id,ArrayRef<Type * > Tys)629 Function *GenXIntrinsic::getGenXDeclaration(Module *M, GenXIntrinsic::ID id,
630 ArrayRef<Type *> Tys) {
631 assert(isGenXNonTrivialIntrinsic(id));
632 assert(Tys.empty() ||
633 (isOverloaded(id) && "Non-overloadable intrinsic was overloaded!"));
634
635 auto GenXName = getGenXName(id, Tys);
636 FunctionType *FTy = getGenXType(M->getContext(), id, Tys);
637 Function *F = M->getFunction(GenXName);
638 if (!F)
639 F = Function::Create(FTy, GlobalVariable::ExternalLinkage, GenXName, M);
640
641 assert(isCompatibleIntrinsicSignature(FTy, F->getFunctionType()) &&
642 "Module contains intrinsic declaration with incompatible type!");
643
644 resetGenXAttributes(F);
645 return F;
646 }
647
resetGenXAttributes(Function * F)648 void GenXIntrinsic::resetGenXAttributes(Function *F) {
649
650 assert(F);
651
652 GenXIntrinsic::ID GXID = getGenXIntrinsicID(F);
653
654 assert(GXID != GenXIntrinsic::not_genx_intrinsic);
655
656 // Since Function::isIntrinsic() will return true due to llvm. prefix,
657 // Module::getOrInsertFunction fails to add the attributes. explicitly adding
658 // the attribute to handle this problem. This since is setup on the function
659 // declaration, attribute assignment is global and hence this approach
660 // suffices.
661 F->setAttributes(GenXIntrinsic::getAttributes(F->getContext(), GXID));
662
663 // Cache intrinsic ID in metadata.
664 if (EnableGenXIntrinsicsCache && !F->hasMetadata(GenXIntrinsicMDName)) {
665 LLVMContext &Ctx = F->getContext();
666 auto *Ty = IntegerType::getInt32Ty(Ctx);
667 auto *Cached = ConstantInt::get(Ty, GXID);
668 auto *MD = MDNode::get(Ctx, {ConstantAsMetadata::get(Cached)});
669 F->addMetadata(GenXIntrinsicMDName, *MD);
670 }
671 }
672
getAnyName(unsigned id,ArrayRef<Type * > Tys)673 std::string GenXIntrinsic::getAnyName(unsigned id, ArrayRef<Type *> Tys) {
674 assert(isAnyIntrinsic(id));
675 if (id == not_any_intrinsic) {
676 std::string Result("not_any_intrinsic");
677 for (Type *Ty : Tys) {
678 Result += "." + getMangledTypeStr(Ty);
679 }
680 return Result;
681 } else if (isGenXIntrinsic(id))
682 return getGenXName((GenXIntrinsic::ID)id, Tys);
683 else
684 return VCINTR::Intrinsic::getName((Intrinsic::ID)id, Tys);
685 }
686
getLSCVectorSize(const Instruction * I)687 GenXIntrinsic::LSCVectorSize GenXIntrinsic::getLSCVectorSize(
688 const Instruction *I) {
689 assert(isLSC(I));
690 switch (getLSCCategory(I)) {
691 case LSCCategory::Load:
692 case LSCCategory::Prefetch:
693 case LSCCategory::Store:
694 case LSCCategory::Atomic:
695 return static_cast<LSCVectorSize>(
696 cast<ConstantInt>(I->getOperand(7))->getZExtValue());
697 case LSCCategory::LegacyAtomic:
698 return static_cast<LSCVectorSize>(
699 cast<ConstantInt>(I->getOperand(8))->getZExtValue());
700 case LSCCategory::Fence:
701 case LSCCategory::Load2D:
702 case LSCCategory::Prefetch2D:
703 case LSCCategory::Store2D:
704 case LSCCategory::NotLSC:
705 return LSCVectorSize::N0;
706 }
707 llvm_unreachable("Unknown LSC category");
708 }
709
getLSCDataSize(const Instruction * I)710 GenXIntrinsic::LSCDataSize GenXIntrinsic::getLSCDataSize(
711 const Instruction *I) {
712 assert(isLSC(I));
713 switch (getLSCCategory(I)) {
714 case LSCCategory::Load:
715 case LSCCategory::Prefetch:
716 case LSCCategory::Store:
717 case LSCCategory::LegacyAtomic:
718 case LSCCategory::Atomic:
719 return static_cast<LSCDataSize>(
720 cast<ConstantInt>(I->getOperand(6))->getZExtValue());
721 case LSCCategory::Load2D:
722 case LSCCategory::Prefetch2D:
723 case LSCCategory::Store2D:
724 return static_cast<LSCDataSize>(
725 cast<ConstantInt>(I->getOperand(3))->getZExtValue());
726 case LSCCategory::Fence:
727 case LSCCategory::NotLSC:
728 return LSCDataSize::Invalid;
729 }
730 llvm_unreachable("Unknown LSC category");
731 }
732
getLSCDataOrder(const Instruction * I)733 GenXIntrinsic::LSCDataOrder GenXIntrinsic::getLSCDataOrder(
734 const Instruction *I) {
735 assert(isLSC(I));
736 switch (getLSCCategory(I)) {
737 case LSCCategory::Load:
738 case LSCCategory::Prefetch:
739 case LSCCategory::Store:
740 case LSCCategory::Atomic:
741 return static_cast<LSCDataOrder>(
742 cast<ConstantInt>(I->getOperand(8))->getZExtValue());
743 case LSCCategory::LegacyAtomic:
744 return static_cast<LSCDataOrder>(
745 cast<ConstantInt>(I->getOperand(7))->getZExtValue());
746 case LSCCategory::Load2D:
747 case LSCCategory::Prefetch2D:
748 case LSCCategory::Store2D:
749 return static_cast<LSCDataOrder>(
750 cast<ConstantInt>(I->getOperand(4))->getZExtValue());
751 case LSCCategory::Fence:
752 case LSCCategory::NotLSC:
753 return LSCDataOrder::Invalid;
754 }
755 llvm_unreachable("Unknown LSC category");
756 }
757
getLSCWidth(const Instruction * I)758 unsigned GenXIntrinsic::getLSCWidth(const Instruction *I) {
759 assert(isLSC(I));
760 switch(getLSCCategory(I)) {
761 case LSCCategory::Load:
762 case LSCCategory::Prefetch:
763 case LSCCategory::Store:
764 case LSCCategory::Fence:
765 case LSCCategory::LegacyAtomic:
766 case LSCCategory::Atomic: {
767 case LSCCategory::Prefetch2D:
768 if (auto VT = dyn_cast<VectorType>(I->getOperand(0)->getType()))
769 return VCINTR::VectorType::getNumElements(VT);
770 return 1;
771 }
772 case LSCCategory::Load2D:
773 case LSCCategory::Store2D:
774 case LSCCategory::NotLSC:
775 return 1;
776 }
777 llvm_unreachable("Unknown LSC category");
778 }
779
780