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 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
94bool 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
101bool 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
108bool 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
116bool hlfir::isFortranScalarNumericalType(mlir::Type type) {
117 return fir::isa_integer(type) || fir::isa_real(type) ||
118 fir::isa_complex(type);
119}
120
121bool 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
130bool 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
142bool hlfir::isFortranArrayObject(mlir::Type type) {
143 if (isBoxAddressType(type))
144 return false;
145 return !!getFortranElementOrSequenceType(type).dyn_cast<fir::SequenceType>();
146}
147
148bool hlfir::isPassByRefOrIntegerType(mlir::Type type) {
149 mlir::Type unwrappedType = fir::unwrapPassByRefType(type);
150 return fir::isa_integer(unwrappedType);
151}
152
153bool 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
160bool 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
171bool 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
185bool 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
192mlir::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
212bool hlfir::mayHaveAllocatableComponent(mlir::Type ty) {
213 return fir::isPolymorphicType(ty) || fir::isUnlimitedPolymorphicType(ty) ||
214 fir::isRecordWithAllocatableMember(hlfir::getFortranElementType(ty));
215}
216

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