brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.0 KiB · 5db40af Raw
384 lines · cpp
1//===-- Optimizer/Builder/TemporaryStorage.cpp ------------------*- C++ -*-===//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// Implementation of utility data structures to create and manipulate temporary9// storages to stack Fortran values or pointers in HLFIR.10//===----------------------------------------------------------------------===//11 12#include "flang/Optimizer/Builder/TemporaryStorage.h"13#include "flang/Optimizer/Builder/FIRBuilder.h"14#include "flang/Optimizer/Builder/HLFIRTools.h"15#include "flang/Optimizer/Builder/Runtime/TemporaryStack.h"16#include "flang/Optimizer/Builder/Todo.h"17#include "flang/Optimizer/HLFIR/HLFIROps.h"18 19//===----------------------------------------------------------------------===//20// fir::factory::Counter implementation.21//===----------------------------------------------------------------------===//22 23fir::factory::Counter::Counter(mlir::Location loc, fir::FirOpBuilder &builder,24                               mlir::Value initialValue,25                               bool canCountThroughLoops)26    : canCountThroughLoops{canCountThroughLoops}, initialValue{initialValue} {27  mlir::Type type = initialValue.getType();28  one = builder.createIntegerConstant(loc, type, 1);29  if (canCountThroughLoops) {30    index = builder.createTemporary(loc, type);31    fir::StoreOp::create(builder, loc, initialValue, index);32  } else {33    index = initialValue;34  }35}36 37mlir::Value38fir::factory::Counter::getAndIncrementIndex(mlir::Location loc,39                                            fir::FirOpBuilder &builder) {40  if (canCountThroughLoops) {41    mlir::Value indexValue = fir::LoadOp::create(builder, loc, index);42    mlir::Value newValue =43        mlir::arith::AddIOp::create(builder, loc, indexValue, one);44    fir::StoreOp::create(builder, loc, newValue, index);45    return indexValue;46  }47  mlir::Value indexValue = index;48  index = mlir::arith::AddIOp::create(builder, loc, indexValue, one);49  return indexValue;50}51 52void fir::factory::Counter::reset(mlir::Location loc,53                                  fir::FirOpBuilder &builder) {54  if (canCountThroughLoops)55    fir::StoreOp::create(builder, loc, initialValue, index);56  else57    index = initialValue;58}59 60//===----------------------------------------------------------------------===//61// fir::factory::HomogeneousScalarStack implementation.62//===----------------------------------------------------------------------===//63 64fir::factory::HomogeneousScalarStack::HomogeneousScalarStack(65    mlir::Location loc, fir::FirOpBuilder &builder,66    fir::SequenceType declaredType, mlir::Value extent,67    llvm::ArrayRef<mlir::Value> lengths, bool allocateOnHeap,68    bool stackThroughLoops, llvm::StringRef tempName)69    : allocateOnHeap{allocateOnHeap},70      counter{loc, builder,71              builder.createIntegerConstant(loc, builder.getIndexType(), 1),72              stackThroughLoops} {73  // Allocate the temporary storage.74  llvm::SmallVector<mlir::Value, 1> extents{extent};75  mlir::Value tempStorage;76  if (allocateOnHeap)77    tempStorage = builder.createHeapTemporary(loc, declaredType, tempName,78                                              extents, lengths);79  else80    tempStorage =81        builder.createTemporary(loc, declaredType, tempName, extents, lengths);82 83  mlir::Value shape = builder.genShape(loc, extents);84  temp = hlfir::DeclareOp::create(builder, loc, tempStorage, tempName, shape,85                                  lengths)86             .getBase();87}88 89void fir::factory::HomogeneousScalarStack::pushValue(mlir::Location loc,90                                                     fir::FirOpBuilder &builder,91                                                     mlir::Value value) {92  hlfir::Entity entity{value};93  assert(entity.isScalar() && "cannot use inlined temp with array");94  mlir::Value indexValue = counter.getAndIncrementIndex(loc, builder);95  hlfir::Entity tempElement = hlfir::getElementAt(96      loc, builder, hlfir::Entity{temp}, mlir::ValueRange{indexValue});97  // TODO: "copy" would probably be better than assign to ensure there are no98  // side effects (user assignments, temp, lhs finalization)?99  // This only makes a difference for derived types, and for now derived types100  // will use the runtime strategy to avoid any bad behaviors. So the todo101  // below should not get hit but is added as a remainder/safety.102  if (!entity.hasIntrinsicType())103    TODO(loc, "creating inlined temporary stack for derived types");104  hlfir::AssignOp::create(builder, loc, value, tempElement);105}106 107void fir::factory::HomogeneousScalarStack::resetFetchPosition(108    mlir::Location loc, fir::FirOpBuilder &builder) {109  counter.reset(loc, builder);110}111 112mlir::Value113fir::factory::HomogeneousScalarStack::fetch(mlir::Location loc,114                                            fir::FirOpBuilder &builder) {115  mlir::Value indexValue = counter.getAndIncrementIndex(loc, builder);116  hlfir::Entity tempElement = hlfir::getElementAt(117      loc, builder, hlfir::Entity{temp}, mlir::ValueRange{indexValue});118  return hlfir::loadTrivialScalar(loc, builder, tempElement);119}120 121void fir::factory::HomogeneousScalarStack::destroy(mlir::Location loc,122                                                   fir::FirOpBuilder &builder) {123  if (allocateOnHeap) {124    auto declare = temp.getDefiningOp<hlfir::DeclareOp>();125    assert(declare && "temp must have been declared");126    fir::FreeMemOp::create(builder, loc, declare.getMemref());127  }128}129 130hlfir::Entity fir::factory::HomogeneousScalarStack::moveStackAsArrayExpr(131    mlir::Location loc, fir::FirOpBuilder &builder) {132  mlir::Value mustFree = builder.createBool(loc, allocateOnHeap);133  auto hlfirExpr = hlfir::AsExprOp::create(builder, loc, temp, mustFree);134  return hlfir::Entity{hlfirExpr};135}136 137//===----------------------------------------------------------------------===//138// fir::factory::SimpleCopy implementation.139//===----------------------------------------------------------------------===//140 141fir::factory::SimpleCopy::SimpleCopy(mlir::Location loc,142                                     fir::FirOpBuilder &builder,143                                     hlfir::Entity source,144                                     llvm::StringRef tempName) {145  // Use hlfir.as_expr and hlfir.associate to create a copy and leave146  // bufferization deals with how best to make the copy.147  if (source.isVariable())148    source = hlfir::Entity{hlfir::AsExprOp::create(builder, loc, source)};149  copy = hlfir::genAssociateExpr(loc, builder, source,150                                 source.getFortranElementType(), tempName);151}152 153void fir::factory::SimpleCopy::destroy(mlir::Location loc,154                                       fir::FirOpBuilder &builder) {155  hlfir::EndAssociateOp::create(builder, loc, copy);156}157 158//===----------------------------------------------------------------------===//159// fir::factory::AnyValueStack implementation.160//===----------------------------------------------------------------------===//161 162fir::factory::AnyValueStack::AnyValueStack(mlir::Location loc,163                                           fir::FirOpBuilder &builder,164                                           mlir::Type valueStaticType)165    : valueStaticType{valueStaticType},166      counter{loc, builder,167              builder.createIntegerConstant(loc, builder.getI64Type(), 0),168              /*stackThroughLoops=*/true} {169  opaquePtr = fir::runtime::genCreateValueStack(loc, builder);170  // Compute the storage type. I1 are stored as fir.logical<1>. This is required171  // to use descriptor.172  mlir::Type storageType =173      hlfir::getFortranElementOrSequenceType(valueStaticType);174  mlir::Type i1Type = builder.getI1Type();175  if (storageType == i1Type)176    storageType = fir::LogicalType::get(builder.getContext(), 1);177  assert(hlfir::getFortranElementType(storageType) != i1Type &&178         "array of i1 should not be used");179  mlir::Type heapType = fir::HeapType::get(storageType);180  mlir::Type boxType;181  if (hlfir::isPolymorphicType(valueStaticType))182    boxType = fir::ClassType::get(heapType);183  else184    boxType = fir::BoxType::get(heapType);185  retValueBox = builder.createTemporary(loc, boxType);186}187 188void fir::factory::AnyValueStack::pushValue(mlir::Location loc,189                                            fir::FirOpBuilder &builder,190                                            mlir::Value value) {191  hlfir::Entity entity{value};192  mlir::Type storageElementType =193      hlfir::getFortranElementType(retValueBox.getType());194  auto [box, maybeCleanUp] =195      hlfir::convertToBox(loc, builder, entity, storageElementType);196  fir::runtime::genPushValue(loc, builder, opaquePtr, fir::getBase(box));197  if (maybeCleanUp)198    (*maybeCleanUp)();199}200 201void fir::factory::AnyValueStack::resetFetchPosition(202    mlir::Location loc, fir::FirOpBuilder &builder) {203  counter.reset(loc, builder);204}205 206mlir::Value fir::factory::AnyValueStack::fetch(mlir::Location loc,207                                               fir::FirOpBuilder &builder) {208  mlir::Value indexValue = counter.getAndIncrementIndex(loc, builder);209  fir::runtime::genValueAt(loc, builder, opaquePtr, indexValue, retValueBox);210  // Dereference the allocatable "retValueBox", and load if trivial scalar211  // value.212  mlir::Value result =213      hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{retValueBox});214  if (valueStaticType != result.getType()) {215    // Cast back saved simple scalars stored with another type to their original216    // type (like i1).217    if (fir::isa_trivial(valueStaticType))218      return builder.createConvert(loc, valueStaticType, result);219    // Memory type mismatches (e.g. fir.ref vs fir.heap) or hlfir.expr vs220    // variable type mismatches are OK, but the base Fortran type must be the221    // same.222    assert(hlfir::getFortranElementOrSequenceType(valueStaticType) ==223               hlfir::getFortranElementOrSequenceType(result.getType()) &&224           "non trivial values must be saved with their original type");225  }226  return result;227}228 229void fir::factory::AnyValueStack::destroy(mlir::Location loc,230                                          fir::FirOpBuilder &builder) {231  fir::runtime::genDestroyValueStack(loc, builder, opaquePtr);232}233 234//===----------------------------------------------------------------------===//235// fir::factory::AnyVariableStack implementation.236//===----------------------------------------------------------------------===//237 238fir::factory::AnyVariableStack::AnyVariableStack(mlir::Location loc,239                                                 fir::FirOpBuilder &builder,240                                                 mlir::Type variableStaticType)241    : variableStaticType{variableStaticType},242      counter{loc, builder,243              builder.createIntegerConstant(loc, builder.getI64Type(), 0),244              /*stackThroughLoops=*/true} {245  opaquePtr = fir::runtime::genCreateDescriptorStack(loc, builder);246  mlir::Type storageType =247      hlfir::getFortranElementOrSequenceType(variableStaticType);248  mlir::Type ptrType = fir::PointerType::get(storageType);249  mlir::Type boxType;250  if (hlfir::isPolymorphicType(variableStaticType))251    boxType = fir::ClassType::get(ptrType);252  else253    boxType = fir::BoxType::get(ptrType);254  retValueBox = builder.createTemporary(loc, boxType);255}256 257void fir::factory::AnyVariableStack::pushValue(mlir::Location loc,258                                               fir::FirOpBuilder &builder,259                                               mlir::Value variable) {260  hlfir::Entity entity{variable};261  mlir::Value box =262      hlfir::genVariableBox(loc, builder, entity, entity.getBoxType());263  fir::runtime::genPushDescriptor(loc, builder, opaquePtr, fir::getBase(box));264}265 266void fir::factory::AnyVariableStack::resetFetchPosition(267    mlir::Location loc, fir::FirOpBuilder &builder) {268  counter.reset(loc, builder);269}270 271mlir::Value fir::factory::AnyVariableStack::fetch(mlir::Location loc,272                                                  fir::FirOpBuilder &builder) {273  mlir::Value indexValue = counter.getAndIncrementIndex(loc, builder);274  fir::runtime::genDescriptorAt(loc, builder, opaquePtr, indexValue,275                                retValueBox);276  hlfir::Entity retBox{fir::LoadOp::create(builder, loc, retValueBox)};277  // The runtime always tracks variable as address, but the form of the variable278  // that was saved may be different (raw address, fir.boxchar), ensure279  // the returned variable has the same form of the one that was saved.280  if (mlir::isa<fir::BaseBoxType>(variableStaticType))281    return builder.createConvert(loc, variableStaticType, retBox);282  if (mlir::isa<fir::BoxCharType>(variableStaticType))283    return hlfir::genVariableBoxChar(loc, builder, retBox);284  mlir::Value rawAddr = genVariableRawAddress(loc, builder, retBox);285  return builder.createConvert(loc, variableStaticType, rawAddr);286}287 288void fir::factory::AnyVariableStack::destroy(mlir::Location loc,289                                             fir::FirOpBuilder &builder) {290  fir::runtime::genDestroyDescriptorStack(loc, builder, opaquePtr);291}292 293//===----------------------------------------------------------------------===//294// fir::factory::AnyVectorSubscriptStack implementation.295//===----------------------------------------------------------------------===//296 297fir::factory::AnyVectorSubscriptStack::AnyVectorSubscriptStack(298    mlir::Location loc, fir::FirOpBuilder &builder,299    mlir::Type variableStaticType, bool shapeCanBeSavedAsRegister, int rank)300    : AnyVariableStack{loc, builder, variableStaticType} {301  if (shapeCanBeSavedAsRegister) {302    shapeTemp = std::make_unique<TemporaryStorage>(SSARegister{});303    return;304  }305  // The shape will be tracked as the dimension inside a descriptor because306  // that is the easiest from a lowering point of view, and this is an307  // edge case situation that will probably not very well be exercised.308  mlir::Type type =309      fir::BoxType::get(builder.getVarLenSeqTy(builder.getI32Type(), rank));310  boxType = type;311  shapeTemp =312      std::make_unique<TemporaryStorage>(AnyVariableStack{loc, builder, type});313}314 315void fir::factory::AnyVectorSubscriptStack::pushShape(316    mlir::Location loc, fir::FirOpBuilder &builder, mlir::Value shape) {317  if (boxType) {318    // The shape is saved as a dimensions inside a descriptors.319    mlir::Type refType = fir::ReferenceType::get(320        hlfir::getFortranElementOrSequenceType(*boxType));321    mlir::Value null = builder.createNullConstant(loc, refType);322    mlir::Value descriptor =323        fir::EmboxOp::create(builder, loc, *boxType, null, shape);324    shapeTemp->pushValue(loc, builder, descriptor);325    return;326  }327  // Otherwise, simply keep track of the fir.shape itself, it is invariant.328  shapeTemp->cast<SSARegister>().pushValue(loc, builder, shape);329}330 331void fir::factory::AnyVectorSubscriptStack::resetFetchPosition(332    mlir::Location loc, fir::FirOpBuilder &builder) {333  static_cast<AnyVariableStack *>(this)->resetFetchPosition(loc, builder);334  shapeTemp->resetFetchPosition(loc, builder);335}336 337mlir::Value338fir::factory::AnyVectorSubscriptStack::fetchShape(mlir::Location loc,339                                                  fir::FirOpBuilder &builder) {340  if (boxType) {341    hlfir::Entity descriptor{shapeTemp->fetch(loc, builder)};342    return hlfir::genShape(loc, builder, descriptor);343  }344  return shapeTemp->cast<SSARegister>().fetch(loc, builder);345}346 347void fir::factory::AnyVectorSubscriptStack::destroy(348    mlir::Location loc, fir::FirOpBuilder &builder) {349  static_cast<AnyVariableStack *>(this)->destroy(loc, builder);350  shapeTemp->destroy(loc, builder);351}352 353//===----------------------------------------------------------------------===//354// fir::factory::AnyAddressStack implementation.355//===----------------------------------------------------------------------===//356 357fir::factory::AnyAddressStack::AnyAddressStack(mlir::Location loc,358                                               fir::FirOpBuilder &builder,359                                               mlir::Type addressType)360    : AnyValueStack(loc, builder, builder.getIntPtrType()),361      addressType{addressType} {}362 363void fir::factory::AnyAddressStack::pushValue(mlir::Location loc,364                                              fir::FirOpBuilder &builder,365                                              mlir::Value variable) {366  mlir::Value cast = variable;367  if (auto boxProcType = llvm::dyn_cast<fir::BoxProcType>(variable.getType())) {368    cast =369        fir::BoxAddrOp::create(builder, loc, boxProcType.getEleTy(), variable);370  }371  cast = builder.createConvert(loc, builder.getIntPtrType(), cast);372  static_cast<AnyValueStack *>(this)->pushValue(loc, builder, cast);373}374 375mlir::Value fir::factory::AnyAddressStack::fetch(mlir::Location loc,376                                                 fir::FirOpBuilder &builder) {377  mlir::Value addr = static_cast<AnyValueStack *>(this)->fetch(loc, builder);378  if (auto boxProcType = llvm::dyn_cast<fir::BoxProcType>(addressType)) {379    mlir::Value cast = builder.createConvert(loc, boxProcType.getEleTy(), addr);380    return fir::EmboxProcOp::create(builder, loc, boxProcType, cast);381  }382  return builder.createConvert(loc, addressType, addr);383}384