1 #include "CIRGenTypes.h" 2 3 #include "CIRGenModule.h" 4 5 #include "clang/AST/ASTContext.h" 6 #include "clang/AST/Type.h" 7 #include "clang/Basic/TargetInfo.h" 8 9 #include <cassert> 10 11 using namespace clang; 12 using namespace clang::CIRGen; 13 14 CIRGenTypes::CIRGenTypes(CIRGenModule &genModule) 15 : cgm(genModule), astContext(genModule.getASTContext()), 16 builder(cgm.getBuilder()) {} 17 18 CIRGenTypes::~CIRGenTypes() {} 19 20 mlir::MLIRContext &CIRGenTypes::getMLIRContext() const { 21 return *builder.getContext(); 22 } 23 24 /// Return true if the specified type in a function parameter or result position 25 /// can be converted to a CIR type at this point. This boils down to being 26 /// whether it is complete, as well as whether we've temporarily deferred 27 /// expanding the type because we're in a recursive context. 28 bool CIRGenTypes::isFuncParamTypeConvertible(clang::QualType type) { 29 // Some ABIs cannot have their member pointers represented in LLVM IR unless 30 // certain circumstances have been reached. 31 assert(!type->getAs<MemberPointerType>() && "NYI"); 32 33 // If this isn't a tag type, we can convert it. 34 const TagType *tagType = type->getAs<TagType>(); 35 if (!tagType) 36 return true; 37 38 // Function types involving incomplete class types are problematic in MLIR. 39 return !tagType->isIncompleteType(); 40 } 41 42 /// Code to verify a given function type is complete, i.e. the return type and 43 /// all of the parameter types are complete. Also check to see if we are in a 44 /// RS_StructPointer context, and if so whether any struct types have been 45 /// pended. If so, we don't want to ask the ABI lowering code to handle a type 46 /// that cannot be converted to a CIR type. 47 bool CIRGenTypes::isFuncTypeConvertible(const FunctionType *ft) { 48 if (!isFuncParamTypeConvertible(ft->getReturnType())) 49 return false; 50 51 if (const auto *fpt = dyn_cast<FunctionProtoType>(ft)) 52 for (unsigned i = 0, e = fpt->getNumParams(); i != e; i++) 53 if (!isFuncParamTypeConvertible(fpt->getParamType(i))) 54 return false; 55 56 return true; 57 } 58 59 mlir::Type CIRGenTypes::ConvertFunctionTypeInternal(QualType qft) { 60 assert(qft.isCanonical()); 61 const FunctionType *ft = cast<FunctionType>(qft.getTypePtr()); 62 // First, check whether we can build the full fucntion type. If the function 63 // type depends on an incomplete type (e.g. a struct or enum), we cannot lower 64 // the function type. 65 if (!isFuncTypeConvertible(ft)) { 66 cgm.errorNYI(SourceLocation(), "function type involving an incomplete type", 67 qft); 68 return cir::FuncType::get(SmallVector<mlir::Type, 1>{}, cgm.VoidTy); 69 } 70 71 // TODO(CIR): This is a stub of what the final code will be. See the 72 // implementation of this function and the implementation of class 73 // CIRGenFunction in the ClangIR incubator project. 74 75 if (const auto *fpt = dyn_cast<FunctionProtoType>(ft)) { 76 SmallVector<mlir::Type> mlirParamTypes; 77 for (unsigned i = 0; i < fpt->getNumParams(); ++i) { 78 mlirParamTypes.push_back(convertType(fpt->getParamType(i))); 79 } 80 return cir::FuncType::get( 81 mlirParamTypes, convertType(fpt->getReturnType().getUnqualifiedType()), 82 fpt->isVariadic()); 83 } 84 cgm.errorNYI(SourceLocation(), "non-prototype function type", qft); 85 return cir::FuncType::get(SmallVector<mlir::Type, 1>{}, cgm.VoidTy); 86 } 87 88 mlir::Type CIRGenTypes::convertType(QualType type) { 89 type = astContext.getCanonicalType(type); 90 const Type *ty = type.getTypePtr(); 91 92 // Has the type already been processed? 93 TypeCacheTy::iterator tci = typeCache.find(ty); 94 if (tci != typeCache.end()) 95 return tci->second; 96 97 // For types that haven't been implemented yet or are otherwise unsupported, 98 // report an error and return 'int'. 99 100 mlir::Type resultType = nullptr; 101 switch (ty->getTypeClass()) { 102 case Type::Builtin: { 103 switch (cast<BuiltinType>(ty)->getKind()) { 104 105 // void 106 case BuiltinType::Void: 107 resultType = cgm.VoidTy; 108 break; 109 110 // Signed integral types. 111 case BuiltinType::Char_S: 112 case BuiltinType::Int: 113 case BuiltinType::Int128: 114 case BuiltinType::Long: 115 case BuiltinType::LongLong: 116 case BuiltinType::SChar: 117 case BuiltinType::Short: 118 case BuiltinType::WChar_S: 119 resultType = 120 cir::IntType::get(&getMLIRContext(), astContext.getTypeSize(ty), 121 /*isSigned=*/true); 122 break; 123 // Unsigned integral types. 124 case BuiltinType::Char8: 125 case BuiltinType::Char16: 126 case BuiltinType::Char32: 127 case BuiltinType::Char_U: 128 case BuiltinType::UChar: 129 case BuiltinType::UInt: 130 case BuiltinType::UInt128: 131 case BuiltinType::ULong: 132 case BuiltinType::ULongLong: 133 case BuiltinType::UShort: 134 case BuiltinType::WChar_U: 135 resultType = 136 cir::IntType::get(&getMLIRContext(), astContext.getTypeSize(ty), 137 /*isSigned=*/false); 138 break; 139 140 // Floating-point types 141 case BuiltinType::Float16: 142 resultType = cgm.FP16Ty; 143 break; 144 case BuiltinType::Half: 145 if (astContext.getLangOpts().NativeHalfType || 146 !astContext.getTargetInfo().useFP16ConversionIntrinsics()) { 147 resultType = cgm.FP16Ty; 148 } else { 149 cgm.errorNYI(SourceLocation(), "processing of built-in type", type); 150 resultType = cgm.SInt32Ty; 151 } 152 break; 153 case BuiltinType::BFloat16: 154 resultType = cgm.BFloat16Ty; 155 break; 156 case BuiltinType::Float: 157 assert(&astContext.getFloatTypeSemantics(type) == 158 &llvm::APFloat::IEEEsingle() && 159 "ClangIR NYI: 'float' in a format other than IEEE 32-bit"); 160 resultType = cgm.FloatTy; 161 break; 162 case BuiltinType::Double: 163 assert(&astContext.getFloatTypeSemantics(type) == 164 &llvm::APFloat::IEEEdouble() && 165 "ClangIR NYI: 'double' in a format other than IEEE 64-bit"); 166 resultType = cgm.DoubleTy; 167 break; 168 case BuiltinType::LongDouble: 169 resultType = 170 builder.getLongDoubleTy(astContext.getFloatTypeSemantics(type)); 171 break; 172 case BuiltinType::Float128: 173 resultType = cgm.FP128Ty; 174 break; 175 case BuiltinType::Ibm128: 176 cgm.errorNYI(SourceLocation(), "processing of built-in type", type); 177 resultType = cgm.SInt32Ty; 178 break; 179 180 default: 181 cgm.errorNYI(SourceLocation(), "processing of built-in type", type); 182 resultType = cgm.SInt32Ty; 183 break; 184 } 185 break; 186 } 187 188 case Type::Pointer: { 189 const PointerType *ptrTy = cast<PointerType>(ty); 190 QualType elemTy = ptrTy->getPointeeType(); 191 assert(!elemTy->isConstantMatrixType() && "not implemented"); 192 193 mlir::Type pointeeType = convertType(elemTy); 194 195 resultType = builder.getPointerTo(pointeeType); 196 break; 197 } 198 199 case Type::FunctionNoProto: 200 case Type::FunctionProto: 201 resultType = ConvertFunctionTypeInternal(type); 202 break; 203 204 case Type::BitInt: { 205 const auto *bitIntTy = cast<BitIntType>(type); 206 if (bitIntTy->getNumBits() > cir::IntType::maxBitwidth()) { 207 cgm.errorNYI(SourceLocation(), "large _BitInt type", type); 208 resultType = cgm.SInt32Ty; 209 } else { 210 resultType = cir::IntType::get(&getMLIRContext(), bitIntTy->getNumBits(), 211 bitIntTy->isSigned()); 212 } 213 break; 214 } 215 216 default: 217 cgm.errorNYI(SourceLocation(), "processing of type", type); 218 resultType = cgm.SInt32Ty; 219 break; 220 } 221 222 assert(resultType && "Type conversion not yet implemented"); 223 224 typeCache[ty] = resultType; 225 return resultType; 226 } 227