}
};
-// Code shared between insert_value and extract_value Ops.
-struct ValueOpCommon {
- // Translate the arguments pertaining to any multidimensional array to
- // row-major order for LLVM-IR.
- static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
- mlir::Type ty) {
- assert(ty && "type is null");
- const auto end = attrs.size();
- for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
- if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
- const auto dim = getDimension(seq);
- if (dim > 1) {
- auto ub = std::min(i + dim, end);
- std::reverse(attrs.begin() + i, attrs.begin() + ub);
- i += dim - 1;
- }
- ty = getArrayElementType(seq);
- } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
- ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
- } else {
- llvm_unreachable("index into invalid type");
- }
- }
- }
-
- static llvm::SmallVector<mlir::Attribute>
- collectIndices(mlir::ConversionPatternRewriter &rewriter,
- mlir::ArrayAttr arrAttr) {
- llvm::SmallVector<mlir::Attribute> attrs;
- for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
- if (i->isa<mlir::IntegerAttr>()) {
- attrs.push_back(*i);
- } else {
- auto fieldName = i->cast<mlir::StringAttr>().getValue();
- ++i;
- auto ty = i->cast<mlir::TypeAttr>().getValue();
- auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
- attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
- }
- }
- return attrs;
- }
-
-private:
- static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
- unsigned result = 1;
- for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
- eleTy;
- eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
- ++result;
- return result;
- }
-
- static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
- auto eleTy = ty.getElementType();
- while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
- eleTy = arrTy.getElementType();
- return eleTy;
- }
-};
-
-/// Extract a subobject value from an ssa-value of aggregate type
-struct ExtractValueOpConversion
- : public FIROpAndTypeConversion<fir::ExtractValueOp>,
- public ValueOpCommon {
- using FIROpAndTypeConversion::FIROpAndTypeConversion;
-
- mlir::LogicalResult
- doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
- mlir::ConversionPatternRewriter &rewriter) const override {
- auto attrs = collectIndices(rewriter, extractVal.coor());
- toRowMajor(attrs, adaptor.getOperands()[0].getType());
- auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
- rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
- extractVal, ty, adaptor.getOperands()[0], position);
- return success();
- }
-};
-
-/// InsertValue is the generalized instruction for the composition of new
-/// aggregate type values.
-struct InsertValueOpConversion
- : public FIROpAndTypeConversion<fir::InsertValueOp>,
- public ValueOpCommon {
- using FIROpAndTypeConversion::FIROpAndTypeConversion;
-
- mlir::LogicalResult
- doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
- mlir::ConversionPatternRewriter &rewriter) const override {
- auto attrs = collectIndices(rewriter, insertVal.coor());
- toRowMajor(attrs, adaptor.getOperands()[0].getType());
- auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
- rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
- insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
- position);
- return success();
- }
-};
-
/// InsertOnRange inserts a value into a sequence over a range of offsets.
struct InsertOnRangeOpConversion
: public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
auto *context = getModule().getContext();
fir::LLVMTypeConverter typeConverter{getModule()};
mlir::OwningRewritePatternList pattern(context);
- pattern.insert<
- AddrOfOpConversion, ExtractValueOpConversion, HasValueOpConversion,
- GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
- SelectOpConversion, SelectRankOpConversion, UndefOpConversion,
- UnreachableOpConversion, ZeroOpConversion>(typeConverter);
+ pattern.insert<AddrOfOpConversion, HasValueOpConversion, GlobalOpConversion,
+ InsertOnRangeOpConversion, SelectOpConversion,
+ SelectRankOpConversion, UnreachableOpConversion,
+ ZeroOpConversion, UndefOpConversion>(typeConverter);
mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
pattern);
+++ /dev/null
-//===-- DescriptorModel.h -- model of descriptors for codegen ---*- 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
-//
-//===----------------------------------------------------------------------===//
-// LLVM IR dialect models of C++ types.
-//
-// This supplies a set of model builders to decompose the C declaration of a
-// descriptor (as encoded in ISO_Fortran_binding.h and elsewhere) and
-// reconstruct that type in the LLVM IR dialect.
-//
-// TODO: It is understood that this is deeply incorrect as far as building a
-// portability layer for cross-compilation as these reflected types are those of
-// the build machine and not necessarily that of either the host or the target.
-// This assumption that build == host == target is actually pervasive across the
-// compiler (https://llvm.org/PR52418).
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef OPTIMIZER_DESCRIPTOR_MODEL_H
-#define OPTIMIZER_DESCRIPTOR_MODEL_H
-
-#include "flang/ISO_Fortran_binding.h"
-#include "flang/Runtime/descriptor.h"
-#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
-#include "llvm/Support/ErrorHandling.h"
-#include <tuple>
-
-namespace fir {
-
-using TypeBuilderFunc = mlir::Type (*)(mlir::MLIRContext *);
-
-/// Get the LLVM IR dialect model for building a particular C++ type, `T`.
-template <typename T>
-TypeBuilderFunc getModel();
-
-template <>
-TypeBuilderFunc getModel<void *>() {
- return [](mlir::MLIRContext *context) -> mlir::Type {
- return mlir::LLVM::LLVMPointerType::get(mlir::IntegerType::get(context, 8));
- };
-}
-template <>
-TypeBuilderFunc getModel<unsigned>() {
- return [](mlir::MLIRContext *context) -> mlir::Type {
- return mlir::IntegerType::get(context, sizeof(unsigned) * 8);
- };
-}
-template <>
-TypeBuilderFunc getModel<int>() {
- return [](mlir::MLIRContext *context) -> mlir::Type {
- return mlir::IntegerType::get(context, sizeof(int) * 8);
- };
-}
-template <>
-TypeBuilderFunc getModel<unsigned long>() {
- return [](mlir::MLIRContext *context) -> mlir::Type {
- return mlir::IntegerType::get(context, sizeof(unsigned long) * 8);
- };
-}
-template <>
-TypeBuilderFunc getModel<unsigned long long>() {
- return [](mlir::MLIRContext *context) -> mlir::Type {
- return mlir::IntegerType::get(context, sizeof(unsigned long long) * 8);
- };
-}
-template <>
-TypeBuilderFunc getModel<long long>() {
- return [](mlir::MLIRContext *context) -> mlir::Type {
- return mlir::IntegerType::get(context, sizeof(long long) * 8);
- };
-}
-template <>
-TypeBuilderFunc getModel<Fortran::ISO::CFI_rank_t>() {
- return [](mlir::MLIRContext *context) -> mlir::Type {
- return mlir::IntegerType::get(context,
- sizeof(Fortran::ISO::CFI_rank_t) * 8);
- };
-}
-template <>
-TypeBuilderFunc getModel<Fortran::ISO::CFI_type_t>() {
- return [](mlir::MLIRContext *context) -> mlir::Type {
- return mlir::IntegerType::get(context,
- sizeof(Fortran::ISO::CFI_type_t) * 8);
- };
-}
-template <>
-TypeBuilderFunc getModel<Fortran::ISO::CFI_dim_t>() {
- return [](mlir::MLIRContext *context) -> mlir::Type {
- auto indexTy = getModel<Fortran::ISO::CFI_index_t>()(context);
- return mlir::LLVM::LLVMArrayType::get(indexTy, 3);
- };
-}
-template <>
-TypeBuilderFunc
-getModel<Fortran::ISO::cfi_internal::FlexibleArray<Fortran::ISO::CFI_dim_t>>() {
- return getModel<Fortran::ISO::CFI_dim_t>();
-}
-
-//===----------------------------------------------------------------------===//
-// Descriptor reflection
-//===----------------------------------------------------------------------===//
-
-/// Get the type model of the field number `Field` in an ISO CFI descriptor.
-template <int Field>
-static constexpr TypeBuilderFunc getDescFieldTypeModel() {
- Fortran::ISO::Fortran_2018::CFI_cdesc_t dummyDesc{};
- // check that the descriptor is exactly 8 fields as specified in CFI_cdesc_t
- // in flang/include/flang/ISO_Fortran_binding.h.
- auto [a, b, c, d, e, f, g, h] = dummyDesc;
- auto tup = std::tie(a, b, c, d, e, f, g, h);
- auto field = std::get<Field>(tup);
- return getModel<decltype(field)>();
-}
-
-/// An extended descriptor is defined by a class in runtime/descriptor.h. The
-/// three fields in the class are hard-coded here, unlike the reflection used on
-/// the ISO parts, which are a POD.
-template <int Field>
-static constexpr TypeBuilderFunc getExtendedDescFieldTypeModel() {
- if constexpr (Field == 8) {
- return getModel<void *>();
- } else if constexpr (Field == 9) {
- return getModel<Fortran::runtime::typeInfo::TypeParameterValue>();
- } else {
- llvm_unreachable("extended ISO descriptor only has 10 fields");
- }
-}
-
-} // namespace fir
-
-#endif // OPTIMIZER_DESCRIPTOR_MODEL_H
#ifndef FORTRAN_OPTIMIZER_CODEGEN_TYPECONVERTER_H
#define FORTRAN_OPTIMIZER_CODEGEN_TYPECONVERTER_H
-#include "DescriptorModel.h"
-#include "flang/Lower/Todo.h" // remove when TODO's are done
-#include "llvm/ADT/StringMap.h"
#include "llvm/Support/Debug.h"
namespace fir {
// Each conversion should return a value of type mlir::Type.
addConversion(
- [&](fir::RecordType derived) { return convertRecordType(derived); });
- addConversion(
[&](fir::ReferenceType ref) { return convertPointerLike(ref); });
addConversion(
[&](SequenceType sequence) { return convertSequenceType(sequence); });
- addConversion([&](mlir::TupleType tuple) {
- LLVM_DEBUG(llvm::dbgs() << "type convert: " << tuple << '\n');
- llvm::SmallVector<mlir::Type> inMembers;
- tuple.getFlattenedTypes(inMembers);
- llvm::SmallVector<mlir::Type> members;
- for (auto mem : inMembers)
- members.push_back(convertType(mem).cast<mlir::Type>());
- return mlir::LLVM::LLVMStructType::getLiteral(&getContext(), members,
- /*isPacked=*/false);
- });
- }
-
- // fir.type<name(p : TY'...){f : TY...}> --> llvm<"%name = { ty... }">
- mlir::Type convertRecordType(fir::RecordType derived) {
- auto name = derived.getName();
- auto st = mlir::LLVM::LLVMStructType::getIdentified(&getContext(), name);
- llvm::SmallVector<mlir::Type> members;
- for (auto mem : derived.getTypeList()) {
- members.push_back(convertType(mem.second).cast<mlir::Type>());
- }
- if (mlir::succeeded(st.setBody(members, /*isPacked=*/false)))
- return st;
- return mlir::Type();
}
template <typename A>
// CHECK: 3: ^bb3(%[[ARG1]], %[[C2]] : i32, i32),
// CHECK: 4: ^bb4(%[[C1]] : i32)
// CHECK: ]
-
-// -----
-
-// Test fir.extract_value operation conversion with derived type.
-
-func @extract_derived_type() -> f32 {
- %0 = fir.undefined !fir.type<derived{f:f32}>
- %1 = fir.extract_value %0, ["f", !fir.type<derived{f:f32}>] : (!fir.type<derived{f:f32}>) -> f32
- return %1 : f32
-}
-
-// CHECK-LABEL: llvm.func @extract_derived_type
-// CHECK: %[[STRUCT:.*]] = llvm.mlir.undef : !llvm.struct<"derived", (f32)>
-// CHECK: %[[VALUE:.*]] = llvm.extractvalue %[[STRUCT]][0 : i32] : !llvm.struct<"derived", (f32)>
-// CHECK: llvm.return %[[VALUE]] : f32
-
-// -----
-
-// Test fir.extract_value operation conversion with a multi-dimensional array
-// of tuple.
-
-func @extract_array(%a : !fir.array<10x10xtuple<i32, f32>>) -> f32 {
- %0 = fir.extract_value %a, [5 : index, 4 : index, 1 : index] : (!fir.array<10x10xtuple<i32, f32>>) -> f32
- return %0 : f32
-}
-
-// CHECK-LABEL: llvm.func @extract_array(
-// CHECK-SAME: %[[ARR:.*]]: !llvm.array<10 x array<10 x struct<(i32, f32)>>>
-// CHECK: %[[VALUE:.*]] = llvm.extractvalue %[[ARR]][4 : index, 5 : index, 1 : index] : !llvm.array<10 x array<10 x struct<(i32, f32)>>>
-// CHECK: llvm.return %[[VALUE]] : f32
-
-// -----
-
-// Test fir.insert_value operation conversion with a multi-dimensional array
-// of tuple.
-
-func @extract_array(%a : !fir.array<10x10xtuple<i32, f32>>) {
- %f = arith.constant 2.0 : f32
- %i = arith.constant 1 : i32
- %0 = fir.insert_value %a, %i, [5 : index, 4 : index, 0 : index] : (!fir.array<10x10xtuple<i32, f32>>, i32) -> !fir.array<10x10xtuple<i32, f32>>
- %1 = fir.insert_value %a, %f, [5 : index, 4 : index, 1 : index] : (!fir.array<10x10xtuple<i32, f32>>, f32) -> !fir.array<10x10xtuple<i32, f32>>
- return
-}
-
-// CHECK-LABEL: llvm.func @extract_array(
-// CHECK-SAME: %[[ARR:.*]]: !llvm.array<10 x array<10 x struct<(i32, f32)>>>
-// CHECK: %{{.*}} = llvm.insertvalue %{{.*}}, %[[ARR]][4 : index, 5 : index, 0 : index] : !llvm.array<10 x array<10 x struct<(i32, f32)>>>
-// CHECK: %{{.*}} = llvm.insertvalue %{{.*}}, %[[ARR]][4 : index, 5 : index, 1 : index] : !llvm.array<10 x array<10 x struct<(i32, f32)>>>
-// CHECK: llvm.return
-
-// -----
-
-// Test fir.insert_value operation conversion with derived type.
-
-func @insert_tuple(%a : tuple<i32, f32>) {
- %f = arith.constant 2.0 : f32
- %1 = fir.insert_value %a, %f, [1 : index] : (tuple<i32, f32>, f32) -> tuple<i32, f32>
- return
-}
-
-// CHECK-LABEL: func @insert_tuple(
-// CHECK-SAME: %[[TUPLE:.*]]: !llvm.struct<(i32, f32)>
-// CHECK: %{{.*}} = llvm.insertvalue %{{.*}}, %[[TUPLE]][1 : index] : !llvm.struct<(i32, f32)>
-// CHECK: llvm.return