blob: 6d214ed30236b621e4511dadaeac5a366bbe1cbe [file] [log] [blame]
//===- DataLayoutInterfaces.h - Data Layout Interface Decls -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Defines the interfaces for the data layout specification, operations to which
// they can be attached, types subject to data layout and dialects containing
// data layout entries.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_INTERFACES_DATALAYOUTINTERFACES_H
#define MLIR_INTERFACES_DATALAYOUTINTERFACES_H
#include "mlir/IR/DialectInterface.h"
#include "mlir/IR/OpDefinition.h"
#include "llvm/ADT/DenseMap.h"
namespace mlir {
class DataLayout;
class DataLayoutEntryInterface;
using DataLayoutEntryKey = llvm::PointerUnion<Type, StringAttr>;
// Using explicit SmallVector size because we cannot infer the size from the
// forward declaration, and we need the typedef in the actual declaration.
using DataLayoutEntryList = llvm::SmallVector<DataLayoutEntryInterface, 4>;
using DataLayoutEntryListRef = llvm::ArrayRef<DataLayoutEntryInterface>;
class DataLayoutOpInterface;
class DataLayoutSpecInterface;
class ModuleOp;
namespace detail {
/// Default handler for the type size request. Computes results for built-in
/// types and dispatches to the DataLayoutTypeInterface for other types.
unsigned getDefaultTypeSize(Type type, const DataLayout &dataLayout,
DataLayoutEntryListRef params);
/// Default handler for the type size in bits request. Computes results for
/// built-in types and dispatches to the DataLayoutTypeInterface for other
/// types.
unsigned getDefaultTypeSizeInBits(Type type, const DataLayout &dataLayout,
DataLayoutEntryListRef params);
/// Default handler for the required alignemnt request. Computes results for
/// built-in types and dispatches to the DataLayoutTypeInterface for other
/// types.
unsigned getDefaultABIAlignment(Type type, const DataLayout &dataLayout,
ArrayRef<DataLayoutEntryInterface> params);
/// Default handler for the preferred alignemnt request. Computes results for
/// built-in types and dispatches to the DataLayoutTypeInterface for other
/// types.
unsigned
getDefaultPreferredAlignment(Type type, const DataLayout &dataLayout,
ArrayRef<DataLayoutEntryInterface> params);
/// Given a list of data layout entries, returns a new list containing the
/// entries with keys having the given type ID, i.e. belonging to the same type
/// class.
DataLayoutEntryList filterEntriesForType(DataLayoutEntryListRef entries,
TypeID typeID);
/// Given a list of data layout entries, returns the entry that has the given
/// identifier as key, if such an entry exists in the list.
DataLayoutEntryInterface
filterEntryForIdentifier(DataLayoutEntryListRef entries, StringAttr id);
/// Verifies that the operation implementing the data layout interface, or a
/// module operation, is valid. This calls the verifier of the spec attribute
/// and checks if the layout is compatible with specs attached to the enclosing
/// operations.
LogicalResult verifyDataLayoutOp(Operation *op);
/// Verifies that a data layout spec is valid. This dispatches to individual
/// entry verifiers, and then to the verifiers implemented by the relevant type
/// and dialect interfaces for type and identifier keys respectively.
LogicalResult verifyDataLayoutSpec(DataLayoutSpecInterface spec, Location loc);
} // namespace detail
} // namespace mlir
#include "mlir/Interfaces/DataLayoutAttrInterface.h.inc"
#include "mlir/Interfaces/DataLayoutOpInterface.h.inc"
#include "mlir/Interfaces/DataLayoutTypeInterface.h.inc"
namespace mlir {
//===----------------------------------------------------------------------===//
// DataLayoutDialectInterface
//===----------------------------------------------------------------------===//
/// An interface to be implemented by dialects that can have identifiers in the
/// data layout specification entries. Provides hooks for verifying the entry
/// validity and combining two entries.
class DataLayoutDialectInterface
: public DialectInterface::Base<DataLayoutDialectInterface> {
public:
DataLayoutDialectInterface(Dialect *dialect) : Base(dialect) {}
/// Checks whether the given data layout entry is valid and reports any errors
/// at the provided location. Derived classes should override this.
virtual LogicalResult verifyEntry(DataLayoutEntryInterface entry,
Location loc) const {
return success();
}
/// Default implementation of entry combination that combines identical
/// entries and returns null otherwise.
static DataLayoutEntryInterface
defaultCombine(DataLayoutEntryInterface outer,
DataLayoutEntryInterface inner) {
if (!outer || outer == inner)
return inner;
return {};
}
/// Combines two entries with identifiers that belong to this dialect. Returns
/// the combined entry or null if the entries are not compatible. Derived
/// classes likely need to reimplement this.
virtual DataLayoutEntryInterface
combine(DataLayoutEntryInterface outer,
DataLayoutEntryInterface inner) const {
return defaultCombine(outer, inner);
}
};
//===----------------------------------------------------------------------===//
// DataLayout
//===----------------------------------------------------------------------===//
/// The main mechanism for performing data layout queries. Instances of this
/// class can be created for an operation implementing DataLayoutOpInterface.
/// Upon construction, a layout spec combining that of the given operation with
/// all its ancestors will be computed and used to handle further requests. For
/// efficiency, results to all requests will be cached in this object.
/// Therefore, if the data layout spec for the scoping operation, or any of the
/// enclosing operations, changes, the cache is no longer valid. The user is
/// responsible creating a new DataLayout object after any spec change. In debug
/// mode, the cache validity is being checked in every request.
class DataLayout {
public:
explicit DataLayout();
explicit DataLayout(DataLayoutOpInterface op);
explicit DataLayout(ModuleOp op);
/// Returns the layout of the closest parent operation carrying layout info.
static DataLayout closest(Operation *op);
/// Returns the size of the given type in the current scope.
unsigned getTypeSize(Type t) const;
/// Returns the size in bits of the given type in the current scope.
unsigned getTypeSizeInBits(Type t) const;
/// Returns the required alignment of the given type in the current scope.
unsigned getTypeABIAlignment(Type t) const;
/// Returns the preferred of the given type in the current scope.
unsigned getTypePreferredAlignment(Type t) const;
private:
/// Combined layout spec at the given scope.
const DataLayoutSpecInterface originalLayout;
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
/// List of enclosing layout specs.
SmallVector<DataLayoutSpecInterface, 2> layoutStack;
#endif
/// Asserts that the cache is still valid. Expensive in debug mode. No-op in
/// release mode.
void checkValid() const;
/// Operation defining the scope of requests.
// TODO: this is mutable because the generated interface method are not const.
// Update the generator to support const methods and change this to const.
mutable Operation *scope;
/// Caches for individual requests.
mutable DenseMap<Type, unsigned> sizes;
mutable DenseMap<Type, unsigned> bitsizes;
mutable DenseMap<Type, unsigned> abiAlignments;
mutable DenseMap<Type, unsigned> preferredAlignments;
};
} // namespace mlir
#endif // MLIR_INTERFACES_DATALAYOUTINTERFACES_H