| 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 | |