1 //===-- BoxValue.cpp ------------------------------------------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
9 // Pretty printers for box values, etc.
11 //===----------------------------------------------------------------------===//
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"
19 #define DEBUG_TYPE "flang-box-value"
21 mlir::Value
fir::getBase(const fir::ExtendedValue
&exv
) {
22 return exv
.match([](const fir::UnboxedValue
&x
) { return x
; },
23 [](const auto &x
) { return x
.getAddr(); });
26 mlir::Value
fir::getLen(const fir::ExtendedValue
&exv
) {
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");
33 [](const fir::MutableBoxValue
&) -> mlir::Value
{
34 llvm::report_fatal_error("Need to read len from MutableBoxValue Exv");
36 [](const auto &) { return mlir::Value
{}; });
39 fir::ExtendedValue
fir::substBase(const fir::ExtendedValue
&exv
,
42 [=](const fir::UnboxedValue
&x
) { return fir::ExtendedValue(base
); },
43 [=](const auto &x
) { return fir::ExtendedValue(x
.clone(base
)); });
46 llvm::SmallVector
<mlir::Value
>
47 fir::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
))
52 baseTy
= fir::unwrapSequenceType(baseTy
);
53 if (!fir::hasDynamicSize(baseTy
))
54 return {}; // type has constant size, no type parameters needed
55 [[maybe_unused
]] auto loc
= fir::getBase(exv
).getLoc();
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");
63 [&](const fir::MutableBoxValue
&) -> RT
{
64 // In this case, the type params may be bound to the variable in an
65 // ALLOCATE statement as part of a type-spec.
66 TODO(loc
, "mutable box value is missing type parameters");
69 [](const auto &) -> RT
{ return {}; });
72 bool fir::isArray(const fir::ExtendedValue
&exv
) {
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; });
81 llvm::raw_ostream
&fir::operator<<(llvm::raw_ostream
&os
,
82 const fir::CharBoxValue
&box
) {
83 return os
<< "boxchar { addr: " << box
.getAddr() << ", len: " << box
.getLen()
87 llvm::raw_ostream
&fir::operator<<(llvm::raw_ostream
&os
,
88 const fir::PolymorphicValue
&p
) {
89 return os
<< "polymorphicvalue: { addr: " << p
.getAddr()
90 << ", sourceBox: " << p
.getSourceBox() << " }";
93 llvm::raw_ostream
&fir::operator<<(llvm::raw_ostream
&os
,
94 const fir::ArrayBoxValue
&box
) {
95 os
<< "boxarray { addr: " << box
.getAddr();
96 if (box
.getLBounds().size()) {
98 llvm::interleaveComma(box
.getLBounds(), os
);
101 os
<< ", lbounds: all-ones";
104 llvm::interleaveComma(box
.getExtents(), os
);
108 llvm::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
);
116 os
<< " lbounds: all-ones";
119 llvm::interleaveComma(box
.getExtents(), os
);
123 llvm::raw_ostream
&fir::operator<<(llvm::raw_ostream
&os
,
124 const fir::ProcBoxValue
&box
) {
125 return os
<< "boxproc: { procedure: " << box
.getAddr()
126 << ", context: " << box
.hostContext
<< "}";
129 llvm::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
);
137 if (!box
.explicitParams
.empty()) {
138 os
<< ", explicit type params: [";
139 llvm::interleaveComma(box
.explicitParams
, os
);
142 if (!box
.extents
.empty()) {
143 os
<< ", explicit extents: [";
144 llvm::interleaveComma(box
.extents
, os
);
150 llvm::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
);
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
);
166 if (!properties
.extents
.empty()) {
168 llvm::interleaveComma(properties
.extents
, os
);
171 if (!properties
.deferredParams
.empty()) {
172 os
<< ", deferred type params: [";
173 llvm::interleaveComma(properties
.deferredParams
, os
);
181 llvm::raw_ostream
&fir::operator<<(llvm::raw_ostream
&os
,
182 const fir::ExtendedValue
&exv
) {
183 exv
.match([&](const auto &value
) { os
<< value
; });
187 /// Debug verifier for MutableBox ctor. There is no guarantee that this will
188 /// always be called, so it should not have any functional side effects,
189 /// the const is here to enforce that.
190 bool fir::MutableBoxValue::verify() const {
191 mlir::Type type
= fir::dyn_cast_ptrEleTy(getAddr().getType());
194 auto box
= mlir::dyn_cast
<fir::BaseBoxType
>(type
);
197 // A boxed value always takes a memory reference,
199 auto nParams
= lenParams
.size();
203 } else if (!isDerived()) {
210 /// Debug verifier for BoxValue ctor. There is no guarantee this will
211 /// always be called.
212 bool fir::BoxValue::verify() const {
213 if (!mlir::isa
<fir::BaseBoxType
>(addr
.getType()))
215 if (!lbounds
.empty() && lbounds
.size() != rank())
217 if (!extents
.empty() && extents
.size() != rank())
219 if (isCharacter() && explicitParams
.size() > 1)
224 /// Get exactly one extent for any array-like extended value, \p exv. If \p exv
225 /// is not an array or has rank less then \p dim, the result will be a nullptr.
226 mlir::Value
fir::factory::getExtentAtDimension(mlir::Location loc
,
227 fir::FirOpBuilder
&builder
,
228 const fir::ExtendedValue
&exv
,
230 auto extents
= fir::factory::getExtents(loc
, builder
, exv
);
231 if (dim
< extents
.size())