| 1 | #include "CIRGenTypes.h" |
| 2 | |
| 3 | #include "CIRGenFunctionInfo.h" |
| 4 | #include "CIRGenModule.h" |
| 5 | |
| 6 | #include "clang/AST/ASTContext.h" |
| 7 | #include "clang/AST/GlobalDecl.h" |
| 8 | #include "clang/AST/Type.h" |
| 9 | #include "clang/Basic/TargetInfo.h" |
| 10 | |
| 11 | #include <cassert> |
| 12 | |
| 13 | using namespace clang; |
| 14 | using namespace clang::CIRGen; |
| 15 | |
| 16 | CIRGenTypes::CIRGenTypes(CIRGenModule &genModule) |
| 17 | : cgm(genModule), astContext(genModule.getASTContext()), |
| 18 | builder(cgm.getBuilder()), theCXXABI(cgm.getCXXABI()), |
| 19 | theABIInfo(cgm.getTargetCIRGenInfo().getABIInfo()) {} |
| 20 | |
| 21 | CIRGenTypes::~CIRGenTypes() { |
| 22 | for (auto i = functionInfos.begin(), e = functionInfos.end(); i != e;) |
| 23 | delete &*i++; |
| 24 | } |
| 25 | |
| 26 | mlir::MLIRContext &CIRGenTypes::getMLIRContext() const { |
| 27 | return *builder.getContext(); |
| 28 | } |
| 29 | |
| 30 | /// Return true if the specified type in a function parameter or result position |
| 31 | /// can be converted to a CIR type at this point. This boils down to being |
| 32 | /// whether it is complete, as well as whether we've temporarily deferred |
| 33 | /// expanding the type because we're in a recursive context. |
| 34 | bool CIRGenTypes::isFuncParamTypeConvertible(clang::QualType type) { |
| 35 | // Some ABIs cannot have their member pointers represented in LLVM IR unless |
| 36 | // certain circumstances have been reached. |
| 37 | assert(!type->getAs<MemberPointerType>() && "NYI" ); |
| 38 | |
| 39 | // If this isn't a tag type, we can convert it. |
| 40 | const TagType *tagType = type->getAs<TagType>(); |
| 41 | if (!tagType) |
| 42 | return true; |
| 43 | |
| 44 | // Function types involving incomplete class types are problematic in MLIR. |
| 45 | return !tagType->isIncompleteType(); |
| 46 | } |
| 47 | |
| 48 | /// Code to verify a given function type is complete, i.e. the return type and |
| 49 | /// all of the parameter types are complete. Also check to see if we are in a |
| 50 | /// RS_StructPointer context, and if so whether any struct types have been |
| 51 | /// pended. If so, we don't want to ask the ABI lowering code to handle a type |
| 52 | /// that cannot be converted to a CIR type. |
| 53 | bool CIRGenTypes::isFuncTypeConvertible(const FunctionType *ft) { |
| 54 | if (!isFuncParamTypeConvertible(type: ft->getReturnType())) |
| 55 | return false; |
| 56 | |
| 57 | if (const auto *fpt = dyn_cast<FunctionProtoType>(Val: ft)) |
| 58 | for (unsigned i = 0, e = fpt->getNumParams(); i != e; i++) |
| 59 | if (!isFuncParamTypeConvertible(type: fpt->getParamType(i))) |
| 60 | return false; |
| 61 | |
| 62 | return true; |
| 63 | } |
| 64 | |
| 65 | mlir::Type CIRGenTypes::convertFunctionTypeInternal(QualType qft) { |
| 66 | assert(qft.isCanonical()); |
| 67 | const FunctionType *ft = cast<FunctionType>(Val: qft.getTypePtr()); |
| 68 | // First, check whether we can build the full function type. If the function |
| 69 | // type depends on an incomplete type (e.g. a struct or enum), we cannot lower |
| 70 | // the function type. |
| 71 | if (!isFuncTypeConvertible(ft)) { |
| 72 | cgm.errorNYI(loc: SourceLocation(), feature: "function type involving an incomplete type" , |
| 73 | name: qft); |
| 74 | return cir::FuncType::get(SmallVector<mlir::Type, 1>{}, cgm.VoidTy); |
| 75 | } |
| 76 | |
| 77 | const CIRGenFunctionInfo *fi; |
| 78 | if (const auto *fpt = dyn_cast<FunctionProtoType>(Val: ft)) { |
| 79 | fi = &arrangeFreeFunctionType( |
| 80 | fpt: CanQual<FunctionProtoType>::CreateUnsafe(Other: QualType(fpt, 0))); |
| 81 | } else { |
| 82 | const FunctionNoProtoType *fnpt = cast<FunctionNoProtoType>(Val: ft); |
| 83 | fi = &arrangeFreeFunctionType( |
| 84 | fnpt: CanQual<FunctionNoProtoType>::CreateUnsafe(Other: QualType(fnpt, 0))); |
| 85 | } |
| 86 | |
| 87 | mlir::Type resultType = getFunctionType(*fi); |
| 88 | |
| 89 | return resultType; |
| 90 | } |
| 91 | |
| 92 | // This is CIR's version of CodeGenTypes::addRecordTypeName. It isn't shareable |
| 93 | // because CIR has different uniquing requirements. |
| 94 | std::string CIRGenTypes::getRecordTypeName(const clang::RecordDecl *recordDecl, |
| 95 | StringRef suffix) { |
| 96 | llvm::SmallString<256> typeName; |
| 97 | llvm::raw_svector_ostream outStream(typeName); |
| 98 | |
| 99 | PrintingPolicy policy = recordDecl->getASTContext().getPrintingPolicy(); |
| 100 | policy.SuppressInlineNamespace = false; |
| 101 | policy.AlwaysIncludeTypeForTemplateArgument = true; |
| 102 | policy.PrintAsCanonical = true; |
| 103 | policy.SuppressTagKeyword = true; |
| 104 | |
| 105 | if (recordDecl->getIdentifier()) |
| 106 | astContext.getRecordType(Decl: recordDecl).print(OS&: outStream, Policy: policy); |
| 107 | else if (auto *typedefNameDecl = recordDecl->getTypedefNameForAnonDecl()) |
| 108 | typedefNameDecl->printQualifiedName(outStream, policy); |
| 109 | else |
| 110 | outStream << builder.getUniqueAnonRecordName(); |
| 111 | |
| 112 | if (!suffix.empty()) |
| 113 | outStream << suffix; |
| 114 | |
| 115 | return builder.getUniqueRecordName(baseName: std::string(typeName)); |
| 116 | } |
| 117 | |
| 118 | /// Return true if the specified type is already completely laid out. |
| 119 | bool CIRGenTypes::isRecordLayoutComplete(const Type *ty) const { |
| 120 | const auto it = recordDeclTypes.find(ty); |
| 121 | return it != recordDeclTypes.end() && it->second.isComplete(); |
| 122 | } |
| 123 | |
| 124 | // We have multiple forms of this function that call each other, so we need to |
| 125 | // declare one in advance. |
| 126 | static bool |
| 127 | isSafeToConvert(QualType qt, CIRGenTypes &cgt, |
| 128 | llvm::SmallPtrSetImpl<const RecordDecl *> &alreadyChecked); |
| 129 | |
| 130 | /// Return true if it is safe to convert the specified record decl to CIR and |
| 131 | /// lay it out, false if doing so would cause us to get into a recursive |
| 132 | /// compilation mess. |
| 133 | static bool |
| 134 | isSafeToConvert(const RecordDecl *rd, CIRGenTypes &cgt, |
| 135 | llvm::SmallPtrSetImpl<const RecordDecl *> &alreadyChecked) { |
| 136 | // If we have already checked this type (maybe the same type is used by-value |
| 137 | // multiple times in multiple record fields, don't check again. |
| 138 | if (!alreadyChecked.insert(Ptr: rd).second) |
| 139 | return true; |
| 140 | |
| 141 | const Type *key = cgt.getASTContext().getTagDeclType(rd).getTypePtr(); |
| 142 | |
| 143 | // If this type is already laid out, converting it is a noop. |
| 144 | if (cgt.isRecordLayoutComplete(ty: key)) |
| 145 | return true; |
| 146 | |
| 147 | // If this type is currently being laid out, we can't recursively compile it. |
| 148 | if (cgt.isRecordBeingLaidOut(ty: key)) |
| 149 | return false; |
| 150 | |
| 151 | // If this type would require laying out bases that are currently being laid |
| 152 | // out, don't do it. This includes virtual base classes which get laid out |
| 153 | // when a class is translated, even though they aren't embedded by-value into |
| 154 | // the class. |
| 155 | if (auto *crd = dyn_cast<CXXRecordDecl>(Val: rd)) { |
| 156 | if (crd->getNumBases() > 0) { |
| 157 | assert(!cir::MissingFeatures::cxxSupport()); |
| 158 | cgt.getCGModule().errorNYI(rd->getSourceRange(), |
| 159 | "isSafeToConvert: CXXRecordDecl with bases" ); |
| 160 | return false; |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | // If this type would require laying out members that are currently being laid |
| 165 | // out, don't do it. |
| 166 | for (const FieldDecl *field : rd->fields()) |
| 167 | if (!isSafeToConvert(field->getType(), cgt, alreadyChecked)) |
| 168 | return false; |
| 169 | |
| 170 | // If there are no problems, lets do it. |
| 171 | return true; |
| 172 | } |
| 173 | |
| 174 | /// Return true if it is safe to convert this field type, which requires the |
| 175 | /// record elements contained by-value to all be recursively safe to convert. |
| 176 | static bool |
| 177 | isSafeToConvert(QualType qt, CIRGenTypes &cgt, |
| 178 | llvm::SmallPtrSetImpl<const RecordDecl *> &alreadyChecked) { |
| 179 | // Strip off atomic type sugar. |
| 180 | if (const auto *at = qt->getAs<AtomicType>()) |
| 181 | qt = at->getValueType(); |
| 182 | |
| 183 | // If this is a record, check it. |
| 184 | if (const auto *rt = qt->getAs<RecordType>()) |
| 185 | return isSafeToConvert(rd: rt->getDecl(), cgt, alreadyChecked); |
| 186 | |
| 187 | // If this is an array, check the elements, which are embedded inline. |
| 188 | if (const auto *at = cgt.getASTContext().getAsArrayType(T: qt)) |
| 189 | return isSafeToConvert(qt: at->getElementType(), cgt, alreadyChecked); |
| 190 | |
| 191 | // Otherwise, there is no concern about transforming this. We only care about |
| 192 | // things that are contained by-value in a record that can have another |
| 193 | // record as a member. |
| 194 | return true; |
| 195 | } |
| 196 | |
| 197 | // Return true if it is safe to convert the specified record decl to CIR and lay |
| 198 | // it out, false if doing so would cause us to get into a recursive compilation |
| 199 | // mess. |
| 200 | static bool isSafeToConvert(const RecordDecl *rd, CIRGenTypes &cgt) { |
| 201 | // If no records are being laid out, we can certainly do this one. |
| 202 | if (cgt.noRecordsBeingLaidOut()) |
| 203 | return true; |
| 204 | |
| 205 | llvm::SmallPtrSet<const RecordDecl *, 16> alreadyChecked; |
| 206 | return isSafeToConvert(rd, cgt, alreadyChecked); |
| 207 | } |
| 208 | |
| 209 | /// Lay out a tagged decl type like struct or union. |
| 210 | mlir::Type CIRGenTypes::convertRecordDeclType(const clang::RecordDecl *rd) { |
| 211 | // TagDecl's are not necessarily unique, instead use the (clang) type |
| 212 | // connected to the decl. |
| 213 | const Type *key = astContext.getTagDeclType(rd).getTypePtr(); |
| 214 | cir::RecordType entry = recordDeclTypes[key]; |
| 215 | |
| 216 | // If we don't have an entry for this record yet, create one. |
| 217 | // We create an incomplete type initially. If `rd` is complete, we will |
| 218 | // add the members below. |
| 219 | if (!entry) { |
| 220 | auto name = getRecordTypeName(recordDecl: rd, suffix: "" ); |
| 221 | entry = builder.getIncompleteRecordTy(name, rd); |
| 222 | recordDeclTypes[key] = entry; |
| 223 | } |
| 224 | |
| 225 | rd = rd->getDefinition(); |
| 226 | if (!rd || !rd->isCompleteDefinition() || entry.isComplete()) |
| 227 | return entry; |
| 228 | |
| 229 | // If converting this type would cause us to infinitely loop, don't do it! |
| 230 | if (!isSafeToConvert(rd, cgt&: *this)) { |
| 231 | deferredRecords.push_back(Elt: rd); |
| 232 | return entry; |
| 233 | } |
| 234 | |
| 235 | // Okay, this is a definition of a type. Compile the implementation now. |
| 236 | bool insertResult = recordsBeingLaidOut.insert(Ptr: key).second; |
| 237 | (void)insertResult; |
| 238 | assert(insertResult && "isSafeToCovert() should have caught this." ); |
| 239 | |
| 240 | // Force conversion of non-virtual base classes recursively. |
| 241 | if (const auto *cxxRecordDecl = dyn_cast<CXXRecordDecl>(Val: rd)) { |
| 242 | for (const auto &base : cxxRecordDecl->bases()) { |
| 243 | if (base.isVirtual()) |
| 244 | continue; |
| 245 | convertRecordDeclType(base.getType()->castAs<RecordType>()->getDecl()); |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | // Layout fields. |
| 250 | std::unique_ptr<CIRGenRecordLayout> layout = computeRecordLayout(rd, &entry); |
| 251 | recordDeclTypes[key] = entry; |
| 252 | cirGenRecordLayouts[key] = std::move(layout); |
| 253 | |
| 254 | // We're done laying out this record. |
| 255 | bool eraseResult = recordsBeingLaidOut.erase(Ptr: key); |
| 256 | (void)eraseResult; |
| 257 | assert(eraseResult && "record not in RecordsBeingLaidOut set?" ); |
| 258 | |
| 259 | // If this record blocked a FunctionType conversion, then recompute whatever |
| 260 | // was derived from that. |
| 261 | assert(!cir::MissingFeatures::skippedLayout()); |
| 262 | |
| 263 | // If we're done converting the outer-most record, then convert any deferred |
| 264 | // records as well. |
| 265 | if (recordsBeingLaidOut.empty()) |
| 266 | while (!deferredRecords.empty()) |
| 267 | convertRecordDeclType(deferredRecords.pop_back_val()); |
| 268 | |
| 269 | return entry; |
| 270 | } |
| 271 | |
| 272 | mlir::Type CIRGenTypes::convertType(QualType type) { |
| 273 | type = astContext.getCanonicalType(T: type); |
| 274 | const Type *ty = type.getTypePtr(); |
| 275 | |
| 276 | // Process record types before the type cache lookup. |
| 277 | if (const auto *recordType = dyn_cast<RecordType>(type)) |
| 278 | return convertRecordDeclType(recordType->getDecl()); |
| 279 | |
| 280 | // Has the type already been processed? |
| 281 | TypeCacheTy::iterator tci = typeCache.find(Val: ty); |
| 282 | if (tci != typeCache.end()) |
| 283 | return tci->second; |
| 284 | |
| 285 | // For types that haven't been implemented yet or are otherwise unsupported, |
| 286 | // report an error and return 'int'. |
| 287 | |
| 288 | mlir::Type resultType = nullptr; |
| 289 | switch (ty->getTypeClass()) { |
| 290 | case Type::Record: |
| 291 | llvm_unreachable("Should have been handled above" ); |
| 292 | |
| 293 | case Type::Builtin: { |
| 294 | switch (cast<BuiltinType>(Val: ty)->getKind()) { |
| 295 | // void |
| 296 | case BuiltinType::Void: |
| 297 | resultType = cgm.VoidTy; |
| 298 | break; |
| 299 | |
| 300 | // bool |
| 301 | case BuiltinType::Bool: |
| 302 | resultType = cir::BoolType::get(&getMLIRContext()); |
| 303 | break; |
| 304 | |
| 305 | // Signed integral types. |
| 306 | case BuiltinType::Char_S: |
| 307 | case BuiltinType::Int: |
| 308 | case BuiltinType::Int128: |
| 309 | case BuiltinType::Long: |
| 310 | case BuiltinType::LongLong: |
| 311 | case BuiltinType::SChar: |
| 312 | case BuiltinType::Short: |
| 313 | case BuiltinType::WChar_S: |
| 314 | resultType = |
| 315 | cir::IntType::get(&getMLIRContext(), astContext.getTypeSize(ty), |
| 316 | /*isSigned=*/true); |
| 317 | break; |
| 318 | // Unsigned integral types. |
| 319 | case BuiltinType::Char8: |
| 320 | case BuiltinType::Char16: |
| 321 | case BuiltinType::Char32: |
| 322 | case BuiltinType::Char_U: |
| 323 | case BuiltinType::UChar: |
| 324 | case BuiltinType::UInt: |
| 325 | case BuiltinType::UInt128: |
| 326 | case BuiltinType::ULong: |
| 327 | case BuiltinType::ULongLong: |
| 328 | case BuiltinType::UShort: |
| 329 | case BuiltinType::WChar_U: |
| 330 | resultType = |
| 331 | cir::IntType::get(&getMLIRContext(), astContext.getTypeSize(ty), |
| 332 | /*isSigned=*/false); |
| 333 | break; |
| 334 | |
| 335 | // Floating-point types |
| 336 | case BuiltinType::Float16: |
| 337 | resultType = cgm.FP16Ty; |
| 338 | break; |
| 339 | case BuiltinType::Half: |
| 340 | if (astContext.getLangOpts().NativeHalfType || |
| 341 | !astContext.getTargetInfo().useFP16ConversionIntrinsics()) { |
| 342 | resultType = cgm.FP16Ty; |
| 343 | } else { |
| 344 | cgm.errorNYI(loc: SourceLocation(), feature: "processing of built-in type" , name: type); |
| 345 | resultType = cgm.SInt32Ty; |
| 346 | } |
| 347 | break; |
| 348 | case BuiltinType::BFloat16: |
| 349 | resultType = cgm.BFloat16Ty; |
| 350 | break; |
| 351 | case BuiltinType::Float: |
| 352 | assert(&astContext.getFloatTypeSemantics(type) == |
| 353 | &llvm::APFloat::IEEEsingle() && |
| 354 | "ClangIR NYI: 'float' in a format other than IEEE 32-bit" ); |
| 355 | resultType = cgm.FloatTy; |
| 356 | break; |
| 357 | case BuiltinType::Double: |
| 358 | assert(&astContext.getFloatTypeSemantics(type) == |
| 359 | &llvm::APFloat::IEEEdouble() && |
| 360 | "ClangIR NYI: 'double' in a format other than IEEE 64-bit" ); |
| 361 | resultType = cgm.DoubleTy; |
| 362 | break; |
| 363 | case BuiltinType::LongDouble: |
| 364 | resultType = |
| 365 | builder.getLongDoubleTy(astContext.getFloatTypeSemantics(T: type)); |
| 366 | break; |
| 367 | case BuiltinType::Float128: |
| 368 | resultType = cgm.FP128Ty; |
| 369 | break; |
| 370 | case BuiltinType::Ibm128: |
| 371 | cgm.errorNYI(loc: SourceLocation(), feature: "processing of built-in type" , name: type); |
| 372 | resultType = cgm.SInt32Ty; |
| 373 | break; |
| 374 | |
| 375 | case BuiltinType::NullPtr: |
| 376 | // Add proper CIR type for it? this looks mostly useful for sema related |
| 377 | // things (like for overloads accepting void), for now, given that |
| 378 | // `sizeof(std::nullptr_t)` is equal to `sizeof(void *)`, model |
| 379 | // std::nullptr_t as !cir.ptr<!void> |
| 380 | resultType = builder.getVoidPtrTy(); |
| 381 | break; |
| 382 | |
| 383 | default: |
| 384 | cgm.errorNYI(loc: SourceLocation(), feature: "processing of built-in type" , name: type); |
| 385 | resultType = cgm.SInt32Ty; |
| 386 | break; |
| 387 | } |
| 388 | break; |
| 389 | } |
| 390 | |
| 391 | case Type::Complex: { |
| 392 | const auto *ct = cast<clang::ComplexType>(Val: ty); |
| 393 | mlir::Type elementTy = convertType(ct->getElementType()); |
| 394 | resultType = cir::ComplexType::get(elementTy); |
| 395 | break; |
| 396 | } |
| 397 | |
| 398 | case Type::LValueReference: |
| 399 | case Type::RValueReference: { |
| 400 | const ReferenceType *refTy = cast<ReferenceType>(Val: ty); |
| 401 | QualType elemTy = refTy->getPointeeType(); |
| 402 | auto pointeeType = convertTypeForMem(elemTy); |
| 403 | resultType = builder.getPointerTo(pointeeType); |
| 404 | assert(resultType && "Cannot get pointer type?" ); |
| 405 | break; |
| 406 | } |
| 407 | |
| 408 | case Type::Pointer: { |
| 409 | const PointerType *ptrTy = cast<PointerType>(Val: ty); |
| 410 | QualType elemTy = ptrTy->getPointeeType(); |
| 411 | assert(!elemTy->isConstantMatrixType() && "not implemented" ); |
| 412 | |
| 413 | mlir::Type pointeeType = convertType(elemTy); |
| 414 | |
| 415 | resultType = builder.getPointerTo(pointeeType); |
| 416 | break; |
| 417 | } |
| 418 | |
| 419 | case Type::ConstantArray: { |
| 420 | const ConstantArrayType *arrTy = cast<ConstantArrayType>(Val: ty); |
| 421 | mlir::Type elemTy = convertTypeForMem(arrTy->getElementType()); |
| 422 | resultType = cir::ArrayType::get(elemTy, arrTy->getSize().getZExtValue()); |
| 423 | break; |
| 424 | } |
| 425 | |
| 426 | case Type::ExtVector: |
| 427 | case Type::Vector: { |
| 428 | const VectorType *vec = cast<VectorType>(Val: ty); |
| 429 | const mlir::Type elemTy = convertType(vec->getElementType()); |
| 430 | resultType = cir::VectorType::get(elemTy, vec->getNumElements()); |
| 431 | break; |
| 432 | } |
| 433 | |
| 434 | case Type::Enum: { |
| 435 | const EnumDecl *ED = cast<EnumType>(Val: ty)->getDecl(); |
| 436 | if (auto integerType = ED->getIntegerType(); !integerType.isNull()) |
| 437 | return convertType(integerType); |
| 438 | // Return a placeholder 'i32' type. This can be changed later when the |
| 439 | // type is defined (see UpdateCompletedType), but is likely to be the |
| 440 | // "right" answer. |
| 441 | resultType = cgm.UInt32Ty; |
| 442 | break; |
| 443 | } |
| 444 | |
| 445 | case Type::FunctionNoProto: |
| 446 | case Type::FunctionProto: |
| 447 | resultType = convertFunctionTypeInternal(type); |
| 448 | break; |
| 449 | |
| 450 | case Type::BitInt: { |
| 451 | const auto *bitIntTy = cast<BitIntType>(Val&: type); |
| 452 | if (bitIntTy->getNumBits() > cir::IntType::maxBitwidth()) { |
| 453 | cgm.errorNYI(loc: SourceLocation(), feature: "large _BitInt type" , name: type); |
| 454 | resultType = cgm.SInt32Ty; |
| 455 | } else { |
| 456 | resultType = cir::IntType::get(&getMLIRContext(), bitIntTy->getNumBits(), |
| 457 | bitIntTy->isSigned()); |
| 458 | } |
| 459 | break; |
| 460 | } |
| 461 | |
| 462 | default: |
| 463 | cgm.errorNYI(loc: SourceLocation(), feature: "processing of type" , |
| 464 | name: type->getTypeClassName()); |
| 465 | resultType = cgm.SInt32Ty; |
| 466 | break; |
| 467 | } |
| 468 | |
| 469 | assert(resultType && "Type conversion not yet implemented" ); |
| 470 | |
| 471 | typeCache[ty] = resultType; |
| 472 | return resultType; |
| 473 | } |
| 474 | |
| 475 | mlir::Type CIRGenTypes::convertTypeForMem(clang::QualType qualType, |
| 476 | bool forBitField) { |
| 477 | assert(!qualType->isConstantMatrixType() && "Matrix types NYI" ); |
| 478 | |
| 479 | mlir::Type convertedType = convertType(qualType); |
| 480 | |
| 481 | assert(!forBitField && "Bit fields NYI" ); |
| 482 | |
| 483 | // If this is a bit-precise integer type in a bitfield representation, map |
| 484 | // this integer to the target-specified size. |
| 485 | if (forBitField && qualType->isBitIntType()) |
| 486 | assert(!qualType->isBitIntType() && "Bit field with type _BitInt NYI" ); |
| 487 | |
| 488 | return convertedType; |
| 489 | } |
| 490 | |
| 491 | /// Return record layout info for the given record decl. |
| 492 | const CIRGenRecordLayout & |
| 493 | CIRGenTypes::getCIRGenRecordLayout(const RecordDecl *rd) { |
| 494 | const auto *key = astContext.getTagDeclType(rd).getTypePtr(); |
| 495 | |
| 496 | // If we have already computed the layout, return it. |
| 497 | auto it = cirGenRecordLayouts.find(key); |
| 498 | if (it != cirGenRecordLayouts.end()) |
| 499 | return *it->second; |
| 500 | |
| 501 | // Compute the type information. |
| 502 | convertRecordDeclType(rd); |
| 503 | |
| 504 | // Now try again. |
| 505 | it = cirGenRecordLayouts.find(key); |
| 506 | |
| 507 | assert(it != cirGenRecordLayouts.end() && |
| 508 | "Unable to find record layout information for type" ); |
| 509 | return *it->second; |
| 510 | } |
| 511 | |
| 512 | bool CIRGenTypes::isZeroInitializable(clang::QualType t) { |
| 513 | if (t->getAs<PointerType>()) |
| 514 | return astContext.getTargetNullPointerValue(QT: t) == 0; |
| 515 | |
| 516 | if (const auto *at = astContext.getAsArrayType(T: t)) { |
| 517 | if (isa<IncompleteArrayType>(Val: at)) |
| 518 | return true; |
| 519 | |
| 520 | if (const auto *cat = dyn_cast<ConstantArrayType>(Val: at)) |
| 521 | if (astContext.getConstantArrayElementCount(CA: cat) == 0) |
| 522 | return true; |
| 523 | } |
| 524 | |
| 525 | if (const RecordType *rt = t->getAs<RecordType>()) { |
| 526 | const RecordDecl *rd = rt->getDecl(); |
| 527 | return isZeroInitializable(rd); |
| 528 | } |
| 529 | |
| 530 | if (t->getAs<MemberPointerType>()) { |
| 531 | cgm.errorNYI(loc: SourceLocation(), feature: "isZeroInitializable for MemberPointerType" , |
| 532 | name: t); |
| 533 | return false; |
| 534 | } |
| 535 | |
| 536 | return true; |
| 537 | } |
| 538 | |
| 539 | bool CIRGenTypes::isZeroInitializable(const RecordDecl *rd) { |
| 540 | return getCIRGenRecordLayout(rd).isZeroInitializable(); |
| 541 | } |
| 542 | |
| 543 | const CIRGenFunctionInfo & |
| 544 | CIRGenTypes::arrangeCIRFunctionInfo(CanQualType returnType, |
| 545 | llvm::ArrayRef<CanQualType> argTypes, |
| 546 | RequiredArgs required) { |
| 547 | assert(llvm::all_of(argTypes, |
| 548 | [](CanQualType t) { return t.isCanonicalAsParam(); })); |
| 549 | // Lookup or create unique function info. |
| 550 | llvm::FoldingSetNodeID id; |
| 551 | CIRGenFunctionInfo::Profile(id, required, resultType: returnType, argTypes); |
| 552 | |
| 553 | void *insertPos = nullptr; |
| 554 | CIRGenFunctionInfo *fi = functionInfos.FindNodeOrInsertPos(ID: id, InsertPos&: insertPos); |
| 555 | if (fi) { |
| 556 | // We found a matching function info based on id. These asserts verify that |
| 557 | // it really is a match. |
| 558 | assert( |
| 559 | fi->getReturnType() == returnType && |
| 560 | std::equal(fi->argTypesBegin(), fi->argTypesEnd(), argTypes.begin()) && |
| 561 | "Bad match based on CIRGenFunctionInfo folding set id" ); |
| 562 | return *fi; |
| 563 | } |
| 564 | |
| 565 | assert(!cir::MissingFeatures::opCallCallConv()); |
| 566 | |
| 567 | // Construction the function info. We co-allocate the ArgInfos. |
| 568 | fi = CIRGenFunctionInfo::create(resultType: returnType, argTypes, required); |
| 569 | functionInfos.InsertNode(N: fi, InsertPos: insertPos); |
| 570 | |
| 571 | return *fi; |
| 572 | } |
| 573 | |
| 574 | const CIRGenFunctionInfo &CIRGenTypes::arrangeGlobalDeclaration(GlobalDecl gd) { |
| 575 | assert(!dyn_cast<ObjCMethodDecl>(gd.getDecl()) && |
| 576 | "This is reported as a FIXME in LLVM codegen" ); |
| 577 | const auto *fd = cast<FunctionDecl>(Val: gd.getDecl()); |
| 578 | |
| 579 | if (isa<CXXConstructorDecl>(Val: gd.getDecl()) || |
| 580 | isa<CXXDestructorDecl>(Val: gd.getDecl())) { |
| 581 | cgm.errorNYI(SourceLocation(), |
| 582 | "arrangeGlobalDeclaration for C++ constructor or destructor" ); |
| 583 | } |
| 584 | |
| 585 | return arrangeFunctionDeclaration(fd); |
| 586 | } |
| 587 | |
| 588 | // When we find the full definition for a TagDecl, replace the 'opaque' type we |
| 589 | // previously made for it if applicable. |
| 590 | void CIRGenTypes::updateCompletedType(const TagDecl *td) { |
| 591 | // If this is an enum being completed, then we flush all non-struct types |
| 592 | // from the cache. This allows function types and other things that may be |
| 593 | // derived from the enum to be recomputed. |
| 594 | if (const auto *ed = dyn_cast<EnumDecl>(Val: td)) { |
| 595 | // Classic codegen clears the type cache if it contains an entry for this |
| 596 | // enum type that doesn't use i32 as the underlying type, but I can't find |
| 597 | // a test case that meets that condition. C++ doesn't allow forward |
| 598 | // declaration of enums, and C doesn't allow an incomplete forward |
| 599 | // declaration with a non-default type. |
| 600 | assert( |
| 601 | !typeCache.count(ed->getTypeForDecl()) || |
| 602 | (convertType(ed->getIntegerType()) == typeCache[ed->getTypeForDecl()])); |
| 603 | // If necessary, provide the full definition of a type only used with a |
| 604 | // declaration so far. |
| 605 | assert(!cir::MissingFeatures::generateDebugInfo()); |
| 606 | return; |
| 607 | } |
| 608 | |
| 609 | // If we completed a RecordDecl that we previously used and converted to an |
| 610 | // anonymous type, then go ahead and complete it now. |
| 611 | const auto *rd = cast<RecordDecl>(Val: td); |
| 612 | if (rd->isDependentType()) |
| 613 | return; |
| 614 | |
| 615 | // Only complete if we converted it already. If we haven't converted it yet, |
| 616 | // we'll just do it lazily. |
| 617 | if (recordDeclTypes.count(astContext.getTagDeclType(rd).getTypePtr())) |
| 618 | convertRecordDeclType(rd); |
| 619 | |
| 620 | // If necessary, provide the full definition of a type only used with a |
| 621 | // declaration so far. |
| 622 | assert(!cir::MissingFeatures::generateDebugInfo()); |
| 623 | } |
| 624 | |