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 "clang/CIR/Dialect/IR/CIRTypesDetails.h" |
18 | #include "clang/CIR/MissingFeatures.h" |
19 | #include "llvm/ADT/TypeSwitch.h" |
20 | |
21 | //===----------------------------------------------------------------------===// |
22 | // CIR Custom Parser/Printer Signatures |
23 | //===----------------------------------------------------------------------===// |
24 | |
25 | static mlir::ParseResult |
26 | parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> ¶ms, |
27 | bool &isVarArg); |
28 | static void printFuncTypeParams(mlir::AsmPrinter &p, |
29 | mlir::ArrayRef<mlir::Type> params, |
30 | bool isVarArg); |
31 | |
32 | //===----------------------------------------------------------------------===// |
33 | // Get autogenerated stuff |
34 | //===----------------------------------------------------------------------===// |
35 | |
36 | namespace cir { |
37 | |
38 | #include "clang/CIR/Dialect/IR/CIRTypeConstraints.cpp.inc" |
39 | |
40 | } // namespace cir |
41 | |
42 | #define GET_TYPEDEF_CLASSES |
43 | #include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc" |
44 | |
45 | using namespace mlir; |
46 | using namespace cir; |
47 | |
48 | //===----------------------------------------------------------------------===// |
49 | // General CIR parsing / printing |
50 | //===----------------------------------------------------------------------===// |
51 | |
52 | Type CIRDialect::parseType(DialectAsmParser &parser) const { |
53 | llvm::SMLoc typeLoc = parser.getCurrentLocation(); |
54 | llvm::StringRef mnemonic; |
55 | Type genType; |
56 | |
57 | // Try to parse as a tablegen'd type. |
58 | OptionalParseResult parseResult = |
59 | generatedTypeParser(parser, &mnemonic, genType); |
60 | if (parseResult.has_value()) |
61 | return genType; |
62 | |
63 | // Type is not tablegen'd: try to parse as a raw C++ type. |
64 | return StringSwitch<function_ref<Type()>>(mnemonic) |
65 | .Case("record" , [&] { return RecordType::parse(parser); }) |
66 | .Default(Value: [&] { |
67 | parser.emitError(loc: typeLoc) << "unknown CIR type: " << mnemonic; |
68 | return Type(); |
69 | })(); |
70 | } |
71 | |
72 | void CIRDialect::printType(Type type, DialectAsmPrinter &os) const { |
73 | // Try to print as a tablegen'd type. |
74 | if (generatedTypePrinter(type, os).succeeded()) |
75 | return; |
76 | |
77 | // TODO(CIR) Attempt to print as a raw C++ type. |
78 | llvm::report_fatal_error(reason: "printer is missing a handler for this type" ); |
79 | } |
80 | |
81 | //===----------------------------------------------------------------------===// |
82 | // RecordType Definitions |
83 | //===----------------------------------------------------------------------===// |
84 | |
85 | Type RecordType::parse(mlir::AsmParser &parser) { |
86 | FailureOr<AsmParser::CyclicParseReset> cyclicParseGuard; |
87 | const llvm::SMLoc loc = parser.getCurrentLocation(); |
88 | const mlir::Location eLoc = parser.getEncodedSourceLoc(loc); |
89 | RecordKind kind; |
90 | mlir::MLIRContext *context = parser.getContext(); |
91 | |
92 | if (parser.parseLess()) |
93 | return {}; |
94 | |
95 | // TODO(cir): in the future we should probably separate types for different |
96 | // source language declarations such as cir.record and cir.union |
97 | if (parser.parseOptionalKeyword("struct" ).succeeded()) |
98 | kind = RecordKind::Struct; |
99 | else if (parser.parseOptionalKeyword("union" ).succeeded()) |
100 | kind = RecordKind::Union; |
101 | else if (parser.parseOptionalKeyword("class" ).succeeded()) |
102 | kind = RecordKind::Class; |
103 | else { |
104 | parser.emitError(loc, "unknown record type" ); |
105 | return {}; |
106 | } |
107 | |
108 | mlir::StringAttr name; |
109 | parser.parseOptionalAttribute(name); |
110 | |
111 | // Is a self reference: ensure referenced type was parsed. |
112 | if (name && parser.parseOptionalGreater().succeeded()) { |
113 | RecordType type = getChecked(eLoc, context, name, kind); |
114 | if (succeeded(parser.tryStartCyclicParse(type))) { |
115 | parser.emitError(loc, "invalid self-reference within record" ); |
116 | return {}; |
117 | } |
118 | return type; |
119 | } |
120 | |
121 | // Is a named record definition: ensure name has not been parsed yet. |
122 | if (name) { |
123 | RecordType type = getChecked(eLoc, context, name, kind); |
124 | cyclicParseGuard = parser.tryStartCyclicParse(type); |
125 | if (failed(cyclicParseGuard)) { |
126 | parser.emitError(loc, "record already defined" ); |
127 | return {}; |
128 | } |
129 | } |
130 | |
131 | // Parse record members or lack thereof. |
132 | bool incomplete = true; |
133 | llvm::SmallVector<mlir::Type> members; |
134 | if (parser.parseOptionalKeyword("incomplete" ).failed()) { |
135 | incomplete = false; |
136 | const auto delimiter = AsmParser::Delimiter::Braces; |
137 | const auto parseElementFn = [&parser, &members]() { |
138 | return parser.parseType(members.emplace_back()); |
139 | }; |
140 | if (parser.parseCommaSeparatedList(delimiter, parseElementFn).failed()) |
141 | return {}; |
142 | } |
143 | |
144 | if (parser.parseGreater()) |
145 | return {}; |
146 | |
147 | // Try to create the proper record type. |
148 | ArrayRef<mlir::Type> membersRef(members); // Needed for template deduction. |
149 | mlir::Type type = {}; |
150 | if (name && incomplete) { // Identified & incomplete |
151 | type = getChecked(eLoc, context, name, kind); |
152 | } else if (!incomplete) { // complete |
153 | parser.emitError(loc, "complete records are not yet supported" ); |
154 | } else { // anonymous & incomplete |
155 | parser.emitError(loc, "anonymous records must be complete" ); |
156 | return {}; |
157 | } |
158 | |
159 | return type; |
160 | } |
161 | |
162 | void RecordType::print(mlir::AsmPrinter &printer) const { |
163 | FailureOr<AsmPrinter::CyclicPrintReset> cyclicPrintGuard; |
164 | printer << '<'; |
165 | |
166 | switch (getKind()) { |
167 | case RecordKind::Struct: |
168 | printer << "struct " ; |
169 | break; |
170 | case RecordKind::Union: |
171 | printer << "union " ; |
172 | break; |
173 | case RecordKind::Class: |
174 | printer << "class " ; |
175 | break; |
176 | } |
177 | |
178 | if (getName()) |
179 | printer << getName(); |
180 | |
181 | // Current type has already been printed: print as self reference. |
182 | cyclicPrintGuard = printer.tryStartCyclicPrint(*this); |
183 | if (failed(cyclicPrintGuard)) { |
184 | printer << '>'; |
185 | return; |
186 | } |
187 | |
188 | // Type not yet printed: continue printing the entire record. |
189 | printer << ' '; |
190 | |
191 | if (getPacked()) |
192 | printer << "packed " ; |
193 | |
194 | if (getPadded()) |
195 | printer << "padded " ; |
196 | |
197 | if (isIncomplete()) { |
198 | printer << "incomplete" ; |
199 | } else { |
200 | printer << "{" ; |
201 | llvm::interleaveComma(getMembers(), printer); |
202 | printer << "}" ; |
203 | } |
204 | |
205 | printer << '>'; |
206 | } |
207 | |
208 | mlir::LogicalResult |
209 | RecordType::verify(function_ref<mlir::InFlightDiagnostic()> emitError, |
210 | llvm::ArrayRef<mlir::Type> members, mlir::StringAttr name, |
211 | bool incomplete, bool packed, bool padded, |
212 | RecordType::RecordKind kind) { |
213 | if (name && name.getValue().empty()) |
214 | return emitError() << "identified records cannot have an empty name" ; |
215 | return mlir::success(); |
216 | } |
217 | |
218 | ::llvm::ArrayRef<mlir::Type> RecordType::getMembers() const { |
219 | return getImpl()->members; |
220 | } |
221 | |
222 | bool RecordType::isIncomplete() const { return getImpl()->incomplete; } |
223 | |
224 | mlir::StringAttr RecordType::getName() const { return getImpl()->name; } |
225 | |
226 | bool RecordType::getIncomplete() const { return getImpl()->incomplete; } |
227 | |
228 | bool RecordType::getPacked() const { return getImpl()->packed; } |
229 | |
230 | bool RecordType::getPadded() const { return getImpl()->padded; } |
231 | |
232 | cir::RecordType::RecordKind RecordType::getKind() const { |
233 | return getImpl()->kind; |
234 | } |
235 | |
236 | void RecordType::complete(ArrayRef<Type> members, bool packed, bool padded) { |
237 | assert(!cir::MissingFeatures::astRecordDeclAttr()); |
238 | if (mutate(members, packed, padded).failed()) |
239 | llvm_unreachable("failed to complete record" ); |
240 | } |
241 | |
242 | /// Return the largest member of in the type. |
243 | /// |
244 | /// Recurses into union members never returning a union as the largest member. |
245 | Type RecordType::getLargestMember(const ::mlir::DataLayout &dataLayout) const { |
246 | assert(isUnion() && "Only call getLargestMember on unions" ); |
247 | llvm::ArrayRef<Type> members = getMembers(); |
248 | // If the union is padded, we need to ignore the last member, |
249 | // which is the padding. |
250 | return *std::max_element( |
251 | members.begin(), getPadded() ? members.end() - 1 : members.end(), |
252 | [&](Type lhs, Type rhs) { |
253 | return dataLayout.getTypeABIAlignment(lhs) < |
254 | dataLayout.getTypeABIAlignment(rhs) || |
255 | (dataLayout.getTypeABIAlignment(lhs) == |
256 | dataLayout.getTypeABIAlignment(rhs) && |
257 | dataLayout.getTypeSize(lhs) < dataLayout.getTypeSize(rhs)); |
258 | }); |
259 | } |
260 | |
261 | //===----------------------------------------------------------------------===// |
262 | // Data Layout information for types |
263 | //===----------------------------------------------------------------------===// |
264 | |
265 | llvm::TypeSize |
266 | RecordType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, |
267 | mlir::DataLayoutEntryListRef params) const { |
268 | if (isUnion()) |
269 | return dataLayout.getTypeSize(getLargestMember(dataLayout)); |
270 | |
271 | unsigned recordSize = computeStructSize(dataLayout); |
272 | return llvm::TypeSize::getFixed(recordSize * 8); |
273 | } |
274 | |
275 | uint64_t |
276 | RecordType::getABIAlignment(const ::mlir::DataLayout &dataLayout, |
277 | ::mlir::DataLayoutEntryListRef params) const { |
278 | if (isUnion()) |
279 | return dataLayout.getTypeABIAlignment(getLargestMember(dataLayout)); |
280 | |
281 | // Packed structures always have an ABI alignment of 1. |
282 | if (getPacked()) |
283 | return 1; |
284 | return computeStructAlignment(dataLayout); |
285 | } |
286 | |
287 | unsigned |
288 | RecordType::computeStructSize(const mlir::DataLayout &dataLayout) const { |
289 | assert(isComplete() && "Cannot get layout of incomplete records" ); |
290 | |
291 | // This is a similar algorithm to LLVM's StructLayout. |
292 | unsigned recordSize = 0; |
293 | uint64_t recordAlignment = 1; |
294 | |
295 | for (mlir::Type ty : getMembers()) { |
296 | // This assumes that we're calculating size based on the ABI alignment, not |
297 | // the preferred alignment for each type. |
298 | const uint64_t tyAlign = |
299 | (getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty)); |
300 | |
301 | // Add padding to the struct size to align it to the abi alignment of the |
302 | // element type before than adding the size of the element. |
303 | recordSize = llvm::alignTo(recordSize, tyAlign); |
304 | recordSize += dataLayout.getTypeSize(ty); |
305 | |
306 | // The alignment requirement of a struct is equal to the strictest alignment |
307 | // requirement of its elements. |
308 | recordAlignment = std::max(tyAlign, recordAlignment); |
309 | } |
310 | |
311 | // At the end, add padding to the struct to satisfy its own alignment |
312 | // requirement. Otherwise structs inside of arrays would be misaligned. |
313 | recordSize = llvm::alignTo(recordSize, recordAlignment); |
314 | return recordSize; |
315 | } |
316 | |
317 | // We also compute the alignment as part of computeStructSize, but this is more |
318 | // efficient. Ideally, we'd like to compute both at once and cache the result, |
319 | // but that's implemented yet. |
320 | // TODO(CIR): Implement a way to cache the result. |
321 | uint64_t |
322 | RecordType::computeStructAlignment(const mlir::DataLayout &dataLayout) const { |
323 | assert(isComplete() && "Cannot get layout of incomplete records" ); |
324 | |
325 | // This is a similar algorithm to LLVM's StructLayout. |
326 | uint64_t recordAlignment = 1; |
327 | for (mlir::Type ty : getMembers()) |
328 | recordAlignment = |
329 | std::max(dataLayout.getTypeABIAlignment(ty), recordAlignment); |
330 | |
331 | return recordAlignment; |
332 | } |
333 | |
334 | uint64_t RecordType::getElementOffset(const ::mlir::DataLayout &dataLayout, |
335 | unsigned idx) const { |
336 | assert(idx < getMembers().size() && "access not valid" ); |
337 | |
338 | // All union elements are at offset zero. |
339 | if (isUnion() || idx == 0) |
340 | return 0; |
341 | |
342 | assert(isComplete() && "Cannot get layout of incomplete records" ); |
343 | assert(idx < getNumElements()); |
344 | llvm::ArrayRef<mlir::Type> members = getMembers(); |
345 | |
346 | unsigned offset = 0; |
347 | |
348 | for (mlir::Type ty : |
349 | llvm::make_range(members.begin(), std::next(members.begin(), idx))) { |
350 | // This matches LLVM since it uses the ABI instead of preferred alignment. |
351 | const llvm::Align tyAlign = |
352 | llvm::Align(getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty)); |
353 | |
354 | // Add padding if necessary to align the data element properly. |
355 | offset = llvm::alignTo(offset, tyAlign); |
356 | |
357 | // Consume space for this data item |
358 | offset += dataLayout.getTypeSize(ty); |
359 | } |
360 | |
361 | // Account for padding, if necessary, for the alignment of the field whose |
362 | // offset we are calculating. |
363 | const llvm::Align tyAlign = llvm::Align( |
364 | getPacked() ? 1 : dataLayout.getTypeABIAlignment(members[idx])); |
365 | offset = llvm::alignTo(offset, tyAlign); |
366 | |
367 | return offset; |
368 | } |
369 | |
370 | //===----------------------------------------------------------------------===// |
371 | // IntType Definitions |
372 | //===----------------------------------------------------------------------===// |
373 | |
374 | Type IntType::parse(mlir::AsmParser &parser) { |
375 | mlir::MLIRContext *context = parser.getBuilder().getContext(); |
376 | llvm::SMLoc loc = parser.getCurrentLocation(); |
377 | bool isSigned; |
378 | unsigned width; |
379 | |
380 | if (parser.parseLess()) |
381 | return {}; |
382 | |
383 | // Fetch integer sign. |
384 | llvm::StringRef sign; |
385 | if (parser.parseKeyword(&sign)) |
386 | return {}; |
387 | if (sign == "s" ) |
388 | isSigned = true; |
389 | else if (sign == "u" ) |
390 | isSigned = false; |
391 | else { |
392 | parser.emitError(loc, "expected 's' or 'u'" ); |
393 | return {}; |
394 | } |
395 | |
396 | if (parser.parseComma()) |
397 | return {}; |
398 | |
399 | // Fetch integer size. |
400 | if (parser.parseInteger(width)) |
401 | return {}; |
402 | if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) { |
403 | parser.emitError(loc, "expected integer width to be from " ) |
404 | << IntType::minBitwidth() << " up to " << IntType::maxBitwidth(); |
405 | return {}; |
406 | } |
407 | |
408 | if (parser.parseGreater()) |
409 | return {}; |
410 | |
411 | return IntType::get(context, width, isSigned); |
412 | } |
413 | |
414 | void IntType::print(mlir::AsmPrinter &printer) const { |
415 | char sign = isSigned() ? 's' : 'u'; |
416 | printer << '<' << sign << ", " << getWidth() << '>'; |
417 | } |
418 | |
419 | llvm::TypeSize |
420 | IntType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, |
421 | mlir::DataLayoutEntryListRef params) const { |
422 | return llvm::TypeSize::getFixed(getWidth()); |
423 | } |
424 | |
425 | uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout, |
426 | mlir::DataLayoutEntryListRef params) const { |
427 | return (uint64_t)(getWidth() / 8); |
428 | } |
429 | |
430 | mlir::LogicalResult |
431 | IntType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError, |
432 | unsigned width, bool isSigned) { |
433 | if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) |
434 | return emitError() << "IntType only supports widths from " |
435 | << IntType::minBitwidth() << " up to " |
436 | << IntType::maxBitwidth(); |
437 | return mlir::success(); |
438 | } |
439 | |
440 | bool cir::isValidFundamentalIntWidth(unsigned width) { |
441 | return width == 8 || width == 16 || width == 32 || width == 64; |
442 | } |
443 | |
444 | //===----------------------------------------------------------------------===// |
445 | // Floating-point type definitions |
446 | //===----------------------------------------------------------------------===// |
447 | |
448 | const llvm::fltSemantics &SingleType::getFloatSemantics() const { |
449 | return llvm::APFloat::IEEEsingle(); |
450 | } |
451 | |
452 | llvm::TypeSize |
453 | SingleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, |
454 | mlir::DataLayoutEntryListRef params) const { |
455 | return llvm::TypeSize::getFixed(getWidth()); |
456 | } |
457 | |
458 | uint64_t |
459 | SingleType::getABIAlignment(const mlir::DataLayout &dataLayout, |
460 | mlir::DataLayoutEntryListRef params) const { |
461 | return (uint64_t)(getWidth() / 8); |
462 | } |
463 | |
464 | const llvm::fltSemantics &DoubleType::getFloatSemantics() const { |
465 | return llvm::APFloat::IEEEdouble(); |
466 | } |
467 | |
468 | llvm::TypeSize |
469 | DoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, |
470 | mlir::DataLayoutEntryListRef params) const { |
471 | return llvm::TypeSize::getFixed(getWidth()); |
472 | } |
473 | |
474 | uint64_t |
475 | DoubleType::getABIAlignment(const mlir::DataLayout &dataLayout, |
476 | mlir::DataLayoutEntryListRef params) const { |
477 | return (uint64_t)(getWidth() / 8); |
478 | } |
479 | |
480 | const llvm::fltSemantics &FP16Type::getFloatSemantics() const { |
481 | return llvm::APFloat::IEEEhalf(); |
482 | } |
483 | |
484 | llvm::TypeSize |
485 | FP16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, |
486 | mlir::DataLayoutEntryListRef params) const { |
487 | return llvm::TypeSize::getFixed(getWidth()); |
488 | } |
489 | |
490 | uint64_t FP16Type::getABIAlignment(const mlir::DataLayout &dataLayout, |
491 | mlir::DataLayoutEntryListRef params) const { |
492 | return (uint64_t)(getWidth() / 8); |
493 | } |
494 | |
495 | const llvm::fltSemantics &BF16Type::getFloatSemantics() const { |
496 | return llvm::APFloat::BFloat(); |
497 | } |
498 | |
499 | llvm::TypeSize |
500 | BF16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, |
501 | mlir::DataLayoutEntryListRef params) const { |
502 | return llvm::TypeSize::getFixed(getWidth()); |
503 | } |
504 | |
505 | uint64_t BF16Type::getABIAlignment(const mlir::DataLayout &dataLayout, |
506 | mlir::DataLayoutEntryListRef params) const { |
507 | return (uint64_t)(getWidth() / 8); |
508 | } |
509 | |
510 | const llvm::fltSemantics &FP80Type::getFloatSemantics() const { |
511 | return llvm::APFloat::x87DoubleExtended(); |
512 | } |
513 | |
514 | llvm::TypeSize |
515 | FP80Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, |
516 | mlir::DataLayoutEntryListRef params) const { |
517 | // Though only 80 bits are used for the value, the type is 128 bits in size. |
518 | return llvm::TypeSize::getFixed(128); |
519 | } |
520 | |
521 | uint64_t FP80Type::getABIAlignment(const mlir::DataLayout &dataLayout, |
522 | mlir::DataLayoutEntryListRef params) const { |
523 | return 16; |
524 | } |
525 | |
526 | const llvm::fltSemantics &FP128Type::getFloatSemantics() const { |
527 | return llvm::APFloat::IEEEquad(); |
528 | } |
529 | |
530 | llvm::TypeSize |
531 | FP128Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, |
532 | mlir::DataLayoutEntryListRef params) const { |
533 | return llvm::TypeSize::getFixed(getWidth()); |
534 | } |
535 | |
536 | uint64_t FP128Type::getABIAlignment(const mlir::DataLayout &dataLayout, |
537 | mlir::DataLayoutEntryListRef params) const { |
538 | return 16; |
539 | } |
540 | |
541 | const llvm::fltSemantics &LongDoubleType::getFloatSemantics() const { |
542 | return mlir::cast<cir::CIRFPTypeInterface>(getUnderlying()) |
543 | .getFloatSemantics(); |
544 | } |
545 | |
546 | llvm::TypeSize |
547 | LongDoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, |
548 | mlir::DataLayoutEntryListRef params) const { |
549 | return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying()) |
550 | .getTypeSizeInBits(dataLayout, params); |
551 | } |
552 | |
553 | uint64_t |
554 | LongDoubleType::getABIAlignment(const mlir::DataLayout &dataLayout, |
555 | mlir::DataLayoutEntryListRef params) const { |
556 | return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying()) |
557 | .getABIAlignment(dataLayout, params); |
558 | } |
559 | |
560 | //===----------------------------------------------------------------------===// |
561 | // ComplexType Definitions |
562 | //===----------------------------------------------------------------------===// |
563 | |
564 | llvm::TypeSize |
565 | cir::ComplexType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, |
566 | mlir::DataLayoutEntryListRef params) const { |
567 | // C17 6.2.5p13: |
568 | // Each complex type has the same representation and alignment requirements |
569 | // as an array type containing exactly two elements of the corresponding |
570 | // real type. |
571 | |
572 | return dataLayout.getTypeSizeInBits(getElementType()) * 2; |
573 | } |
574 | |
575 | uint64_t |
576 | cir::ComplexType::getABIAlignment(const mlir::DataLayout &dataLayout, |
577 | mlir::DataLayoutEntryListRef params) const { |
578 | // C17 6.2.5p13: |
579 | // Each complex type has the same representation and alignment requirements |
580 | // as an array type containing exactly two elements of the corresponding |
581 | // real type. |
582 | |
583 | return dataLayout.getTypeABIAlignment(getElementType()); |
584 | } |
585 | |
586 | FuncType FuncType::clone(TypeRange inputs, TypeRange results) const { |
587 | assert(results.size() == 1 && "expected exactly one result type" ); |
588 | return get(llvm::to_vector(inputs), results[0], isVarArg()); |
589 | } |
590 | |
591 | // Custom parser that parses function parameters of form `(<type>*, ...)`. |
592 | static mlir::ParseResult |
593 | parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> ¶ms, |
594 | bool &isVarArg) { |
595 | isVarArg = false; |
596 | return p.parseCommaSeparatedList( |
597 | delimiter: AsmParser::Delimiter::Paren, parseElementFn: [&]() -> mlir::ParseResult { |
598 | if (isVarArg) |
599 | return p.emitError(loc: p.getCurrentLocation(), |
600 | message: "variadic `...` must be the last parameter" ); |
601 | if (succeeded(Result: p.parseOptionalEllipsis())) { |
602 | isVarArg = true; |
603 | return success(); |
604 | } |
605 | mlir::Type type; |
606 | if (failed(Result: p.parseType(result&: type))) |
607 | return failure(); |
608 | params.push_back(Elt: type); |
609 | return success(); |
610 | }); |
611 | } |
612 | |
613 | static void printFuncTypeParams(mlir::AsmPrinter &p, |
614 | mlir::ArrayRef<mlir::Type> params, |
615 | bool isVarArg) { |
616 | p << '('; |
617 | llvm::interleaveComma(c: params, os&: p, |
618 | each_fn: [&p](mlir::Type type) { p.printType(type); }); |
619 | if (isVarArg) { |
620 | if (!params.empty()) |
621 | p << ", " ; |
622 | p << "..." ; |
623 | } |
624 | p << ')'; |
625 | } |
626 | |
627 | /// Get the C-style return type of the function, which is !cir.void if the |
628 | /// function returns nothing and the actual return type otherwise. |
629 | mlir::Type FuncType::getReturnType() const { |
630 | if (hasVoidReturn()) |
631 | return cir::VoidType::get(getContext()); |
632 | return getOptionalReturnType(); |
633 | } |
634 | |
635 | /// Get the MLIR-style return type of the function, which is an empty |
636 | /// ArrayRef if the function returns nothing and a single-element ArrayRef |
637 | /// with the actual return type otherwise. |
638 | llvm::ArrayRef<mlir::Type> FuncType::getReturnTypes() const { |
639 | if (hasVoidReturn()) |
640 | return {}; |
641 | // Can't use getOptionalReturnType() here because llvm::ArrayRef hold a |
642 | // pointer to its elements and doesn't do lifetime extension. That would |
643 | // result in returning a pointer to a temporary that has gone out of scope. |
644 | return getImpl()->optionalReturnType; |
645 | } |
646 | |
647 | // Does the fuction type return nothing? |
648 | bool FuncType::hasVoidReturn() const { return !getOptionalReturnType(); } |
649 | |
650 | mlir::LogicalResult |
651 | FuncType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError, |
652 | llvm::ArrayRef<mlir::Type> argTypes, mlir::Type returnType, |
653 | bool isVarArg) { |
654 | if (mlir::isa_and_nonnull<cir::VoidType>(returnType)) |
655 | return emitError() |
656 | << "!cir.func cannot have an explicit 'void' return type" ; |
657 | return mlir::success(); |
658 | } |
659 | |
660 | //===----------------------------------------------------------------------===// |
661 | // BoolType |
662 | //===----------------------------------------------------------------------===// |
663 | |
664 | llvm::TypeSize |
665 | BoolType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout, |
666 | ::mlir::DataLayoutEntryListRef params) const { |
667 | return llvm::TypeSize::getFixed(8); |
668 | } |
669 | |
670 | uint64_t |
671 | BoolType::getABIAlignment(const ::mlir::DataLayout &dataLayout, |
672 | ::mlir::DataLayoutEntryListRef params) const { |
673 | return 1; |
674 | } |
675 | |
676 | //===----------------------------------------------------------------------===// |
677 | // ArrayType Definitions |
678 | //===----------------------------------------------------------------------===// |
679 | |
680 | llvm::TypeSize |
681 | ArrayType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout, |
682 | ::mlir::DataLayoutEntryListRef params) const { |
683 | return getSize() * dataLayout.getTypeSizeInBits(getElementType()); |
684 | } |
685 | |
686 | uint64_t |
687 | ArrayType::getABIAlignment(const ::mlir::DataLayout &dataLayout, |
688 | ::mlir::DataLayoutEntryListRef params) const { |
689 | return dataLayout.getTypeABIAlignment(getElementType()); |
690 | } |
691 | |
692 | //===----------------------------------------------------------------------===// |
693 | // VectorType Definitions |
694 | //===----------------------------------------------------------------------===// |
695 | |
696 | llvm::TypeSize cir::VectorType::getTypeSizeInBits( |
697 | const ::mlir::DataLayout &dataLayout, |
698 | ::mlir::DataLayoutEntryListRef params) const { |
699 | return llvm::TypeSize::getFixed( |
700 | getSize() * dataLayout.getTypeSizeInBits(getElementType())); |
701 | } |
702 | |
703 | uint64_t |
704 | cir::VectorType::getABIAlignment(const ::mlir::DataLayout &dataLayout, |
705 | ::mlir::DataLayoutEntryListRef params) const { |
706 | return llvm::NextPowerOf2(dataLayout.getTypeSizeInBits(*this)); |
707 | } |
708 | |
709 | mlir::LogicalResult cir::VectorType::verify( |
710 | llvm::function_ref<mlir::InFlightDiagnostic()> emitError, |
711 | mlir::Type elementType, uint64_t size) { |
712 | if (size == 0) |
713 | return emitError() << "the number of vector elements must be non-zero" ; |
714 | return success(); |
715 | } |
716 | |
717 | //===----------------------------------------------------------------------===// |
718 | // PointerType Definitions |
719 | //===----------------------------------------------------------------------===// |
720 | |
721 | llvm::TypeSize |
722 | PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout, |
723 | ::mlir::DataLayoutEntryListRef params) const { |
724 | // FIXME: improve this in face of address spaces |
725 | return llvm::TypeSize::getFixed(64); |
726 | } |
727 | |
728 | uint64_t |
729 | PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout, |
730 | ::mlir::DataLayoutEntryListRef params) const { |
731 | // FIXME: improve this in face of address spaces |
732 | return 8; |
733 | } |
734 | |
735 | mlir::LogicalResult |
736 | PointerType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError, |
737 | mlir::Type pointee) { |
738 | // TODO(CIR): Verification of the address space goes here. |
739 | return mlir::success(); |
740 | } |
741 | |
742 | //===----------------------------------------------------------------------===// |
743 | // CIR Dialect |
744 | //===----------------------------------------------------------------------===// |
745 | |
746 | void CIRDialect::registerTypes() { |
747 | // Register tablegen'd types. |
748 | addTypes< |
749 | #define GET_TYPEDEF_LIST |
750 | #include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc" |
751 | >(); |
752 | |
753 | // Register raw C++ types. |
754 | // TODO(CIR) addTypes<RecordType>(); |
755 | } |
756 | |