1//===-- HLFIRDialect.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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10//
11//===----------------------------------------------------------------------===//
12
13#include "flang/Optimizer/HLFIR/HLFIRDialect.h"
14#include "flang/Optimizer/Dialect/FIROps.h"
15#include "flang/Optimizer/Dialect/FIRType.h"
16#include "flang/Optimizer/HLFIR/HLFIROps.h"
17#include "mlir/Dialect/Arith/IR/Arith.h"
18#include "mlir/IR/Builders.h"
19#include "mlir/IR/BuiltinTypes.h"
20#include "mlir/IR/DialectImplementation.h"
21#include "mlir/IR/Matchers.h"
22#include "mlir/IR/OpImplementation.h"
23#include "llvm/ADT/SmallVector.h"
24#include "llvm/ADT/TypeSwitch.h"
25
26#include "flang/Optimizer/HLFIR/HLFIRDialect.cpp.inc"
27
28#define GET_TYPEDEF_CLASSES
29#include "flang/Optimizer/HLFIR/HLFIRTypes.cpp.inc"
30
31#define GET_ATTRDEF_CLASSES
32#include "flang/Optimizer/HLFIR/HLFIRAttributes.cpp.inc"
33
34void hlfir::hlfirDialect::initialize() {
35 addTypes<
36#define GET_TYPEDEF_LIST
37#include "flang/Optimizer/HLFIR/HLFIRTypes.cpp.inc"
38 >();
39 addOperations<
40#define GET_OP_LIST
41#include "flang/Optimizer/HLFIR/HLFIROps.cpp.inc"
42 >();
43}
44
45// `expr` `<` `*` | bounds (`x` bounds)* `:` type [`?`] `>`
46// bounds ::= `?` | int-lit
47mlir::Type hlfir::ExprType::parse(mlir::AsmParser &parser) {
48 if (parser.parseLess())
49 return {};
50 ExprType::Shape shape;
51 if (parser.parseOptionalStar()) {
52 if (parser.parseDimensionList(shape, /*allowDynamic=*/true))
53 return {};
54 } else if (parser.parseColon()) {
55 return {};
56 }
57 mlir::Type eleTy;
58 if (parser.parseType(eleTy))
59 return {};
60 const bool polymorphic = mlir::succeeded(parser.parseOptionalQuestion());
61 if (parser.parseGreater())
62 return {};
63 return ExprType::get(parser.getContext(), shape, eleTy, polymorphic);
64}
65
66void hlfir::ExprType::print(mlir::AsmPrinter &printer) const {
67 auto shape = getShape();
68 printer << '<';
69 if (shape.size()) {
70 for (const auto &b : shape) {
71 if (b >= 0)
72 printer << b << 'x';
73 else
74 printer << "?x";
75 }
76 }
77 printer << getEleTy();
78 if (isPolymorphic())
79 printer << '?';
80 printer << '>';
81}
82
83bool hlfir::isFortranVariableType(mlir::Type type) {
84 return llvm::TypeSwitch<mlir::Type, bool>(type)
85 .Case<fir::ReferenceType, fir::PointerType, fir::HeapType>([](auto p) {
86 mlir::Type eleType = p.getEleTy();
87 return mlir::isa<fir::BaseBoxType>(eleType) ||
88 !fir::hasDynamicSize(eleType);
89 })
90 .Case<fir::BaseBoxType, fir::BoxCharType>([](auto) { return true; })
91 .Case<fir::VectorType>([](auto) { return true; })
92 .Default([](mlir::Type) { return false; });
93}
94
95bool hlfir::isFortranScalarCharacterType(mlir::Type type) {
96 return isFortranScalarCharacterExprType(type) ||
97 mlir::isa<fir::BoxCharType>(type) ||
98 mlir::isa<fir::CharacterType>(
99 fir::unwrapPassByRefType(fir::unwrapRefType(type)));
100}
101
102bool hlfir::isFortranScalarCharacterExprType(mlir::Type type) {
103 if (auto exprType = mlir::dyn_cast<hlfir::ExprType>(type))
104 return exprType.isScalar() &&
105 mlir::isa<fir::CharacterType>(exprType.getElementType());
106 return false;
107}
108
109bool hlfir::isFortranArrayCharacterExprType(mlir::Type type) {
110 if (auto exprType = mlir::dyn_cast<hlfir::ExprType>(type))
111 return exprType.isArray() &&
112 mlir::isa<fir::CharacterType>(exprType.getElementType());
113
114 return false;
115}
116
117bool hlfir::isFortranScalarNumericalType(mlir::Type type) {
118 return fir::isa_integer(type) || fir::isa_real(type) ||
119 fir::isa_complex(type);
120}
121
122bool hlfir::isFortranNumericalArrayObject(mlir::Type type) {
123 if (isBoxAddressType(type))
124 return false;
125 if (auto arrayTy = mlir::dyn_cast<fir::SequenceType>(
126 getFortranElementOrSequenceType(type)))
127 return isFortranScalarNumericalType(arrayTy.getEleTy());
128 return false;
129}
130
131bool hlfir::isFortranNumericalOrLogicalArrayObject(mlir::Type type) {
132 if (isBoxAddressType(type))
133 return false;
134 if (auto arrayTy = mlir::dyn_cast<fir::SequenceType>(
135 getFortranElementOrSequenceType(type))) {
136 mlir::Type eleTy = arrayTy.getEleTy();
137 return isFortranScalarNumericalType(eleTy) ||
138 mlir::isa<fir::LogicalType>(eleTy);
139 }
140 return false;
141}
142
143bool hlfir::isFortranArrayObject(mlir::Type type) {
144 if (isBoxAddressType(type))
145 return false;
146 return !!mlir::dyn_cast<fir::SequenceType>(
147 getFortranElementOrSequenceType(type));
148}
149
150bool hlfir::isPassByRefOrIntegerType(mlir::Type type) {
151 mlir::Type unwrappedType = fir::unwrapPassByRefType(type);
152 return fir::isa_integer(unwrappedType);
153}
154
155bool hlfir::isI1Type(mlir::Type type) {
156 if (mlir::IntegerType integer = mlir::dyn_cast<mlir::IntegerType>(type))
157 if (integer.getWidth() == 1)
158 return true;
159 return false;
160}
161
162bool hlfir::isFortranLogicalArrayObject(mlir::Type type) {
163 if (isBoxAddressType(type))
164 return false;
165 if (auto arrayTy = mlir::dyn_cast<fir::SequenceType>(
166 getFortranElementOrSequenceType(type))) {
167 mlir::Type eleTy = arrayTy.getEleTy();
168 return mlir::isa<fir::LogicalType>(eleTy);
169 }
170 return false;
171}
172
173bool hlfir::isMaskArgument(mlir::Type type) {
174 if (isBoxAddressType(type))
175 return false;
176
177 mlir::Type unwrappedType = fir::unwrapPassByRefType(fir::unwrapRefType(type));
178 mlir::Type elementType = getFortranElementType(unwrappedType);
179 if (unwrappedType != elementType)
180 // input type is an array
181 return mlir::isa<fir::LogicalType>(elementType);
182
183 // input is a scalar, so allow i1 too
184 return mlir::isa<fir::LogicalType>(elementType) || isI1Type(elementType);
185}
186
187bool hlfir::isPolymorphicObject(mlir::Type type) {
188 if (auto exprType = mlir::dyn_cast<hlfir::ExprType>(type))
189 return exprType.isPolymorphic();
190
191 return fir::isPolymorphicType(type);
192}
193
194mlir::Value hlfir::genExprShape(mlir::OpBuilder &builder,
195 const mlir::Location &loc,
196 const hlfir::ExprType &expr) {
197 mlir::IndexType indexTy = builder.getIndexType();
198 llvm::SmallVector<mlir::Value> extents;
199 extents.reserve(expr.getRank());
200
201 for (std::int64_t extent : expr.getShape()) {
202 if (extent == hlfir::ExprType::getUnknownExtent())
203 return {};
204 extents.emplace_back(builder.create<mlir::arith::ConstantOp>(
205 loc, indexTy, builder.getIntegerAttr(indexTy, extent)));
206 }
207
208 fir::ShapeType shapeTy =
209 fir::ShapeType::get(builder.getContext(), expr.getRank());
210 fir::ShapeOp shape = builder.create<fir::ShapeOp>(loc, shapeTy, extents);
211 return shape.getResult();
212}
213
214bool hlfir::mayHaveAllocatableComponent(mlir::Type ty) {
215 return fir::isPolymorphicType(ty) || fir::isUnlimitedPolymorphicType(ty) ||
216 fir::isRecordWithAllocatableMember(hlfir::getFortranElementType(ty));
217}
218
219mlir::Type hlfir::getExprType(mlir::Type variableType) {
220 hlfir::ExprType::Shape typeShape;
221 bool isPolymorphic = fir::isPolymorphicType(variableType);
222 mlir::Type type = getFortranElementOrSequenceType(variableType);
223 if (auto seqType = mlir::dyn_cast<fir::SequenceType>(type)) {
224 assert(!seqType.hasUnknownShape() && "assumed-rank cannot be expressions");
225 typeShape.append(seqType.getShape().begin(), seqType.getShape().end());
226 type = seqType.getEleTy();
227 }
228 return hlfir::ExprType::get(variableType.getContext(), typeShape, type,
229 isPolymorphic);
230}
231
232bool hlfir::isFortranIntegerScalarOrArrayObject(mlir::Type type) {
233 if (isBoxAddressType(type))
234 return false;
235
236 mlir::Type unwrappedType = fir::unwrapPassByRefType(fir::unwrapRefType(type));
237 mlir::Type elementType = getFortranElementType(unwrappedType);
238 return mlir::isa<mlir::IntegerType>(elementType);
239}
240

source code of flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp