1 //===-- PolymorphicOpConversion.cpp ---------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "flang/Lower/BuiltinModules.h"
10 #include "flang/Optimizer/Builder/Todo.h"
11 #include "flang/Optimizer/Dialect/FIRDialect.h"
12 #include "flang/Optimizer/Dialect/FIROps.h"
13 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
14 #include "flang/Optimizer/Dialect/FIRType.h"
15 #include "flang/Optimizer/Dialect/Support/FIRContext.h"
16 #include "flang/Optimizer/Dialect/Support/KindMapping.h"
17 #include "flang/Optimizer/Support/InternalNames.h"
18 #include "flang/Optimizer/Support/TypeCode.h"
19 #include "flang/Optimizer/Support/Utils.h"
20 #include "flang/Optimizer/Transforms/Passes.h"
21 #include "flang/Runtime/derived-api.h"
22 #include "flang/Semantics/runtime-type-info.h"
23 #include "mlir/Dialect/Affine/IR/AffineOps.h"
24 #include "mlir/Dialect/Arith/IR/Arith.h"
25 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
26 #include "mlir/Dialect/Func/IR/FuncOps.h"
27 #include "mlir/IR/BuiltinOps.h"
28 #include "mlir/Pass/Pass.h"
29 #include "mlir/Transforms/DialectConversion.h"
30 #include "llvm/ADT/SmallSet.h"
31 #include "llvm/Support/CommandLine.h"
35 #define GEN_PASS_DEF_POLYMORPHICOPCONVERSION
36 #include "flang/Optimizer/Transforms/Passes.h.inc"
44 /// SelectTypeOp converted to an if-then-else chain
46 /// This lowers the test conditions to calls into the runtime.
47 class SelectTypeConv
: public OpConversionPattern
<fir::SelectTypeOp
> {
49 using OpConversionPattern
<fir::SelectTypeOp
>::OpConversionPattern
;
51 SelectTypeConv(mlir::MLIRContext
*ctx
, std::mutex
*moduleMutex
)
52 : mlir::OpConversionPattern
<fir::SelectTypeOp
>(ctx
),
53 moduleMutex(moduleMutex
) {}
56 matchAndRewrite(fir::SelectTypeOp selectType
, OpAdaptor adaptor
,
57 mlir::ConversionPatternRewriter
&rewriter
) const override
;
60 // Generate comparison of type descriptor addresses.
61 mlir::Value
genTypeDescCompare(mlir::Location loc
, mlir::Value selector
,
62 mlir::Type ty
, mlir::ModuleOp mod
,
63 mlir::PatternRewriter
&rewriter
) const;
65 static int getTypeCode(mlir::Type ty
, fir::KindMapping
&kindMap
);
67 mlir::LogicalResult
genTypeLadderStep(mlir::Location loc
,
69 mlir::Attribute attr
, mlir::Block
*dest
,
70 std::optional
<mlir::ValueRange
> destOps
,
72 mlir::PatternRewriter
&rewriter
,
73 fir::KindMapping
&kindMap
) const;
75 llvm::SmallSet
<llvm::StringRef
, 4> collectAncestors(fir::DispatchTableOp dt
,
76 mlir::ModuleOp mod
) const;
78 // Mutex used to guard insertion of mlir::func::FuncOp in the module.
79 std::mutex
*moduleMutex
;
82 /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
84 struct DispatchOpConv
: public OpConversionPattern
<fir::DispatchOp
> {
85 using OpConversionPattern
<fir::DispatchOp
>::OpConversionPattern
;
87 DispatchOpConv(mlir::MLIRContext
*ctx
, const BindingTables
&bindingTables
)
88 : mlir::OpConversionPattern
<fir::DispatchOp
>(ctx
),
89 bindingTables(bindingTables
) {}
92 matchAndRewrite(fir::DispatchOp dispatch
, OpAdaptor adaptor
,
93 mlir::ConversionPatternRewriter
&rewriter
) const override
{
94 mlir::Location loc
= dispatch
.getLoc();
96 if (bindingTables
.empty())
97 return emitError(loc
) << "no binding tables found";
99 // Get derived type information.
100 mlir::Type declaredType
=
101 fir::getDerivedType(dispatch
.getObject().getType().getEleTy());
102 assert(declaredType
.isa
<fir::RecordType
>() && "expecting fir.type");
103 auto recordType
= declaredType
.dyn_cast
<fir::RecordType
>();
105 // Lookup for the binding table.
106 auto bindingsIter
= bindingTables
.find(recordType
.getName());
107 if (bindingsIter
== bindingTables
.end())
108 return emitError(loc
)
109 << "cannot find binding table for " << recordType
.getName();
111 // Lookup for the binding.
112 const BindingTable
&bindingTable
= bindingsIter
->second
;
113 auto bindingIter
= bindingTable
.find(dispatch
.getMethod());
114 if (bindingIter
== bindingTable
.end())
115 return emitError(loc
)
116 << "cannot find binding for " << dispatch
.getMethod();
117 unsigned bindingIdx
= bindingIter
->second
;
119 mlir::Value passedObject
= dispatch
.getObject();
121 auto module
= dispatch
.getOperation()->getParentOfType
<mlir::ModuleOp
>();
123 std::string typeDescName
=
124 NameUniquer::getTypeDescriptorName(recordType
.getName());
125 if (auto global
= module
.lookupSymbol
<fir::GlobalOp
>(typeDescName
)) {
126 typeDescTy
= global
.getType();
131 // fir.dispatch "proc1"(%11 :
132 // !fir.class<!fir.heap<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>)
135 // %12 = fir.box_tdesc %11 : (!fir.class<!fir.heap<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>) -> !fir.tdesc<none>
136 // %13 = fir.convert %12 : (!fir.tdesc<none>) -> !fir.ref<!fir.type<_QM__fortran_type_infoTderivedtype>>
137 // %14 = fir.field_index binding, !fir.type<_QM__fortran_type_infoTderivedtype>
138 // %15 = fir.coordinate_of %13, %14 : (!fir.ref<!fir.type<_QM__fortran_type_infoTderivedtype>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTbinding>>>>>
139 // %bindings = fir.load %15 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTbinding>>>>>
140 // %16 = fir.box_addr %bindings : (!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTbinding>>>>) -> !fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTbinding>>>
141 // %17 = fir.coordinate_of %16, %c0 : (!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTbinding>>>, index) -> !fir.ref<!fir.type<_QM__fortran_type_infoTbinding>>
142 // %18 = fir.field_index proc, !fir.type<_QM__fortran_type_infoTbinding>
143 // %19 = fir.coordinate_of %17, %18 : (!fir.ref<!fir.type<_QM__fortran_type_infoTbinding>>, !fir.field) -> !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_funptr>>
144 // %20 = fir.field_index __address, !fir.type<_QM__fortran_builtinsT__builtin_c_funptr>
145 // %21 = fir.coordinate_of %19, %20 : (!fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_funptr>>, !fir.field) -> !fir.ref<i64>
146 // %22 = fir.load %21 : !fir.ref<i64>
147 // %23 = fir.convert %22 : (i64) -> (() -> ())
148 // fir.call %23() : () -> ()
151 // Load the descriptor.
152 mlir::Type fieldTy
= fir::FieldType::get(rewriter
.getContext());
153 mlir::Type tdescType
=
154 fir::TypeDescType::get(mlir::NoneType::get(rewriter
.getContext()));
155 mlir::Value boxDesc
=
156 rewriter
.create
<fir::BoxTypeDescOp
>(loc
, tdescType
, passedObject
);
157 boxDesc
= rewriter
.create
<fir::ConvertOp
>(
158 loc
, fir::ReferenceType::get(typeDescTy
), boxDesc
);
160 // Load the bindings descriptor.
161 auto bindingsCompName
= Fortran::semantics::bindingDescCompName
;
162 fir::RecordType typeDescRecTy
= typeDescTy
.cast
<fir::RecordType
>();
163 mlir::Value field
= rewriter
.create
<fir::FieldIndexOp
>(
164 loc
, fieldTy
, bindingsCompName
, typeDescRecTy
, mlir::ValueRange
{});
166 fir::ReferenceType::get(typeDescRecTy
.getType(bindingsCompName
));
167 mlir::Value bindingBoxAddr
=
168 rewriter
.create
<fir::CoordinateOp
>(loc
, coorTy
, boxDesc
, field
);
169 mlir::Value bindingBox
= rewriter
.create
<fir::LoadOp
>(loc
, bindingBoxAddr
);
171 // Load the correct binding.
172 mlir::Value bindings
= rewriter
.create
<fir::BoxAddrOp
>(loc
, bindingBox
);
173 fir::RecordType bindingTy
=
174 fir::unwrapIfDerived(bindingBox
.getType().cast
<fir::BaseBoxType
>());
175 mlir::Type bindingAddrTy
= fir::ReferenceType::get(bindingTy
);
176 mlir::Value bindingIdxVal
= rewriter
.create
<mlir::arith::ConstantOp
>(
177 loc
, rewriter
.getIndexType(), rewriter
.getIndexAttr(bindingIdx
));
178 mlir::Value bindingAddr
= rewriter
.create
<fir::CoordinateOp
>(
179 loc
, bindingAddrTy
, bindings
, bindingIdxVal
);
181 // Get the function pointer.
182 auto procCompName
= Fortran::semantics::procCompName
;
183 mlir::Value procField
= rewriter
.create
<fir::FieldIndexOp
>(
184 loc
, fieldTy
, procCompName
, bindingTy
, mlir::ValueRange
{});
185 fir::RecordType procTy
=
186 bindingTy
.getType(procCompName
).cast
<fir::RecordType
>();
187 mlir::Type procRefTy
= fir::ReferenceType::get(procTy
);
188 mlir::Value procRef
= rewriter
.create
<fir::CoordinateOp
>(
189 loc
, procRefTy
, bindingAddr
, procField
);
191 auto addressFieldName
= Fortran::lower::builtin::cptrFieldName
;
192 mlir::Value addressField
= rewriter
.create
<fir::FieldIndexOp
>(
193 loc
, fieldTy
, addressFieldName
, procTy
, mlir::ValueRange
{});
194 mlir::Type addressTy
= procTy
.getType(addressFieldName
);
195 mlir::Type addressRefTy
= fir::ReferenceType::get(addressTy
);
196 mlir::Value addressRef
= rewriter
.create
<fir::CoordinateOp
>(
197 loc
, addressRefTy
, procRef
, addressField
);
198 mlir::Value address
= rewriter
.create
<fir::LoadOp
>(loc
, addressRef
);
200 // Get the function type.
201 llvm::SmallVector
<mlir::Type
> argTypes
;
202 for (mlir::Value operand
: dispatch
.getArgs())
203 argTypes
.push_back(operand
.getType());
204 llvm::SmallVector
<mlir::Type
> resTypes
;
205 if (!dispatch
.getResults().empty())
206 resTypes
.push_back(dispatch
.getResults()[0].getType());
209 mlir::FunctionType::get(rewriter
.getContext(), argTypes
, resTypes
);
210 mlir::Value funcPtr
= rewriter
.create
<fir::ConvertOp
>(loc
, funTy
, address
);
213 llvm::SmallVector
<mlir::Value
> args
{funcPtr
};
214 args
.append(dispatch
.getArgs().begin(), dispatch
.getArgs().end());
215 rewriter
.replaceOpWithNewOp
<fir::CallOp
>(dispatch
, resTypes
, nullptr, args
);
216 return mlir::success();
220 BindingTables bindingTables
;
223 /// Convert FIR structured control flow ops to CFG ops.
224 class PolymorphicOpConversion
225 : public fir::impl::PolymorphicOpConversionBase
<PolymorphicOpConversion
> {
227 mlir::LogicalResult
initialize(mlir::MLIRContext
*ctx
) override
{
228 moduleMutex
= new std::mutex();
229 return mlir::success();
232 void runOnOperation() override
{
233 auto *context
= &getContext();
234 auto mod
= getOperation()->getParentOfType
<ModuleOp
>();
235 mlir::RewritePatternSet
patterns(context
);
237 BindingTables bindingTables
;
238 buildBindingTables(bindingTables
, mod
);
240 patterns
.insert
<SelectTypeConv
>(context
, moduleMutex
);
241 patterns
.insert
<DispatchOpConv
>(context
, bindingTables
);
242 mlir::ConversionTarget
target(*context
);
243 target
.addLegalDialect
<mlir::AffineDialect
, mlir::cf::ControlFlowDialect
,
244 FIROpsDialect
, mlir::func::FuncDialect
>();
246 // apply the patterns
247 target
.addIllegalOp
<SelectTypeOp
>();
248 target
.addIllegalOp
<DispatchOp
>();
249 target
.markUnknownOpDynamicallyLegal([](Operation
*) { return true; });
250 if (mlir::failed(mlir::applyPartialConversion(getOperation(), target
,
251 std::move(patterns
)))) {
252 mlir::emitError(mlir::UnknownLoc::get(context
),
253 "error in converting to CFG\n");
259 std::mutex
*moduleMutex
;
263 mlir::LogicalResult
SelectTypeConv::matchAndRewrite(
264 fir::SelectTypeOp selectType
, OpAdaptor adaptor
,
265 mlir::ConversionPatternRewriter
&rewriter
) const {
266 auto operands
= adaptor
.getOperands();
267 auto typeGuards
= selectType
.getCases();
268 unsigned typeGuardNum
= typeGuards
.size();
269 auto selector
= selectType
.getSelector();
270 auto loc
= selectType
.getLoc();
271 auto mod
= selectType
.getOperation()->getParentOfType
<mlir::ModuleOp
>();
272 fir::KindMapping kindMap
= fir::getKindMapping(mod
);
274 // Order type guards so the condition and branches are done to respect the
275 // Execution of SELECT TYPE construct as described in the Fortran 2018
276 // standard 11.1.11.2 point 4.
277 // 1. If a TYPE IS type guard statement matches the selector, the block
278 // following that statement is executed.
279 // 2. Otherwise, if exactly one CLASS IS type guard statement matches the
280 // selector, the block following that statement is executed.
281 // 3. Otherwise, if several CLASS IS type guard statements match the
282 // selector, one of these statements will inevitably specify a type that
283 // is an extension of all the types specified in the others; the block
284 // following that statement is executed.
285 // 4. Otherwise, if there is a CLASS DEFAULT type guard statement, the block
286 // following that statement is executed.
287 // 5. Otherwise, no block is executed.
289 llvm::SmallVector
<unsigned> orderedTypeGuards
;
290 llvm::SmallVector
<unsigned> orderedClassIsGuards
;
291 unsigned defaultGuard
= typeGuardNum
- 1;
293 // The following loop go through the type guards in the fir.select_type
294 // operation and sort them into two lists.
295 // - All the TYPE IS type guard are added in order to the orderedTypeGuards
296 // list. This list is used at the end to generate the if-then-else ladder.
297 // - CLASS IS type guard are added in a separate list. If a CLASS IS type
298 // guard type extends a type already present, the type guard is inserted
299 // before in the list to respect point 3. above. Otherwise it is just
300 // added in order at the end.
301 for (unsigned t
= 0; t
< typeGuardNum
; ++t
) {
302 if (auto a
= typeGuards
[t
].dyn_cast
<fir::ExactTypeAttr
>()) {
303 orderedTypeGuards
.push_back(t
);
307 if (auto a
= typeGuards
[t
].dyn_cast
<fir::SubclassAttr
>()) {
308 if (auto recTy
= a
.getType().dyn_cast
<fir::RecordType
>()) {
309 auto dt
= mod
.lookupSymbol
<fir::DispatchTableOp
>(recTy
.getName());
310 assert(dt
&& "dispatch table not found");
311 llvm::SmallSet
<llvm::StringRef
, 4> ancestors
=
312 collectAncestors(dt
, mod
);
313 if (!ancestors
.empty()) {
314 auto it
= orderedClassIsGuards
.begin();
315 while (it
!= orderedClassIsGuards
.end()) {
316 fir::SubclassAttr sAttr
=
317 typeGuards
[*it
].dyn_cast
<fir::SubclassAttr
>();
318 if (auto ty
= sAttr
.getType().dyn_cast
<fir::RecordType
>()) {
319 if (ancestors
.contains(ty
.getName()))
324 if (it
!= orderedClassIsGuards
.end()) {
325 // Parent type is present so place it before.
326 orderedClassIsGuards
.insert(it
, t
);
331 orderedClassIsGuards
.push_back(t
);
334 orderedTypeGuards
.append(orderedClassIsGuards
);
335 orderedTypeGuards
.push_back(defaultGuard
);
336 assert(orderedTypeGuards
.size() == typeGuardNum
&&
337 "ordered type guard size doesn't match number of type guards");
339 for (unsigned idx
: orderedTypeGuards
) {
340 auto *dest
= selectType
.getSuccessor(idx
);
341 std::optional
<mlir::ValueRange
> destOps
=
342 selectType
.getSuccessorOperands(operands
, idx
);
343 if (typeGuards
[idx
].dyn_cast
<mlir::UnitAttr
>())
344 rewriter
.replaceOpWithNewOp
<mlir::cf::BranchOp
>(selectType
, dest
);
345 else if (mlir::failed(genTypeLadderStep(loc
, selector
, typeGuards
[idx
],
346 dest
, destOps
, mod
, rewriter
,
348 return mlir::failure();
350 return mlir::success();
353 mlir::LogicalResult
SelectTypeConv::genTypeLadderStep(
354 mlir::Location loc
, mlir::Value selector
, mlir::Attribute attr
,
355 mlir::Block
*dest
, std::optional
<mlir::ValueRange
> destOps
,
356 mlir::ModuleOp mod
, mlir::PatternRewriter
&rewriter
,
357 fir::KindMapping
&kindMap
) const {
359 // TYPE IS type guard comparison are all done inlined.
360 if (auto a
= attr
.dyn_cast
<fir::ExactTypeAttr
>()) {
361 if (fir::isa_trivial(a
.getType()) ||
362 a
.getType().isa
<fir::CharacterType
>()) {
363 // For type guard statement with Intrinsic type spec the type code of
364 // the descriptor is compared.
365 int code
= getTypeCode(a
.getType(), kindMap
);
367 return mlir::emitError(loc
)
368 << "type code unavailable for " << a
.getType();
369 mlir::Value typeCode
= rewriter
.create
<mlir::arith::ConstantOp
>(
370 loc
, rewriter
.getI8IntegerAttr(code
));
371 mlir::Value selectorTypeCode
= rewriter
.create
<fir::BoxTypeCodeOp
>(
372 loc
, rewriter
.getI8Type(), selector
);
373 cmp
= rewriter
.create
<mlir::arith::CmpIOp
>(
374 loc
, mlir::arith::CmpIPredicate::eq
, selectorTypeCode
, typeCode
);
376 // Flang inline the kind parameter in the type descriptor so we can
377 // directly check if the type descriptor addresses are identical for
378 // the TYPE IS type guard statement.
380 genTypeDescCompare(loc
, selector
, a
.getType(), mod
, rewriter
);
382 return mlir::failure();
385 // CLASS IS type guard statement is done with a runtime call.
386 } else if (auto a
= attr
.dyn_cast
<fir::SubclassAttr
>()) {
387 // Retrieve the type descriptor from the type guard statement record type.
388 assert(a
.getType().isa
<fir::RecordType
>() && "expect fir.record type");
389 fir::RecordType recTy
= a
.getType().dyn_cast
<fir::RecordType
>();
390 std::string typeDescName
=
391 fir::NameUniquer::getTypeDescriptorName(recTy
.getName());
392 auto typeDescGlobal
= mod
.lookupSymbol
<fir::GlobalOp
>(typeDescName
);
393 auto typeDescAddr
= rewriter
.create
<fir::AddrOfOp
>(
394 loc
, fir::ReferenceType::get(typeDescGlobal
.getType()),
395 typeDescGlobal
.getSymbol());
396 mlir::Type typeDescTy
= ReferenceType::get(rewriter
.getNoneType());
397 mlir::Value typeDesc
=
398 rewriter
.create
<ConvertOp
>(loc
, typeDescTy
, typeDescAddr
);
400 // Prepare the selector descriptor for the runtime call.
401 mlir::Type descNoneTy
= fir::BoxType::get(rewriter
.getNoneType());
402 mlir::Value descSelector
=
403 rewriter
.create
<ConvertOp
>(loc
, descNoneTy
, selector
);
405 // Generate runtime call.
406 llvm::StringRef fctName
= RTNAME_STRING(ClassIs
);
407 mlir::func::FuncOp callee
;
409 // Since conversion is done in parallel for each fir.select_type
410 // operation, the runtime function insertion must be threadsafe.
411 std::lock_guard
<std::mutex
> lock(*moduleMutex
);
413 fir::createFuncOp(rewriter
.getUnknownLoc(), mod
, fctName
,
414 rewriter
.getFunctionType({descNoneTy
, typeDescTy
},
415 rewriter
.getI1Type()));
418 .create
<fir::CallOp
>(loc
, callee
,
419 mlir::ValueRange
{descSelector
, typeDesc
})
423 auto *thisBlock
= rewriter
.getInsertionBlock();
425 rewriter
.createBlock(dest
->getParent(), mlir::Region::iterator(dest
));
426 rewriter
.setInsertionPointToEnd(thisBlock
);
427 if (destOps
.has_value())
428 rewriter
.create
<mlir::cf::CondBranchOp
>(loc
, cmp
, dest
, destOps
.value(),
429 newBlock
, std::nullopt
);
431 rewriter
.create
<mlir::cf::CondBranchOp
>(loc
, cmp
, dest
, newBlock
);
432 rewriter
.setInsertionPointToEnd(newBlock
);
433 return mlir::success();
436 // Generate comparison of type descriptor addresses.
438 SelectTypeConv::genTypeDescCompare(mlir::Location loc
, mlir::Value selector
,
439 mlir::Type ty
, mlir::ModuleOp mod
,
440 mlir::PatternRewriter
&rewriter
) const {
441 assert(ty
.isa
<fir::RecordType
>() && "expect fir.record type");
442 fir::RecordType recTy
= ty
.dyn_cast
<fir::RecordType
>();
443 std::string typeDescName
=
444 fir::NameUniquer::getTypeDescriptorName(recTy
.getName());
445 auto typeDescGlobal
= mod
.lookupSymbol
<fir::GlobalOp
>(typeDescName
);
448 auto typeDescAddr
= rewriter
.create
<fir::AddrOfOp
>(
449 loc
, fir::ReferenceType::get(typeDescGlobal
.getType()),
450 typeDescGlobal
.getSymbol());
451 auto intPtrTy
= rewriter
.getIndexType();
452 mlir::Type tdescType
=
453 fir::TypeDescType::get(mlir::NoneType::get(rewriter
.getContext()));
454 mlir::Value selectorTdescAddr
=
455 rewriter
.create
<fir::BoxTypeDescOp
>(loc
, tdescType
, selector
);
457 rewriter
.create
<fir::ConvertOp
>(loc
, intPtrTy
, typeDescAddr
);
458 auto selectorTdescInt
=
459 rewriter
.create
<fir::ConvertOp
>(loc
, intPtrTy
, selectorTdescAddr
);
460 return rewriter
.create
<mlir::arith::CmpIOp
>(
461 loc
, mlir::arith::CmpIPredicate::eq
, typeDescInt
, selectorTdescInt
);
464 int SelectTypeConv::getTypeCode(mlir::Type ty
, fir::KindMapping
&kindMap
) {
465 if (auto intTy
= ty
.dyn_cast
<mlir::IntegerType
>())
466 return fir::integerBitsToTypeCode(intTy
.getWidth());
467 if (auto floatTy
= ty
.dyn_cast
<mlir::FloatType
>())
468 return fir::realBitsToTypeCode(floatTy
.getWidth());
469 if (auto logicalTy
= ty
.dyn_cast
<fir::LogicalType
>())
470 return fir::logicalBitsToTypeCode(
471 kindMap
.getLogicalBitsize(logicalTy
.getFKind()));
472 if (fir::isa_complex(ty
)) {
473 if (auto cmplxTy
= ty
.dyn_cast
<mlir::ComplexType
>())
474 return fir::complexBitsToTypeCode(
475 cmplxTy
.getElementType().cast
<mlir::FloatType
>().getWidth());
476 auto cmplxTy
= ty
.cast
<fir::ComplexType
>();
477 return fir::complexBitsToTypeCode(
478 kindMap
.getRealBitsize(cmplxTy
.getFKind()));
480 if (auto charTy
= ty
.dyn_cast
<fir::CharacterType
>())
481 return fir::characterBitsToTypeCode(
482 kindMap
.getCharacterBitsize(charTy
.getFKind()));
486 llvm::SmallSet
<llvm::StringRef
, 4>
487 SelectTypeConv::collectAncestors(fir::DispatchTableOp dt
,
488 mlir::ModuleOp mod
) const {
489 llvm::SmallSet
<llvm::StringRef
, 4> ancestors
;
490 if (!dt
.getParent().has_value())
492 while (dt
.getParent().has_value()) {
493 ancestors
.insert(*dt
.getParent());
494 dt
= mod
.lookupSymbol
<fir::DispatchTableOp
>(*dt
.getParent());
499 std::unique_ptr
<mlir::Pass
> fir::createPolymorphicOpConversionPass() {
500 return std::make_unique
<PolymorphicOpConversion
>();