235 lines · cpp
1//===-- BoxValue.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-exception6//7//===----------------------------------------------------------------------===//8//9// Pretty printers for box values, etc.10//11//===----------------------------------------------------------------------===//12 13#include "flang/Optimizer/Builder/BoxValue.h"14#include "flang/Optimizer/Builder/FIRBuilder.h"15#include "flang/Optimizer/Builder/Todo.h"16#include "mlir/IR/BuiltinTypes.h"17#include "llvm/Support/Debug.h"18 19#define DEBUG_TYPE "flang-box-value"20 21mlir::Value fir::getBase(const fir::ExtendedValue &exv) {22 return exv.match([](const fir::UnboxedValue &x) { return x; },23 [](const auto &x) { return x.getAddr(); });24}25 26mlir::Value fir::getLen(const fir::ExtendedValue &exv) {27 return exv.match(28 [](const fir::CharBoxValue &x) { return x.getLen(); },29 [](const fir::CharArrayBoxValue &x) { return x.getLen(); },30 [](const fir::BoxValue &) -> mlir::Value {31 llvm::report_fatal_error("Need to read len from BoxValue Exv");32 },33 [](const fir::MutableBoxValue &) -> mlir::Value {34 llvm::report_fatal_error("Need to read len from MutableBoxValue Exv");35 },36 [](const auto &) { return mlir::Value{}; });37}38 39fir::ExtendedValue fir::substBase(const fir::ExtendedValue &exv,40 mlir::Value base) {41 return exv.match(42 [=](const fir::UnboxedValue &x) { return fir::ExtendedValue(base); },43 [=](const auto &x) { return fir::ExtendedValue(x.clone(base)); });44}45 46llvm::SmallVector<mlir::Value>47fir::getTypeParams(const fir::ExtendedValue &exv) {48 using RT = llvm::SmallVector<mlir::Value>;49 auto baseTy = fir::getBase(exv).getType();50 if (auto t = fir::dyn_cast_ptrEleTy(baseTy))51 baseTy = t;52 baseTy = fir::unwrapSequenceType(baseTy);53 if (!fir::hasDynamicSize(baseTy))54 return {}; // type has constant size, no type parameters needed55 [[maybe_unused]] auto loc = fir::getBase(exv).getLoc();56 return exv.match(57 [](const fir::CharBoxValue &x) -> RT { return {x.getLen()}; },58 [](const fir::CharArrayBoxValue &x) -> RT { return {x.getLen()}; },59 [&](const fir::BoxValue &) -> RT {60 TODO(loc, "box value is missing type parameters");61 return {};62 },63 [&](const fir::MutableBoxValue &) -> RT {64 // In this case, the type params may be bound to the variable in an65 // ALLOCATE statement as part of a type-spec.66 TODO(loc, "mutable box value is missing type parameters");67 return {};68 },69 [](const auto &) -> RT { return {}; });70}71 72bool fir::isArray(const fir::ExtendedValue &exv) {73 return exv.match(74 [](const fir::ArrayBoxValue &) { return true; },75 [](const fir::CharArrayBoxValue &) { return true; },76 [](const fir::BoxValue &box) { return box.hasRank(); },77 [](const fir::MutableBoxValue &box) { return box.hasRank(); },78 [](auto) { return false; });79}80 81llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,82 const fir::CharBoxValue &box) {83 return os << "boxchar { addr: " << box.getAddr() << ", len: " << box.getLen()84 << " }";85}86 87llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,88 const fir::PolymorphicValue &p) {89 return os << "polymorphicvalue: { addr: " << p.getAddr()90 << ", sourceBox: " << p.getSourceBox() << " }";91}92 93llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,94 const fir::ArrayBoxValue &box) {95 os << "boxarray { addr: " << box.getAddr();96 if (box.getLBounds().size()) {97 os << ", lbounds: [";98 llvm::interleaveComma(box.getLBounds(), os);99 os << "]";100 } else {101 os << ", lbounds: all-ones";102 }103 os << ", shape: [";104 llvm::interleaveComma(box.getExtents(), os);105 return os << "]}";106}107 108llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,109 const fir::CharArrayBoxValue &box) {110 os << "boxchararray { addr: " << box.getAddr() << ", len : " << box.getLen();111 if (box.getLBounds().size()) {112 os << ", lbounds: [";113 llvm::interleaveComma(box.getLBounds(), os);114 os << "]";115 } else {116 os << " lbounds: all-ones";117 }118 os << ", shape: [";119 llvm::interleaveComma(box.getExtents(), os);120 return os << "]}";121}122 123llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,124 const fir::ProcBoxValue &box) {125 return os << "boxproc: { procedure: " << box.getAddr()126 << ", context: " << box.hostContext << "}";127}128 129llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,130 const fir::BoxValue &box) {131 os << "box: { value: " << box.getAddr();132 if (box.lbounds.size()) {133 os << ", lbounds: [";134 llvm::interleaveComma(box.lbounds, os);135 os << "]";136 }137 if (!box.explicitParams.empty()) {138 os << ", explicit type params: [";139 llvm::interleaveComma(box.explicitParams, os);140 os << "]";141 }142 if (!box.extents.empty()) {143 os << ", explicit extents: [";144 llvm::interleaveComma(box.extents, os);145 os << "]";146 }147 return os << "}";148}149 150llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,151 const fir::MutableBoxValue &box) {152 os << "mutablebox: { addr: " << box.getAddr();153 if (!box.lenParams.empty()) {154 os << ", non deferred type params: [";155 llvm::interleaveComma(box.lenParams, os);156 os << "]";157 }158 const auto &properties = box.mutableProperties;159 if (!properties.isEmpty()) {160 os << ", mutableProperties: { addr: " << properties.addr;161 if (!properties.lbounds.empty()) {162 os << ", lbounds: [";163 llvm::interleaveComma(properties.lbounds, os);164 os << "]";165 }166 if (!properties.extents.empty()) {167 os << ", shape: [";168 llvm::interleaveComma(properties.extents, os);169 os << "]";170 }171 if (!properties.deferredParams.empty()) {172 os << ", deferred type params: [";173 llvm::interleaveComma(properties.deferredParams, os);174 os << "]";175 }176 os << "}";177 }178 return os << "}";179}180 181llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,182 const fir::ExtendedValue &exv) {183 exv.match([&](const auto &value) { os << value; });184 return os;185}186 187/// Debug verifier for MutableBox ctor. There is no guarantee that this will188/// always be called, so it should not have any functional side effects,189/// the const is here to enforce that.190bool fir::MutableBoxValue::verify() const {191 mlir::Type type = fir::dyn_cast_ptrEleTy(getAddr().getType());192 if (!type)193 return false;194 auto box = mlir::dyn_cast<fir::BaseBoxType>(type);195 if (!box)196 return false;197 // A boxed value always takes a memory reference,198 199 auto nParams = lenParams.size();200 if (isCharacter()) {201 if (nParams > 1)202 return false;203 } else if (!isDerived()) {204 if (nParams != 0)205 return false;206 }207 return true;208}209 210/// Debug verifier for BoxValue ctor. There is no guarantee this will211/// always be called.212bool fir::BoxValue::verify() const {213 if (!mlir::isa<fir::BaseBoxType>(addr.getType()))214 return false;215 if (!lbounds.empty() && lbounds.size() != rank())216 return false;217 if (!extents.empty() && extents.size() != rank())218 return false;219 if (isCharacter() && explicitParams.size() > 1)220 return false;221 return true;222}223 224/// Get exactly one extent for any array-like extended value, \p exv. If \p exv225/// is not an array or has rank less then \p dim, the result will be a nullptr.226mlir::Value fir::factory::getExtentAtDimension(mlir::Location loc,227 fir::FirOpBuilder &builder,228 const fir::ExtendedValue &exv,229 unsigned dim) {230 auto extents = fir::factory::getExtents(loc, builder, exv);231 if (dim < extents.size())232 return extents[dim];233 return {};234}235