#include "flang/Optimizer/CodeGen/CodeGenOpenMP.h"
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Builder/LowLevelIntrinsics.h"
#include "flang/Optimizer/CodeGen/CodeGen.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
#include "flang/Optimizer/Support/FatalError.h"
#include "flang/Optimizer/Support/InternalNames.h"
#include "flang/Optimizer/Support/Utils.h"
#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
#include "mlir/Conversion/LLVMCommon/Pattern.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/Transforms/DialectConversion.h"
using namespace fir;
#define DEBUG_TYPE "flang-codegen-openmp"
#include "flang/Optimizer/CodeGen/TypeConverter.h"
namespace {
template <typename OpType>
class OpenMPFIROpConversion : public mlir::ConvertOpToLLVMPattern<OpType> {
public:
explicit OpenMPFIROpConversion(const fir::LLVMTypeConverter &lowering)
: mlir::ConvertOpToLLVMPattern<OpType>(lowering) {}
const fir::LLVMTypeConverter &lowerTy() const {
return *static_cast<const fir::LLVMTypeConverter *>(
this->getTypeConverter());
}
};
struct MapInfoOpConversion
: public OpenMPFIROpConversion<mlir::omp::MapInfoOp> {
using OpenMPFIROpConversion::OpenMPFIROpConversion;
mlir::omp::MapBoundsOp
createBoundsForCharString(mlir::ConversionPatternRewriter &rewriter,
unsigned int len, mlir::Location loc) const {
mlir::Type i64Ty = rewriter.getIntegerType(64);
auto lBound = mlir::LLVM::ConstantOp::create(rewriter, loc, i64Ty, 0);
auto uBoundAndExt =
mlir::LLVM::ConstantOp::create(rewriter, loc, i64Ty, len - 1);
auto stride = mlir::LLVM::ConstantOp::create(rewriter, loc, i64Ty, 1);
auto baseLb = mlir::LLVM::ConstantOp::create(rewriter, loc, i64Ty, 1);
auto mapBoundType = rewriter.getType<mlir::omp::MapBoundsType>();
return mlir::omp::MapBoundsOp::create(rewriter, loc, mapBoundType, lBound,
uBoundAndExt, uBoundAndExt, stride,
false, baseLb);
}
llvm::LogicalResult
matchAndRewrite(mlir::omp::MapInfoOp curOp, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const override {
const mlir::TypeConverter *converter = getTypeConverter();
llvm::SmallVector<mlir::Type> resTypes;
if (failed(converter->convertTypes(curOp->getResultTypes(), resTypes)))
return mlir::failure();
llvm::SmallVector<mlir::NamedAttribute> newAttrs;
mlir::omp::MapBoundsOp mapBoundsOp;
for (mlir::NamedAttribute attr : curOp->getAttrs()) {
if (auto typeAttr = mlir::dyn_cast<mlir::TypeAttr>(attr.getValue())) {
mlir::Type newAttr;
if (fir::isTypeWithDescriptor(typeAttr.getValue())) {
newAttr = lowerTy().convertBoxTypeAsStruct(
mlir::cast<fir::BaseBoxType>(typeAttr.getValue()));
} else if (fir::isa_char_string(fir::unwrapSequenceType(
fir::unwrapPassByRefType(typeAttr.getValue()))) &&
!characterWithDynamicLen(
fir::unwrapPassByRefType(typeAttr.getValue()))) {
if (auto ct = mlir::dyn_cast_or_null<fir::CharacterType>(
fir::unwrapSequenceType(typeAttr.getValue()))) {
newAttr = converter->convertType(
fir::unwrapSequenceType(typeAttr.getValue()));
if (auto type = mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(newAttr))
newAttr = type.getElementType();
auto offloadMod =
llvm::dyn_cast_or_null<mlir::omp::OffloadModuleInterface>(
*curOp->getParentOfType<mlir::ModuleOp>());
if (!offloadMod.getIsTargetDevice())
mapBoundsOp = createBoundsForCharString(rewriter, ct.getLen(),
curOp.getLoc());
} else {
newAttr = converter->convertType(typeAttr.getValue());
}
} else {
newAttr = converter->convertType(typeAttr.getValue());
}
newAttrs.emplace_back(attr.getName(), mlir::TypeAttr::get(newAttr));
} else {
newAttrs.push_back(attr);
}
}
auto newOp = rewriter.replaceOpWithNewOp<mlir::omp::MapInfoOp>(
curOp, resTypes, adaptor.getOperands(), newAttrs);
if (mapBoundsOp) {
rewriter.startOpModification(newOp);
newOp.getBoundsMutable().append(mlir::ValueRange{mapBoundsOp});
rewriter.finalizeOpModification(newOp);
}
return mlir::success();
}
};
struct PrivateClauseOpConversion
: public OpenMPFIROpConversion<mlir::omp::PrivateClauseOp> {
using OpenMPFIROpConversion::OpenMPFIROpConversion;
llvm::LogicalResult
matchAndRewrite(mlir::omp::PrivateClauseOp curOp, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const override {
const fir::LLVMTypeConverter &converter = lowerTy();
mlir::Type convertedAllocType;
if (auto box = mlir::dyn_cast<fir::BaseBoxType>(curOp.getType())) {
if (box.isAssumedRank())
TODO(curOp->getLoc(), "Privatize an assumed rank array");
unsigned rank = 0;
if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(
fir::unwrapRefType(box.getEleTy())))
rank = seqTy.getShape().size();
convertedAllocType = converter.convertBoxTypeAsStruct(box, rank);
} else {
convertedAllocType = converter.convertType(adaptor.getType());
}
if (!convertedAllocType)
return mlir::failure();
rewriter.startOpModification(curOp);
curOp.setType(convertedAllocType);
rewriter.finalizeOpModification(curOp);
return mlir::success();
}
};
static mlir::Type convertObjectType(const fir::LLVMTypeConverter &converter,
mlir::Type firType) {
if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(firType))
return converter.convertBoxTypeAsStruct(boxTy);
return converter.convertType(firType);
}
struct TargetAllocMemOpConversion
: public OpenMPFIROpConversion<mlir::omp::TargetAllocMemOp> {
using OpenMPFIROpConversion::OpenMPFIROpConversion;
llvm::LogicalResult
matchAndRewrite(mlir::omp::TargetAllocMemOp allocmemOp, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const override {
mlir::Type heapTy = allocmemOp.getAllocatedType();
mlir::Location loc = allocmemOp.getLoc();
auto ity = lowerTy().indexType();
mlir::Type dataTy = fir::unwrapRefType(heapTy);
mlir::Type llvmObjectTy = convertObjectType(lowerTy(), dataTy);
if (fir::isRecordWithTypeParameters(fir::unwrapSequenceType(dataTy)))
TODO(loc, "omp.target_allocmem codegen of derived type with length "
"parameters");
mlir::Value size = fir::computeElementDistance(
loc, llvmObjectTy, ity, rewriter, lowerTy().getDataLayout());
if (auto scaleSize = fir::genAllocationScaleSize(
loc, allocmemOp.getInType(), ity, rewriter))
size = mlir::LLVM::MulOp::create(rewriter, loc, ity, size, scaleSize);
for (mlir::Value opnd : adaptor.getOperands().drop_front())
size = mlir::LLVM::MulOp::create(
rewriter, loc, ity, size,
integerCast(lowerTy(), loc, rewriter, ity, opnd));
auto mallocTyWidth = lowerTy().getIndexTypeBitwidth();
auto mallocTy =
mlir::IntegerType::get(rewriter.getContext(), mallocTyWidth);
if (mallocTyWidth != ity.getIntOrFloatBitWidth())
size = integerCast(lowerTy(), loc, rewriter, mallocTy, size);
rewriter.modifyOpInPlace(allocmemOp, [&]() {
allocmemOp.setInType(rewriter.getI8Type());
allocmemOp.getTypeparamsMutable().clear();
allocmemOp.getTypeparamsMutable().append(size);
});
return mlir::success();
}
};
}
void fir::populateOpenMPFIRToLLVMConversionPatterns(
const LLVMTypeConverter &converter, mlir::RewritePatternSet &patterns) {
patterns.add<MapInfoOpConversion>(converter);
patterns.add<PrivateClauseOpConversion>(converter);
patterns.add<TargetAllocMemOpConversion>(converter);
}