!llvm.ptr<T> typed pointers are depreciated in MLIR LLVM dialects. Flang codegen still generated them and relied on mlir.llvm codegen to LLVM to turn them into opaque pointers. This patch update FIR codegen to directly emit and work with LLVM opaque pointers. Addresses https://github.com/llvm/llvm-project/issues/69303 - All places generating GEPs need to add an extra type argument with the base type (the T that was previously in the llvm.ptr<T> of the base). - llvm.alloca must also be provided the object type. In the process, I doscovered that we were shamelessly copying all the attribute from fir.alloca to the llvm.alloca, which makes no sense for the operand segments. The updated code that cannot take an attribute dictionnary in the llvm.alloca builder with opaque pointers only propagate the "pinned" and "bindc_name" attributes to help debugging the generated IR. - Updating all the places that rely on getting the llvm object type from lowered llvm.ptr<T> arguments to get it from a type conversion of the original fir types. - Updating all the places that were generating llvm.ptr<T> types to generate the opaque llvm.ptr type. - Updating all the codegen tests checking generated MLIR llvm dialect. Many tests are testing directly LLVM IR, and this change is a no-op for those (which is expected).
142 lines
4.9 KiB
C++
142 lines
4.9 KiB
C++
//===-- 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_wrapper.h"
|
|
#include "flang/Runtime/descriptor.h"
|
|
#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
|
|
#include "mlir/IR/BuiltinTypes.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(context);
|
|
};
|
|
}
|
|
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<long>() {
|
|
return [](mlir::MLIRContext *context) -> mlir::Type {
|
|
return mlir::IntegerType::get(context, sizeof(long) * 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
|