| 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-exception |
| 6 | // |
| 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 "mlir/Conversion/LLVMCommon/ConversionTarget.h" |
| 25 | #include "mlir/Conversion/LLVMCommon/Pattern.h" |
| 26 | #include "mlir/Dialect/LLVMIR/LLVMDialect.h" |
| 27 | #include "mlir/Dialect/OpenMP/OpenMPDialect.h" |
| 28 | #include "mlir/IR/PatternMatch.h" |
| 29 | #include "mlir/Transforms/DialectConversion.h" |
| 30 | |
| 31 | using namespace fir; |
| 32 | |
| 33 | #define DEBUG_TYPE "flang-codegen-openmp" |
| 34 | |
| 35 | // fir::LLVMTypeConverter for converting to LLVM IR dialect types. |
| 36 | #include "flang/Optimizer/CodeGen/TypeConverter.h" |
| 37 | |
| 38 | namespace { |
| 39 | /// A pattern that converts the region arguments in a single-region OpenMP |
| 40 | /// operation to the LLVM dialect. The body of the region is not modified and is |
| 41 | /// expected to either be processed by the conversion infrastructure or already |
| 42 | /// contain ops compatible with LLVM dialect types. |
| 43 | template <typename OpType> |
| 44 | class OpenMPFIROpConversion : public mlir::ConvertOpToLLVMPattern<OpType> { |
| 45 | public: |
| 46 | explicit OpenMPFIROpConversion(const fir::LLVMTypeConverter &lowering) |
| 47 | : mlir::ConvertOpToLLVMPattern<OpType>(lowering) {} |
| 48 | |
| 49 | const fir::LLVMTypeConverter &lowerTy() const { |
| 50 | return *static_cast<const fir::LLVMTypeConverter *>( |
| 51 | this->getTypeConverter()); |
| 52 | } |
| 53 | }; |
| 54 | |
| 55 | // FIR Op specific conversion for MapInfoOp that overwrites the default OpenMP |
| 56 | // Dialect lowering, this allows FIR specific lowering of types, required for |
| 57 | // descriptors of allocatables currently. |
| 58 | struct MapInfoOpConversion |
| 59 | : public OpenMPFIROpConversion<mlir::omp::MapInfoOp> { |
| 60 | using OpenMPFIROpConversion::OpenMPFIROpConversion; |
| 61 | |
| 62 | llvm::LogicalResult |
| 63 | matchAndRewrite(mlir::omp::MapInfoOp curOp, OpAdaptor adaptor, |
| 64 | mlir::ConversionPatternRewriter &rewriter) const override { |
| 65 | const mlir::TypeConverter *converter = getTypeConverter(); |
| 66 | llvm::SmallVector<mlir::Type> resTypes; |
| 67 | if (failed(converter->convertTypes(curOp->getResultTypes(), resTypes))) |
| 68 | return mlir::failure(); |
| 69 | |
| 70 | llvm::SmallVector<mlir::NamedAttribute> newAttrs; |
| 71 | mlir::omp::MapInfoOp newOp; |
| 72 | for (mlir::NamedAttribute attr : curOp->getAttrs()) { |
| 73 | if (auto typeAttr = mlir::dyn_cast<mlir::TypeAttr>(attr.getValue())) { |
| 74 | mlir::Type newAttr; |
| 75 | if (fir::isTypeWithDescriptor(typeAttr.getValue())) { |
| 76 | newAttr = lowerTy().convertBoxTypeAsStruct( |
| 77 | mlir::cast<fir::BaseBoxType>(typeAttr.getValue())); |
| 78 | } else { |
| 79 | newAttr = converter->convertType(typeAttr.getValue()); |
| 80 | } |
| 81 | newAttrs.emplace_back(attr.getName(), mlir::TypeAttr::get(newAttr)); |
| 82 | } else { |
| 83 | newAttrs.push_back(attr); |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | rewriter.replaceOpWithNewOp<mlir::omp::MapInfoOp>( |
| 88 | curOp, resTypes, adaptor.getOperands(), newAttrs); |
| 89 | |
| 90 | return mlir::success(); |
| 91 | } |
| 92 | }; |
| 93 | |
| 94 | // FIR op specific conversion for PrivateClauseOp that overwrites the default |
| 95 | // OpenMP Dialect lowering, this allows FIR-aware lowering of types, required |
| 96 | // for boxes because the OpenMP dialect conversion doesn't know anything about |
| 97 | // FIR types. |
| 98 | struct PrivateClauseOpConversion |
| 99 | : public OpenMPFIROpConversion<mlir::omp::PrivateClauseOp> { |
| 100 | using OpenMPFIROpConversion::OpenMPFIROpConversion; |
| 101 | |
| 102 | llvm::LogicalResult |
| 103 | matchAndRewrite(mlir::omp::PrivateClauseOp curOp, OpAdaptor adaptor, |
| 104 | mlir::ConversionPatternRewriter &rewriter) const override { |
| 105 | const fir::LLVMTypeConverter &converter = lowerTy(); |
| 106 | mlir::Type convertedAllocType; |
| 107 | if (auto box = mlir::dyn_cast<fir::BaseBoxType>(curOp.getType())) { |
| 108 | // In LLVM codegen fir.box<> == fir.ref<fir.box<>> == llvm.ptr |
| 109 | // Here we really do want the actual structure |
| 110 | if (box.isAssumedRank()) |
| 111 | TODO(curOp->getLoc(), "Privatize an assumed rank array" ); |
| 112 | unsigned rank = 0; |
| 113 | if (auto seqTy = mlir::dyn_cast<fir::SequenceType>( |
| 114 | fir::unwrapRefType(box.getEleTy()))) |
| 115 | rank = seqTy.getShape().size(); |
| 116 | convertedAllocType = converter.convertBoxTypeAsStruct(box, rank); |
| 117 | } else { |
| 118 | convertedAllocType = converter.convertType(adaptor.getType()); |
| 119 | } |
| 120 | if (!convertedAllocType) |
| 121 | return mlir::failure(); |
| 122 | rewriter.startOpModification(curOp); |
| 123 | curOp.setType(convertedAllocType); |
| 124 | rewriter.finalizeOpModification(curOp); |
| 125 | return mlir::success(); |
| 126 | } |
| 127 | }; |
| 128 | } // namespace |
| 129 | |
| 130 | void fir::populateOpenMPFIRToLLVMConversionPatterns( |
| 131 | const LLVMTypeConverter &converter, mlir::RewritePatternSet &patterns) { |
| 132 | patterns.add<MapInfoOpConversion>(converter); |
| 133 | patterns.add<PrivateClauseOpConversion>(converter); |
| 134 | } |
| 135 | |