xref: /llvm-project/clang/lib/CIR/Dialect/IR/CIRTypes.cpp (revision 8ae8a905855ca1b07a72059d8225ab1f9cae65dc)
1 //===- CIRTypes.cpp - MLIR CIR Types --------------------------------------===//
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 defines the types in the CIR dialect.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "clang/CIR/Dialect/IR/CIRTypes.h"
14 
15 #include "mlir/IR/DialectImplementation.h"
16 #include "clang/CIR/Dialect/IR/CIRDialect.h"
17 #include "llvm/ADT/TypeSwitch.h"
18 
19 //===----------------------------------------------------------------------===//
20 // CIR Custom Parser/Printer Signatures
21 //===----------------------------------------------------------------------===//
22 
23 static mlir::ParseResult
24 parseFuncTypeArgs(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> &params,
25                   bool &isVarArg);
26 static void printFuncTypeArgs(mlir::AsmPrinter &p,
27                               mlir::ArrayRef<mlir::Type> params, bool isVarArg);
28 
29 //===----------------------------------------------------------------------===//
30 // Get autogenerated stuff
31 //===----------------------------------------------------------------------===//
32 
33 #define GET_TYPEDEF_CLASSES
34 #include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc"
35 
36 using namespace mlir;
37 using namespace cir;
38 
39 //===----------------------------------------------------------------------===//
40 // General CIR parsing / printing
41 //===----------------------------------------------------------------------===//
42 
43 Type CIRDialect::parseType(DialectAsmParser &parser) const {
44   llvm::SMLoc typeLoc = parser.getCurrentLocation();
45   llvm::StringRef mnemonic;
46   Type genType;
47 
48   // Try to parse as a tablegen'd type.
49   OptionalParseResult parseResult =
50       generatedTypeParser(parser, &mnemonic, genType);
51   if (parseResult.has_value())
52     return genType;
53 
54   // TODO(CIR) Attempt to parse as a raw C++ type.
55   parser.emitError(typeLoc) << "unknown CIR type: " << mnemonic;
56   return Type();
57 }
58 
59 void CIRDialect::printType(Type type, DialectAsmPrinter &os) const {
60   // Try to print as a tablegen'd type.
61   if (generatedTypePrinter(type, os).succeeded())
62     return;
63 
64   // TODO(CIR) Attempt to print as a raw C++ type.
65   llvm::report_fatal_error("printer is missing a handler for this type");
66 }
67 
68 //===----------------------------------------------------------------------===//
69 // IntType Definitions
70 //===----------------------------------------------------------------------===//
71 
72 Type IntType::parse(mlir::AsmParser &parser) {
73   mlir::MLIRContext *context = parser.getBuilder().getContext();
74   llvm::SMLoc loc = parser.getCurrentLocation();
75   bool isSigned;
76   unsigned width;
77 
78   if (parser.parseLess())
79     return {};
80 
81   // Fetch integer sign.
82   llvm::StringRef sign;
83   if (parser.parseKeyword(&sign))
84     return {};
85   if (sign == "s")
86     isSigned = true;
87   else if (sign == "u")
88     isSigned = false;
89   else {
90     parser.emitError(loc, "expected 's' or 'u'");
91     return {};
92   }
93 
94   if (parser.parseComma())
95     return {};
96 
97   // Fetch integer size.
98   if (parser.parseInteger(width))
99     return {};
100   if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) {
101     parser.emitError(loc, "expected integer width to be from ")
102         << IntType::minBitwidth() << " up to " << IntType::maxBitwidth();
103     return {};
104   }
105 
106   if (parser.parseGreater())
107     return {};
108 
109   return IntType::get(context, width, isSigned);
110 }
111 
112 void IntType::print(mlir::AsmPrinter &printer) const {
113   char sign = isSigned() ? 's' : 'u';
114   printer << '<' << sign << ", " << getWidth() << '>';
115 }
116 
117 llvm::TypeSize
118 IntType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
119                            mlir::DataLayoutEntryListRef params) const {
120   return llvm::TypeSize::getFixed(getWidth());
121 }
122 
123 uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout,
124                                   mlir::DataLayoutEntryListRef params) const {
125   return (uint64_t)(getWidth() / 8);
126 }
127 
128 uint64_t
129 IntType::getPreferredAlignment(const ::mlir::DataLayout &dataLayout,
130                                ::mlir::DataLayoutEntryListRef params) const {
131   return (uint64_t)(getWidth() / 8);
132 }
133 
134 mlir::LogicalResult
135 IntType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
136                 unsigned width, bool isSigned) {
137   if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) {
138     emitError() << "IntType only supports widths from "
139                 << IntType::minBitwidth() << " up to "
140                 << IntType::maxBitwidth();
141     return mlir::failure();
142   }
143   return mlir::success();
144 }
145 
146 //===----------------------------------------------------------------------===//
147 // Floating-point type definitions
148 //===----------------------------------------------------------------------===//
149 
150 const llvm::fltSemantics &SingleType::getFloatSemantics() const {
151   return llvm::APFloat::IEEEsingle();
152 }
153 
154 llvm::TypeSize
155 SingleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
156                               mlir::DataLayoutEntryListRef params) const {
157   return llvm::TypeSize::getFixed(getWidth());
158 }
159 
160 uint64_t
161 SingleType::getABIAlignment(const mlir::DataLayout &dataLayout,
162                             mlir::DataLayoutEntryListRef params) const {
163   return (uint64_t)(getWidth() / 8);
164 }
165 
166 uint64_t
167 SingleType::getPreferredAlignment(const ::mlir::DataLayout &dataLayout,
168                                   ::mlir::DataLayoutEntryListRef params) const {
169   return (uint64_t)(getWidth() / 8);
170 }
171 
172 const llvm::fltSemantics &DoubleType::getFloatSemantics() const {
173   return llvm::APFloat::IEEEdouble();
174 }
175 
176 llvm::TypeSize
177 DoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
178                               mlir::DataLayoutEntryListRef params) const {
179   return llvm::TypeSize::getFixed(getWidth());
180 }
181 
182 uint64_t
183 DoubleType::getABIAlignment(const mlir::DataLayout &dataLayout,
184                             mlir::DataLayoutEntryListRef params) const {
185   return (uint64_t)(getWidth() / 8);
186 }
187 
188 uint64_t
189 DoubleType::getPreferredAlignment(const ::mlir::DataLayout &dataLayout,
190                                   ::mlir::DataLayoutEntryListRef params) const {
191   return (uint64_t)(getWidth() / 8);
192 }
193 
194 const llvm::fltSemantics &FP16Type::getFloatSemantics() const {
195   return llvm::APFloat::IEEEhalf();
196 }
197 
198 llvm::TypeSize
199 FP16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
200                             mlir::DataLayoutEntryListRef params) const {
201   return llvm::TypeSize::getFixed(getWidth());
202 }
203 
204 uint64_t FP16Type::getABIAlignment(const mlir::DataLayout &dataLayout,
205                                    mlir::DataLayoutEntryListRef params) const {
206   return (uint64_t)(getWidth() / 8);
207 }
208 
209 uint64_t
210 FP16Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout,
211                                 ::mlir::DataLayoutEntryListRef params) const {
212   return (uint64_t)(getWidth() / 8);
213 }
214 
215 const llvm::fltSemantics &BF16Type::getFloatSemantics() const {
216   return llvm::APFloat::BFloat();
217 }
218 
219 llvm::TypeSize
220 BF16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
221                             mlir::DataLayoutEntryListRef params) const {
222   return llvm::TypeSize::getFixed(getWidth());
223 }
224 
225 uint64_t BF16Type::getABIAlignment(const mlir::DataLayout &dataLayout,
226                                    mlir::DataLayoutEntryListRef params) const {
227   return (uint64_t)(getWidth() / 8);
228 }
229 
230 uint64_t
231 BF16Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout,
232                                 ::mlir::DataLayoutEntryListRef params) const {
233   return (uint64_t)(getWidth() / 8);
234 }
235 
236 const llvm::fltSemantics &FP80Type::getFloatSemantics() const {
237   return llvm::APFloat::x87DoubleExtended();
238 }
239 
240 llvm::TypeSize
241 FP80Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
242                             mlir::DataLayoutEntryListRef params) const {
243   // Though only 80 bits are used for the value, the type is 128 bits in size.
244   return llvm::TypeSize::getFixed(128);
245 }
246 
247 uint64_t FP80Type::getABIAlignment(const mlir::DataLayout &dataLayout,
248                                    mlir::DataLayoutEntryListRef params) const {
249   return 16;
250 }
251 
252 uint64_t
253 FP80Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout,
254                                 ::mlir::DataLayoutEntryListRef params) const {
255   return 16;
256 }
257 
258 const llvm::fltSemantics &FP128Type::getFloatSemantics() const {
259   return llvm::APFloat::IEEEquad();
260 }
261 
262 llvm::TypeSize
263 FP128Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
264                              mlir::DataLayoutEntryListRef params) const {
265   return llvm::TypeSize::getFixed(getWidth());
266 }
267 
268 uint64_t FP128Type::getABIAlignment(const mlir::DataLayout &dataLayout,
269                                     mlir::DataLayoutEntryListRef params) const {
270   return 16;
271 }
272 
273 uint64_t
274 FP128Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout,
275                                  ::mlir::DataLayoutEntryListRef params) const {
276   return 16;
277 }
278 
279 const llvm::fltSemantics &LongDoubleType::getFloatSemantics() const {
280   return mlir::cast<cir::CIRFPTypeInterface>(getUnderlying())
281       .getFloatSemantics();
282 }
283 
284 llvm::TypeSize
285 LongDoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
286                                   mlir::DataLayoutEntryListRef params) const {
287   return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying())
288       .getTypeSizeInBits(dataLayout, params);
289 }
290 
291 uint64_t
292 LongDoubleType::getABIAlignment(const mlir::DataLayout &dataLayout,
293                                 mlir::DataLayoutEntryListRef params) const {
294   return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying())
295       .getABIAlignment(dataLayout, params);
296 }
297 
298 uint64_t LongDoubleType::getPreferredAlignment(
299     const ::mlir::DataLayout &dataLayout,
300     mlir::DataLayoutEntryListRef params) const {
301   return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying())
302       .getPreferredAlignment(dataLayout, params);
303 }
304 
305 LogicalResult
306 LongDoubleType::verify(function_ref<InFlightDiagnostic()> emitError,
307                        mlir::Type underlying) {
308   if (!mlir::isa<DoubleType, FP80Type, FP128Type>(underlying)) {
309     emitError() << "invalid underlying type for long double";
310     return failure();
311   }
312 
313   return success();
314 }
315 
316 //===----------------------------------------------------------------------===//
317 // Floating-point type helpers
318 //===----------------------------------------------------------------------===//
319 
320 bool cir::isAnyFloatingPointType(mlir::Type t) {
321   return isa<cir::SingleType, cir::DoubleType, cir::LongDoubleType,
322              cir::FP80Type, cir::BF16Type, cir::FP16Type, cir::FP128Type>(t);
323 }
324 
325 //===----------------------------------------------------------------------===//
326 // FuncType Definitions
327 //===----------------------------------------------------------------------===//
328 
329 FuncType FuncType::clone(TypeRange inputs, TypeRange results) const {
330   assert(results.size() == 1 && "expected exactly one result type");
331   return get(llvm::to_vector(inputs), results[0], isVarArg());
332 }
333 
334 mlir::ParseResult parseFuncTypeArgs(mlir::AsmParser &p,
335                                     llvm::SmallVector<mlir::Type> &params,
336                                     bool &isVarArg) {
337   isVarArg = false;
338   // `(` `)`
339   if (succeeded(p.parseOptionalRParen()))
340     return mlir::success();
341 
342   // `(` `...` `)`
343   if (succeeded(p.parseOptionalEllipsis())) {
344     isVarArg = true;
345     return p.parseRParen();
346   }
347 
348   // type (`,` type)* (`,` `...`)?
349   mlir::Type type;
350   if (p.parseType(type))
351     return mlir::failure();
352   params.push_back(type);
353   while (succeeded(p.parseOptionalComma())) {
354     if (succeeded(p.parseOptionalEllipsis())) {
355       isVarArg = true;
356       return p.parseRParen();
357     }
358     if (p.parseType(type))
359       return mlir::failure();
360     params.push_back(type);
361   }
362 
363   return p.parseRParen();
364 }
365 
366 void printFuncTypeArgs(mlir::AsmPrinter &p, mlir::ArrayRef<mlir::Type> params,
367                        bool isVarArg) {
368   llvm::interleaveComma(params, p,
369                         [&p](mlir::Type type) { p.printType(type); });
370   if (isVarArg) {
371     if (!params.empty())
372       p << ", ";
373     p << "...";
374   }
375   p << ')';
376 }
377 
378 llvm::ArrayRef<mlir::Type> FuncType::getReturnTypes() const {
379   return static_cast<detail::FuncTypeStorage *>(getImpl())->returnType;
380 }
381 
382 bool FuncType::isVoid() const { return mlir::isa<VoidType>(getReturnType()); }
383 
384 //===----------------------------------------------------------------------===//
385 // PointerType Definitions
386 //===----------------------------------------------------------------------===//
387 
388 llvm::TypeSize
389 PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
390                                ::mlir::DataLayoutEntryListRef params) const {
391   // FIXME: improve this in face of address spaces
392   return llvm::TypeSize::getFixed(64);
393 }
394 
395 uint64_t
396 PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
397                              ::mlir::DataLayoutEntryListRef params) const {
398   // FIXME: improve this in face of address spaces
399   return 8;
400 }
401 
402 uint64_t PointerType::getPreferredAlignment(
403     const ::mlir::DataLayout &dataLayout,
404     ::mlir::DataLayoutEntryListRef params) const {
405   // FIXME: improve this in face of address spaces
406   return 8;
407 }
408 
409 mlir::LogicalResult
410 PointerType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
411                     mlir::Type pointee) {
412   // TODO(CIR): Verification of the address space goes here.
413   return mlir::success();
414 }
415 
416 //===----------------------------------------------------------------------===//
417 // CIR Dialect
418 //===----------------------------------------------------------------------===//
419 
420 void CIRDialect::registerTypes() {
421   // Register tablegen'd types.
422   addTypes<
423 #define GET_TYPEDEF_LIST
424 #include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc"
425       >();
426 
427   // Register raw C++ types.
428   // TODO(CIR) addTypes<StructType>();
429 }
430