7#include "mlir/IR/BuiltinTypes.h"
23 builder(cgm.
getBuilder()), theCXXABI(cgm.getCXXABI()),
24 theABIInfo(cgm.getTargetCIRGenInfo().
getABIInfo()) {}
27 for (
auto i = functionInfos.begin(), e = functionInfos.end(); i != e;)
32 return *builder.getContext();
52 return !
tagType->isIncompleteType();
64 if (
const auto *fpt = dyn_cast<FunctionProtoType>(ft))
65 for (
unsigned i = 0, e = fpt->getNumParams(); i != e; i++)
72mlir::Type CIRGenTypes::convertFunctionTypeInternal(
QualType qft) {
85 if (
const auto *fpt = dyn_cast<FunctionProtoType>(ft)) {
104 llvm::raw_svector_ostream outStream(typeName);
115 .
print(outStream, policy);
119 outStream << builder.getUniqueAnonRecordName();
124 return builder.getUniqueRecordName(std::string(typeName));
129 const auto it = recordDeclTypes.find(ty);
130 return it != recordDeclTypes.end() && it->second.isComplete();
137 llvm::SmallPtrSetImpl<const RecordDecl *> &alreadyChecked);
144 llvm::SmallPtrSetImpl<const RecordDecl *> &alreadyChecked) {
147 if (!alreadyChecked.insert(rd).second)
151 "Expect RecordDecl to be CompleteDefinition");
172 if (
const CXXRecordDecl *crd = dyn_cast<CXXRecordDecl>(rd)) {
175 ->castAs<RecordType>()
177 ->getDefinitionOrSelf(),
178 cgt, alreadyChecked))
200 llvm::SmallPtrSetImpl<const RecordDecl *> &alreadyChecked) {
203 qt = at->getValueType();
236 return astContext.getTypeSize(
type) !=
237 astContext.getTypeSize(
type->getValueType());
244 const Type *key = astContext.getCanonicalTagType(rd).getTypePtr();
252 entry = builder.getIncompleteRecordTy(name, rd);
253 recordDeclTypes[key] = entry;
262 deferredRecords.push_back(rd);
267 bool insertResult = recordsBeingLaidOut.insert(key).second;
269 assert(insertResult &&
"isSafeToCovert() should have caught this.");
272 safeToConvertCache.clear();
275 if (
const auto *
cxxRecordDecl = dyn_cast<CXXRecordDecl>(rd)) {
277 if (base.isVirtual())
285 recordDeclTypes[key] = entry;
286 cirGenRecordLayouts[key] = std::move(layout);
289 bool eraseResult = recordsBeingLaidOut.erase(key);
291 assert(eraseResult &&
"record not in RecordsBeingLaidOut set?");
294 safeToConvertCache.clear();
298 if (recordsBeingLaidOut.empty())
299 while (!deferredRecords.empty())
306 type = astContext.getCanonicalType(
type);
309 if (astContext.getLangOpts().CUDAIsDevice) {
310 if (
type->isCUDADeviceBuiltinSurfaceType()) {
312 cgm.getTargetCIRGenInfo().getCUDADeviceBuiltinSurfaceDeviceType())
314 }
else if (
type->isCUDADeviceBuiltinTextureType()) {
316 cgm.getTargetCIRGenInfo().getCUDADeviceBuiltinTextureDeviceType())
328 TypeCacheTy::iterator tci =
typeCache.find(ty);
335 mlir::Type resultType =
nullptr;
338 llvm_unreachable(
"Should have been handled above");
340 case Type::Builtin: {
343 case BuiltinType::Void:
344 resultType = cgm.voidTy;
348 case BuiltinType::Bool:
353 case BuiltinType::Char_S:
354 case BuiltinType::Int:
355 case BuiltinType::Int128:
356 case BuiltinType::Long:
357 case BuiltinType::LongLong:
358 case BuiltinType::SChar:
359 case BuiltinType::Short:
360 case BuiltinType::WChar_S:
361 case BuiltinType::Accum:
362 case BuiltinType::Fract:
363 case BuiltinType::LongAccum:
364 case BuiltinType::LongFract:
365 case BuiltinType::ShortAccum:
366 case BuiltinType::ShortFract:
368 case BuiltinType::SatAccum:
369 case BuiltinType::SatFract:
370 case BuiltinType::SatLongAccum:
371 case BuiltinType::SatLongFract:
372 case BuiltinType::SatShortAccum:
373 case BuiltinType::SatShortFract:
380 case BuiltinType::SveInt8:
382 cir::VectorType::get(builder.getSInt8Ty(), 16,
true);
384 case BuiltinType::SveUint8:
386 cir::VectorType::get(builder.getUInt8Ty(), 16,
true);
388 case BuiltinType::SveInt16:
390 cir::VectorType::get(builder.getSInt16Ty(), 8,
true);
392 case BuiltinType::SveUint16:
394 cir::VectorType::get(builder.getUInt16Ty(), 8,
true);
396 case BuiltinType::SveFloat16:
397 resultType = cir::VectorType::get(builder.getFp16Ty(), 8,
400 case BuiltinType::SveBFloat16:
401 resultType = cir::VectorType::get(builder.getFp16Ty(), 8,
404 case BuiltinType::SveInt32:
406 cir::VectorType::get(builder.getSInt32Ty(), 4,
true);
408 case BuiltinType::SveUint32:
410 cir::VectorType::get(builder.getUInt32Ty(), 4,
true);
412 case BuiltinType::SveFloat32:
413 resultType = cir::VectorType::get(builder.getSingleTy(), 4,
416 case BuiltinType::SveInt64:
418 cir::VectorType::get(builder.getSInt64Ty(), 2,
true);
420 case BuiltinType::SveUint64:
422 cir::VectorType::get(builder.getUInt64Ty(), 2,
true);
424 case BuiltinType::SveFloat64:
425 resultType = cir::VectorType::get(builder.getDoubleTy(), 2,
428 case BuiltinType::SveBool:
429 resultType = cir::VectorType::get(builder.getUIntNTy(1), 16,
434 case BuiltinType::Char8:
435 case BuiltinType::Char16:
436 case BuiltinType::Char32:
437 case BuiltinType::Char_U:
438 case BuiltinType::UChar:
439 case BuiltinType::UInt:
440 case BuiltinType::UInt128:
441 case BuiltinType::ULong:
442 case BuiltinType::ULongLong:
443 case BuiltinType::UShort:
444 case BuiltinType::WChar_U:
445 case BuiltinType::UAccum:
446 case BuiltinType::UFract:
447 case BuiltinType::ULongAccum:
448 case BuiltinType::ULongFract:
449 case BuiltinType::UShortAccum:
450 case BuiltinType::UShortFract:
452 case BuiltinType::SatUAccum:
453 case BuiltinType::SatUFract:
454 case BuiltinType::SatULongAccum:
455 case BuiltinType::SatULongFract:
456 case BuiltinType::SatUShortAccum:
457 case BuiltinType::SatUShortFract:
464 case BuiltinType::Float16:
465 resultType = cgm.fP16Ty;
467 case BuiltinType::Half:
468 resultType = cgm.fP16Ty;
470 case BuiltinType::BFloat16:
471 resultType = cgm.bFloat16Ty;
473 case BuiltinType::MFloat8:
474 resultType = cgm.uInt8Ty;
476 case BuiltinType::Float:
477 assert(&astContext.getFloatTypeSemantics(
type) ==
478 &llvm::APFloat::IEEEsingle() &&
479 "ClangIR NYI: 'float' in a format other than IEEE 32-bit");
480 resultType = cgm.floatTy;
482 case BuiltinType::Double:
483 assert(&astContext.getFloatTypeSemantics(
type) ==
484 &llvm::APFloat::IEEEdouble() &&
485 "ClangIR NYI: 'double' in a format other than IEEE 64-bit");
486 resultType = cgm.doubleTy;
488 case BuiltinType::LongDouble:
490 builder.getLongDoubleTy(astContext.getFloatTypeSemantics(
type));
492 case BuiltinType::Float128:
493 resultType = cgm.fP128Ty;
495 case BuiltinType::Ibm128:
497 resultType = cgm.sInt32Ty;
500 case BuiltinType::NullPtr:
505 resultType = builder.getVoidPtrTy();
508#define AMDGPU_OPAQUE_PTR_TYPE(Name, Id, SingletonId, Width, Align, AS) \
509 case BuiltinType::Id: { \
510 if (BuiltinType::Id == BuiltinType::AMDGPUTexture) { \
511 resultType = cir::VectorType::get(builder.getSInt32Ty(), 8); \
513 resultType = builder.getPointerTo( \
515 cir::TargetAddressSpaceAttr::get(&getMLIRContext(), AS)); \
519#define AMDGPU_NAMED_BARRIER_TYPE(Name, Id, SingletonId, Width, Align, Scope) \
520 case BuiltinType::Id: \
521 llvm_unreachable("NYI");
522#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) \
523 case BuiltinType::Id: \
524 llvm_unreachable("NYI");
525#include "clang/Basic/AMDGPUTypes.def"
529 resultType = cgm.sInt32Ty;
535 case Type::Complex: {
537 mlir::Type elementTy =
convertType(ct->getElementType());
538 resultType = cir::ComplexType::get(elementTy);
542 case Type::LValueReference:
543 case Type::RValueReference: {
547 resultType = builder.getPointerTo(pointeeType, elemTy.
getAddressSpace());
548 assert(resultType &&
"Cannot get pointer type?");
552 case Type::Pointer: {
559 resultType = builder.getPointerTo(pointeeType, elemTy.
getAddressSpace());
563 case Type::VariableArray: {
573 case Type::IncompleteArray: {
582 elemTy = cgm.sInt8Ty;
585 resultType = cir::ArrayType::get(elemTy, 0);
589 case Type::ConstantArray: {
597 resultType = cir::ArrayType::get(elemTy, arrTy->
getSize().getZExtValue());
601 case Type::ExtVector:
611 if (
auto integerType = ed->getIntegerType(); !integerType.isNull())
616 resultType = cgm.uInt32Ty;
620 case Type::MemberPointer: {
624 auto clsTy = mlir::cast<cir::RecordType>(
626 if (mpt->isMemberDataPointer()) {
627 mlir::Type memberTy =
convertType(mpt->getPointeeType());
628 resultType = cir::DataMemberType::get(memberTy, clsTy);
630 auto memberFuncTy =
getFunctionType(cgm.getTypes().arrangeCXXMethodType(
634 resultType = cir::MethodType::get(memberFuncTy, clsTy);
639 case Type::FunctionNoProto:
640 case Type::FunctionProto:
641 resultType = convertFunctionTypeInternal(
type);
646 unsigned numBits = bitIntTy->getNumBits();
647 assert(numBits <= cir::IntType::maxBitwidth() &&
648 "_BitInt width exceeds CIR IntType maximum");
650 cir::IntType::get(&
getMLIRContext(), numBits, bitIntTy->isSigned(),
660 uint64_t valueSize = astContext.getTypeSize(valueType);
661 uint64_t atomicSize = astContext.getTypeSize(ty);
662 if (valueSize != atomicSize) {
663 assert(valueSize < atomicSize);
665 cir::ArrayType::get(cgm.sInt8Ty, (atomicSize - valueSize) / 8);
666 mlir::Type elements[] = {resultType, paddingArray};
667 cir::RecordMemberKind kinds[] = {cir::RecordMemberKind::Data,
668 cir::RecordMemberKind::Pad};
671 false,
false, kinds);
679 type->getTypeClassName());
680 resultType = cgm.sInt32Ty;
684 assert(resultType &&
"Type conversion not yet implemented");
692 if (
qualType->isConstantMatrixType()) {
693 cgm.errorNYI(
"Matrix type conversion");
699 assert(!forBitField &&
"Bit fields NYI");
703 if (forBitField &&
qualType->isBitIntType())
704 assert(!
qualType->isBitIntType() &&
"Bit field with type _BitInt NYI");
706 return convertedType;
712 const auto *key = astContext.getCanonicalTagType(rd).getTypePtr();
715 auto it = cirGenRecordLayouts.find(key);
716 if (it != cirGenRecordLayouts.end())
723 it = cirGenRecordLayouts.find(key);
725 assert(it != cirGenRecordLayouts.end() &&
726 "Unable to find record layout information for type");
732 return astContext.getTargetNullPointerValue(t) == 0;
734 if (
const auto *at = astContext.getAsArrayType(t)) {
738 if (
const auto *cat = dyn_cast<ConstantArrayType>(at))
739 if (astContext.getConstantArrayElementCount(cat) == 0)
747 return theCXXABI.isZeroInitializable(mpt);
749 if (t->
getAs<HLSLInlineSpirvType>())
751 "isZeroInitializable for HLSLInlineSpirvType");
765 if (cgm.getTriple().isSPIROrSPIRV())
766 return cir::CallingConv::SpirFunction;
767 return cir::CallingConv::C;
769 return cgm.getTargetCIRGenInfo().getDeviceKernelCallingConv();
772 return cir::CallingConv::C;
780 assert(llvm::all_of(argTypes,
783 llvm::FoldingSetNodeID id;
787 llvm::FoldingSetInsertToken insertToken;
795 "Bad match based on CIRGenFunctionInfo folding set id");
804 functionInfos.insert(fi, insertToken);
813 for (
const VarDecl *arg : args)
814 argTypes.push_back(astContext.getCanonicalParamType(arg->getType()));
824 assert(!dyn_cast<ObjCMethodDecl>(gd.
getDecl()) &&
825 "This is reported as a FIXME in LLVM codegen");
841 if ([[maybe_unused]]
const auto *ed = dyn_cast<EnumDecl>(td)) {
849 ed->getASTContext().getCanonicalTagType(ed)->getTypePtr()) ||
851 typeCache[ed->getASTContext().getCanonicalTagType(ed)->getTypePtr()]));
861 if (rd->isDependentType())
866 if (recordDeclTypes.count(astContext.getCanonicalTagType(rd).getTypePtr()))
880 ? cgm.getDataLayout().getProgramAddressSpace()
Defines the clang::ASTContext interface.
static bool isSafeToConvert(QualType qt, CIRGenTypes &cgt, llvm::SmallPtrSetImpl< const RecordDecl * > &alreadyChecked)
Return true if it is safe to convert this field type, which requires the record elements contained by...
static Decl::Kind getKind(const Decl *D)
C Language Family Type Representation.
C++ view class that accepts both !cir.struct and !cir.union types.
const ArrayType * getAsArrayType(QualType T) const
Type Query functions.
CanQualType getCanonicalTagType(const TagDecl *TD) const
unsigned getTargetAddressSpace(LangAS AS) const
QualType getElementType() const
unsigned getIndexTypeCVRQualifiers() const
CanQualType getReturnType() const
const_arg_iterator argTypesEnd() const
static CIRGenFunctionInfo * create(cir::CallingConv cirCC, FunctionType::ExtInfo info, bool instanceMethod, CanQualType resultType, llvm::ArrayRef< CanQualType > argTypes, RequiredArgs required)
static void Profile(llvm::FoldingSetNodeID &id, bool instanceMethod, FunctionType::ExtInfo info, RequiredArgs required, CanQualType resultType, llvm::ArrayRef< CanQualType > argTypes)
const_arg_iterator argTypesBegin() const
This class organizes the cross-function state that is used while generating CIR code.
bool isPaddedAtomicType(QualType type)
This class handles record and union layout info while lowering AST types to CIR types.
bool isZeroInitializable() const
Check whether this struct can be C++ zero-initialized with a zeroinitializer.
This class organizes the cross-module state that is used while lowering AST types to CIR types.
cir::CallingConv clangCallConvToCIRCallConv(clang::CallingConv cc)
Convert a clang calling convention to a CIR calling convention.
const CIRGenFunctionInfo & arrangeGlobalDeclaration(GlobalDecl gd)
unsigned getTargetAddressSpace(QualType ty) const
const CIRGenFunctionInfo & arrangeCXXStructorDeclaration(clang::GlobalDecl gd)
const CIRGenFunctionInfo & arrangeCIRFunctionInfo(CanQualType returnType, bool isInstanceMethod, llvm::ArrayRef< CanQualType > argTypes, FunctionType::ExtInfo info, RequiredArgs required)
const CIRGenFunctionInfo & arrangeFreeFunctionType(CanQual< FunctionProtoType > fpt)
bool isZeroInitializable(clang::QualType ty)
Return whether a type can be zero-initialized (in the C++ sense) with an LLVM zeroinitializer.
bool isFuncTypeConvertible(const clang::FunctionType *ft)
Utility to check whether a function type can be converted to a CIR type (i.e.
CIRGenTypes(CIRGenModule &cgm)
bool isRecordBeingLaidOut(const clang::Type *ty) const
CIRGenBuilderTy & getBuilder() const
mlir::MLIRContext & getMLIRContext() const
bool isCachedSafeToConvert(const clang::Type *key) const
Check if a record type key is in the safe-to-convert cache.
cir::FuncType getFunctionType(const CIRGenFunctionInfo &info)
Get the CIR function type for.
bool isFuncParamTypeConvertible(clang::QualType type)
Return true if the specified type in a function parameter or result position can be converted to a CI...
void updateCompletedType(const clang::TagDecl *td)
UpdateCompletedType - when we find the full definition for a TagDecl, replace the 'opaque' type we pr...
std::string getRecordTypeName(const clang::RecordDecl *, llvm::StringRef suffix)
bool noRecordsBeingLaidOut() const
const ABIInfo & getABIInfo() const
const CIRGenFunctionInfo & arrangeFunctionDeclaration(const clang::FunctionDecl *fd)
Free functions are functions that are compatible with an ordinary C function pointer type.
clang::ASTContext & getASTContext() const
bool isRecordLayoutComplete(const clang::Type *ty) const
Return true if the specified type is already completely laid out.
const CIRGenFunctionInfo & arrangeDeviceKernelCallerDeclaration(clang::QualType resultType, const FunctionArgList &args)
Arrange the function info for a device kernel caller entry point (e.g.
mlir::Type convertType(clang::QualType type)
Convert a Clang type into a mlir::Type.
const CIRGenRecordLayout & getCIRGenRecordLayout(const clang::RecordDecl *rd)
Return record layout info for the given record decl.
std::unique_ptr< CIRGenRecordLayout > computeRecordLayout(const clang::RecordDecl *rd, cir::RecordType *ty)
mlir::Type convertRecordDeclType(const clang::RecordDecl *recordDecl)
Lay out a tagged decl type like struct or union.
void cacheSafeToConvert(const clang::Type *key)
Add a record type key to the safe-to-convert cache.
mlir::Type convertTypeForMem(clang::QualType, bool forBitField=false)
Convert type T into an mlir::Type.
Type for representing both the decl and type of parameters to a function.
A class for recording the number of arguments that a function signature requires.
Represents a base class of a C++ class.
Represents a C++ struct/union/class.
static CanQual< T > CreateUnsafe(QualType Other)
Builds a canonical type from a QualType.
bool isCanonicalAsParam() const
Determines if this canonical type is furthermore canonical as a parameter.
const T * getTypePtr() const
Retrieve the underlying type pointer, which refers to a canonical type.
Represents the canonical version of C arrays with a specified constant size.
llvm::APInt getSize() const
Return the constant array size as an APInt.
Represents a member of a struct/union/class.
Represents a K&R-style 'int foo()' function, which has no information available about its arguments.
Represents a prototype with parameter type info, e.g.
A class which abstracts out some details necessary for making a call.
FunctionType - C99 6.7.5.3 - Function Declarators.
QualType getReturnType() const
GlobalDecl - represents a global declaration.
const Decl * getDecl() const
Represents a C array with an unspecified size.
A pointer to member type per C++ 8.3.3 - Pointers to members.
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
CXXRecordDecl * getAsRecordDecl() const
Retrieve the record declaration stored in this nested name specifier, or null.
const Type * getAsType() const
PointerType - C99 6.7.5.1 - Pointer Declarators.
QualType getPointeeType() const
A (possibly-)qualified type.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
LangAS getAddressSpace() const
Return the address space of this type.
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
bool hasAddressSpace() const
Check if this type has any address space qualifier.
Represents a struct/union/class.
field_range fields() const
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
Base for LValueReferenceType and RValueReferenceType.
QualType getPointeeType() const
Encodes a location in the source.
Represents the declaration of a struct/union/class/enum.
bool isCompleteDefinition() const
Return true if this decl has its body fully specified.
The base class of the type hierarchy.
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
bool isConstantMatrixType() const
CanQualType getCanonicalTypeUnqualified() const
EnumDecl * castAsEnumDecl() const
bool isFunctionType() const
TypeClass getTypeClass() const
const T * getAs() const
Member-template getAs<specific type>'.
Represents a variable declaration or definition.
Represents a C array with a specified size that is not an integer-constant-expression.
Represents a GCC generic vector type.
unsigned getNumElements() const
QualType getElementType() const
Defines the clang::TargetInfo interface.
bool isSized(mlir::Type ty)
Returns true if the type is a CIR sized type.
@ Type
The l-value was considered opaque, so the alignment was determined from a type.
const internal::VariadicDynCastAllOfMatcher< Decl, TypedefNameDecl > typedefNameDecl
Matches typedef name declarations.
const AstTypeMatcher< TagType > tagType
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const AstTypeMatcher< RecordType > recordType
const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class declarations.
const internal::VariadicDynCastAllOfMatcher< Decl, RecordDecl > recordDecl
Matches class, struct, and union declarations.
const internal::VariadicAllOfMatcher< QualType > qualType
Matches QualTypes in the clang AST.
Top level wrappers for InstallAPI frontend operations.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
bool isInstanceMethod(const Decl *D)
CallingConv
CallingConv - Specifies the calling convention that a function uses.
U cast(CodeGen::Address addr)
static bool cudaTextureType()
static bool generateDebugInfo()
Describes how types, statements, expressions, and declarations should be printed.
unsigned SuppressTagKeyword
Whether type printing should skip printing the tag keyword.
unsigned AlwaysIncludeTypeForTemplateArgument
Whether to use type suffixes (eg: 1U) on integral non-type template parameters.
unsigned SuppressInlineNamespace
Suppress printing parts of scope specifiers that correspond to inline namespaces.
unsigned PrintAsCanonical
Whether to print entities as written or canonically.