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