clang 23.0.0git
CIRTypes.cpp
Go to the documentation of this file.
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
14
15#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h"
16#include "mlir/IR/BuiltinAttributes.h"
17#include "mlir/IR/DialectImplementation.h"
18#include "mlir/IR/MLIRContext.h"
19#include "mlir/Support/LLVM.h"
26#include "llvm/ADT/APInt.h"
27#include "llvm/ADT/APSInt.h"
28#include "llvm/ADT/TypeSwitch.h"
29
30//===----------------------------------------------------------------------===//
31// CIR Helpers
32//===----------------------------------------------------------------------===//
33bool cir::isSized(mlir::Type ty) {
34 if (auto sizedTy = mlir::dyn_cast<cir::SizedTypeInterface>(ty))
35 return sizedTy.isSized();
37 return false;
38}
39
40//===----------------------------------------------------------------------===//
41// CIR Custom Parser/Printer Signatures
42//===----------------------------------------------------------------------===//
43
44static mlir::ParseResult
45parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> &params,
46 bool &isVarArg);
47static void printFuncTypeParams(mlir::AsmPrinter &p,
48 mlir::ArrayRef<mlir::Type> params,
49 bool isVarArg);
50//===----------------------------------------------------------------------===//
51// CIR Custom Parser/Printer Signatures
52//===----------------------------------------------------------------------===//
53
54static mlir::ParseResult
55parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> &params,
56 bool &isVarArg);
57
58static void printFuncTypeParams(mlir::AsmPrinter &p,
59 mlir::ArrayRef<mlir::Type> params,
60 bool isVarArg);
61
62//===----------------------------------------------------------------------===//
63// AddressSpace
64//===----------------------------------------------------------------------===//
65
66mlir::ParseResult
67parseAddressSpaceValue(mlir::AsmParser &p,
68 mlir::ptr::MemorySpaceAttrInterface &attr);
69
70void printAddressSpaceValue(mlir::AsmPrinter &printer,
71 mlir::ptr::MemorySpaceAttrInterface attr);
72
73// Custom parser/printer for the `addrSpace` parameter in `!cir.ptr`.
74mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p,
75 cir::TargetAddressSpaceAttr &attr);
76
77void printTargetAddressSpace(mlir::AsmPrinter &p,
78 cir::TargetAddressSpaceAttr attr);
79
80//===----------------------------------------------------------------------===//
81// Get autogenerated stuff
82//===----------------------------------------------------------------------===//
83
84namespace cir {
85
86#include "clang/CIR/Dialect/IR/CIRTypeConstraints.cpp.inc"
87
88} // namespace cir
89
90#define GET_TYPEDEF_CLASSES
91#include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc"
92
93using namespace mlir;
94using namespace cir;
95
96//===----------------------------------------------------------------------===//
97// General CIR parsing / printing
98//===----------------------------------------------------------------------===//
99
100Type CIRDialect::parseType(DialectAsmParser &parser) const {
101 llvm::SMLoc typeLoc = parser.getCurrentLocation();
102 llvm::StringRef mnemonic;
103 Type genType;
104
105 // Try to parse as a tablegen'd type.
106 OptionalParseResult parseResult =
107 generatedTypeParser(parser, &mnemonic, genType);
108 if (parseResult.has_value())
109 return genType;
110
111 // Type is not tablegen'd: try to parse as a raw C++ type.
112 return StringSwitch<function_ref<Type()>>(mnemonic)
113 .Case("record", [&] { return RecordType::parse(parser); })
114 .Default([&] {
115 parser.emitError(typeLoc) << "unknown CIR type: " << mnemonic;
116 return Type();
117 })();
118}
119
120void CIRDialect::printType(Type type, DialectAsmPrinter &os) const {
121 // Try to print as a tablegen'd type.
122 if (generatedTypePrinter(type, os).succeeded())
123 return;
124
125 // TODO(CIR) Attempt to print as a raw C++ type.
126 llvm::report_fatal_error("printer is missing a handler for this type");
127}
128
129//===----------------------------------------------------------------------===//
130// RecordType Definitions
131//===----------------------------------------------------------------------===//
132
133Type RecordType::parse(mlir::AsmParser &parser) {
134 FailureOr<AsmParser::CyclicParseReset> cyclicParseGuard;
135 const llvm::SMLoc loc = parser.getCurrentLocation();
136 const mlir::Location eLoc = parser.getEncodedSourceLoc(loc);
137 bool packed = false;
138 bool padded = false;
139 RecordKind kind;
140 mlir::MLIRContext *context = parser.getContext();
141
142 if (parser.parseLess())
143 return {};
144
145 // TODO(cir): in the future we should probably separate types for different
146 // source language declarations such as cir.record and cir.union
147 if (parser.parseOptionalKeyword("struct").succeeded())
148 kind = RecordKind::Struct;
149 else if (parser.parseOptionalKeyword("union").succeeded())
150 kind = RecordKind::Union;
151 else if (parser.parseOptionalKeyword("class").succeeded())
152 kind = RecordKind::Class;
153 else {
154 parser.emitError(loc, "unknown record type");
155 return {};
156 }
157
158 mlir::StringAttr name;
159 parser.parseOptionalAttribute(name);
160
161 // Is a self reference: ensure referenced type was parsed.
162 if (name && parser.parseOptionalGreater().succeeded()) {
163 RecordType type = getChecked(eLoc, context, name, kind);
164 if (succeeded(parser.tryStartCyclicParse(type))) {
165 parser.emitError(loc, "invalid self-reference within record");
166 return {};
167 }
168 return type;
169 }
170
171 // Is a named record definition: ensure name has not been parsed yet.
172 if (name) {
173 RecordType type = getChecked(eLoc, context, name, kind);
174 cyclicParseGuard = parser.tryStartCyclicParse(type);
175 if (failed(cyclicParseGuard)) {
176 parser.emitError(loc, "record already defined");
177 return {};
178 }
179 }
180
181 if (parser.parseOptionalKeyword("packed").succeeded())
182 packed = true;
183
184 if (parser.parseOptionalKeyword("padded").succeeded())
185 padded = true;
186
187 // Parse record members or lack thereof.
188 bool incomplete = true;
189 llvm::SmallVector<mlir::Type> members;
190 if (parser.parseOptionalKeyword("incomplete").failed()) {
191 incomplete = false;
192 const auto delimiter = AsmParser::Delimiter::Braces;
193 const auto parseElementFn = [&parser, &members]() {
194 return parser.parseType(members.emplace_back());
195 };
196 if (parser.parseCommaSeparatedList(delimiter, parseElementFn).failed())
197 return {};
198 }
199
200 if (parser.parseGreater())
201 return {};
202
203 // Try to create the proper record type.
204 ArrayRef<mlir::Type> membersRef(members); // Needed for template deduction.
205 mlir::Type type = {};
206 if (name && incomplete) { // Identified & incomplete
207 type = getChecked(eLoc, context, name, kind);
208 } else if (!name && !incomplete) { // Anonymous & complete
209 type = getChecked(eLoc, context, membersRef, packed, padded, kind);
210 } else if (!incomplete) { // Identified & complete
211 type = getChecked(eLoc, context, membersRef, name, packed, padded, kind);
212 // If the record has a self-reference, its type already exists in a
213 // incomplete state. In this case, we must complete it.
214 if (mlir::cast<RecordType>(type).isIncomplete())
215 mlir::cast<RecordType>(type).complete(membersRef, packed, padded);
217 } else { // anonymous & incomplete
218 parser.emitError(loc, "anonymous records must be complete");
219 return {};
220 }
221
222 return type;
223}
224
225void RecordType::print(mlir::AsmPrinter &printer) const {
226 FailureOr<AsmPrinter::CyclicPrintReset> cyclicPrintGuard;
227 printer << '<';
228
229 switch (getKind()) {
230 case RecordKind::Struct:
231 printer << "struct ";
232 break;
233 case RecordKind::Union:
234 printer << "union ";
235 break;
236 case RecordKind::Class:
237 printer << "class ";
238 break;
239 }
240
241 if (getName())
242 printer << getName();
243
244 // Current type has already been printed: print as self reference.
245 cyclicPrintGuard = printer.tryStartCyclicPrint(*this);
246 if (failed(cyclicPrintGuard)) {
247 printer << '>';
248 return;
249 }
250
251 // Type not yet printed: continue printing the entire record.
252 printer << ' ';
253
254 if (getPacked())
255 printer << "packed ";
256
257 if (getPadded())
258 printer << "padded ";
259
260 if (isIncomplete()) {
261 printer << "incomplete";
262 } else {
263 printer << "{";
264 llvm::interleaveComma(getMembers(), printer);
265 printer << "}";
266 }
267
268 printer << '>';
269}
270
271mlir::LogicalResult
272RecordType::verify(function_ref<mlir::InFlightDiagnostic()> emitError,
273 llvm::ArrayRef<mlir::Type> members, mlir::StringAttr name,
274 bool incomplete, bool packed, bool padded,
275 RecordType::RecordKind kind) {
276 if (name && name.getValue().empty())
277 return emitError() << "identified records cannot have an empty name";
278 return mlir::success();
279}
280
281::llvm::ArrayRef<mlir::Type> RecordType::getMembers() const {
282 return getImpl()->members;
283}
284
285bool RecordType::isIncomplete() const { return getImpl()->incomplete; }
286
287mlir::StringAttr RecordType::getName() const { return getImpl()->name; }
288
289bool RecordType::getIncomplete() const { return getImpl()->incomplete; }
290
291bool RecordType::getPacked() const { return getImpl()->packed; }
292
293bool RecordType::getPadded() const { return getImpl()->padded; }
294
295cir::RecordType::RecordKind RecordType::getKind() const {
296 return getImpl()->kind;
297}
298
299void RecordType::complete(ArrayRef<Type> members, bool packed, bool padded) {
301 if (mutate(members, packed, padded).failed())
302 llvm_unreachable("failed to complete record");
303}
304
305/// Return the largest member of in the type.
306///
307/// Recurses into union members never returning a union as the largest member.
308Type RecordType::getLargestMember(const ::mlir::DataLayout &dataLayout) const {
309 assert(isUnion() && "Only call getLargestMember on unions");
310 llvm::ArrayRef<Type> members = getMembers();
311 if (members.empty())
312 return {};
313
314 // If the union is padded, we need to ignore the last member,
315 // which is the padding.
316 auto endIt = getPadded() ? std::prev(members.end()) : members.end();
317 if (endIt == members.begin())
318 return {};
319 return *std::max_element(
320 members.begin(), endIt, [&](Type lhs, Type rhs) {
321 return dataLayout.getTypeABIAlignment(lhs) <
322 dataLayout.getTypeABIAlignment(rhs) ||
323 (dataLayout.getTypeABIAlignment(lhs) ==
324 dataLayout.getTypeABIAlignment(rhs) &&
325 dataLayout.getTypeSize(lhs) < dataLayout.getTypeSize(rhs));
326 });
327}
328
329bool RecordType::isLayoutIdentical(const RecordType &other) {
330 if (getImpl() == other.getImpl())
331 return true;
332
333 if (getPacked() != other.getPacked())
334 return false;
335
336 return getMembers() == other.getMembers();
337}
338
339//===----------------------------------------------------------------------===//
340// Data Layout information for types
341//===----------------------------------------------------------------------===//
342
343llvm::TypeSize
344PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
345 ::mlir::DataLayoutEntryListRef params) const {
346 // FIXME: improve this in face of address spaces
348 return llvm::TypeSize::getFixed(64);
349}
350
352PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
353 ::mlir::DataLayoutEntryListRef params) const {
354 // FIXME: improve this in face of address spaces
356 return 8;
357}
358
359llvm::TypeSize
360RecordType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
361 mlir::DataLayoutEntryListRef params) const {
362 if (isUnion())
363 return dataLayout.getTypeSize(getLargestMember(dataLayout));
364
365 auto recordSize = static_cast<uint64_t>(computeStructSize(dataLayout));
366 return llvm::TypeSize::getFixed(recordSize * 8);
367}
368
370RecordType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
371 ::mlir::DataLayoutEntryListRef params) const {
372 if (isUnion())
373 return dataLayout.getTypeABIAlignment(getLargestMember(dataLayout));
374
375 // Packed structures always have an ABI alignment of 1.
376 if (getPacked())
377 return 1;
378 return computeStructAlignment(dataLayout);
379}
380
381unsigned
382RecordType::computeStructSize(const mlir::DataLayout &dataLayout) const {
383 assert(isComplete() && "Cannot get layout of incomplete records");
384
385 // This is a similar algorithm to LLVM's StructLayout.
386 unsigned recordSize = 0;
387 uint64_t recordAlignment = 1;
388
389 for (mlir::Type ty : getMembers()) {
390 // This assumes that we're calculating size based on the ABI alignment, not
391 // the preferred alignment for each type.
392 const uint64_t tyAlign =
393 (getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty));
394
395 // Add padding to the struct size to align it to the abi alignment of the
396 // element type before than adding the size of the element.
397 recordSize = llvm::alignTo(recordSize, tyAlign);
398 recordSize += dataLayout.getTypeSize(ty);
399
400 // The alignment requirement of a struct is equal to the strictest alignment
401 // requirement of its elements.
402 recordAlignment = std::max(tyAlign, recordAlignment);
403 }
404
405 // At the end, add padding to the struct to satisfy its own alignment
406 // requirement. Otherwise structs inside of arrays would be misaligned.
407 recordSize = llvm::alignTo(recordSize, recordAlignment);
408 return recordSize;
409}
410
411// We also compute the alignment as part of computeStructSize, but this is more
412// efficient. Ideally, we'd like to compute both at once and cache the result,
413// but that's implemented yet.
414// TODO(CIR): Implement a way to cache the result.
416RecordType::computeStructAlignment(const mlir::DataLayout &dataLayout) const {
417 assert(isComplete() && "Cannot get layout of incomplete records");
418
419 // This is a similar algorithm to LLVM's StructLayout.
420 uint64_t recordAlignment = 1;
421 for (mlir::Type ty : getMembers())
422 recordAlignment =
423 std::max(dataLayout.getTypeABIAlignment(ty), recordAlignment);
424
425 return recordAlignment;
426}
427
428uint64_t RecordType::getElementOffset(const ::mlir::DataLayout &dataLayout,
429 unsigned idx) const {
430 assert(idx < getMembers().size() && "access not valid");
431
432 // All union elements are at offset zero.
433 if (isUnion() || idx == 0)
434 return 0;
435
436 assert(isComplete() && "Cannot get layout of incomplete records");
437 assert(idx < getNumElements());
438 llvm::ArrayRef<mlir::Type> members = getMembers();
439
440 unsigned offset = 0;
441
442 for (mlir::Type ty :
443 llvm::make_range(members.begin(), std::next(members.begin(), idx))) {
444 // This matches LLVM since it uses the ABI instead of preferred alignment.
445 const llvm::Align tyAlign =
446 llvm::Align(getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty));
447
448 // Add padding if necessary to align the data element properly.
449 offset = llvm::alignTo(offset, tyAlign);
450
451 // Consume space for this data item
452 offset += dataLayout.getTypeSize(ty);
453 }
454
455 // Account for padding, if necessary, for the alignment of the field whose
456 // offset we are calculating.
457 const llvm::Align tyAlign = llvm::Align(
458 getPacked() ? 1 : dataLayout.getTypeABIAlignment(members[idx]));
459 offset = llvm::alignTo(offset, tyAlign);
460
461 return offset;
462}
463
464//===----------------------------------------------------------------------===//
465// IntType Definitions
466//===----------------------------------------------------------------------===//
467
468Type IntType::parse(mlir::AsmParser &parser) {
469 mlir::MLIRContext *context = parser.getBuilder().getContext();
470 llvm::SMLoc loc = parser.getCurrentLocation();
471 bool isSigned;
472 unsigned width;
473
474 if (parser.parseLess())
475 return {};
476
477 // Fetch integer sign.
478 llvm::StringRef sign;
479 if (parser.parseKeyword(&sign))
480 return {};
481 if (sign == "s")
482 isSigned = true;
483 else if (sign == "u")
484 isSigned = false;
485 else {
486 parser.emitError(loc, "expected 's' or 'u'");
487 return {};
488 }
489
490 if (parser.parseComma())
491 return {};
492
493 // Fetch integer size.
494 if (parser.parseInteger(width))
495 return {};
496 if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) {
497 parser.emitError(loc, "expected integer width to be from ")
498 << IntType::minBitwidth() << " up to " << IntType::maxBitwidth();
499 return {};
500 }
501
502 if (parser.parseGreater())
503 return {};
504
505 return IntType::get(context, width, isSigned);
506}
507
508void IntType::print(mlir::AsmPrinter &printer) const {
509 char sign = isSigned() ? 's' : 'u';
510 printer << '<' << sign << ", " << getWidth() << '>';
511}
512
513llvm::TypeSize
514IntType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
515 mlir::DataLayoutEntryListRef params) const {
516 return llvm::TypeSize::getFixed(getWidth());
517}
518
519uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout,
520 mlir::DataLayoutEntryListRef params) const {
521 return (uint64_t)(getWidth() / 8);
522}
523
524mlir::LogicalResult
525IntType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
526 unsigned width, bool isSigned) {
527 if (width < IntType::minBitwidth() || width > IntType::maxBitwidth())
528 return emitError() << "IntType only supports widths from "
529 << IntType::minBitwidth() << " up to "
530 << IntType::maxBitwidth();
531 return mlir::success();
532}
533
535 return width == 8 || width == 16 || width == 32 || width == 64;
536}
537
538//===----------------------------------------------------------------------===//
539// Floating-point type definitions
540//===----------------------------------------------------------------------===//
541
542const llvm::fltSemantics &SingleType::getFloatSemantics() const {
543 return llvm::APFloat::IEEEsingle();
544}
545
546llvm::TypeSize
547SingleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
548 mlir::DataLayoutEntryListRef params) const {
549 return llvm::TypeSize::getFixed(getWidth());
550}
551
553SingleType::getABIAlignment(const mlir::DataLayout &dataLayout,
554 mlir::DataLayoutEntryListRef params) const {
555 return (uint64_t)(getWidth() / 8);
556}
557
558const llvm::fltSemantics &DoubleType::getFloatSemantics() const {
559 return llvm::APFloat::IEEEdouble();
560}
561
562llvm::TypeSize
563DoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
564 mlir::DataLayoutEntryListRef params) const {
565 return llvm::TypeSize::getFixed(getWidth());
566}
567
569DoubleType::getABIAlignment(const mlir::DataLayout &dataLayout,
570 mlir::DataLayoutEntryListRef params) const {
571 return (uint64_t)(getWidth() / 8);
572}
573
574const llvm::fltSemantics &FP16Type::getFloatSemantics() const {
575 return llvm::APFloat::IEEEhalf();
576}
577
578llvm::TypeSize
579FP16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
580 mlir::DataLayoutEntryListRef params) const {
581 return llvm::TypeSize::getFixed(getWidth());
582}
583
584uint64_t FP16Type::getABIAlignment(const mlir::DataLayout &dataLayout,
585 mlir::DataLayoutEntryListRef params) const {
586 return (uint64_t)(getWidth() / 8);
587}
588
589const llvm::fltSemantics &BF16Type::getFloatSemantics() const {
590 return llvm::APFloat::BFloat();
591}
592
593llvm::TypeSize
594BF16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
595 mlir::DataLayoutEntryListRef params) const {
596 return llvm::TypeSize::getFixed(getWidth());
597}
598
599uint64_t BF16Type::getABIAlignment(const mlir::DataLayout &dataLayout,
600 mlir::DataLayoutEntryListRef params) const {
601 return (uint64_t)(getWidth() / 8);
602}
603
604const llvm::fltSemantics &FP80Type::getFloatSemantics() const {
605 return llvm::APFloat::x87DoubleExtended();
606}
607
608llvm::TypeSize
609FP80Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
610 mlir::DataLayoutEntryListRef params) const {
611 // Though only 80 bits are used for the value, the type is 128 bits in size.
612 return llvm::TypeSize::getFixed(128);
613}
614
615uint64_t FP80Type::getABIAlignment(const mlir::DataLayout &dataLayout,
616 mlir::DataLayoutEntryListRef params) const {
617 return 16;
618}
619
620const llvm::fltSemantics &FP128Type::getFloatSemantics() const {
621 return llvm::APFloat::IEEEquad();
622}
623
624llvm::TypeSize
625FP128Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
626 mlir::DataLayoutEntryListRef params) const {
627 return llvm::TypeSize::getFixed(getWidth());
628}
629
630uint64_t FP128Type::getABIAlignment(const mlir::DataLayout &dataLayout,
631 mlir::DataLayoutEntryListRef params) const {
632 return 16;
633}
634
635const llvm::fltSemantics &LongDoubleType::getFloatSemantics() const {
636 return mlir::cast<cir::FPTypeInterface>(getUnderlying()).getFloatSemantics();
637}
638
639llvm::TypeSize
640LongDoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
641 mlir::DataLayoutEntryListRef params) const {
642 return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying())
643 .getTypeSizeInBits(dataLayout, params);
644}
645
647LongDoubleType::getABIAlignment(const mlir::DataLayout &dataLayout,
648 mlir::DataLayoutEntryListRef params) const {
649 return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying())
650 .getABIAlignment(dataLayout, params);
651}
652
653//===----------------------------------------------------------------------===//
654// ComplexType Definitions
655//===----------------------------------------------------------------------===//
656
657llvm::TypeSize
658cir::ComplexType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
659 mlir::DataLayoutEntryListRef params) const {
660 // C17 6.2.5p13:
661 // Each complex type has the same representation and alignment requirements
662 // as an array type containing exactly two elements of the corresponding
663 // real type.
664
665 return dataLayout.getTypeSizeInBits(getElementType()) * 2;
666}
667
669cir::ComplexType::getABIAlignment(const mlir::DataLayout &dataLayout,
670 mlir::DataLayoutEntryListRef params) const {
671 // C17 6.2.5p13:
672 // Each complex type has the same representation and alignment requirements
673 // as an array type containing exactly two elements of the corresponding
674 // real type.
675
676 return dataLayout.getTypeABIAlignment(getElementType());
677}
678
679FuncType FuncType::clone(TypeRange inputs, TypeRange results) const {
680 assert(results.size() == 1 && "expected exactly one result type");
681 return get(llvm::to_vector(inputs), results[0], isVarArg());
682}
683
684// Custom parser that parses function parameters of form `(<type>*, ...)`.
685static mlir::ParseResult
687 bool &isVarArg) {
688 isVarArg = false;
689 return p.parseCommaSeparatedList(
690 AsmParser::Delimiter::Paren, [&]() -> mlir::ParseResult {
691 if (isVarArg)
692 return p.emitError(p.getCurrentLocation(),
693 "variadic `...` must be the last parameter");
694 if (succeeded(p.parseOptionalEllipsis())) {
695 isVarArg = true;
696 return success();
697 }
698 mlir::Type type;
699 if (failed(p.parseType(type)))
700 return failure();
701 params.push_back(type);
702 return success();
703 });
704}
705
706static void printFuncTypeParams(mlir::AsmPrinter &p,
707 mlir::ArrayRef<mlir::Type> params,
708 bool isVarArg) {
709 p << '(';
710 llvm::interleaveComma(params, p,
711 [&p](mlir::Type type) { p.printType(type); });
712 if (isVarArg) {
713 if (!params.empty())
714 p << ", ";
715 p << "...";
716 }
717 p << ')';
718}
719
720/// Get the C-style return type of the function, which is !cir.void if the
721/// function returns nothing and the actual return type otherwise.
722mlir::Type FuncType::getReturnType() const {
723 if (hasVoidReturn())
724 return cir::VoidType::get(getContext());
725 return getOptionalReturnType();
726}
727
728/// Get the MLIR-style return type of the function, which is an empty
729/// ArrayRef if the function returns nothing and a single-element ArrayRef
730/// with the actual return type otherwise.
731llvm::ArrayRef<mlir::Type> FuncType::getReturnTypes() const {
732 if (hasVoidReturn())
733 return {};
734 // Can't use getOptionalReturnType() here because llvm::ArrayRef hold a
735 // pointer to its elements and doesn't do lifetime extension. That would
736 // result in returning a pointer to a temporary that has gone out of scope.
737 return getImpl()->optionalReturnType;
738}
739
740// Does the fuction type return nothing?
741bool FuncType::hasVoidReturn() const { return !getOptionalReturnType(); }
742
743mlir::LogicalResult
744FuncType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
745 llvm::ArrayRef<mlir::Type> argTypes, mlir::Type returnType,
746 bool isVarArg) {
747 if (mlir::isa_and_nonnull<cir::VoidType>(returnType))
748 return emitError()
749 << "!cir.func cannot have an explicit 'void' return type";
750 return mlir::success();
751}
752
753//===----------------------------------------------------------------------===//
754// MethodType Definitions
755//===----------------------------------------------------------------------===//
756
757static mlir::Type getMethodLayoutType(mlir::MLIRContext *ctx) {
758 // With Itanium ABI, member function pointers have the same layout as the
759 // following struct: struct { fnptr_t, ptrdiff_t }, where fnptr_t is a
760 // function pointer type.
761 // TODO: consider member function pointer layout in other ABIs
762 auto voidPtrTy = cir::PointerType::get(cir::VoidType::get(ctx));
763 mlir::Type fields[2]{voidPtrTy, voidPtrTy};
764 return cir::RecordType::get(ctx, fields, /*packed=*/false,
765 /*padded=*/false, cir::RecordType::Struct);
766}
767
768llvm::TypeSize
769MethodType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
770 mlir::DataLayoutEntryListRef params) const {
771 return dataLayout.getTypeSizeInBits(getMethodLayoutType(getContext()));
772}
773
775MethodType::getABIAlignment(const mlir::DataLayout &dataLayout,
776 mlir::DataLayoutEntryListRef params) const {
777 return dataLayout.getTypeSizeInBits(getMethodLayoutType(getContext()));
778}
779
780//===----------------------------------------------------------------------===//
781// BoolType
782//===----------------------------------------------------------------------===//
783
784llvm::TypeSize
785BoolType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
786 ::mlir::DataLayoutEntryListRef params) const {
787 return llvm::TypeSize::getFixed(8);
788}
789
791BoolType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
792 ::mlir::DataLayoutEntryListRef params) const {
793 return 1;
794}
795
796//===----------------------------------------------------------------------===//
797// DataMemberType Definitions
798//===----------------------------------------------------------------------===//
799
800llvm::TypeSize
801DataMemberType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
802 ::mlir::DataLayoutEntryListRef params) const {
803 // FIXME: consider size differences under different ABIs
804 assert(!MissingFeatures::cxxABI());
805 return llvm::TypeSize::getFixed(64);
806}
807
809DataMemberType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
810 ::mlir::DataLayoutEntryListRef params) const {
811 // FIXME: consider alignment differences under different ABIs
812 assert(!MissingFeatures::cxxABI());
813 return 8;
814}
815
816//===----------------------------------------------------------------------===//
817// VPtrType Definitions
818//===----------------------------------------------------------------------===//
819
820llvm::TypeSize
821VPtrType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
822 mlir::DataLayoutEntryListRef params) const {
823 // FIXME: consider size differences under different ABIs
824 return llvm::TypeSize::getFixed(64);
825}
826
827uint64_t VPtrType::getABIAlignment(const mlir::DataLayout &dataLayout,
828 mlir::DataLayoutEntryListRef params) const {
829 // FIXME: consider alignment differences under different ABIs
830 return 8;
831}
832
833//===----------------------------------------------------------------------===//
834// ArrayType Definitions
835//===----------------------------------------------------------------------===//
836
837llvm::TypeSize
838ArrayType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
839 ::mlir::DataLayoutEntryListRef params) const {
840 return getSize() * dataLayout.getTypeSizeInBits(getElementType());
841}
842
844ArrayType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
845 ::mlir::DataLayoutEntryListRef params) const {
846 return dataLayout.getTypeABIAlignment(getElementType());
847}
848
849//===----------------------------------------------------------------------===//
850// VectorType Definitions
851//===----------------------------------------------------------------------===//
852
853llvm::TypeSize cir::VectorType::getTypeSizeInBits(
854 const ::mlir::DataLayout &dataLayout,
855 ::mlir::DataLayoutEntryListRef params) const {
856 return llvm::TypeSize::getFixed(
857 getSize() * dataLayout.getTypeSizeInBits(getElementType()));
858}
859
861cir::VectorType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
862 ::mlir::DataLayoutEntryListRef params) const {
863 return llvm::NextPowerOf2(dataLayout.getTypeSizeInBits(*this));
864}
865
866mlir::LogicalResult cir::VectorType::verify(
867 llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
868 mlir::Type elementType, uint64_t size, bool scalable) {
869 if (size == 0)
870 return emitError() << "the number of vector elements must be non-zero";
871 return success();
872}
873
874mlir::Type cir::VectorType::parse(::mlir::AsmParser &odsParser) {
875
876 llvm::SMLoc odsLoc = odsParser.getCurrentLocation();
877 mlir::Builder odsBuilder(odsParser.getContext());
878 mlir::FailureOr<::mlir::Type> elementType;
879 mlir::FailureOr<uint64_t> size;
880 bool isScalabe = false;
881
882 // Parse literal '<'
883 if (odsParser.parseLess())
884 return {};
885
886 // Parse literal '[', if present, and set the scalability flag accordingly
887 if (odsParser.parseOptionalLSquare().succeeded())
888 isScalabe = true;
889
890 // Parse variable 'size'
891 size = mlir::FieldParser<uint64_t>::parse(odsParser);
892 if (mlir::failed(size)) {
893 odsParser.emitError(odsParser.getCurrentLocation(),
894 "failed to parse CIR_VectorType parameter 'size' which "
895 "is to be a `uint64_t`");
896 return {};
897 }
898
899 // Parse literal ']', which is expected when dealing with scalable
900 // dim sizes
901 if (isScalabe && odsParser.parseRSquare().failed()) {
902 odsParser.emitError(odsParser.getCurrentLocation(),
903 "missing closing `]` for scalable dim size");
904 return {};
905 }
906
907 // Parse literal 'x'
908 if (odsParser.parseKeyword("x"))
909 return {};
910
911 // Parse variable 'elementType'
912 elementType = mlir::FieldParser<::mlir::Type>::parse(odsParser);
913 if (mlir::failed(elementType)) {
914 odsParser.emitError(odsParser.getCurrentLocation(),
915 "failed to parse CIR_VectorType parameter "
916 "'elementType' which is to be a `mlir::Type`");
917 return {};
918 }
919
920 // Parse literal '>'
921 if (odsParser.parseGreater())
922 return {};
923 return odsParser.getChecked<VectorType>(odsLoc, odsParser.getContext(),
924 mlir::Type((*elementType)),
925 uint64_t((*size)), isScalabe);
926}
927
928void cir::VectorType::print(mlir::AsmPrinter &odsPrinter) const {
929 mlir::Builder odsBuilder(getContext());
930 odsPrinter << "<";
931 if (this->getIsScalable())
932 odsPrinter << "[";
933
934 odsPrinter.printStrippedAttrOrType(getSize());
935 if (this->getIsScalable())
936 odsPrinter << "]";
937 odsPrinter << ' ' << "x";
938 odsPrinter << ' ';
939 odsPrinter.printStrippedAttrOrType(getElementType());
940 odsPrinter << ">";
941}
942
943//===----------------------------------------------------------------------===//
944// AddressSpace definitions
945//===----------------------------------------------------------------------===//
946
948 mlir::ptr::MemorySpaceAttrInterface memorySpace) {
949 return mlir::isa<cir::LangAddressSpaceAttr, cir::TargetAddressSpaceAttr>(
950 memorySpace);
951}
952
953cir::LangAddressSpace cir::toCIRLangAddressSpace(clang::LangAS langAS) {
954 using clang::LangAS;
955 switch (langAS) {
956 case LangAS::Default:
957 return LangAddressSpace::Default;
958 case LangAS::opencl_global:
959 return LangAddressSpace::OffloadGlobal;
960 case LangAS::opencl_local:
961 case LangAS::cuda_shared:
962 // Local means local among the work-group (OpenCL) or block (CUDA).
963 // All threads inside the kernel can access local memory.
964 return LangAddressSpace::OffloadLocal;
965 case LangAS::cuda_device:
966 return LangAddressSpace::OffloadGlobal;
967 case LangAS::opencl_constant:
968 case LangAS::cuda_constant:
969 return LangAddressSpace::OffloadConstant;
970 case LangAS::opencl_private:
971 return LangAddressSpace::OffloadPrivate;
972 case LangAS::opencl_generic:
973 return LangAddressSpace::OffloadGeneric;
974 case LangAS::opencl_global_device:
975 case LangAS::opencl_global_host:
976 case LangAS::sycl_global:
977 case LangAS::sycl_global_device:
978 case LangAS::sycl_global_host:
979 case LangAS::sycl_local:
980 case LangAS::sycl_private:
981 case LangAS::ptr32_sptr:
982 case LangAS::ptr32_uptr:
983 case LangAS::ptr64:
984 case LangAS::hlsl_groupshared:
985 case LangAS::wasm_funcref:
986 llvm_unreachable("NYI");
987 default:
988 llvm_unreachable("unknown/unsupported clang language address space");
989 }
990}
991
992mlir::ParseResult
993parseAddressSpaceValue(mlir::AsmParser &p,
994 mlir::ptr::MemorySpaceAttrInterface &attr) {
995
996 llvm::SMLoc loc = p.getCurrentLocation();
997
998 // Try to parse target address space first.
999 attr = nullptr;
1000 if (p.parseOptionalKeyword("target_address_space").succeeded()) {
1001 unsigned val;
1002 if (p.parseLParen())
1003 return p.emitError(loc, "expected '(' after 'target_address_space'");
1004
1005 if (p.parseInteger(val))
1006 return p.emitError(loc, "expected target address space value");
1007
1008 if (p.parseRParen())
1009 return p.emitError(loc, "expected ')'");
1010
1011 attr = cir::TargetAddressSpaceAttr::get(p.getContext(), val);
1012 return mlir::success();
1013 }
1014
1015 // Try to parse language specific address space.
1016 if (p.parseOptionalKeyword("lang_address_space").succeeded()) {
1017 if (p.parseLParen())
1018 return p.emitError(loc, "expected '(' after 'lang_address_space'");
1019
1020 mlir::FailureOr<cir::LangAddressSpace> result =
1021 mlir::FieldParser<cir::LangAddressSpace>::parse(p);
1022 if (mlir::failed(result))
1023 return mlir::failure();
1024
1025 if (p.parseRParen())
1026 return p.emitError(loc, "expected ')'");
1027
1028 attr = cir::LangAddressSpaceAttr::get(p.getContext(), result.value());
1029 return mlir::success();
1030 }
1031
1032 llvm::StringRef keyword;
1033 if (p.parseOptionalKeyword(&keyword).succeeded())
1034 return p.emitError(loc, "unknown address space specifier '")
1035 << keyword << "'; expected 'target_address_space' or "
1036 << "'lang_address_space'";
1037
1038 return mlir::success();
1039}
1040
1041void printAddressSpaceValue(mlir::AsmPrinter &p,
1042 mlir::ptr::MemorySpaceAttrInterface attr) {
1043 if (!attr)
1044 return;
1045
1046 if (auto language = dyn_cast<cir::LangAddressSpaceAttr>(attr)) {
1047 p << "lang_address_space("
1048 << cir::stringifyLangAddressSpace(language.getValue()) << ')';
1049 return;
1050 }
1051
1052 if (auto target = dyn_cast<cir::TargetAddressSpaceAttr>(attr)) {
1053 p << "target_address_space(" << target.getValue() << ')';
1054 return;
1055 }
1056
1057 llvm_unreachable("unexpected address-space attribute kind");
1058}
1059
1060mlir::ptr::MemorySpaceAttrInterface cir::normalizeDefaultAddressSpace(
1061 mlir::ptr::MemorySpaceAttrInterface addrSpace) {
1062 if (auto langAS =
1063 mlir::dyn_cast_if_present<cir::LangAddressSpaceAttr>(addrSpace))
1064 if (langAS.getValue() == cir::LangAddressSpace::Default)
1065 return {};
1066 return addrSpace;
1067}
1068
1069mlir::ptr::MemorySpaceAttrInterface
1070cir::toCIRAddressSpaceAttr(mlir::MLIRContext &ctx, clang::LangAS langAS) {
1071 using clang::LangAS;
1072
1073 if (langAS == LangAS::Default)
1074 return cir::LangAddressSpaceAttr::get(&ctx, cir::LangAddressSpace::Default);
1075
1076 if (clang::isTargetAddressSpace(langAS)) {
1077 unsigned targetAS = clang::toTargetAddressSpace(langAS);
1078 return cir::TargetAddressSpaceAttr::get(&ctx, targetAS);
1079 }
1080
1081 return cir::LangAddressSpaceAttr::get(&ctx, toCIRLangAddressSpace(langAS));
1082}
1083
1084bool cir::isMatchingAddressSpace(mlir::ptr::MemorySpaceAttrInterface cirAS,
1085 clang::LangAS as) {
1086 cirAS = normalizeDefaultAddressSpace(cirAS);
1087 if (!cirAS)
1088 return as == clang::LangAS::Default;
1089 mlir::ptr::MemorySpaceAttrInterface expected = normalizeDefaultAddressSpace(
1090 toCIRAddressSpaceAttr(*cirAS.getContext(), as));
1091 return expected == cirAS;
1092}
1093
1094//===----------------------------------------------------------------------===//
1095// PointerType Definitions
1096//===----------------------------------------------------------------------===//
1097
1098mlir::LogicalResult cir::PointerType::verify(
1099 llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
1100 mlir::Type pointee, mlir::ptr::MemorySpaceAttrInterface addrSpace) {
1101 if (addrSpace) {
1102 if (!isSupportedCIRMemorySpaceAttr(addrSpace)) {
1103 return emitError() << "unsupported address space attribute; expected "
1104 "'target_address_space' or 'lang_address_space'";
1105 }
1106 }
1107
1108 return success();
1109}
1110
1111//===----------------------------------------------------------------------===//
1112// CIR Dialect
1113//===----------------------------------------------------------------------===//
1114
1115void CIRDialect::registerTypes() {
1116 // Register tablegen'd types.
1117 addTypes<
1118#define GET_TYPEDEF_LIST
1119#include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc"
1120 >();
1121
1122 // Register raw C++ types.
1123 // TODO(CIR) addTypes<RecordType>();
1124}
Provides definitions for the various language-specific address spaces.
void printAddressSpaceValue(mlir::AsmPrinter &p, cir::LangAddressSpace addrSpace)
Definition CIRAttrs.cpp:62
mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p, cir::LangAddressSpace &addrSpace)
Definition CIRAttrs.cpp:51
void printAddressSpaceValue(mlir::AsmPrinter &printer, mlir::ptr::MemorySpaceAttrInterface attr)
mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p, cir::TargetAddressSpaceAttr &attr)
mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p, mlir::ptr::MemorySpaceAttrInterface &attr)
Definition CIRTypes.cpp:993
static mlir::ParseResult parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector< mlir::Type > &params, bool &isVarArg)
Definition CIRTypes.cpp:686
static mlir::Type getMethodLayoutType(mlir::MLIRContext *ctx)
Definition CIRTypes.cpp:757
static void printFuncTypeParams(mlir::AsmPrinter &p, mlir::ArrayRef< mlir::Type > params, bool isVarArg)
Definition CIRTypes.cpp:706
void printTargetAddressSpace(mlir::AsmPrinter &p, cir::TargetAddressSpaceAttr attr)
static Decl::Kind getKind(const Decl *D)
static LiveVariablesImpl & getImpl(void *x)
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
bool isMatchingAddressSpace(mlir::ptr::MemorySpaceAttrInterface cirAS, clang::LangAS as)
cir::LangAddressSpace toCIRLangAddressSpace(clang::LangAS langAS)
Definition CIRTypes.cpp:953
bool isValidFundamentalIntWidth(unsigned width)
Definition CIRTypes.cpp:534
mlir::ptr::MemorySpaceAttrInterface toCIRAddressSpaceAttr(mlir::MLIRContext &ctx, clang::LangAS langAS)
Convert an AST LangAS to the appropriate CIR address space attribute interface.
mlir::ptr::MemorySpaceAttrInterface normalizeDefaultAddressSpace(mlir::ptr::MemorySpaceAttrInterface addrSpace)
Normalize LangAddressSpace::Default to null (empty attribute).
bool isSized(mlir::Type ty)
Returns true if the type is a CIR sized type.
Definition CIRTypes.cpp:33
bool isSupportedCIRMemorySpaceAttr(mlir::ptr::MemorySpaceAttrInterface memorySpace)
Definition CIRTypes.cpp:947
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
StringRef getName(const HeaderType T)
Definition HeaderFile.h:38
RangeSelector name(std::string ID)
Given a node with a "name", (like NamedDecl, DeclRefExpr, CxxCtorInitializer, and TypeLoc) selects th...
bool isTargetAddressSpace(LangAS AS)
unsigned toTargetAddressSpace(LangAS AS)
LangAS
Defines the address space values used by the address space qualifier of QualType.
unsigned long uint64_t
float __ovld __cnfn sign(float)
Returns 1.0 if x > 0, -0.0 if x = -0.0, +0.0 if x = +0.0, or -1.0 if x < 0.
static bool unsizedTypes()
static bool dataLayoutPtrHandlingBasedOnLangAS()
static bool astRecordDeclAttr()