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