blob: 9341a5a11cd629020326e87f2b25bffd23b717e2 [file] [log] [blame]
//===- LLVMDialect.h - MLIR LLVM IR dialect ---------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the LLVM IR dialect in MLIR, containing LLVM operations and
// LLVM type system.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_DIALECT_LLVMIR_LLVMDIALECT_H_
#define MLIR_DIALECT_LLVMIR_LLVMDIALECT_H_
#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/IR/OpImplementation.h"
#include "mlir/IR/TypeSupport.h"
#include "mlir/IR/Types.h"
#include "mlir/Interfaces/CallInterfaces.h"
#include "mlir/Interfaces/ControlFlowInterfaces.h"
#include "mlir/Interfaces/FunctionInterfaces.h"
#include "mlir/Interfaces/InferTypeOpInterface.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
#include "mlir/Support/ThreadLocalCache.h"
#include "llvm/ADT/PointerEmbeddedInt.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
namespace llvm {
class Type;
class LLVMContext;
namespace sys {
template <bool mt_only>
class SmartMutex;
} // namespace sys
} // namespace llvm
namespace mlir {
namespace LLVM {
class LLVMDialect;
namespace detail {
struct LLVMTypeStorage;
struct LLVMDialectImpl;
} // namespace detail
} // namespace LLVM
} // namespace mlir
namespace mlir {
namespace LLVM {
template <typename Values>
class GEPIndicesAdaptor;
/// Bit-width of a 'GEPConstantIndex' within GEPArg.
constexpr int kGEPConstantBitWidth = 29;
/// Wrapper around a int32_t for use in a PointerUnion.
using GEPConstantIndex =
llvm::PointerEmbeddedInt<int32_t, kGEPConstantBitWidth>;
/// Class used for building a 'llvm.getelementptr'. A single instance represents
/// a sum type that is either a 'Value' or a constant 'GEPConstantIndex' index.
/// The former represents a dynamic index in a GEP operation, while the later is
/// a constant index as is required for indices into struct types.
class GEPArg : public PointerUnion<Value, GEPConstantIndex> {
using BaseT = PointerUnion<Value, GEPConstantIndex>;
public:
/// Constructs a GEPArg with a constant index.
/*implicit*/ GEPArg(int32_t integer) : BaseT(integer) {}
/// Constructs a GEPArg with a dynamic index.
/*implicit*/ GEPArg(Value value) : BaseT(value) {}
using BaseT::operator=;
};
} // namespace LLVM
} // namespace mlir
///// Ops /////
#define GET_OP_CLASSES
#include "mlir/Dialect/LLVMIR/LLVMOps.h.inc"
#define GET_OP_CLASSES
#include "mlir/Dialect/LLVMIR/LLVMIntrinsicOps.h.inc"
#include "mlir/Dialect/LLVMIR/LLVMOpsDialect.h.inc"
namespace mlir {
namespace LLVM {
/// Class used for convenient access and iteration over GEP indices.
/// This class is templated to support not only retrieving the dynamic operands
/// of a GEP operation, but also as an adaptor during folding or conversion to
/// LLVM IR.
///
/// GEP indices may either be constant indices or dynamic indices. The
/// 'rawConstantIndices' is specially encoded by GEPOp and contains either the
/// constant index or the information that an index is a dynamic index.
///
/// When an access to such an index is made it is done through the
/// 'DynamicRange' of this class. This way it can be used as getter in GEPOp via
/// 'GEPIndicesAdaptor<ValueRange>' or during folding via
/// 'GEPIndicesAdaptor<ArrayRef<Attribute>>'.
template <typename DynamicRange>
class GEPIndicesAdaptor {
public:
/// Return type of 'operator[]' and the iterators 'operator*'. It is depended
/// upon the value type of 'DynamicRange'. If 'DynamicRange' contains
/// Attributes or subclasses thereof, then value_type is 'Attribute'. In
/// all other cases it is a pointer union between the value type of
/// 'DynamicRange' and IntegerAttr.
using value_type = std::conditional_t<
std::is_base_of<Attribute,
llvm::detail::ValueOfRange<DynamicRange>>::value,
Attribute,
PointerUnion<IntegerAttr, llvm::detail::ValueOfRange<DynamicRange>>>;
/// Constructs a GEPIndicesAdaptor with the raw constant indices of a GEPOp
/// and the range that is indexed into for retrieving dynamic indices.
GEPIndicesAdaptor(DenseI32ArrayAttr rawConstantIndices, DynamicRange values)
: rawConstantIndices(rawConstantIndices), values(std::move(values)) {}
/// Returns the GEP index at the given position. Note that this operation has
/// a linear complexity in regards to the accessed position. To iterate over
/// all indices, use the iterators.
///
/// This operation is invalid if the index is out of bounds.
value_type operator[](size_t index) const {
assert(index < size() && "index out of bounds");
return *std::next(begin(), index);
}
/// Returns whether the GEP index at the given position is a dynamic index.
bool isDynamicIndex(size_t index) const {
return rawConstantIndices[index] == GEPOp::kDynamicIndex;
}
/// Returns the amount of indices of the GEPOp.
size_t size() const { return rawConstantIndices.size(); }
/// Returns true if this GEPOp does not have any indices.
bool empty() const { return rawConstantIndices.empty(); }
class iterator
: public llvm::iterator_facade_base<iterator, std::forward_iterator_tag,
value_type, std::ptrdiff_t,
value_type *, value_type> {
public:
iterator(const GEPIndicesAdaptor *base,
ArrayRef<int32_t>::iterator rawConstantIter,
llvm::detail::IterOfRange<const DynamicRange> valuesIter)
: base(base), rawConstantIter(rawConstantIter), valuesIter(valuesIter) {
}
value_type operator*() const {
if (*rawConstantIter == GEPOp::kDynamicIndex)
return *valuesIter;
return IntegerAttr::get(base->rawConstantIndices.getElementType(),
*rawConstantIter);
}
iterator &operator++() {
if (*rawConstantIter == GEPOp::kDynamicIndex)
valuesIter++;
rawConstantIter++;
return *this;
}
bool operator==(const iterator &rhs) const {
return base == rhs.base && rawConstantIter == rhs.rawConstantIter &&
valuesIter == rhs.valuesIter;
}
private:
const GEPIndicesAdaptor *base;
ArrayRef<int32_t>::const_iterator rawConstantIter;
llvm::detail::IterOfRange<const DynamicRange> valuesIter;
};
/// Returns the begin iterator, iterating over all GEP indices.
iterator begin() const {
return iterator(this, rawConstantIndices.asArrayRef().begin(),
values.begin());
}
/// Returns the end iterator, iterating over all GEP indices.
iterator end() const {
return iterator(this, rawConstantIndices.asArrayRef().end(), values.end());
}
private:
DenseI32ArrayAttr rawConstantIndices;
DynamicRange values;
};
/// Create an LLVM global containing the string "value" at the module containing
/// surrounding the insertion point of builder. Obtain the address of that
/// global and use it to compute the address of the first character in the
/// string (operations inserted at the builder insertion point).
Value createGlobalString(Location loc, OpBuilder &builder, StringRef name,
StringRef value, Linkage linkage);
/// LLVM requires some operations to be inside of a Module operation. This
/// function confirms that the Operation has the desired properties.
bool satisfiesLLVMModule(Operation *op);
/// Convert an array of integer attributes to a vector of integers that can be
/// used as indices in LLVM operations.
template <typename IntT = int64_t>
SmallVector<IntT> convertArrayToIndices(ArrayRef<Attribute> attrs) {
SmallVector<IntT> indices;
indices.reserve(attrs.size());
for (Attribute attr : attrs)
indices.push_back(cast<IntegerAttr>(attr).getInt());
return indices;
}
/// Convert an `ArrayAttr` of integer attributes to a vector of integers that
/// can be used as indices in LLVM operations.
template <typename IntT = int64_t>
SmallVector<IntT> convertArrayToIndices(ArrayAttr attrs) {
return convertArrayToIndices<IntT>(attrs.getValue());
}
} // namespace LLVM
} // namespace mlir
namespace llvm {
// Allow llvm::cast style functions.
template <typename To>
struct CastInfo<To, mlir::LLVM::GEPArg>
: public CastInfo<To, mlir::LLVM::GEPArg::PointerUnion> {};
template <typename To>
struct CastInfo<To, const mlir::LLVM::GEPArg>
: public CastInfo<To, const mlir::LLVM::GEPArg::PointerUnion> {};
} // namespace llvm
#endif // MLIR_DIALECT_LLVMIR_LLVMDIALECT_H_