23#include "llvm/ADT/TypeSwitch.h"
24#include "llvm/Support/TypeSize.h"
53 params.push_back(type);
61 params.push_back(type);
68 llvm::interleaveComma(params, p,
93 auto typeOrIntParser = [&]() -> ParseResult {
96 if (intResult.has_value() && !failed(*intResult)) {
98 intParams.push_back(i);
108 typeParams.push_back(t);
116 "failed to parse parameter list for target extension type");
125 if (!typeParams.empty() && !intParams.empty())
142#include "mlir/Dialect/LLVMIR/LLVMTypeInterfaces.cpp.inc"
144#define GET_TYPEDEF_CLASSES
145#include "mlir/Dialect/LLVMIR/LLVMTypes.cpp.inc"
151bool LLVMArrayType::isValidElementType(
Type type) {
152 return !llvm::isa<LLVMVoidType, LLVMLabelType, LLVMMetadataType,
153 LLVMFunctionType, LLVMTokenType>(type);
156LLVMArrayType LLVMArrayType::get(
Type elementType, uint64_t numElements) {
157 assert(elementType &&
"expected non-null subtype");
158 return Base::get(elementType.
getContext(), elementType, numElements);
163 Type elementType, uint64_t numElements) {
164 assert(elementType &&
"expected non-null subtype");
171 Type elementType, uint64_t numElements) {
172 if (!isValidElementType(elementType))
173 return emitError() <<
"invalid array element type: " << elementType;
182LLVMArrayType::getTypeSizeInBits(
const DataLayout &dataLayout,
185 getTypeSize(dataLayout, params));
188llvm::TypeSize LLVMArrayType::getTypeSize(
const DataLayout &dataLayout,
195uint64_t LLVMArrayType::getABIAlignment(
const DataLayout &dataLayout,
201LLVMArrayType::getPreferredAlignment(
const DataLayout &dataLayout,
210bool LLVMFunctionType::isValidArgumentType(
Type type) {
211 if (
auto structType = dyn_cast<LLVMStructType>(type))
212 return !structType.isOpaque();
214 return !llvm::isa<LLVMVoidType, LLVMFunctionType>(type);
217bool LLVMFunctionType::isValidResultType(Type type) {
218 return !llvm::isa<LLVMFunctionType, LLVMMetadataType, LLVMLabelType>(type);
221LLVMFunctionType LLVMFunctionType::get(Type
result, ArrayRef<Type> arguments,
223 assert(
result &&
"expected non-null result");
224 return Base::get(
result.getContext(),
result, arguments, isVarArg);
229 Type
result, ArrayRef<Type> arguments,
231 assert(
result &&
"expected non-null result");
236LLVMFunctionType LLVMFunctionType::clone(
TypeRange inputs,
241 if (results.size() > 1)
244 results.empty() ? LLVMVoidType::get(
getContext()) : results[0];
245 if (!isValidResultType(resultType))
247 if (!llvm::all_of(inputs, isValidArgumentType))
249 return get(resultType, llvm::to_vector(inputs), isVarArg());
252ArrayRef<Type> LLVMFunctionType::getReturnTypes()
const {
253 return static_cast<detail::LLVMFunctionTypeStorage *
>(getImpl())->returnType;
258 Type
result, ArrayRef<Type> arguments,
bool) {
259 if (!isValidResultType(
result))
262 for (Type arg : arguments)
263 if (!isValidArgumentType(arg))
264 return emitError() <<
"invalid function argument type: " << arg;
278 auto spec = cast<DenseIntElementsAttr>(attr);
279 auto idx =
static_cast<int64_t>(pos);
280 if (idx >= spec.size())
282 return spec.getValues<uint64_t>()[idx];
289static std::optional<uint64_t>
294 for (DataLayoutEntryInterface entry : params) {
295 if (!entry.isTypeEntry())
297 if (cast<LLVMPointerType>(cast<Type>(entry.getKey())).getAddressSpace() ==
298 type.getAddressSpace()) {
299 currentEntry = entry.getValue();
316 if (type.getAddressSpace() == 0) {
326LLVMPointerType::getTypeSizeInBits(
const DataLayout &dataLayout,
328 if (std::optional<uint64_t> size =
330 return llvm::TypeSize::getFixed(*size);
337uint64_t LLVMPointerType::getABIAlignment(
const DataLayout &dataLayout,
339 if (std::optional<uint64_t> alignment =
347LLVMPointerType::getPreferredAlignment(
const DataLayout &dataLayout,
349 if (std::optional<uint64_t> alignment =
356std::optional<uint64_t>
357LLVMPointerType::getIndexBitwidth(
const DataLayout &dataLayout,
359 if (std::optional<uint64_t> indexBitwidth =
361 return *indexBitwidth;
366bool LLVMPointerType::areCompatible(
368 DataLayoutSpecInterface newSpec,
370 for (DataLayoutEntryInterface newEntry : newLayout) {
371 if (!newEntry.isTypeEntry())
376 llvm::cast<LLVMPointerType>(llvm::cast<Type>(newEntry.getKey()));
378 llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) {
379 if (
auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
380 return llvm::cast<LLVMPointerType>(type).getAddressSpace() ==
381 newType.getAddressSpace();
385 if (it == oldLayout.end()) {
386 llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) {
387 if (
auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
388 return llvm::cast<LLVMPointerType>(type).getAddressSpace() == 0;
393 if (it != oldLayout.end()) {
398 Attribute newSpec = llvm::cast<DenseIntElementsAttr>(newEntry.getValue());
401 if (size != newSize || abi < newAbi || abi % newAbi != 0)
408 Location loc)
const {
409 for (DataLayoutEntryInterface entry : entries) {
410 if (!entry.isTypeEntry())
412 auto key = llvm::cast<Type>(entry.getKey());
413 auto values = llvm::dyn_cast<DenseIntElementsAttr>(entry.getValue());
414 if (!values || (values.size() != 3 && values.size() != 4)) {
416 <<
"expected layout attribute for " << key
417 <<
" to be a dense integer elements attribute with 3 or 4 "
420 if (!values.getElementType().isInteger(64))
421 return emitError(loc) <<
"expected i64 parameters for " << key;
425 return emitError(loc) <<
"preferred alignment is expected to be at least "
426 "as large as ABI alignment";
436bool LLVMStructType::isValidElementType(Type type) {
437 return !llvm::isa<LLVMVoidType, LLVMLabelType, LLVMMetadataType,
438 LLVMFunctionType, LLVMTokenType>(type);
441LLVMStructType LLVMStructType::getIdentified(MLIRContext *context,
443 return Base::get(context, name,
false);
446LLVMStructType LLVMStructType::getIdentifiedChecked(
449 return Base::getChecked(
emitError, context, name,
false);
452LLVMStructType LLVMStructType::getNewIdentified(MLIRContext *context,
454 ArrayRef<Type> elements,
456 std::string stringName = name.str();
457 unsigned counter = 0;
459 auto type = LLVMStructType::getIdentified(context, stringName);
460 if (type.isInitialized() ||
failed(type.setBody(elements, isPacked))) {
462 stringName = (Twine(name) +
"." + std::to_string(counter)).str();
469LLVMStructType LLVMStructType::getLiteral(MLIRContext *context,
470 ArrayRef<Type> types,
bool isPacked) {
471 return Base::get(context, types, isPacked);
476 MLIRContext *context, ArrayRef<Type> types,
478 return Base::getChecked(
emitError, context, types, isPacked);
481LLVMStructType LLVMStructType::getOpaque(StringRef name, MLIRContext *context) {
482 return Base::get(context, name,
true);
487 MLIRContext *context, StringRef name) {
488 return Base::getChecked(
emitError, context, name,
true);
491LogicalResult LLVMStructType::setBody(ArrayRef<Type> types,
bool isPacked) {
492 assert(isIdentified() &&
"can only set bodies of identified structs");
493 assert(llvm::all_of(types, LLVMStructType::isValidElementType) &&
494 "expected valid body types");
495 return Base::mutate(types, isPacked);
498bool LLVMStructType::isPacked()
const {
return getImpl()->isPacked(); }
499bool LLVMStructType::isIdentified()
const {
return getImpl()->isIdentified(); }
500bool LLVMStructType::isOpaque()
const {
501 return getImpl()->isIdentified() &&
502 (getImpl()->isOpaque() || !getImpl()->isInitialized());
504bool LLVMStructType::isInitialized() {
return getImpl()->isInitialized(); }
505StringRef LLVMStructType::getName()
const {
return getImpl()->getIdentifier(); }
506ArrayRef<Type> LLVMStructType::getBody()
const {
507 return isIdentified() ? getImpl()->getIdentifiedStructBody()
508 : getImpl()->getTypeList();
512LLVMStructType::verifyInvariants(
function_ref<InFlightDiagnostic()>, StringRef,
519 ArrayRef<Type> types,
bool) {
521 if (!isValidElementType(t))
522 return emitError() <<
"invalid LLVM structure element type: " << t;
528LLVMStructType::getTypeSizeInBits(
const DataLayout &dataLayout,
530 auto structSize = llvm::TypeSize::getFixed(0);
531 uint64_t structAlignment = 1;
532 for (Type element : getBody()) {
533 uint64_t elementAlignment =
537 structSize = llvm::alignTo(structSize, elementAlignment);
542 structAlignment = std::max(elementAlignment, structAlignment);
546 structSize = llvm::alignTo(structSize, structAlignment);
554static std::optional<uint64_t>
556 StructDLEntryPos pos) {
557 const auto *currentEntry =
558 llvm::find_if(params, [](DataLayoutEntryInterface entry) {
559 return entry.isTypeEntry();
561 if (currentEntry == params.end())
564 auto attr = llvm::cast<DenseIntElementsAttr>(currentEntry->getValue());
565 if (pos == StructDLEntryPos::Preferred &&
566 attr.size() <=
static_cast<int64_t>(StructDLEntryPos::Preferred))
568 pos = StructDLEntryPos::Abi;
570 return attr.getValues<uint64_t>()[
static_cast<size_t>(pos)];
576 StructDLEntryPos pos) {
578 if (pos == StructDLEntryPos::Abi && type.isPacked()) {
584 uint64_t structAlignment = 1;
585 for (
Type iter : type.getBody()) {
591 if (std::optional<uint64_t> entryResult =
593 return std::max(*entryResult /
kBitsInByte, structAlignment);
595 return structAlignment;
598uint64_t LLVMStructType::getABIAlignment(
const DataLayout &dataLayout,
601 StructDLEntryPos::Abi);
605LLVMStructType::getPreferredAlignment(
const DataLayout &dataLayout,
608 StructDLEntryPos::Preferred);
612 return llvm::cast<DenseIntElementsAttr>(attr)
613 .getValues<uint64_t>()[
static_cast<size_t>(pos)];
616bool LLVMStructType::areCompatible(
618 DataLayoutSpecInterface newSpec,
620 for (DataLayoutEntryInterface newEntry : newLayout) {
621 if (!newEntry.isTypeEntry())
624 const auto *previousEntry =
625 llvm::find_if(oldLayout, [](DataLayoutEntryInterface entry) {
626 return entry.isTypeEntry();
628 if (previousEntry == oldLayout.end())
632 StructDLEntryPos::Abi);
635 if (abi < newAbi || abi % newAbi != 0)
642 Location loc)
const {
643 for (DataLayoutEntryInterface entry : entries) {
644 if (!entry.isTypeEntry())
647 auto key = llvm::cast<LLVMStructType>(llvm::cast<Type>(entry.getKey()));
648 auto values = llvm::dyn_cast<DenseIntElementsAttr>(entry.getValue());
649 if (!values || (values.size() != 2 && values.size() != 1)) {
651 <<
"expected layout attribute for "
652 << llvm::cast<Type>(entry.getKey())
653 <<
" to be a dense integer elements attribute of 1 or 2 elements";
655 if (!values.getElementType().isInteger(64))
656 return emitError(loc) <<
"expected i64 entries for " << key;
658 if (key.isIdentified() || !key.getBody().empty()) {
659 return emitError(loc) <<
"unexpected layout attribute for struct " << key;
662 if (values.size() == 1)
667 return emitError(loc) <<
"preferred alignment is expected to be at least "
668 "as large as ABI alignment";
671 return mlir::success();
682bool LLVM::LLVMTargetExtType::hasProperty(Property prop)
const {
684 uint64_t properties = 0;
688 (LLVMTargetExtType::HasZeroInit | LLVM::LLVMTargetExtType::CanBeGlobal);
691 properties |= LLVMTargetExtType::CanBeGlobal;
693 return (properties & prop) == prop;
696bool LLVM::LLVMTargetExtType::supportsMemOps()
const {
711const llvm::fltSemantics &LLVMPPCFP128Type::getFloatSemantics()
const {
712 return APFloat::PPCDoubleDouble();
723 auto ptrTy = dyn_cast<PtrLikeTypeInterface>(type);
726 return !ptrTy.hasPtrMetadata() && ptrTy.getElementType() ==
nullptr &&
727 isa<LLVMAddrSpaceAttrInterface>(ptrTy.getMemorySpace());
756 if (
auto intType = llvm::dyn_cast<IntegerType>(type))
757 return intType.isSignless();
760 if (
auto vecType = llvm::dyn_cast<VectorType>(type))
761 return vecType.getRank() == 1;
767 if (!compatibleTypes.insert(type).second)
770 auto isCompatible = [&](
Type type) {
776 .Case([&](LLVMStructType structType) {
777 return llvm::all_of(structType.getBody(), isCompatible);
779 .Case([&](LLVMFunctionType funcType) {
780 return isCompatible(funcType.getReturnType()) &&
781 llvm::all_of(funcType.getParams(), isCompatible);
783 .Case([](IntegerType intType) {
return intType.isSignless(); })
784 .Case([&](VectorType vecType) {
785 return vecType.getRank() == 1 &&
786 isCompatible(vecType.getElementType());
788 .Case([&](LLVMPointerType pointerType) {
return true; })
789 .Case([&](LLVMTargetExtType extType) {
790 return llvm::all_of(extType.getTypeParams(), isCompatible);
793 .Case([&](LLVMArrayType containerType) {
794 return isCompatible(containerType.getElementType());
809 >([](
Type) {
return true; })
811 .Case<PtrLikeTypeInterface>(
816 compatibleTypes.erase(type);
821bool LLVMDialect::isCompatibleType(
Type type) {
822 if (
auto *llvmDialect =
831 return LLVMDialect::isCompatibleType(type);
837 !isa<LLVM::LLVMVoidType, LLVM::LLVMFunctionType>(type)) &&
839 !(isa<LLVM::LLVMStructType>(type) &&
840 cast<LLVM::LLVMStructType>(type).isOpaque()) &&
842 !(isa<LLVM::LLVMTargetExtType>(type) &&
843 !cast<LLVM::LLVMTargetExtType>(type).supportsMemOps());
847 return llvm::isa<BFloat16Type, Float16Type, Float32Type, Float64Type,
848 Float80Type, Float128Type, LLVMPPCFP128Type>(type);
852 if (
auto vecType = llvm::dyn_cast<VectorType>(type)) {
853 if (vecType.getRank() != 1)
855 Type elementType = vecType.getElementType();
856 if (
auto intType = llvm::dyn_cast<IntegerType>(elementType))
857 return intType.isSignless();
858 return llvm::isa<BFloat16Type, Float16Type, Float32Type, Float64Type,
859 Float80Type, Float128Type, LLVMPointerType>(elementType) ||
866 auto vecTy = dyn_cast<VectorType>(type);
867 assert(vecTy &&
"incompatible with LLVM vector type");
868 if (vecTy.isScalable())
869 return llvm::ElementCount::getScalable(vecTy.getNumElements());
870 return llvm::ElementCount::getFixed(vecTy.getNumElements());
874 assert(llvm::isa<VectorType>(vectorType) &&
875 "expected LLVM-compatible vector type");
876 return llvm::cast<VectorType>(vectorType).isScalable();
881 assert(VectorType::isValidElementType(elementType) &&
882 "incompatible element type");
883 return VectorType::get(numElements, elementType, {isScalable});
887 const llvm::ElementCount &numElements) {
888 if (numElements.isScalable())
889 return getVectorType(elementType, numElements.getKnownMinValue(),
891 return getVectorType(elementType, numElements.getFixedValue(),
897 "expected a type compatible with the LLVM dialect");
900 .Case<BFloat16Type, Float16Type>(
901 [](
Type) {
return llvm::TypeSize::getFixed(16); })
902 .Case<Float32Type>([](
Type) {
return llvm::TypeSize::getFixed(32); })
903 .Case<Float64Type>([](
Type) {
return llvm::TypeSize::getFixed(64); })
904 .Case<Float80Type>([](
Type) {
return llvm::TypeSize::getFixed(80); })
905 .Case<Float128Type>([](
Type) {
return llvm::TypeSize::getFixed(128); })
906 .Case([](IntegerType intTy) {
907 return llvm::TypeSize::getFixed(intTy.getWidth());
909 .Case<LLVMPPCFP128Type>(
910 [](
Type) {
return llvm::TypeSize::getFixed(128); })
911 .Case([](VectorType t) {
913 "unexpected incompatible with LLVM vector type");
914 llvm::TypeSize elementSize =
916 return llvm::TypeSize(elementSize.getFixedValue() * t.getNumElements(),
917 elementSize.isScalable());
919 .Default([](
Type ty) {
920 assert((llvm::isa<LLVMVoidType, LLVMLabelType, LLVMMetadataType,
921 LLVMTokenType, LLVMStructType, LLVMArrayType,
922 LLVMPointerType, LLVMFunctionType, LLVMTargetExtType>(
924 "unexpected missing support for primitive type");
925 return llvm::TypeSize::getFixed(0);
933void LLVMDialect::registerTypes() {
935#define GET_TYPEDEF_LIST
936#include "mlir/Dialect/LLVMIR/LLVMTypes.cpp.inc"
944void LLVMDialect::printType(Type type, DialectAsmPrinter &os)
const {
static Type getElementType(Type type)
Determine the element type of type.
static int64_t getNumElements(Type t)
Compute the total number of elements in the given type, also taking into account nested types.
constexpr static const uint64_t kDefaultPointerAlignment
static void printExtTypeParams(AsmPrinter &p, ArrayRef< Type > typeParams, ArrayRef< unsigned int > intParams)
constexpr static const uint64_t kDefaultPointerSizeBits
static void printFunctionTypes(AsmPrinter &p, ArrayRef< Type > params, bool isVarArg)
static bool isCompatibleImpl(Type type, DenseSet< Type > &compatibleTypes)
static ParseResult parseExtTypeParams(AsmParser &p, SmallVectorImpl< Type > &typeParams, SmallVectorImpl< unsigned int > &intParams)
Parses the parameter list for a target extension type.
static constexpr llvm::StringRef kSpirvPrefix
static std::optional< uint64_t > getPointerDataLayoutEntry(DataLayoutEntryListRef params, LLVMPointerType type, PtrDLEntryPos pos)
Returns the part of the data layout entry that corresponds to pos for the given type by interpreting ...
static bool isCompatiblePtrType(Type type)
Check whether type is a compatible ptr type.
static OptionalParseResult generatedTypeParser(AsmParser &parser, StringRef *mnemonic, Type &value)
These are unused for now.
static ParseResult parseFunctionTypes(AsmParser &p, SmallVector< Type > ¶ms, bool &isVarArg)
constexpr static const uint64_t kBitsInByte
static constexpr llvm::StringRef kArmSVCount
static constexpr llvm::StringRef kAMDGCNNamedBarrier
static LogicalResult generatedTypePrinter(Type def, AsmPrinter &printer)
static std::optional< uint64_t > getStructDataLayoutEntry(DataLayoutEntryListRef params, LLVMStructType type, StructDLEntryPos pos)
static uint64_t extractStructSpecValue(Attribute attr, StructDLEntryPos pos)
static uint64_t calculateStructAlignment(const DataLayout &dataLayout, DataLayoutEntryListRef params, LLVMStructType type, StructDLEntryPos pos)
This base class exposes generic asm parser hooks, usable across the various derived parsers.
virtual OptionalParseResult parseOptionalInteger(APInt &result)=0
Parse an optional integer value from the stream.
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual ParseResult parseRParen()=0
Parse a ) token.
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseOptionalRParen()=0
Parse a ) token if present.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual ParseResult parseOptionalEllipsis()=0
Parse a ... token if present;.
This base class exposes generic asm printer hooks, usable across the various derived printers.
Attributes are known-constant values of operations.
The main mechanism for performing data layout queries.
std::optional< uint64_t > getTypeIndexBitwidth(Type t) const
Returns the bitwidth that should be used when performing index computations for the given pointer-lik...
llvm::TypeSize getTypeSize(Type t) const
Returns the size of the given type in the current scope.
uint64_t getTypePreferredAlignment(Type t) const
Returns the preferred of the given type in the current scope.
uint64_t getTypeABIAlignment(Type t) const
Returns the required alignment of the given type in the current scope.
llvm::TypeSize getTypeSizeInBits(Type t) const
Returns the size in bits of the given type in the current scope.
The DialectAsmParser has methods for interacting with the asm parser when parsing attributes and type...
This class represents a diagnostic that is inflight and set to be reported.
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
This class implements Optional functionality for ParseResult.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
void printType(Type type, AsmPrinter &printer)
Prints an LLVM Dialect type.
Type parseType(DialectAsmParser &parser)
Parses an LLVM dialect type.
Type getVectorType(Type elementType, unsigned numElements, bool isScalable=false)
Creates an LLVM dialect-compatible vector type with the given element type and length.
llvm::TypeSize getPrimitiveTypeSizeInBits(Type type)
Returns the size of the given primitive LLVM dialect-compatible type (including vectors) in bits,...
void printPrettyLLVMType(AsmPrinter &p, Type type)
Print any MLIR type or a concise syntax for LLVM types.
bool isLoadableType(Type type)
Returns true if the given type is a loadable type compatible with the LLVM dialect.
bool isScalableVectorType(Type vectorType)
Returns whether a vector type is scalable or not.
ParseResult parsePrettyLLVMType(AsmParser &p, Type &type)
Parse any MLIR type or a concise syntax for LLVM types.
bool isCompatibleVectorType(Type type)
Returns true if the given type is a vector type compatible with the LLVM dialect.
bool isCompatibleOuterType(Type type)
Returns true if the given outer type is compatible with the LLVM dialect without checking its potenti...
PtrDLEntryPos
The positions of different values in the data layout entry for pointers.
std::optional< uint64_t > extractPointerSpecValue(Attribute attr, PtrDLEntryPos pos)
Returns the value that corresponds to named position pos from the data layout entry attr assuming it'...
bool isCompatibleType(Type type)
Returns true if the given type is compatible with the LLVM dialect.
bool isCompatibleFloatingPointType(Type type)
Returns true if the given type is a floating-point type compatible with the LLVM dialect.
llvm::ElementCount getVectorNumElements(Type type)
Returns the element count of any LLVM-compatible vector type.
Include the generated interface declarations.
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
::llvm::MapVector<::mlir::StringAttr, ::mlir::DataLayoutEntryInterface > DataLayoutIdentifiedEntryMap
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
Type parseType(llvm::StringRef typeStr, MLIRContext *context, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR type to an MLIR context if it was valid.
llvm::ArrayRef< DataLayoutEntryInterface > DataLayoutEntryListRef
llvm::function_ref< Fn > function_ref