xref: /llvm-project/clang/lib/CIR/CodeGen/CIRGenTypes.cpp (revision 8ae8a905855ca1b07a72059d8225ab1f9cae65dc)
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