brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.1 KiB · f74d635 Raw
271 lines · cpp
1//===-- CodeGenOpenMP.cpp -------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/10//11//===----------------------------------------------------------------------===//12 13#include "flang/Optimizer/CodeGen/CodeGenOpenMP.h"14 15#include "flang/Optimizer/Builder/FIRBuilder.h"16#include "flang/Optimizer/Builder/LowLevelIntrinsics.h"17#include "flang/Optimizer/CodeGen/CodeGen.h"18#include "flang/Optimizer/Dialect/FIRDialect.h"19#include "flang/Optimizer/Dialect/FIROps.h"20#include "flang/Optimizer/Dialect/FIRType.h"21#include "flang/Optimizer/Dialect/Support/FIRContext.h"22#include "flang/Optimizer/Support/FatalError.h"23#include "flang/Optimizer/Support/InternalNames.h"24#include "flang/Optimizer/Support/Utils.h"25#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"26#include "mlir/Conversion/LLVMCommon/Pattern.h"27#include "mlir/Dialect/LLVMIR/LLVMDialect.h"28#include "mlir/Dialect/OpenMP/OpenMPDialect.h"29#include "mlir/IR/PatternMatch.h"30#include "mlir/Transforms/DialectConversion.h"31 32using namespace fir;33 34#define DEBUG_TYPE "flang-codegen-openmp"35 36// fir::LLVMTypeConverter for converting to LLVM IR dialect types.37#include "flang/Optimizer/CodeGen/TypeConverter.h"38 39namespace {40/// A pattern that converts the region arguments in a single-region OpenMP41/// operation to the LLVM dialect. The body of the region is not modified and is42/// expected to either be processed by the conversion infrastructure or already43/// contain ops compatible with LLVM dialect types.44template <typename OpType>45class OpenMPFIROpConversion : public mlir::ConvertOpToLLVMPattern<OpType> {46public:47  explicit OpenMPFIROpConversion(const fir::LLVMTypeConverter &lowering)48      : mlir::ConvertOpToLLVMPattern<OpType>(lowering) {}49 50  const fir::LLVMTypeConverter &lowerTy() const {51    return *static_cast<const fir::LLVMTypeConverter *>(52        this->getTypeConverter());53  }54};55 56// FIR Op specific conversion for MapInfoOp that overwrites the default OpenMP57// Dialect lowering, this allows FIR specific lowering of types, required for58// descriptors of allocatables currently.59struct MapInfoOpConversion60    : public OpenMPFIROpConversion<mlir::omp::MapInfoOp> {61  using OpenMPFIROpConversion::OpenMPFIROpConversion;62 63  mlir::omp::MapBoundsOp64  createBoundsForCharString(mlir::ConversionPatternRewriter &rewriter,65                            unsigned int len, mlir::Location loc) const {66    mlir::Type i64Ty = rewriter.getIntegerType(64);67    auto lBound = mlir::LLVM::ConstantOp::create(rewriter, loc, i64Ty, 0);68    auto uBoundAndExt =69        mlir::LLVM::ConstantOp::create(rewriter, loc, i64Ty, len - 1);70    auto stride = mlir::LLVM::ConstantOp::create(rewriter, loc, i64Ty, 1);71    auto baseLb = mlir::LLVM::ConstantOp::create(rewriter, loc, i64Ty, 1);72    auto mapBoundType = rewriter.getType<mlir::omp::MapBoundsType>();73    return mlir::omp::MapBoundsOp::create(rewriter, loc, mapBoundType, lBound,74                                          uBoundAndExt, uBoundAndExt, stride,75                                          /*strideInBytes*/ false, baseLb);76  }77 78  llvm::LogicalResult79  matchAndRewrite(mlir::omp::MapInfoOp curOp, OpAdaptor adaptor,80                  mlir::ConversionPatternRewriter &rewriter) const override {81    const mlir::TypeConverter *converter = getTypeConverter();82    llvm::SmallVector<mlir::Type> resTypes;83    if (failed(converter->convertTypes(curOp->getResultTypes(), resTypes)))84      return mlir::failure();85 86    llvm::SmallVector<mlir::NamedAttribute> newAttrs;87    mlir::omp::MapBoundsOp mapBoundsOp;88    for (mlir::NamedAttribute attr : curOp->getAttrs()) {89      if (auto typeAttr = mlir::dyn_cast<mlir::TypeAttr>(attr.getValue())) {90        mlir::Type newAttr;91        if (fir::isTypeWithDescriptor(typeAttr.getValue())) {92          newAttr = lowerTy().convertBoxTypeAsStruct(93              mlir::cast<fir::BaseBoxType>(typeAttr.getValue()));94        } else if (fir::isa_char_string(fir::unwrapSequenceType(95                       fir::unwrapPassByRefType(typeAttr.getValue()))) &&96                   !characterWithDynamicLen(97                       fir::unwrapPassByRefType(typeAttr.getValue()))) {98          // Characters with a LEN param are represented as strings99          // (array of characters), the lowering to LLVM dialect100          // doesn't generate bounds for these (and this is not101          // done at the initial lowering either) and there is102          // minor inconsistencies in the variable types we103          // create for the map without this step when converting104          // to the LLVM dialect.105          //106          // For example, given the types:107          //108          //  1) CHARACTER(LEN=16), dimension(:,:), allocatable :: char_arr109          //  2) CHARACTER(LEN=16), dimension(10,10) :: char_arr110          //111          // We get the FIR types (note for 1: we already peeled off the112          // dynamic extents from the type at this stage, but the conversion113          // to llvm dialect does that in any case, so the final result114          // is the same):115          //116          //  1) !fir.char<1,16>117          //  2) !fir.array<10x10x!fir.char<1,16>>118          //119          // Which are converted to the LLVM dialect types:120          //121          // 1) !llvm.array<16 x i8>122          // 2) llvm.array<10 x array<10 x array<16 x i8>>123          //124          // And in both cases, we are missing the innermost bounds for125          // the !fir.char<1,16> which is expanded into a 16 x i8 array126          // in the conversion to LLVM dialect.127          //128          // The problem with this is that we would like to treat these129          // cases identically and not have to create specialised130          // lowerings for either of these in the lowering to LLVM-IR131          // and treat them like any other array that passes through.132          //133          // To do so below, we generate an extra bound for the134          // innermost array (the char type/string) using the LEN135          // parameter of the character type. And we "canonicalize"136          // the type, stripping it down to the base element type,137          // which in this case is an i8. This effectively allows138          // the lowering to treat this as a 1-D array with multiple139          // bounds which it is capable of handling without any special140          // casing.141          // TODO: Handle dynamic LEN characters.142          if (auto ct = mlir::dyn_cast_or_null<fir::CharacterType>(143                  fir::unwrapSequenceType(typeAttr.getValue()))) {144            newAttr = converter->convertType(145                fir::unwrapSequenceType(typeAttr.getValue()));146            if (auto type = mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(newAttr))147              newAttr = type.getElementType();148            // We do not generate MapBoundsOps for the device pass, as149            // MapBoundsOps are not generated for the device pass, as150            // they're unused in the device lowering.151            auto offloadMod =152                llvm::dyn_cast_or_null<mlir::omp::OffloadModuleInterface>(153                    *curOp->getParentOfType<mlir::ModuleOp>());154            if (!offloadMod.getIsTargetDevice())155              mapBoundsOp = createBoundsForCharString(rewriter, ct.getLen(),156                                                      curOp.getLoc());157          } else {158            newAttr = converter->convertType(typeAttr.getValue());159          }160        } else {161          newAttr = converter->convertType(typeAttr.getValue());162        }163        newAttrs.emplace_back(attr.getName(), mlir::TypeAttr::get(newAttr));164      } else {165        newAttrs.push_back(attr);166      }167    }168 169    auto newOp = rewriter.replaceOpWithNewOp<mlir::omp::MapInfoOp>(170        curOp, resTypes, adaptor.getOperands(), newAttrs);171    if (mapBoundsOp) {172      rewriter.startOpModification(newOp);173      newOp.getBoundsMutable().append(mlir::ValueRange{mapBoundsOp});174      rewriter.finalizeOpModification(newOp);175    }176 177    return mlir::success();178  }179};180 181// FIR op specific conversion for PrivateClauseOp that overwrites the default182// OpenMP Dialect lowering, this allows FIR-aware lowering of types, required183// for boxes because the OpenMP dialect conversion doesn't know anything about184// FIR types.185struct PrivateClauseOpConversion186    : public OpenMPFIROpConversion<mlir::omp::PrivateClauseOp> {187  using OpenMPFIROpConversion::OpenMPFIROpConversion;188 189  llvm::LogicalResult190  matchAndRewrite(mlir::omp::PrivateClauseOp curOp, OpAdaptor adaptor,191                  mlir::ConversionPatternRewriter &rewriter) const override {192    const fir::LLVMTypeConverter &converter = lowerTy();193    mlir::Type convertedAllocType;194    if (auto box = mlir::dyn_cast<fir::BaseBoxType>(curOp.getType())) {195      // In LLVM codegen fir.box<> == fir.ref<fir.box<>> == llvm.ptr196      // Here we really do want the actual structure197      if (box.isAssumedRank())198        TODO(curOp->getLoc(), "Privatize an assumed rank array");199      unsigned rank = 0;200      if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(201              fir::unwrapRefType(box.getEleTy())))202        rank = seqTy.getShape().size();203      convertedAllocType = converter.convertBoxTypeAsStruct(box, rank);204    } else {205      convertedAllocType = converter.convertType(adaptor.getType());206    }207    if (!convertedAllocType)208      return mlir::failure();209    rewriter.startOpModification(curOp);210    curOp.setType(convertedAllocType);211    rewriter.finalizeOpModification(curOp);212    return mlir::success();213  }214};215 216// Convert FIR type to LLVM without turning fir.box<T> into memory217// reference.218static mlir::Type convertObjectType(const fir::LLVMTypeConverter &converter,219                                    mlir::Type firType) {220  if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(firType))221    return converter.convertBoxTypeAsStruct(boxTy);222  return converter.convertType(firType);223}224 225// FIR Op specific conversion for TargetAllocMemOp226struct TargetAllocMemOpConversion227    : public OpenMPFIROpConversion<mlir::omp::TargetAllocMemOp> {228  using OpenMPFIROpConversion::OpenMPFIROpConversion;229 230  llvm::LogicalResult231  matchAndRewrite(mlir::omp::TargetAllocMemOp allocmemOp, OpAdaptor adaptor,232                  mlir::ConversionPatternRewriter &rewriter) const override {233    mlir::Type heapTy = allocmemOp.getAllocatedType();234    mlir::Location loc = allocmemOp.getLoc();235    auto ity = lowerTy().indexType();236    mlir::Type dataTy = fir::unwrapRefType(heapTy);237    mlir::Type llvmObjectTy = convertObjectType(lowerTy(), dataTy);238    if (fir::isRecordWithTypeParameters(fir::unwrapSequenceType(dataTy)))239      TODO(loc, "omp.target_allocmem codegen of derived type with length "240                "parameters");241    mlir::Value size = fir::computeElementDistance(242        loc, llvmObjectTy, ity, rewriter, lowerTy().getDataLayout());243    if (auto scaleSize = fir::genAllocationScaleSize(244            loc, allocmemOp.getInType(), ity, rewriter))245      size = mlir::LLVM::MulOp::create(rewriter, loc, ity, size, scaleSize);246    for (mlir::Value opnd : adaptor.getOperands().drop_front())247      size = mlir::LLVM::MulOp::create(248          rewriter, loc, ity, size,249          integerCast(lowerTy(), loc, rewriter, ity, opnd));250    auto mallocTyWidth = lowerTy().getIndexTypeBitwidth();251    auto mallocTy =252        mlir::IntegerType::get(rewriter.getContext(), mallocTyWidth);253    if (mallocTyWidth != ity.getIntOrFloatBitWidth())254      size = integerCast(lowerTy(), loc, rewriter, mallocTy, size);255    rewriter.modifyOpInPlace(allocmemOp, [&]() {256      allocmemOp.setInType(rewriter.getI8Type());257      allocmemOp.getTypeparamsMutable().clear();258      allocmemOp.getTypeparamsMutable().append(size);259    });260    return mlir::success();261  }262};263} // namespace264 265void fir::populateOpenMPFIRToLLVMConversionPatterns(266    const LLVMTypeConverter &converter, mlir::RewritePatternSet &patterns) {267  patterns.add<MapInfoOpConversion>(converter);268  patterns.add<PrivateClauseOpConversion>(converter);269  patterns.add<TargetAllocMemOpConversion>(converter);270}271