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 eleType.isa<fir::BaseBoxType>() || !fir::hasDynamicSize(eleType); |
88 | }) |
89 | .Case<fir::BaseBoxType, fir::BoxCharType>([](auto) { return true; }) |
90 | .Case<fir::VectorType>([](auto) { return true; }) |
91 | .Default([](mlir::Type) { return false; }); |
92 | } |
93 | |
94 | bool hlfir::isFortranScalarCharacterType(mlir::Type type) { |
95 | return isFortranScalarCharacterExprType(type) || |
96 | type.isa<fir::BoxCharType>() || |
97 | fir::unwrapPassByRefType(fir::unwrapRefType(type)) |
98 | .isa<fir::CharacterType>(); |
99 | } |
100 | |
101 | bool hlfir::isFortranScalarCharacterExprType(mlir::Type type) { |
102 | if (auto exprType = type.dyn_cast<hlfir::ExprType>()) |
103 | return exprType.isScalar() && |
104 | exprType.getElementType().isa<fir::CharacterType>(); |
105 | return false; |
106 | } |
107 | |
108 | bool hlfir::isFortranArrayCharacterExprType(mlir::Type type) { |
109 | if (auto exprType = mlir::dyn_cast<hlfir::ExprType>(type)) |
110 | return exprType.isArray() && |
111 | mlir::isa<fir::CharacterType>(exprType.getElementType()); |
112 | |
113 | return false; |
114 | } |
115 | |
116 | bool hlfir::isFortranScalarNumericalType(mlir::Type type) { |
117 | return fir::isa_integer(type) || fir::isa_real(type) || |
118 | fir::isa_complex(type); |
119 | } |
120 | |
121 | bool hlfir::isFortranNumericalArrayObject(mlir::Type type) { |
122 | if (isBoxAddressType(type)) |
123 | return false; |
124 | if (auto arrayTy = |
125 | getFortranElementOrSequenceType(type).dyn_cast<fir::SequenceType>()) |
126 | return isFortranScalarNumericalType(arrayTy.getEleTy()); |
127 | return false; |
128 | } |
129 | |
130 | bool hlfir::isFortranNumericalOrLogicalArrayObject(mlir::Type type) { |
131 | if (isBoxAddressType(type)) |
132 | return false; |
133 | if (auto arrayTy = |
134 | getFortranElementOrSequenceType(type).dyn_cast<fir::SequenceType>()) { |
135 | mlir::Type eleTy = arrayTy.getEleTy(); |
136 | return isFortranScalarNumericalType(eleTy) || |
137 | mlir::isa<fir::LogicalType>(eleTy); |
138 | } |
139 | return false; |
140 | } |
141 | |
142 | bool hlfir::isFortranArrayObject(mlir::Type type) { |
143 | if (isBoxAddressType(type)) |
144 | return false; |
145 | return !!getFortranElementOrSequenceType(type).dyn_cast<fir::SequenceType>(); |
146 | } |
147 | |
148 | bool hlfir::isPassByRefOrIntegerType(mlir::Type type) { |
149 | mlir::Type unwrappedType = fir::unwrapPassByRefType(type); |
150 | return fir::isa_integer(unwrappedType); |
151 | } |
152 | |
153 | bool hlfir::isI1Type(mlir::Type type) { |
154 | if (mlir::IntegerType integer = type.dyn_cast<mlir::IntegerType>()) |
155 | if (integer.getWidth() == 1) |
156 | return true; |
157 | return false; |
158 | } |
159 | |
160 | bool hlfir::isFortranLogicalArrayObject(mlir::Type type) { |
161 | if (isBoxAddressType(type)) |
162 | return false; |
163 | if (auto arrayTy = |
164 | getFortranElementOrSequenceType(type).dyn_cast<fir::SequenceType>()) { |
165 | mlir::Type eleTy = arrayTy.getEleTy(); |
166 | return mlir::isa<fir::LogicalType>(eleTy); |
167 | } |
168 | return false; |
169 | } |
170 | |
171 | bool hlfir::isMaskArgument(mlir::Type type) { |
172 | if (isBoxAddressType(type)) |
173 | return false; |
174 | |
175 | mlir::Type unwrappedType = fir::unwrapPassByRefType(fir::unwrapRefType(type)); |
176 | mlir::Type elementType = getFortranElementType(unwrappedType); |
177 | if (unwrappedType != elementType) |
178 | // input type is an array |
179 | return mlir::isa<fir::LogicalType>(elementType); |
180 | |
181 | // input is a scalar, so allow i1 too |
182 | return mlir::isa<fir::LogicalType>(elementType) || isI1Type(elementType); |
183 | } |
184 | |
185 | bool hlfir::isPolymorphicObject(mlir::Type type) { |
186 | if (auto exprType = mlir::dyn_cast<hlfir::ExprType>(type)) |
187 | return exprType.isPolymorphic(); |
188 | |
189 | return fir::isPolymorphicType(type); |
190 | } |
191 | |
192 | mlir::Value hlfir::genExprShape(mlir::OpBuilder &builder, |
193 | const mlir::Location &loc, |
194 | const hlfir::ExprType &expr) { |
195 | mlir::IndexType indexTy = builder.getIndexType(); |
196 | llvm::SmallVector<mlir::Value> extents; |
197 | extents.reserve(expr.getRank()); |
198 | |
199 | for (std::int64_t extent : expr.getShape()) { |
200 | if (extent == hlfir::ExprType::getUnknownExtent()) |
201 | return {}; |
202 | extents.emplace_back(builder.create<mlir::arith::ConstantOp>( |
203 | loc, indexTy, builder.getIntegerAttr(indexTy, extent))); |
204 | } |
205 | |
206 | fir::ShapeType shapeTy = |
207 | fir::ShapeType::get(builder.getContext(), expr.getRank()); |
208 | fir::ShapeOp shape = builder.create<fir::ShapeOp>(loc, shapeTy, extents); |
209 | return shape.getResult(); |
210 | } |
211 | |
212 | bool hlfir::mayHaveAllocatableComponent(mlir::Type ty) { |
213 | return fir::isPolymorphicType(ty) || fir::isUnlimitedPolymorphicType(ty) || |
214 | fir::isRecordWithAllocatableMember(hlfir::getFortranElementType(ty)); |
215 | } |
216 | |