brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.3 KiB · 96e3caa Raw
393 lines · cpp
1//===-- CodeGen.cpp -- bridge to lower to LLVM ----------------------------===//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/FIROpPatterns.h"14#include "flang/Optimizer/Builder/FIRBuilder.h"15#include "mlir/Dialect/OpenMP/OpenMPDialect.h"16#include "llvm/Support/Debug.h"17 18static inline mlir::Type getLlvmPtrType(mlir::MLIRContext *context,19                                        unsigned addressSpace = 0) {20  return mlir::LLVM::LLVMPointerType::get(context, addressSpace);21}22 23static unsigned getTypeDescFieldId(mlir::Type ty) {24  auto isArray = mlir::isa<fir::SequenceType>(fir::dyn_cast_ptrOrBoxEleTy(ty));25  return isArray ? kOptTypePtrPosInBox : kDimsPosInBox;26}27 28namespace fir {29 30ConvertFIRToLLVMPattern::ConvertFIRToLLVMPattern(31    llvm::StringRef rootOpName, mlir::MLIRContext *context,32    const fir::LLVMTypeConverter &typeConverter,33    const fir::FIRToLLVMPassOptions &options, mlir::PatternBenefit benefit)34    : ConvertToLLVMPattern(rootOpName, context, typeConverter, benefit),35      options(options) {}36 37// Convert FIR type to LLVM without turning fir.box<T> into memory38// reference.39mlir::Type40ConvertFIRToLLVMPattern::convertObjectType(mlir::Type firType) const {41  if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(firType))42    return lowerTy().convertBoxTypeAsStruct(boxTy);43  return lowerTy().convertType(firType);44}45 46mlir::LLVM::ConstantOp ConvertFIRToLLVMPattern::genI32Constant(47    mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,48    int value) const {49  mlir::Type i32Ty = rewriter.getI32Type();50  mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value);51  return mlir::LLVM::ConstantOp::create(rewriter, loc, i32Ty, attr);52}53 54mlir::LLVM::ConstantOp ConvertFIRToLLVMPattern::genConstantOffset(55    mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,56    int offset) const {57  mlir::Type ity = lowerTy().offsetType();58  mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset);59  return mlir::LLVM::ConstantOp::create(rewriter, loc, ity, cattr);60}61 62/// Perform an extension or truncation as needed on an integer value. Lowering63/// to the specific target may involve some sign-extending or truncation of64/// values, particularly to fit them from abstract box types to the65/// appropriate reified structures.66mlir::Value ConvertFIRToLLVMPattern::integerCast(67    mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,68    mlir::Type ty, mlir::Value val, bool fold) const {69  auto valTy = val.getType();70  // If the value was not yet lowered, lower its type so that it can71  // be used in getPrimitiveTypeSizeInBits.72  if (!mlir::isa<mlir::IntegerType>(valTy))73    valTy = convertType(valTy);74  auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);75  auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);76  if (fold) {77    if (toSize < fromSize)78      return rewriter.createOrFold<mlir::LLVM::TruncOp>(loc, ty, val);79    if (toSize > fromSize)80      return rewriter.createOrFold<mlir::LLVM::SExtOp>(loc, ty, val);81  } else {82    if (toSize < fromSize)83      return mlir::LLVM::TruncOp::create(rewriter, loc, ty, val);84    if (toSize > fromSize)85      return mlir::LLVM::SExtOp::create(rewriter, loc, ty, val);86  }87  return val;88}89 90fir::ConvertFIRToLLVMPattern::TypePair91ConvertFIRToLLVMPattern::getBoxTypePair(mlir::Type firBoxTy) const {92  mlir::Type llvmBoxTy =93      lowerTy().convertBoxTypeAsStruct(mlir::cast<fir::BaseBoxType>(firBoxTy));94  return TypePair{firBoxTy, llvmBoxTy};95}96 97/// Construct code sequence to extract the specific value from a `fir.box`.98mlir::Value ConvertFIRToLLVMPattern::getValueFromBox(99    mlir::Location loc, TypePair boxTy, mlir::Value box, mlir::Type resultTy,100    mlir::ConversionPatternRewriter &rewriter, int boxValue) const {101  if (mlir::isa<mlir::LLVM::LLVMPointerType>(box.getType())) {102    auto pty = getLlvmPtrType(resultTy.getContext());103    auto p = mlir::LLVM::GEPOp::create(104        rewriter, loc, pty, boxTy.llvm, box,105        llvm::ArrayRef<mlir::LLVM::GEPArg>{0, boxValue});106    auto fldTy = getBoxEleTy(boxTy.llvm, {boxValue});107    auto loadOp = mlir::LLVM::LoadOp::create(rewriter, loc, fldTy, p);108    auto castOp = integerCast(loc, rewriter, resultTy, loadOp);109    attachTBAATag(loadOp, boxTy.fir, nullptr, p);110    return castOp;111  }112  return mlir::LLVM::ExtractValueOp::create(rewriter, loc, box, boxValue);113}114 115/// Method to construct code sequence to get the triple for dimension `dim`116/// from a box.117llvm::SmallVector<mlir::Value, 3> ConvertFIRToLLVMPattern::getDimsFromBox(118    mlir::Location loc, llvm::ArrayRef<mlir::Type> retTys, TypePair boxTy,119    mlir::Value box, mlir::Value dim,120    mlir::ConversionPatternRewriter &rewriter) const {121  mlir::Value l0 =122      loadDimFieldFromBox(loc, boxTy, box, dim, 0, retTys[0], rewriter);123  mlir::Value l1 =124      loadDimFieldFromBox(loc, boxTy, box, dim, 1, retTys[1], rewriter);125  mlir::Value l2 =126      loadDimFieldFromBox(loc, boxTy, box, dim, 2, retTys[2], rewriter);127  return {l0, l1, l2};128}129 130llvm::SmallVector<mlir::Value, 3> ConvertFIRToLLVMPattern::getDimsFromBox(131    mlir::Location loc, llvm::ArrayRef<mlir::Type> retTys, TypePair boxTy,132    mlir::Value box, int dim, mlir::ConversionPatternRewriter &rewriter) const {133  mlir::Value l0 =134      getDimFieldFromBox(loc, boxTy, box, dim, 0, retTys[0], rewriter);135  mlir::Value l1 =136      getDimFieldFromBox(loc, boxTy, box, dim, 1, retTys[1], rewriter);137  mlir::Value l2 =138      getDimFieldFromBox(loc, boxTy, box, dim, 2, retTys[2], rewriter);139  return {l0, l1, l2};140}141 142mlir::Value ConvertFIRToLLVMPattern::loadDimFieldFromBox(143    mlir::Location loc, TypePair boxTy, mlir::Value box, mlir::Value dim,144    int off, mlir::Type ty, mlir::ConversionPatternRewriter &rewriter) const {145  assert(mlir::isa<mlir::LLVM::LLVMPointerType>(box.getType()) &&146         "descriptor inquiry with runtime dim can only be done on descriptor "147         "in memory");148  mlir::LLVM::GEPOp p = genGEP(loc, boxTy.llvm, rewriter, box, 0,149                               static_cast<int>(kDimsPosInBox), dim, off);150  auto loadOp = mlir::LLVM::LoadOp::create(rewriter, loc, ty, p);151  attachTBAATag(loadOp, boxTy.fir, nullptr, p);152  return loadOp;153}154 155mlir::Value ConvertFIRToLLVMPattern::getDimFieldFromBox(156    mlir::Location loc, TypePair boxTy, mlir::Value box, int dim, int off,157    mlir::Type ty, mlir::ConversionPatternRewriter &rewriter) const {158  if (mlir::isa<mlir::LLVM::LLVMPointerType>(box.getType())) {159    mlir::LLVM::GEPOp p = genGEP(loc, boxTy.llvm, rewriter, box, 0,160                                 static_cast<int>(kDimsPosInBox), dim, off);161    auto loadOp = mlir::LLVM::LoadOp::create(rewriter, loc, ty, p);162    attachTBAATag(loadOp, boxTy.fir, nullptr, p);163    return loadOp;164  }165  return mlir::LLVM::ExtractValueOp::create(166      rewriter, loc, box,167      llvm::ArrayRef<std::int64_t>{kDimsPosInBox, dim, off});168}169 170mlir::Value ConvertFIRToLLVMPattern::getStrideFromBox(171    mlir::Location loc, TypePair boxTy, mlir::Value box, unsigned dim,172    mlir::ConversionPatternRewriter &rewriter) const {173  auto idxTy = lowerTy().indexType();174  return getDimFieldFromBox(loc, boxTy, box, dim, kDimStridePos, idxTy,175                            rewriter);176}177 178/// Read base address from a fir.box. Returned address has type ty.179mlir::Value ConvertFIRToLLVMPattern::getBaseAddrFromBox(180    mlir::Location loc, TypePair boxTy, mlir::Value box,181    mlir::ConversionPatternRewriter &rewriter) const {182  mlir::Type resultTy = ::getLlvmPtrType(boxTy.llvm.getContext());183  return getValueFromBox(loc, boxTy, box, resultTy, rewriter, kAddrPosInBox);184}185 186mlir::Value ConvertFIRToLLVMPattern::getElementSizeFromBox(187    mlir::Location loc, mlir::Type resultTy, TypePair boxTy, mlir::Value box,188    mlir::ConversionPatternRewriter &rewriter) const {189  return getValueFromBox(loc, boxTy, box, resultTy, rewriter, kElemLenPosInBox);190}191 192/// Read base address from a fir.box. Returned address has type ty.193mlir::Value ConvertFIRToLLVMPattern::getRankFromBox(194    mlir::Location loc, TypePair boxTy, mlir::Value box,195    mlir::ConversionPatternRewriter &rewriter) const {196  mlir::Type resultTy = getBoxEleTy(boxTy.llvm, {kRankPosInBox});197  return getValueFromBox(loc, boxTy, box, resultTy, rewriter, kRankPosInBox);198}199 200/// Read the extra field from a fir.box.201mlir::Value ConvertFIRToLLVMPattern::getExtraFromBox(202    mlir::Location loc, TypePair boxTy, mlir::Value box,203    mlir::ConversionPatternRewriter &rewriter) const {204  mlir::Type resultTy = getBoxEleTy(boxTy.llvm, {kExtraPosInBox});205  return getValueFromBox(loc, boxTy, box, resultTy, rewriter, kExtraPosInBox);206}207 208// Get the element type given an LLVM type that is of the form209// (array|struct|vector)+ and the provided indexes.210mlir::Type ConvertFIRToLLVMPattern::getBoxEleTy(211    mlir::Type type, llvm::ArrayRef<std::int64_t> indexes) const {212  for (unsigned i : indexes) {213    if (auto t = mlir::dyn_cast<mlir::LLVM::LLVMStructType>(type)) {214      assert(!t.isOpaque() && i < t.getBody().size());215      type = t.getBody()[i];216    } else if (auto t = mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(type)) {217      type = t.getElementType();218    } else if (auto t = mlir::dyn_cast<mlir::VectorType>(type)) {219      type = t.getElementType();220    } else {221      fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()),222                          "request for invalid box element type");223    }224  }225  return type;226}227 228// Return LLVM type of the object described by a fir.box of \p boxType.229mlir::Type ConvertFIRToLLVMPattern::getLlvmObjectTypeFromBoxType(230    mlir::Type boxType) const {231  mlir::Type objectType = fir::dyn_cast_ptrOrBoxEleTy(boxType);232  assert(objectType && "boxType must be a box type");233  return this->convertType(objectType);234}235 236/// Read the address of the type descriptor from a box.237mlir::Value ConvertFIRToLLVMPattern::loadTypeDescAddress(238    mlir::Location loc, TypePair boxTy, mlir::Value box,239    mlir::ConversionPatternRewriter &rewriter) const {240  unsigned typeDescFieldId = getTypeDescFieldId(boxTy.fir);241  mlir::Type tdescType = lowerTy().convertTypeDescType(rewriter.getContext());242  return getValueFromBox(loc, boxTy, box, tdescType, rewriter, typeDescFieldId);243}244 245// Load the attribute from the \p box and perform a check against \p maskValue246// The final comparison is implemented as `(attribute & maskValue) != 0`.247mlir::Value ConvertFIRToLLVMPattern::genBoxAttributeCheck(248    mlir::Location loc, TypePair boxTy, mlir::Value box,249    mlir::ConversionPatternRewriter &rewriter, unsigned maskValue) const {250  mlir::Type attrTy = rewriter.getI32Type();251  mlir::Value attribute =252      getValueFromBox(loc, boxTy, box, attrTy, rewriter, kAttributePosInBox);253  mlir::LLVM::ConstantOp attrMask = genConstantOffset(loc, rewriter, maskValue);254  auto maskRes =255      mlir::LLVM::AndOp::create(rewriter, loc, attrTy, attribute, attrMask);256  mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);257  return mlir::LLVM::ICmpOp::create(rewriter, loc,258                                    mlir::LLVM::ICmpPredicate::ne, maskRes, c0);259}260 261mlir::Value ConvertFIRToLLVMPattern::computeBoxSize(262    mlir::Location loc, TypePair boxTy, mlir::Value box,263    mlir::ConversionPatternRewriter &rewriter) const {264  auto firBoxType = mlir::dyn_cast<fir::BaseBoxType>(boxTy.fir);265  assert(firBoxType && "must be a BaseBoxType");266  const mlir::DataLayout &dl = lowerTy().getDataLayout();267  if (!firBoxType.isAssumedRank())268    return genConstantOffset(loc, rewriter, dl.getTypeSize(boxTy.llvm));269  fir::BaseBoxType firScalarBoxType = firBoxType.getBoxTypeWithNewShape(0);270  mlir::Type llvmScalarBoxType =271      lowerTy().convertBoxTypeAsStruct(firScalarBoxType);272  llvm::TypeSize scalarBoxSizeCst = dl.getTypeSize(llvmScalarBoxType);273  mlir::Value scalarBoxSize =274      genConstantOffset(loc, rewriter, scalarBoxSizeCst);275  mlir::Value rawRank = getRankFromBox(loc, boxTy, box, rewriter);276  mlir::Value rank =277      integerCast(loc, rewriter, scalarBoxSize.getType(), rawRank);278  mlir::Type llvmDimsType = getBoxEleTy(boxTy.llvm, {kDimsPosInBox, 1});279  llvm::TypeSize sizePerDimCst = dl.getTypeSize(llvmDimsType);280  assert((scalarBoxSizeCst + sizePerDimCst ==281          dl.getTypeSize(lowerTy().convertBoxTypeAsStruct(282              firBoxType.getBoxTypeWithNewShape(1)))) &&283         "descriptor layout requires adding padding for dim field");284  mlir::Value sizePerDim = genConstantOffset(loc, rewriter, sizePerDimCst);285  mlir::Value dimsSize = mlir::LLVM::MulOp::create(286      rewriter, loc, sizePerDim.getType(), sizePerDim, rank);287  mlir::Value size = mlir::LLVM::AddOp::create(288      rewriter, loc, scalarBoxSize.getType(), scalarBoxSize, dimsSize);289  return size;290}291 292// Find the Block in which the alloca should be inserted.293// The order to recursively find the proper block:294// 1. An OpenMP Op that will be outlined.295// 2. An OpenMP or OpenACC Op with one or more regions holding executable code.296// 3. A LLVMFuncOp297// 4. The first ancestor that is one of the above.298mlir::Block *ConvertFIRToLLVMPattern::getBlockForAllocaInsert(299    mlir::Operation *op, mlir::Region *parentRegion) const {300  if (auto iface = mlir::dyn_cast<mlir::omp::OutlineableOpenMPOpInterface>(op))301    return iface.getAllocaBlock();302  if (auto recipeIface = mlir::dyn_cast<mlir::accomp::RecipeInterface>(op))303    return recipeIface.getAllocaBlock(*parentRegion);304  if (auto llvmFuncOp = mlir::dyn_cast<mlir::LLVM::LLVMFuncOp>(op))305    return &llvmFuncOp.front();306 307  return getBlockForAllocaInsert(op->getParentOp(), parentRegion);308}309 310// Generate an alloca of size 1 for an object of type \p llvmObjectTy in the311// allocation address space provided for the architecture in the DataLayout312// specification. If the address space is different from the devices313// program address space we perform a cast. In the case of most architectures314// the program and allocation address space will be the default of 0 and no315// cast will be emitted.316mlir::Value ConvertFIRToLLVMPattern::genAllocaAndAddrCastWithType(317    mlir::Location loc, mlir::Type llvmObjectTy, unsigned alignment,318    mlir::ConversionPatternRewriter &rewriter) const {319  auto thisPt = rewriter.saveInsertionPoint();320  mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();321  mlir::Region *parentRegion = rewriter.getInsertionBlock()->getParent();322  mlir::Block *insertBlock = getBlockForAllocaInsert(parentOp, parentRegion);323  rewriter.setInsertionPointToStart(insertBlock);324  auto size = genI32Constant(loc, rewriter, 1);325  unsigned allocaAs = getAllocaAddressSpace(rewriter);326  unsigned programAs = getProgramAddressSpace(rewriter);327 328  mlir::Value al = mlir::LLVM::AllocaOp::create(329      rewriter, loc, ::getLlvmPtrType(llvmObjectTy.getContext(), allocaAs),330      llvmObjectTy, size, alignment);331 332  // if our allocation address space, is not the same as the program address333  // space, then we must emit a cast to the program address space before use.334  // An example case would be on AMDGPU, where the allocation address space is335  // the numeric value 5 (private), and the program address space is 0336  // (generic).337  if (allocaAs != programAs) {338    al = mlir::LLVM::AddrSpaceCastOp::create(339        rewriter, loc, ::getLlvmPtrType(llvmObjectTy.getContext(), programAs),340        al);341  }342 343  rewriter.restoreInsertionPoint(thisPt);344  return al;345}346 347unsigned ConvertFIRToLLVMPattern::getAllocaAddressSpace(348    mlir::ConversionPatternRewriter &rewriter) const {349  mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();350  assert(parentOp != nullptr &&351         "expected insertion block to have parent operation");352  auto module = mlir::isa<mlir::ModuleOp>(parentOp)353                    ? mlir::cast<mlir::ModuleOp>(parentOp)354                    : parentOp->getParentOfType<mlir::ModuleOp>();355  if (module)356    if (mlir::Attribute addrSpace =357            mlir::DataLayout(module).getAllocaMemorySpace())358      return llvm::cast<mlir::IntegerAttr>(addrSpace).getUInt();359  return defaultAddressSpace;360}361 362unsigned ConvertFIRToLLVMPattern::getProgramAddressSpace(363    mlir::ConversionPatternRewriter &rewriter) const {364  mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();365  assert(parentOp != nullptr &&366         "expected insertion block to have parent operation");367  auto module = mlir::isa<mlir::ModuleOp>(parentOp)368                    ? mlir::cast<mlir::ModuleOp>(parentOp)369                    : parentOp->getParentOfType<mlir::ModuleOp>();370  if (module)371    if (mlir::Attribute addrSpace =372            mlir::DataLayout(module).getProgramMemorySpace())373      return llvm::cast<mlir::IntegerAttr>(addrSpace).getUInt();374  return defaultAddressSpace;375}376 377unsigned ConvertFIRToLLVMPattern::getGlobalAddressSpace(378    mlir::ConversionPatternRewriter &rewriter) const {379  mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();380  assert(parentOp != nullptr &&381         "expected insertion block to have parent operation");382  auto module = mlir::isa<mlir::ModuleOp>(parentOp)383                    ? mlir::cast<mlir::ModuleOp>(parentOp)384                    : parentOp->getParentOfType<mlir::ModuleOp>();385  if (module)386    if (mlir::Attribute addrSpace =387            mlir::DataLayout(module).getGlobalMemorySpace())388      return llvm::cast<mlir::IntegerAttr>(addrSpace).getUInt();389  return defaultAddressSpace;390}391 392} // namespace fir393