1 | //===- Type.cpp - Implement the Type class --------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements the Type class for the IR library. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/IR/Type.h" |
14 | #include "LLVMContextImpl.h" |
15 | #include "llvm/ADT/APInt.h" |
16 | #include "llvm/ADT/SetVector.h" |
17 | #include "llvm/ADT/SmallString.h" |
18 | #include "llvm/ADT/StringMap.h" |
19 | #include "llvm/ADT/StringRef.h" |
20 | #include "llvm/IR/Constant.h" |
21 | #include "llvm/IR/Constants.h" |
22 | #include "llvm/IR/DerivedTypes.h" |
23 | #include "llvm/IR/LLVMContext.h" |
24 | #include "llvm/IR/Value.h" |
25 | #include "llvm/Support/Casting.h" |
26 | #include "llvm/Support/Error.h" |
27 | #include "llvm/Support/TypeSize.h" |
28 | #include "llvm/Support/raw_ostream.h" |
29 | #include "llvm/TargetParser/RISCVTargetParser.h" |
30 | #include <cassert> |
31 | #include <utility> |
32 | |
33 | using namespace llvm; |
34 | |
35 | //===----------------------------------------------------------------------===// |
36 | // Type Class Implementation |
37 | //===----------------------------------------------------------------------===// |
38 | |
39 | Type *Type::getPrimitiveType(LLVMContext &C, TypeID IDNumber) { |
40 | switch (IDNumber) { |
41 | case VoidTyID : return getVoidTy(C); |
42 | case HalfTyID : return getHalfTy(C); |
43 | case BFloatTyID : return getBFloatTy(C); |
44 | case FloatTyID : return getFloatTy(C); |
45 | case DoubleTyID : return getDoubleTy(C); |
46 | case X86_FP80TyID : return getX86_FP80Ty(C); |
47 | case FP128TyID : return getFP128Ty(C); |
48 | case PPC_FP128TyID : return getPPC_FP128Ty(C); |
49 | case LabelTyID : return getLabelTy(C); |
50 | case MetadataTyID : return getMetadataTy(C); |
51 | case X86_AMXTyID : return getX86_AMXTy(C); |
52 | case TokenTyID : return getTokenTy(C); |
53 | default: |
54 | return nullptr; |
55 | } |
56 | } |
57 | |
58 | bool Type::isIntegerTy(unsigned Bitwidth) const { |
59 | return isIntegerTy() && cast<IntegerType>(Val: this)->getBitWidth() == Bitwidth; |
60 | } |
61 | |
62 | bool Type::isScalableTy(SmallPtrSetImpl<const Type *> &Visited) const { |
63 | if (const auto *ATy = dyn_cast<ArrayType>(Val: this)) |
64 | return ATy->getElementType()->isScalableTy(Visited); |
65 | if (const auto *STy = dyn_cast<StructType>(Val: this)) |
66 | return STy->isScalableTy(Visited); |
67 | return getTypeID() == ScalableVectorTyID || isScalableTargetExtTy(); |
68 | } |
69 | |
70 | bool Type::isScalableTy() const { |
71 | SmallPtrSet<const Type *, 4> Visited; |
72 | return isScalableTy(Visited); |
73 | } |
74 | |
75 | bool Type::containsNonGlobalTargetExtType( |
76 | SmallPtrSetImpl<const Type *> &Visited) const { |
77 | if (const auto *ATy = dyn_cast<ArrayType>(Val: this)) |
78 | return ATy->getElementType()->containsNonGlobalTargetExtType(Visited); |
79 | if (const auto *STy = dyn_cast<StructType>(Val: this)) |
80 | return STy->containsNonGlobalTargetExtType(Visited); |
81 | if (auto *TT = dyn_cast<TargetExtType>(Val: this)) |
82 | return !TT->hasProperty(Prop: TargetExtType::CanBeGlobal); |
83 | return false; |
84 | } |
85 | |
86 | bool Type::containsNonGlobalTargetExtType() const { |
87 | SmallPtrSet<const Type *, 4> Visited; |
88 | return containsNonGlobalTargetExtType(Visited); |
89 | } |
90 | |
91 | bool Type::containsNonLocalTargetExtType( |
92 | SmallPtrSetImpl<const Type *> &Visited) const { |
93 | if (const auto *ATy = dyn_cast<ArrayType>(Val: this)) |
94 | return ATy->getElementType()->containsNonLocalTargetExtType(Visited); |
95 | if (const auto *STy = dyn_cast<StructType>(Val: this)) |
96 | return STy->containsNonLocalTargetExtType(Visited); |
97 | if (auto *TT = dyn_cast<TargetExtType>(Val: this)) |
98 | return !TT->hasProperty(Prop: TargetExtType::CanBeLocal); |
99 | return false; |
100 | } |
101 | |
102 | bool Type::containsNonLocalTargetExtType() const { |
103 | SmallPtrSet<const Type *, 4> Visited; |
104 | return containsNonLocalTargetExtType(Visited); |
105 | } |
106 | |
107 | const fltSemantics &Type::getFltSemantics() const { |
108 | switch (getTypeID()) { |
109 | case HalfTyID: return APFloat::IEEEhalf(); |
110 | case BFloatTyID: return APFloat::BFloat(); |
111 | case FloatTyID: return APFloat::IEEEsingle(); |
112 | case DoubleTyID: return APFloat::IEEEdouble(); |
113 | case X86_FP80TyID: return APFloat::x87DoubleExtended(); |
114 | case FP128TyID: return APFloat::IEEEquad(); |
115 | case PPC_FP128TyID: return APFloat::PPCDoubleDouble(); |
116 | default: llvm_unreachable("Invalid floating type" ); |
117 | } |
118 | } |
119 | |
120 | bool Type::isScalableTargetExtTy() const { |
121 | if (auto *TT = dyn_cast<TargetExtType>(Val: this)) |
122 | return isa<ScalableVectorType>(Val: TT->getLayoutType()); |
123 | return false; |
124 | } |
125 | |
126 | Type *Type::getFloatingPointTy(LLVMContext &C, const fltSemantics &S) { |
127 | Type *Ty; |
128 | if (&S == &APFloat::IEEEhalf()) |
129 | Ty = Type::getHalfTy(C); |
130 | else if (&S == &APFloat::BFloat()) |
131 | Ty = Type::getBFloatTy(C); |
132 | else if (&S == &APFloat::IEEEsingle()) |
133 | Ty = Type::getFloatTy(C); |
134 | else if (&S == &APFloat::IEEEdouble()) |
135 | Ty = Type::getDoubleTy(C); |
136 | else if (&S == &APFloat::x87DoubleExtended()) |
137 | Ty = Type::getX86_FP80Ty(C); |
138 | else if (&S == &APFloat::IEEEquad()) |
139 | Ty = Type::getFP128Ty(C); |
140 | else { |
141 | assert(&S == &APFloat::PPCDoubleDouble() && "Unknown FP format" ); |
142 | Ty = Type::getPPC_FP128Ty(C); |
143 | } |
144 | return Ty; |
145 | } |
146 | |
147 | bool Type::isRISCVVectorTupleTy() const { |
148 | if (!isTargetExtTy()) |
149 | return false; |
150 | |
151 | return cast<TargetExtType>(Val: this)->getName() == "riscv.vector.tuple" ; |
152 | } |
153 | |
154 | bool Type::canLosslesslyBitCastTo(Type *Ty) const { |
155 | // Identity cast means no change so return true |
156 | if (this == Ty) |
157 | return true; |
158 | |
159 | // They are not convertible unless they are at least first class types |
160 | if (!this->isFirstClassType() || !Ty->isFirstClassType()) |
161 | return false; |
162 | |
163 | // Vector -> Vector conversions are always lossless if the two vector types |
164 | // have the same size, otherwise not. |
165 | if (isa<VectorType>(Val: this) && isa<VectorType>(Val: Ty)) |
166 | return getPrimitiveSizeInBits() == Ty->getPrimitiveSizeInBits(); |
167 | |
168 | // 8192-bit fixed width vector types can be losslessly converted to x86amx. |
169 | if (((isa<FixedVectorType>(Val: this)) && Ty->isX86_AMXTy()) && |
170 | getPrimitiveSizeInBits().getFixedValue() == 8192) |
171 | return true; |
172 | if ((isX86_AMXTy() && isa<FixedVectorType>(Val: Ty)) && |
173 | Ty->getPrimitiveSizeInBits().getFixedValue() == 8192) |
174 | return true; |
175 | |
176 | // Conservatively assume we can't losslessly convert between pointers with |
177 | // different address spaces. |
178 | return false; |
179 | } |
180 | |
181 | bool Type::isEmptyTy() const { |
182 | if (auto *ATy = dyn_cast<ArrayType>(Val: this)) { |
183 | unsigned NumElements = ATy->getNumElements(); |
184 | return NumElements == 0 || ATy->getElementType()->isEmptyTy(); |
185 | } |
186 | |
187 | if (auto *STy = dyn_cast<StructType>(Val: this)) { |
188 | unsigned NumElements = STy->getNumElements(); |
189 | for (unsigned i = 0; i < NumElements; ++i) |
190 | if (!STy->getElementType(N: i)->isEmptyTy()) |
191 | return false; |
192 | return true; |
193 | } |
194 | |
195 | return false; |
196 | } |
197 | |
198 | TypeSize Type::getPrimitiveSizeInBits() const { |
199 | switch (getTypeID()) { |
200 | case Type::HalfTyID: |
201 | return TypeSize::getFixed(ExactSize: 16); |
202 | case Type::BFloatTyID: |
203 | return TypeSize::getFixed(ExactSize: 16); |
204 | case Type::FloatTyID: |
205 | return TypeSize::getFixed(ExactSize: 32); |
206 | case Type::DoubleTyID: |
207 | return TypeSize::getFixed(ExactSize: 64); |
208 | case Type::X86_FP80TyID: |
209 | return TypeSize::getFixed(ExactSize: 80); |
210 | case Type::FP128TyID: |
211 | return TypeSize::getFixed(ExactSize: 128); |
212 | case Type::PPC_FP128TyID: |
213 | return TypeSize::getFixed(ExactSize: 128); |
214 | case Type::X86_AMXTyID: |
215 | return TypeSize::getFixed(ExactSize: 8192); |
216 | case Type::IntegerTyID: |
217 | return TypeSize::getFixed(ExactSize: cast<IntegerType>(Val: this)->getBitWidth()); |
218 | case Type::FixedVectorTyID: |
219 | case Type::ScalableVectorTyID: { |
220 | const VectorType *VTy = cast<VectorType>(Val: this); |
221 | ElementCount EC = VTy->getElementCount(); |
222 | TypeSize ETS = VTy->getElementType()->getPrimitiveSizeInBits(); |
223 | assert(!ETS.isScalable() && "Vector type should have fixed-width elements" ); |
224 | return {ETS.getFixedValue() * EC.getKnownMinValue(), EC.isScalable()}; |
225 | } |
226 | default: |
227 | return TypeSize::getFixed(ExactSize: 0); |
228 | } |
229 | } |
230 | |
231 | unsigned Type::getScalarSizeInBits() const { |
232 | // It is safe to assume that the scalar types have a fixed size. |
233 | return getScalarType()->getPrimitiveSizeInBits().getFixedValue(); |
234 | } |
235 | |
236 | int Type::getFPMantissaWidth() const { |
237 | if (auto *VTy = dyn_cast<VectorType>(Val: this)) |
238 | return VTy->getElementType()->getFPMantissaWidth(); |
239 | assert(isFloatingPointTy() && "Not a floating point type!" ); |
240 | if (getTypeID() == HalfTyID) return 11; |
241 | if (getTypeID() == BFloatTyID) return 8; |
242 | if (getTypeID() == FloatTyID) return 24; |
243 | if (getTypeID() == DoubleTyID) return 53; |
244 | if (getTypeID() == X86_FP80TyID) return 64; |
245 | if (getTypeID() == FP128TyID) return 113; |
246 | assert(getTypeID() == PPC_FP128TyID && "unknown fp type" ); |
247 | return -1; |
248 | } |
249 | |
250 | bool Type::isFirstClassType() const { |
251 | switch (getTypeID()) { |
252 | default: |
253 | return true; |
254 | case FunctionTyID: |
255 | case VoidTyID: |
256 | return false; |
257 | case StructTyID: { |
258 | auto *ST = cast<StructType>(Val: this); |
259 | return !ST->isOpaque(); |
260 | } |
261 | } |
262 | } |
263 | |
264 | bool Type::isSizedDerivedType(SmallPtrSetImpl<Type*> *Visited) const { |
265 | if (auto *ATy = dyn_cast<ArrayType>(Val: this)) |
266 | return ATy->getElementType()->isSized(Visited); |
267 | |
268 | if (auto *VTy = dyn_cast<VectorType>(Val: this)) |
269 | return VTy->getElementType()->isSized(Visited); |
270 | |
271 | if (auto *TTy = dyn_cast<TargetExtType>(Val: this)) |
272 | return TTy->getLayoutType()->isSized(Visited); |
273 | |
274 | return cast<StructType>(Val: this)->isSized(Visited); |
275 | } |
276 | |
277 | //===----------------------------------------------------------------------===// |
278 | // Primitive 'Type' data |
279 | //===----------------------------------------------------------------------===// |
280 | |
281 | Type *Type::getVoidTy(LLVMContext &C) { return &C.pImpl->VoidTy; } |
282 | Type *Type::getLabelTy(LLVMContext &C) { return &C.pImpl->LabelTy; } |
283 | Type *Type::getHalfTy(LLVMContext &C) { return &C.pImpl->HalfTy; } |
284 | Type *Type::getBFloatTy(LLVMContext &C) { return &C.pImpl->BFloatTy; } |
285 | Type *Type::getFloatTy(LLVMContext &C) { return &C.pImpl->FloatTy; } |
286 | Type *Type::getDoubleTy(LLVMContext &C) { return &C.pImpl->DoubleTy; } |
287 | Type *Type::getMetadataTy(LLVMContext &C) { return &C.pImpl->MetadataTy; } |
288 | Type *Type::getTokenTy(LLVMContext &C) { return &C.pImpl->TokenTy; } |
289 | Type *Type::getX86_FP80Ty(LLVMContext &C) { return &C.pImpl->X86_FP80Ty; } |
290 | Type *Type::getFP128Ty(LLVMContext &C) { return &C.pImpl->FP128Ty; } |
291 | Type *Type::getPPC_FP128Ty(LLVMContext &C) { return &C.pImpl->PPC_FP128Ty; } |
292 | Type *Type::getX86_AMXTy(LLVMContext &C) { return &C.pImpl->X86_AMXTy; } |
293 | |
294 | IntegerType *Type::getInt1Ty(LLVMContext &C) { return &C.pImpl->Int1Ty; } |
295 | IntegerType *Type::getInt8Ty(LLVMContext &C) { return &C.pImpl->Int8Ty; } |
296 | IntegerType *Type::getInt16Ty(LLVMContext &C) { return &C.pImpl->Int16Ty; } |
297 | IntegerType *Type::getInt32Ty(LLVMContext &C) { return &C.pImpl->Int32Ty; } |
298 | IntegerType *Type::getInt64Ty(LLVMContext &C) { return &C.pImpl->Int64Ty; } |
299 | IntegerType *Type::getInt128Ty(LLVMContext &C) { return &C.pImpl->Int128Ty; } |
300 | |
301 | IntegerType *Type::getIntNTy(LLVMContext &C, unsigned N) { |
302 | return IntegerType::get(C, NumBits: N); |
303 | } |
304 | |
305 | Type *Type::getWasm_ExternrefTy(LLVMContext &C) { |
306 | // opaque pointer in addrspace(10) |
307 | static PointerType *Ty = PointerType::get(C, AddressSpace: 10); |
308 | return Ty; |
309 | } |
310 | |
311 | Type *Type::getWasm_FuncrefTy(LLVMContext &C) { |
312 | // opaque pointer in addrspace(20) |
313 | static PointerType *Ty = PointerType::get(C, AddressSpace: 20); |
314 | return Ty; |
315 | } |
316 | |
317 | //===----------------------------------------------------------------------===// |
318 | // IntegerType Implementation |
319 | //===----------------------------------------------------------------------===// |
320 | |
321 | IntegerType *IntegerType::get(LLVMContext &C, unsigned NumBits) { |
322 | assert(NumBits >= MIN_INT_BITS && "bitwidth too small" ); |
323 | assert(NumBits <= MAX_INT_BITS && "bitwidth too large" ); |
324 | |
325 | // Check for the built-in integer types |
326 | switch (NumBits) { |
327 | case 1: return cast<IntegerType>(Val: Type::getInt1Ty(C)); |
328 | case 8: return cast<IntegerType>(Val: Type::getInt8Ty(C)); |
329 | case 16: return cast<IntegerType>(Val: Type::getInt16Ty(C)); |
330 | case 32: return cast<IntegerType>(Val: Type::getInt32Ty(C)); |
331 | case 64: return cast<IntegerType>(Val: Type::getInt64Ty(C)); |
332 | case 128: return cast<IntegerType>(Val: Type::getInt128Ty(C)); |
333 | default: |
334 | break; |
335 | } |
336 | |
337 | IntegerType *&Entry = C.pImpl->IntegerTypes[NumBits]; |
338 | |
339 | if (!Entry) |
340 | Entry = new (C.pImpl->Alloc) IntegerType(C, NumBits); |
341 | |
342 | return Entry; |
343 | } |
344 | |
345 | APInt IntegerType::getMask() const { return APInt::getAllOnes(numBits: getBitWidth()); } |
346 | |
347 | //===----------------------------------------------------------------------===// |
348 | // FunctionType Implementation |
349 | //===----------------------------------------------------------------------===// |
350 | |
351 | FunctionType::FunctionType(Type *Result, ArrayRef<Type*> Params, |
352 | bool IsVarArgs) |
353 | : Type(Result->getContext(), FunctionTyID) { |
354 | Type **SubTys = reinterpret_cast<Type**>(this+1); |
355 | assert(isValidReturnType(Result) && "invalid return type for function" ); |
356 | setSubclassData(IsVarArgs); |
357 | |
358 | SubTys[0] = Result; |
359 | |
360 | for (unsigned i = 0, e = Params.size(); i != e; ++i) { |
361 | assert(isValidArgumentType(Params[i]) && |
362 | "Not a valid type for function argument!" ); |
363 | SubTys[i+1] = Params[i]; |
364 | } |
365 | |
366 | ContainedTys = SubTys; |
367 | NumContainedTys = Params.size() + 1; // + 1 for result type |
368 | } |
369 | |
370 | // This is the factory function for the FunctionType class. |
371 | FunctionType *FunctionType::get(Type *ReturnType, |
372 | ArrayRef<Type*> Params, bool isVarArg) { |
373 | LLVMContextImpl *pImpl = ReturnType->getContext().pImpl; |
374 | const FunctionTypeKeyInfo::KeyTy Key(ReturnType, Params, isVarArg); |
375 | FunctionType *FT; |
376 | // Since we only want to allocate a fresh function type in case none is found |
377 | // and we don't want to perform two lookups (one for checking if existent and |
378 | // one for inserting the newly allocated one), here we instead lookup based on |
379 | // Key and update the reference to the function type in-place to a newly |
380 | // allocated one if not found. |
381 | auto Insertion = pImpl->FunctionTypes.insert_as(V: nullptr, LookupKey: Key); |
382 | if (Insertion.second) { |
383 | // The function type was not found. Allocate one and update FunctionTypes |
384 | // in-place. |
385 | FT = (FunctionType *)pImpl->Alloc.Allocate( |
386 | Size: sizeof(FunctionType) + sizeof(Type *) * (Params.size() + 1), |
387 | Alignment: alignof(FunctionType)); |
388 | new (FT) FunctionType(ReturnType, Params, isVarArg); |
389 | *Insertion.first = FT; |
390 | } else { |
391 | // The function type was found. Just return it. |
392 | FT = *Insertion.first; |
393 | } |
394 | return FT; |
395 | } |
396 | |
397 | FunctionType *FunctionType::get(Type *Result, bool isVarArg) { |
398 | return get(ReturnType: Result, Params: {}, isVarArg); |
399 | } |
400 | |
401 | bool FunctionType::isValidReturnType(Type *RetTy) { |
402 | return !RetTy->isFunctionTy() && !RetTy->isLabelTy() && |
403 | !RetTy->isMetadataTy(); |
404 | } |
405 | |
406 | bool FunctionType::isValidArgumentType(Type *ArgTy) { |
407 | return ArgTy->isFirstClassType() && !ArgTy->isLabelTy(); |
408 | } |
409 | |
410 | //===----------------------------------------------------------------------===// |
411 | // StructType Implementation |
412 | //===----------------------------------------------------------------------===// |
413 | |
414 | // Primitive Constructors. |
415 | |
416 | StructType *StructType::get(LLVMContext &Context, ArrayRef<Type*> ETypes, |
417 | bool isPacked) { |
418 | LLVMContextImpl *pImpl = Context.pImpl; |
419 | const AnonStructTypeKeyInfo::KeyTy Key(ETypes, isPacked); |
420 | |
421 | StructType *ST; |
422 | // Since we only want to allocate a fresh struct type in case none is found |
423 | // and we don't want to perform two lookups (one for checking if existent and |
424 | // one for inserting the newly allocated one), here we instead lookup based on |
425 | // Key and update the reference to the struct type in-place to a newly |
426 | // allocated one if not found. |
427 | auto Insertion = pImpl->AnonStructTypes.insert_as(V: nullptr, LookupKey: Key); |
428 | if (Insertion.second) { |
429 | // The struct type was not found. Allocate one and update AnonStructTypes |
430 | // in-place. |
431 | ST = new (Context.pImpl->Alloc) StructType(Context); |
432 | ST->setSubclassData(SCDB_IsLiteral); // Literal struct. |
433 | ST->setBody(Elements: ETypes, isPacked); |
434 | *Insertion.first = ST; |
435 | } else { |
436 | // The struct type was found. Just return it. |
437 | ST = *Insertion.first; |
438 | } |
439 | |
440 | return ST; |
441 | } |
442 | |
443 | bool StructType::isScalableTy(SmallPtrSetImpl<const Type *> &Visited) const { |
444 | if ((getSubclassData() & SCDB_ContainsScalableVector) != 0) |
445 | return true; |
446 | |
447 | if ((getSubclassData() & SCDB_NotContainsScalableVector) != 0) |
448 | return false; |
449 | |
450 | if (!Visited.insert(Ptr: this).second) |
451 | return false; |
452 | |
453 | for (Type *Ty : elements()) { |
454 | if (Ty->isScalableTy(Visited)) { |
455 | const_cast<StructType *>(this)->setSubclassData( |
456 | getSubclassData() | SCDB_ContainsScalableVector); |
457 | return true; |
458 | } |
459 | } |
460 | |
461 | // For structures that are opaque, return false but do not set the |
462 | // SCDB_NotContainsScalableVector flag since it may gain scalable vector type |
463 | // when it becomes non-opaque. |
464 | if (!isOpaque()) |
465 | const_cast<StructType *>(this)->setSubclassData( |
466 | getSubclassData() | SCDB_NotContainsScalableVector); |
467 | return false; |
468 | } |
469 | |
470 | bool StructType::containsNonGlobalTargetExtType( |
471 | SmallPtrSetImpl<const Type *> &Visited) const { |
472 | if ((getSubclassData() & SCDB_ContainsNonGlobalTargetExtType) != 0) |
473 | return true; |
474 | |
475 | if ((getSubclassData() & SCDB_NotContainsNonGlobalTargetExtType) != 0) |
476 | return false; |
477 | |
478 | if (!Visited.insert(Ptr: this).second) |
479 | return false; |
480 | |
481 | for (Type *Ty : elements()) { |
482 | if (Ty->containsNonGlobalTargetExtType(Visited)) { |
483 | const_cast<StructType *>(this)->setSubclassData( |
484 | getSubclassData() | SCDB_ContainsNonGlobalTargetExtType); |
485 | return true; |
486 | } |
487 | } |
488 | |
489 | // For structures that are opaque, return false but do not set the |
490 | // SCDB_NotContainsNonGlobalTargetExtType flag since it may gain non-global |
491 | // target extension types when it becomes non-opaque. |
492 | if (!isOpaque()) |
493 | const_cast<StructType *>(this)->setSubclassData( |
494 | getSubclassData() | SCDB_NotContainsNonGlobalTargetExtType); |
495 | return false; |
496 | } |
497 | |
498 | bool StructType::containsNonLocalTargetExtType( |
499 | SmallPtrSetImpl<const Type *> &Visited) const { |
500 | if ((getSubclassData() & SCDB_ContainsNonLocalTargetExtType) != 0) |
501 | return true; |
502 | |
503 | if ((getSubclassData() & SCDB_NotContainsNonLocalTargetExtType) != 0) |
504 | return false; |
505 | |
506 | if (!Visited.insert(Ptr: this).second) |
507 | return false; |
508 | |
509 | for (Type *Ty : elements()) { |
510 | if (Ty->containsNonLocalTargetExtType(Visited)) { |
511 | const_cast<StructType *>(this)->setSubclassData( |
512 | getSubclassData() | SCDB_ContainsNonLocalTargetExtType); |
513 | return true; |
514 | } |
515 | } |
516 | |
517 | // For structures that are opaque, return false but do not set the |
518 | // SCDB_NotContainsNonLocalTargetExtType flag since it may gain non-local |
519 | // target extension types when it becomes non-opaque. |
520 | if (!isOpaque()) |
521 | const_cast<StructType *>(this)->setSubclassData( |
522 | getSubclassData() | SCDB_NotContainsNonLocalTargetExtType); |
523 | return false; |
524 | } |
525 | |
526 | bool StructType::containsHomogeneousScalableVectorTypes() const { |
527 | if (getNumElements() <= 0 || !isa<ScalableVectorType>(Val: elements().front())) |
528 | return false; |
529 | return containsHomogeneousTypes(); |
530 | } |
531 | |
532 | bool StructType::containsHomogeneousTypes() const { |
533 | ArrayRef<Type *> ElementTys = elements(); |
534 | return !ElementTys.empty() && all_equal(Range&: ElementTys); |
535 | } |
536 | |
537 | void StructType::setBody(ArrayRef<Type*> Elements, bool isPacked) { |
538 | cantFail(Err: setBodyOrError(Elements, isPacked)); |
539 | } |
540 | |
541 | Error StructType::setBodyOrError(ArrayRef<Type *> Elements, bool isPacked) { |
542 | assert(isOpaque() && "Struct body already set!" ); |
543 | |
544 | if (auto E = checkBody(Elements)) |
545 | return E; |
546 | |
547 | setSubclassData(getSubclassData() | SCDB_HasBody); |
548 | if (isPacked) |
549 | setSubclassData(getSubclassData() | SCDB_Packed); |
550 | |
551 | NumContainedTys = Elements.size(); |
552 | ContainedTys = Elements.empty() |
553 | ? nullptr |
554 | : Elements.copy(A&: getContext().pImpl->Alloc).data(); |
555 | |
556 | return Error::success(); |
557 | } |
558 | |
559 | Error StructType::checkBody(ArrayRef<Type *> Elements) { |
560 | SmallSetVector<Type *, 4> Worklist(Elements.begin(), Elements.end()); |
561 | for (unsigned I = 0; I < Worklist.size(); ++I) { |
562 | Type *Ty = Worklist[I]; |
563 | if (Ty == this) |
564 | return createStringError(S: Twine("identified structure type '" ) + |
565 | getName() + "' is recursive" ); |
566 | Worklist.insert_range(R: Ty->subtypes()); |
567 | } |
568 | return Error::success(); |
569 | } |
570 | |
571 | void StructType::setName(StringRef Name) { |
572 | if (Name == getName()) return; |
573 | |
574 | StringMap<StructType *> &SymbolTable = getContext().pImpl->NamedStructTypes; |
575 | |
576 | using EntryTy = StringMap<StructType *>::MapEntryTy; |
577 | |
578 | // If this struct already had a name, remove its symbol table entry. Don't |
579 | // delete the data yet because it may be part of the new name. |
580 | if (SymbolTableEntry) |
581 | SymbolTable.remove(KeyValue: (EntryTy *)SymbolTableEntry); |
582 | |
583 | // If this is just removing the name, we're done. |
584 | if (Name.empty()) { |
585 | if (SymbolTableEntry) { |
586 | // Delete the old string data. |
587 | ((EntryTy *)SymbolTableEntry)->Destroy(allocator&: SymbolTable.getAllocator()); |
588 | SymbolTableEntry = nullptr; |
589 | } |
590 | return; |
591 | } |
592 | |
593 | // Look up the entry for the name. |
594 | auto IterBool = |
595 | getContext().pImpl->NamedStructTypes.insert(KV: std::make_pair(x&: Name, y: this)); |
596 | |
597 | // While we have a name collision, try a random rename. |
598 | if (!IterBool.second) { |
599 | SmallString<64> TempStr(Name); |
600 | TempStr.push_back(Elt: '.'); |
601 | raw_svector_ostream TmpStream(TempStr); |
602 | unsigned NameSize = Name.size(); |
603 | |
604 | do { |
605 | TempStr.resize(N: NameSize + 1); |
606 | TmpStream << getContext().pImpl->NamedStructTypesUniqueID++; |
607 | |
608 | IterBool = getContext().pImpl->NamedStructTypes.insert( |
609 | KV: std::make_pair(x: TmpStream.str(), y: this)); |
610 | } while (!IterBool.second); |
611 | } |
612 | |
613 | // Delete the old string data. |
614 | if (SymbolTableEntry) |
615 | ((EntryTy *)SymbolTableEntry)->Destroy(allocator&: SymbolTable.getAllocator()); |
616 | SymbolTableEntry = &*IterBool.first; |
617 | } |
618 | |
619 | //===----------------------------------------------------------------------===// |
620 | // StructType Helper functions. |
621 | |
622 | StructType *StructType::create(LLVMContext &Context, StringRef Name) { |
623 | StructType *ST = new (Context.pImpl->Alloc) StructType(Context); |
624 | if (!Name.empty()) |
625 | ST->setName(Name); |
626 | return ST; |
627 | } |
628 | |
629 | StructType *StructType::get(LLVMContext &Context, bool isPacked) { |
630 | return get(Context, ETypes: {}, isPacked); |
631 | } |
632 | |
633 | StructType *StructType::create(LLVMContext &Context, ArrayRef<Type*> Elements, |
634 | StringRef Name, bool isPacked) { |
635 | StructType *ST = create(Context, Name); |
636 | ST->setBody(Elements, isPacked); |
637 | return ST; |
638 | } |
639 | |
640 | StructType *StructType::create(LLVMContext &Context, ArrayRef<Type*> Elements) { |
641 | return create(Context, Elements, Name: StringRef()); |
642 | } |
643 | |
644 | StructType *StructType::create(LLVMContext &Context) { |
645 | return create(Context, Name: StringRef()); |
646 | } |
647 | |
648 | StructType *StructType::create(ArrayRef<Type*> Elements, StringRef Name, |
649 | bool isPacked) { |
650 | assert(!Elements.empty() && |
651 | "This method may not be invoked with an empty list" ); |
652 | return create(Context&: Elements[0]->getContext(), Elements, Name, isPacked); |
653 | } |
654 | |
655 | StructType *StructType::create(ArrayRef<Type*> Elements) { |
656 | assert(!Elements.empty() && |
657 | "This method may not be invoked with an empty list" ); |
658 | return create(Context&: Elements[0]->getContext(), Elements, Name: StringRef()); |
659 | } |
660 | |
661 | bool StructType::isSized(SmallPtrSetImpl<Type*> *Visited) const { |
662 | if ((getSubclassData() & SCDB_IsSized) != 0) |
663 | return true; |
664 | if (isOpaque()) |
665 | return false; |
666 | |
667 | if (Visited && !Visited->insert(Ptr: const_cast<StructType*>(this)).second) |
668 | return false; |
669 | |
670 | // Okay, our struct is sized if all of the elements are, but if one of the |
671 | // elements is opaque, the struct isn't sized *yet*, but may become sized in |
672 | // the future, so just bail out without caching. |
673 | // The ONLY special case inside a struct that is considered sized is when the |
674 | // elements are homogeneous of a scalable vector type. |
675 | if (containsHomogeneousScalableVectorTypes()) { |
676 | const_cast<StructType *>(this)->setSubclassData(getSubclassData() | |
677 | SCDB_IsSized); |
678 | return true; |
679 | } |
680 | for (Type *Ty : elements()) { |
681 | // If the struct contains a scalable vector type, don't consider it sized. |
682 | // This prevents it from being used in loads/stores/allocas/GEPs. The ONLY |
683 | // special case right now is a structure of homogenous scalable vector |
684 | // types and is handled by the if-statement before this for-loop. |
685 | if (Ty->isScalableTy()) |
686 | return false; |
687 | if (!Ty->isSized(Visited)) |
688 | return false; |
689 | } |
690 | |
691 | // Here we cheat a bit and cast away const-ness. The goal is to memoize when |
692 | // we find a sized type, as types can only move from opaque to sized, not the |
693 | // other way. |
694 | const_cast<StructType*>(this)->setSubclassData( |
695 | getSubclassData() | SCDB_IsSized); |
696 | return true; |
697 | } |
698 | |
699 | StringRef StructType::getName() const { |
700 | assert(!isLiteral() && "Literal structs never have names" ); |
701 | if (!SymbolTableEntry) return StringRef(); |
702 | |
703 | return ((StringMapEntry<StructType*> *)SymbolTableEntry)->getKey(); |
704 | } |
705 | |
706 | bool StructType::isValidElementType(Type *ElemTy) { |
707 | return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() && |
708 | !ElemTy->isMetadataTy() && !ElemTy->isFunctionTy() && |
709 | !ElemTy->isTokenTy(); |
710 | } |
711 | |
712 | bool StructType::isLayoutIdentical(StructType *Other) const { |
713 | if (this == Other) return true; |
714 | |
715 | if (isPacked() != Other->isPacked()) |
716 | return false; |
717 | |
718 | return elements() == Other->elements(); |
719 | } |
720 | |
721 | Type *StructType::getTypeAtIndex(const Value *V) const { |
722 | unsigned Idx = (unsigned)cast<Constant>(Val: V)->getUniqueInteger().getZExtValue(); |
723 | assert(indexValid(Idx) && "Invalid structure index!" ); |
724 | return getElementType(N: Idx); |
725 | } |
726 | |
727 | bool StructType::indexValid(const Value *V) const { |
728 | // Structure indexes require (vectors of) 32-bit integer constants. In the |
729 | // vector case all of the indices must be equal. |
730 | if (!V->getType()->isIntOrIntVectorTy(BitWidth: 32)) |
731 | return false; |
732 | if (isa<ScalableVectorType>(Val: V->getType())) |
733 | return false; |
734 | const Constant *C = dyn_cast<Constant>(Val: V); |
735 | if (C && V->getType()->isVectorTy()) |
736 | C = C->getSplatValue(); |
737 | const ConstantInt *CU = dyn_cast_or_null<ConstantInt>(Val: C); |
738 | return CU && CU->getZExtValue() < getNumElements(); |
739 | } |
740 | |
741 | StructType *StructType::getTypeByName(LLVMContext &C, StringRef Name) { |
742 | return C.pImpl->NamedStructTypes.lookup(Key: Name); |
743 | } |
744 | |
745 | //===----------------------------------------------------------------------===// |
746 | // ArrayType Implementation |
747 | //===----------------------------------------------------------------------===// |
748 | |
749 | ArrayType::ArrayType(Type *ElType, uint64_t NumEl) |
750 | : Type(ElType->getContext(), ArrayTyID), ContainedType(ElType), |
751 | NumElements(NumEl) { |
752 | ContainedTys = &ContainedType; |
753 | NumContainedTys = 1; |
754 | } |
755 | |
756 | ArrayType *ArrayType::get(Type *ElementType, uint64_t NumElements) { |
757 | assert(isValidElementType(ElementType) && "Invalid type for array element!" ); |
758 | |
759 | LLVMContextImpl *pImpl = ElementType->getContext().pImpl; |
760 | ArrayType *&Entry = |
761 | pImpl->ArrayTypes[std::make_pair(x&: ElementType, y&: NumElements)]; |
762 | |
763 | if (!Entry) |
764 | Entry = new (pImpl->Alloc) ArrayType(ElementType, NumElements); |
765 | return Entry; |
766 | } |
767 | |
768 | bool ArrayType::isValidElementType(Type *ElemTy) { |
769 | return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() && |
770 | !ElemTy->isMetadataTy() && !ElemTy->isFunctionTy() && |
771 | !ElemTy->isTokenTy() && !ElemTy->isX86_AMXTy(); |
772 | } |
773 | |
774 | //===----------------------------------------------------------------------===// |
775 | // VectorType Implementation |
776 | //===----------------------------------------------------------------------===// |
777 | |
778 | VectorType::VectorType(Type *ElType, unsigned EQ, Type::TypeID TID) |
779 | : Type(ElType->getContext(), TID), ContainedType(ElType), |
780 | ElementQuantity(EQ) { |
781 | ContainedTys = &ContainedType; |
782 | NumContainedTys = 1; |
783 | } |
784 | |
785 | VectorType *VectorType::get(Type *ElementType, ElementCount EC) { |
786 | if (EC.isScalable()) |
787 | return ScalableVectorType::get(ElementType, MinNumElts: EC.getKnownMinValue()); |
788 | else |
789 | return FixedVectorType::get(ElementType, NumElts: EC.getKnownMinValue()); |
790 | } |
791 | |
792 | bool VectorType::isValidElementType(Type *ElemTy) { |
793 | if (ElemTy->isIntegerTy() || ElemTy->isFloatingPointTy() || |
794 | ElemTy->isPointerTy() || ElemTy->getTypeID() == TypedPointerTyID) |
795 | return true; |
796 | if (auto *TTy = dyn_cast<TargetExtType>(Val: ElemTy)) |
797 | return TTy->hasProperty(Prop: TargetExtType::CanBeVectorElement); |
798 | return false; |
799 | } |
800 | |
801 | //===----------------------------------------------------------------------===// |
802 | // FixedVectorType Implementation |
803 | //===----------------------------------------------------------------------===// |
804 | |
805 | FixedVectorType *FixedVectorType::get(Type *ElementType, unsigned NumElts) { |
806 | assert(NumElts > 0 && "#Elements of a VectorType must be greater than 0" ); |
807 | assert(isValidElementType(ElementType) && "Element type of a VectorType must " |
808 | "be an integer, floating point, " |
809 | "pointer type, or a valid target " |
810 | "extension type." ); |
811 | |
812 | auto EC = ElementCount::getFixed(MinVal: NumElts); |
813 | |
814 | LLVMContextImpl *pImpl = ElementType->getContext().pImpl; |
815 | VectorType *&Entry = ElementType->getContext() |
816 | .pImpl->VectorTypes[std::make_pair(x&: ElementType, y&: EC)]; |
817 | |
818 | if (!Entry) |
819 | Entry = new (pImpl->Alloc) FixedVectorType(ElementType, NumElts); |
820 | return cast<FixedVectorType>(Val: Entry); |
821 | } |
822 | |
823 | //===----------------------------------------------------------------------===// |
824 | // ScalableVectorType Implementation |
825 | //===----------------------------------------------------------------------===// |
826 | |
827 | ScalableVectorType *ScalableVectorType::get(Type *ElementType, |
828 | unsigned MinNumElts) { |
829 | assert(MinNumElts > 0 && "#Elements of a VectorType must be greater than 0" ); |
830 | assert(isValidElementType(ElementType) && "Element type of a VectorType must " |
831 | "be an integer, floating point, or " |
832 | "pointer type." ); |
833 | |
834 | auto EC = ElementCount::getScalable(MinVal: MinNumElts); |
835 | |
836 | LLVMContextImpl *pImpl = ElementType->getContext().pImpl; |
837 | VectorType *&Entry = ElementType->getContext() |
838 | .pImpl->VectorTypes[std::make_pair(x&: ElementType, y&: EC)]; |
839 | |
840 | if (!Entry) |
841 | Entry = new (pImpl->Alloc) ScalableVectorType(ElementType, MinNumElts); |
842 | return cast<ScalableVectorType>(Val: Entry); |
843 | } |
844 | |
845 | //===----------------------------------------------------------------------===// |
846 | // PointerType Implementation |
847 | //===----------------------------------------------------------------------===// |
848 | |
849 | PointerType *PointerType::get(Type *EltTy, unsigned AddressSpace) { |
850 | assert(EltTy && "Can't get a pointer to <null> type!" ); |
851 | assert(isValidElementType(EltTy) && "Invalid type for pointer element!" ); |
852 | |
853 | // Automatically convert typed pointers to opaque pointers. |
854 | return get(C&: EltTy->getContext(), AddressSpace); |
855 | } |
856 | |
857 | PointerType *PointerType::get(LLVMContext &C, unsigned AddressSpace) { |
858 | LLVMContextImpl *CImpl = C.pImpl; |
859 | |
860 | // Since AddressSpace #0 is the common case, we special case it. |
861 | PointerType *&Entry = AddressSpace == 0 ? CImpl->AS0PointerType |
862 | : CImpl->PointerTypes[AddressSpace]; |
863 | |
864 | if (!Entry) |
865 | Entry = new (CImpl->Alloc) PointerType(C, AddressSpace); |
866 | return Entry; |
867 | } |
868 | |
869 | PointerType::PointerType(LLVMContext &C, unsigned AddrSpace) |
870 | : Type(C, PointerTyID) { |
871 | setSubclassData(AddrSpace); |
872 | } |
873 | |
874 | PointerType *Type::getPointerTo(unsigned AddrSpace) const { |
875 | return PointerType::get(C&: getContext(), AddressSpace: AddrSpace); |
876 | } |
877 | |
878 | bool PointerType::isValidElementType(Type *ElemTy) { |
879 | return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() && |
880 | !ElemTy->isMetadataTy() && !ElemTy->isTokenTy() && |
881 | !ElemTy->isX86_AMXTy(); |
882 | } |
883 | |
884 | bool PointerType::isLoadableOrStorableType(Type *ElemTy) { |
885 | return isValidElementType(ElemTy) && !ElemTy->isFunctionTy(); |
886 | } |
887 | |
888 | //===----------------------------------------------------------------------===// |
889 | // TargetExtType Implementation |
890 | //===----------------------------------------------------------------------===// |
891 | |
892 | TargetExtType::TargetExtType(LLVMContext &C, StringRef Name, |
893 | ArrayRef<Type *> Types, ArrayRef<unsigned> Ints) |
894 | : Type(C, TargetExtTyID), Name(C.pImpl->Saver.save(S: Name)) { |
895 | NumContainedTys = Types.size(); |
896 | |
897 | // Parameter storage immediately follows the class in allocation. |
898 | Type **Params = reinterpret_cast<Type **>(this + 1); |
899 | ContainedTys = Params; |
900 | for (Type *T : Types) |
901 | *Params++ = T; |
902 | |
903 | setSubclassData(Ints.size()); |
904 | unsigned *IntParamSpace = reinterpret_cast<unsigned *>(Params); |
905 | IntParams = IntParamSpace; |
906 | for (unsigned IntParam : Ints) |
907 | *IntParamSpace++ = IntParam; |
908 | } |
909 | |
910 | TargetExtType *TargetExtType::get(LLVMContext &C, StringRef Name, |
911 | ArrayRef<Type *> Types, |
912 | ArrayRef<unsigned> Ints) { |
913 | return cantFail(ValOrErr: getOrError(Context&: C, Name, Types, Ints)); |
914 | } |
915 | |
916 | Expected<TargetExtType *> TargetExtType::getOrError(LLVMContext &C, |
917 | StringRef Name, |
918 | ArrayRef<Type *> Types, |
919 | ArrayRef<unsigned> Ints) { |
920 | const TargetExtTypeKeyInfo::KeyTy Key(Name, Types, Ints); |
921 | TargetExtType *TT; |
922 | // Since we only want to allocate a fresh target type in case none is found |
923 | // and we don't want to perform two lookups (one for checking if existent and |
924 | // one for inserting the newly allocated one), here we instead lookup based on |
925 | // Key and update the reference to the target type in-place to a newly |
926 | // allocated one if not found. |
927 | auto [Iter, Inserted] = C.pImpl->TargetExtTypes.insert_as(V: nullptr, LookupKey: Key); |
928 | if (Inserted) { |
929 | // The target type was not found. Allocate one and update TargetExtTypes |
930 | // in-place. |
931 | TT = (TargetExtType *)C.pImpl->Alloc.Allocate( |
932 | Size: sizeof(TargetExtType) + sizeof(Type *) * Types.size() + |
933 | sizeof(unsigned) * Ints.size(), |
934 | Alignment: alignof(TargetExtType)); |
935 | new (TT) TargetExtType(C, Name, Types, Ints); |
936 | *Iter = TT; |
937 | return checkParams(TTy: TT); |
938 | } |
939 | |
940 | // The target type was found. Just return it. |
941 | return *Iter; |
942 | } |
943 | |
944 | Expected<TargetExtType *> TargetExtType::checkParams(TargetExtType *TTy) { |
945 | // Opaque types in the AArch64 name space. |
946 | if (TTy->Name == "aarch64.svcount" && |
947 | (TTy->getNumTypeParameters() != 0 || TTy->getNumIntParameters() != 0)) |
948 | return createStringError( |
949 | Fmt: "target extension type aarch64.svcount should have no parameters" ); |
950 | |
951 | // Opaque types in the RISC-V name space. |
952 | if (TTy->Name == "riscv.vector.tuple" && |
953 | (TTy->getNumTypeParameters() != 1 || TTy->getNumIntParameters() != 1)) |
954 | return createStringError( |
955 | Fmt: "target extension type riscv.vector.tuple should have one " |
956 | "type parameter and one integer parameter" ); |
957 | |
958 | // Opaque types in the AMDGPU name space. |
959 | if (TTy->Name == "amdgcn.named.barrier" && |
960 | (TTy->getNumTypeParameters() != 0 || TTy->getNumIntParameters() != 1)) { |
961 | return createStringError(Fmt: "target extension type amdgcn.named.barrier " |
962 | "should have no type parameters " |
963 | "and one integer parameter" ); |
964 | } |
965 | |
966 | return TTy; |
967 | } |
968 | |
969 | namespace { |
970 | struct TargetTypeInfo { |
971 | Type *LayoutType; |
972 | uint64_t Properties; |
973 | |
974 | template <typename... ArgTys> |
975 | TargetTypeInfo(Type *LayoutType, ArgTys... Properties) |
976 | : LayoutType(LayoutType), Properties((0 | ... | Properties)) { |
977 | assert((!(this->Properties & TargetExtType::CanBeVectorElement) || |
978 | LayoutType->isSized()) && |
979 | "Vector element type must be sized" ); |
980 | } |
981 | }; |
982 | } // anonymous namespace |
983 | |
984 | static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) { |
985 | LLVMContext &C = Ty->getContext(); |
986 | StringRef Name = Ty->getName(); |
987 | if (Name == "spirv.Image" || Name == "spirv.SignedImage" ) |
988 | return TargetTypeInfo(PointerType::get(C, AddressSpace: 0), TargetExtType::CanBeGlobal, |
989 | TargetExtType::CanBeLocal); |
990 | if (Name == "spirv.Type" ) { |
991 | assert(Ty->getNumIntParameters() == 3 && |
992 | "Wrong number of parameters for spirv.Type" ); |
993 | |
994 | auto Size = Ty->getIntParameter(i: 1); |
995 | auto Alignment = Ty->getIntParameter(i: 2); |
996 | |
997 | llvm::Type *LayoutType = nullptr; |
998 | if (Size > 0 && Alignment > 0) { |
999 | LayoutType = |
1000 | ArrayType::get(ElementType: Type::getIntNTy(C, N: Alignment), NumElements: Size * 8 / Alignment); |
1001 | } else { |
1002 | // LLVM expects variables that can be allocated to have an alignment and |
1003 | // size. Default to using a 32-bit int as the layout type if none are |
1004 | // present. |
1005 | LayoutType = Type::getInt32Ty(C); |
1006 | } |
1007 | |
1008 | return TargetTypeInfo(LayoutType, TargetExtType::CanBeGlobal, |
1009 | TargetExtType::CanBeLocal); |
1010 | } |
1011 | if (Name == "spirv.IntegralConstant" || Name == "spirv.Literal" ) |
1012 | return TargetTypeInfo(Type::getVoidTy(C)); |
1013 | if (Name.starts_with(Prefix: "spirv." )) |
1014 | return TargetTypeInfo(PointerType::get(C, AddressSpace: 0), TargetExtType::HasZeroInit, |
1015 | TargetExtType::CanBeGlobal, |
1016 | TargetExtType::CanBeLocal); |
1017 | |
1018 | // Opaque types in the AArch64 name space. |
1019 | if (Name == "aarch64.svcount" ) |
1020 | return TargetTypeInfo(ScalableVectorType::get(ElementType: Type::getInt1Ty(C), MinNumElts: 16), |
1021 | TargetExtType::HasZeroInit, |
1022 | TargetExtType::CanBeLocal); |
1023 | |
1024 | // RISC-V vector tuple type. The layout is represented as the type that needs |
1025 | // the same number of vector registers(VREGS) as this tuple type, represented |
1026 | // as <vscale x (RVVBitsPerBlock * VREGS / 8) x i8>. |
1027 | if (Name == "riscv.vector.tuple" ) { |
1028 | unsigned TotalNumElts = |
1029 | std::max(a: cast<ScalableVectorType>(Val: Ty->getTypeParameter(i: 0)) |
1030 | ->getMinNumElements(), |
1031 | b: RISCV::RVVBytesPerBlock) * |
1032 | Ty->getIntParameter(i: 0); |
1033 | return TargetTypeInfo( |
1034 | ScalableVectorType::get(ElementType: Type::getInt8Ty(C), MinNumElts: TotalNumElts), |
1035 | TargetExtType::CanBeLocal, TargetExtType::HasZeroInit); |
1036 | } |
1037 | |
1038 | // DirectX resources |
1039 | if (Name.starts_with(Prefix: "dx." )) |
1040 | return TargetTypeInfo(PointerType::get(C, AddressSpace: 0), TargetExtType::CanBeGlobal, |
1041 | TargetExtType::CanBeLocal); |
1042 | |
1043 | // Opaque types in the AMDGPU name space. |
1044 | if (Name == "amdgcn.named.barrier" ) { |
1045 | return TargetTypeInfo(FixedVectorType::get(ElementType: Type::getInt32Ty(C), NumElts: 4), |
1046 | TargetExtType::CanBeGlobal); |
1047 | } |
1048 | |
1049 | // Type used to test vector element target extension property. |
1050 | // Can be removed once a public target extension type uses CanBeVectorElement. |
1051 | if (Name == "llvm.test.vectorelement" ) { |
1052 | return TargetTypeInfo(Type::getInt32Ty(C), TargetExtType::CanBeLocal, |
1053 | TargetExtType::CanBeVectorElement); |
1054 | } |
1055 | |
1056 | return TargetTypeInfo(Type::getVoidTy(C)); |
1057 | } |
1058 | |
1059 | Type *TargetExtType::getLayoutType() const { |
1060 | return getTargetTypeInfo(Ty: this).LayoutType; |
1061 | } |
1062 | |
1063 | bool TargetExtType::hasProperty(Property Prop) const { |
1064 | uint64_t Properties = getTargetTypeInfo(Ty: this).Properties; |
1065 | return (Properties & Prop) == Prop; |
1066 | } |
1067 | |