270 lines · cpp
1//===- FIROpenACCUtils.cpp - FIR OpenACC Utilities ------------------------===//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// This file implements utility functions for FIR OpenACC support.10//11//===----------------------------------------------------------------------===//12 13#include "flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h"14#include "flang/Optimizer/Dialect/FIROps.h"15#include "flang/Optimizer/Dialect/FIROpsSupport.h"16#include "flang/Optimizer/Dialect/FIRType.h"17#include "flang/Optimizer/Dialect/Support/FIRContext.h"18#include "flang/Optimizer/Dialect/Support/KindMapping.h"19#include "flang/Optimizer/HLFIR/HLFIROps.h"20#include "flang/Optimizer/Support/InternalNames.h"21#include "mlir/Dialect/OpenACC/OpenACC.h"22#include "mlir/IR/Matchers.h"23#include "mlir/Interfaces/ViewLikeInterface.h"24#include "llvm/ADT/TypeSwitch.h"25#include "llvm/Support/raw_ostream.h"26 27using namespace mlir;28 29namespace fir {30namespace acc {31 32std::string getVariableName(Value v, bool preferDemangledName) {33 std::string srcName;34 std::string prefix;35 llvm::SmallVector<std::string, 4> arrayIndices;36 bool iterate = true;37 mlir::Operation *defOp;38 39 // For integer constants, no need to further iterate - print their value40 // immediately.41 if (v.getDefiningOp()) {42 IntegerAttr::ValueType val;43 if (matchPattern(v.getDefiningOp(), m_ConstantInt(&val))) {44 llvm::raw_string_ostream os(prefix);45 val.print(os, /*isSigned=*/true);46 return prefix;47 }48 }49 50 while (v && (defOp = v.getDefiningOp()) && iterate) {51 iterate =52 llvm::TypeSwitch<mlir::Operation *, bool>(defOp)53 .Case<mlir::ViewLikeOpInterface>(54 [&v](mlir::ViewLikeOpInterface op) {55 v = op.getViewSource();56 return true;57 })58 .Case<fir::ReboxOp>([&v](fir::ReboxOp op) {59 v = op.getBox();60 return true;61 })62 .Case<fir::EmboxOp>([&v](fir::EmboxOp op) {63 v = op.getMemref();64 return true;65 })66 .Case<fir::ConvertOp>([&v](fir::ConvertOp op) {67 v = op.getValue();68 return true;69 })70 .Case<fir::LoadOp>([&v](fir::LoadOp op) {71 v = op.getMemref();72 return true;73 })74 .Case<fir::BoxAddrOp>([&v](fir::BoxAddrOp op) {75 // The box holds the name of the variable.76 v = op.getVal();77 return true;78 })79 .Case<fir::AddrOfOp>([&](fir::AddrOfOp op) {80 // Only use address_of symbol if mangled name is preferred81 if (!preferDemangledName) {82 auto symRef = op.getSymbol();83 srcName = symRef.getLeafReference().getValue().str();84 }85 return false;86 })87 .Case<fir::ArrayCoorOp>([&](fir::ArrayCoorOp op) {88 v = op.getMemref();89 for (auto coor : op.getIndices()) {90 auto idxName = getVariableName(coor, preferDemangledName);91 arrayIndices.push_back(idxName.empty() ? "?" : idxName);92 }93 return true;94 })95 .Case<fir::CoordinateOp>([&](fir::CoordinateOp op) {96 std::optional<llvm::ArrayRef<int32_t>> fieldIndices =97 op.getFieldIndices();98 if (fieldIndices && fieldIndices->size() > 0 &&99 (*fieldIndices)[0] != fir::CoordinateOp::kDynamicIndex) {100 int fieldId = (*fieldIndices)[0];101 mlir::Type baseType =102 fir::getFortranElementType(op.getRef().getType());103 if (auto recType = llvm::dyn_cast<fir::RecordType>(baseType)) {104 srcName = recType.getTypeList()[fieldId].first;105 }106 }107 if (!srcName.empty()) {108 // If the field name is known - attempt to continue building109 // name by looking at its parents.110 prefix =111 getVariableName(op.getRef(), preferDemangledName) + "%";112 }113 return false;114 })115 .Case<hlfir::DesignateOp>([&](hlfir::DesignateOp op) {116 if (op.getComponent()) {117 srcName = op.getComponent().value().str();118 prefix =119 getVariableName(op.getMemref(), preferDemangledName) + "%";120 return false;121 }122 for (auto coor : op.getIndices()) {123 auto idxName = getVariableName(coor, preferDemangledName);124 arrayIndices.push_back(idxName.empty() ? "?" : idxName);125 }126 v = op.getMemref();127 return true;128 })129 .Case<fir::DeclareOp, hlfir::DeclareOp>([&](auto op) {130 srcName = op.getUniqName().str();131 return false;132 })133 .Case<fir::AllocaOp>([&](fir::AllocaOp op) {134 if (preferDemangledName) {135 // Prefer demangled name (bindc_name over uniq_name)136 srcName = op.getBindcName() ? *op.getBindcName()137 : op.getUniqName() ? *op.getUniqName()138 : "";139 } else {140 // Prefer mangled name (uniq_name over bindc_name)141 srcName = op.getUniqName() ? *op.getUniqName()142 : op.getBindcName() ? *op.getBindcName()143 : "";144 }145 return false;146 })147 .Default([](mlir::Operation *) { return false; });148 }149 150 // Fallback to the default implementation.151 if (srcName.empty())152 return acc::getVariableName(v);153 154 // Build array index suffix if present155 std::string suffix;156 if (!arrayIndices.empty()) {157 llvm::raw_string_ostream os(suffix);158 os << "(";159 llvm::interleaveComma(arrayIndices, os);160 os << ")";161 }162 163 // Names from FIR operations may be mangled.164 // When the demangled name is requested - demangle it.165 if (preferDemangledName) {166 auto [kind, deconstructed] = fir::NameUniquer::deconstruct(srcName);167 if (kind != fir::NameUniquer::NameKind::NOT_UNIQUED)168 return prefix + deconstructed.name + suffix;169 }170 171 return prefix + srcName + suffix;172}173 174bool areAllBoundsConstant(llvm::ArrayRef<Value> bounds) {175 for (auto bound : bounds) {176 auto dataBound =177 mlir::dyn_cast<mlir::acc::DataBoundsOp>(bound.getDefiningOp());178 if (!dataBound)179 return false;180 181 // Check if this bound has constant values182 bool hasConstant = false;183 if (dataBound.getLowerbound() && dataBound.getUpperbound())184 hasConstant =185 fir::getIntIfConstant(dataBound.getLowerbound()).has_value() &&186 fir::getIntIfConstant(dataBound.getUpperbound()).has_value();187 else if (dataBound.getExtent())188 hasConstant = fir::getIntIfConstant(dataBound.getExtent()).has_value();189 190 if (!hasConstant)191 return false;192 }193 return true;194}195 196static std::string getBoundsString(llvm::ArrayRef<Value> bounds) {197 if (bounds.empty())198 return "";199 200 std::string boundStr;201 llvm::raw_string_ostream os(boundStr);202 os << "_section_";203 204 llvm::interleave(205 bounds,206 [&](Value bound) {207 auto boundsOp =208 mlir::cast<mlir::acc::DataBoundsOp>(bound.getDefiningOp());209 if (boundsOp.getLowerbound() &&210 fir::getIntIfConstant(boundsOp.getLowerbound()) &&211 boundsOp.getUpperbound() &&212 fir::getIntIfConstant(boundsOp.getUpperbound())) {213 os << "lb" << *fir::getIntIfConstant(boundsOp.getLowerbound())214 << ".ub" << *fir::getIntIfConstant(boundsOp.getUpperbound());215 } else if (boundsOp.getExtent() &&216 fir::getIntIfConstant(boundsOp.getExtent())) {217 os << "ext" << *fir::getIntIfConstant(boundsOp.getExtent());218 } else {219 os << "?";220 }221 },222 [&] { os << "x"; });223 224 return os.str();225}226 227std::string getRecipeName(mlir::acc::RecipeKind kind, Type type, Value var,228 llvm::ArrayRef<Value> bounds,229 mlir::acc::ReductionOperator reductionOp) {230 assert(fir::isa_fir_type(type) && "getRecipeName expects a FIR type");231 232 // Build the complete prefix with all components before calling233 // getTypeAsString234 std::string prefixStr;235 llvm::raw_string_ostream prefixOS(prefixStr);236 237 switch (kind) {238 case mlir::acc::RecipeKind::private_recipe:239 prefixOS << "privatization";240 // Private recipes do not currently include bounds in the name241 // TODO: They should include them - but lowering tests would need to242 // be updated.243 break;244 case mlir::acc::RecipeKind::firstprivate_recipe:245 prefixOS << "firstprivatization";246 // Add bounds to the prefix if applicable (only for firstprivate)247 if (!bounds.empty() && areAllBoundsConstant(bounds))248 prefixOS << getBoundsString(bounds);249 break;250 case mlir::acc::RecipeKind::reduction_recipe:251 prefixOS << "reduction";252 // Embed the reduction operator in the prefix253 if (reductionOp != mlir::acc::ReductionOperator::AccNone)254 prefixOS << "_"255 << mlir::acc::stringifyReductionOperator(reductionOp).str();256 // Add bounds to the prefix if applicable (only for reduction)257 if (!bounds.empty() && areAllBoundsConstant(bounds))258 prefixOS << getBoundsString(bounds);259 break;260 }261 262 auto kindMap = var && var.getDefiningOp()263 ? fir::getKindMapping(var.getDefiningOp())264 : fir::KindMapping(type.getContext());265 return fir::getTypeAsString(type, kindMap, prefixOS.str());266}267 268} // namespace acc269} // namespace fir270