xref: /llvm-project/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp (revision 1ca392764a0df5a9c263b89b97b882766ed4b3e7)
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