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 | |
34 | void 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 |
47 | mlir::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 | |
66 | void 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 | |
83 | bool 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 | |
95 | bool 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 | |
102 | bool 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 | |
109 | bool 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 | |
117 | bool hlfir::isFortranScalarNumericalType(mlir::Type type) { |
118 | return fir::isa_integer(type) || fir::isa_real(type) || |
119 | fir::isa_complex(type); |
120 | } |
121 | |
122 | bool 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 | |
131 | bool 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 | |
143 | bool hlfir::isFortranArrayObject(mlir::Type type) { |
144 | if (isBoxAddressType(type)) |
145 | return false; |
146 | return !!mlir::dyn_cast<fir::SequenceType>( |
147 | getFortranElementOrSequenceType(type)); |
148 | } |
149 | |
150 | bool hlfir::isPassByRefOrIntegerType(mlir::Type type) { |
151 | mlir::Type unwrappedType = fir::unwrapPassByRefType(type); |
152 | return fir::isa_integer(unwrappedType); |
153 | } |
154 | |
155 | bool 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 | |
162 | bool 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 | |
173 | bool 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 | |
187 | bool 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 | |
194 | mlir::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 | |
214 | bool hlfir::mayHaveAllocatableComponent(mlir::Type ty) { |
215 | return fir::isPolymorphicType(ty) || fir::isUnlimitedPolymorphicType(ty) || |
216 | fir::isRecordWithAllocatableMember(hlfir::getFortranElementType(ty)); |
217 | } |
218 | |
219 | mlir::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 | |
232 | bool 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 | |