diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -1661,7 +1661,7 @@ TypeAttr:$baseType ); - let results = (outs fir_ReferenceType); + let results = (outs RefOrLLVMPtr); let parser = "return parseCoordinateCustom(parser, result);"; let printer = "::print(p, *this);"; diff --git a/flang/include/flang/Optimizer/Dialect/FIRType.h b/flang/include/flang/Optimizer/Dialect/FIRType.h --- a/flang/include/flang/Optimizer/Dialect/FIRType.h +++ b/flang/include/flang/Optimizer/Dialect/FIRType.h @@ -59,7 +59,8 @@ /// Is `t` a FIR dialect type that implies a memory (de)reference? inline bool isa_ref_type(mlir::Type t) { - return t.isa() || t.isa() || t.isa(); + return t.isa() || t.isa() || t.isa() || + t.isa(); } /// Is `t` a boxed type? diff --git a/flang/include/flang/Optimizer/Dialect/FIRTypes.td b/flang/include/flang/Optimizer/Dialect/FIRTypes.td --- a/flang/include/flang/Optimizer/Dialect/FIRTypes.td +++ b/flang/include/flang/Optimizer/Dialect/FIRTypes.td @@ -224,6 +224,22 @@ }]; } +def fir_LLVMPointerType : FIR_Type<"LLVMPointer", "llvm_ptr"> { + let summary = "Like LLVM pointer type"; + + let description = [{ + A pointer type that does not have any of the constraints and semantics + of other FIR pointer types and that translates to llvm pointer types. + It is meant to implement indirection that cannot be expressed directly + in Fortran, but are needed to implement some Fortran features (e.g, + double indirections). + }]; + + let parameters = (ins "mlir::Type":$eleTy); + + let assemblyFormat = "`<` $eleTy `>`"; +} + def fir_PointerType : FIR_Type<"Pointer", "ptr"> { let summary = "Reference to a POINTER attribute type"; @@ -516,7 +532,11 @@ // Reference types def AnyReferenceLike : TypeConstraint, "any reference">; + fir_HeapType.predicate, fir_PointerType.predicate, + fir_LLVMPointerType.predicate]>, "any reference">; + +def RefOrLLVMPtr : TypeConstraint, "fir.ref or fir.llvm_ptr">; def AnyBoxLike : TypeConstraint, "any box">; diff --git a/flang/lib/Optimizer/CodeGen/TypeConverter.h b/flang/lib/Optimizer/CodeGen/TypeConverter.h --- a/flang/lib/Optimizer/CodeGen/TypeConverter.h +++ b/flang/lib/Optimizer/CodeGen/TypeConverter.h @@ -65,6 +65,9 @@ return mlir::IntegerType::get( &getContext(), kindMapping.getLogicalBitsize(boolTy.getFKind())); }); + addConversion([&](fir::LLVMPointerType pointer) { + return convertPointerLike(pointer); + }); addConversion( [&](fir::PointerType pointer) { return convertPointerLike(pointer); }); addConversion( diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -824,8 +824,9 @@ bool fir::ConvertOp::isPointerCompatible(mlir::Type ty) { return ty.isa() || ty.isa() || - ty.isa() || ty.isa() || - ty.isa() || ty.isa(); + ty.isa() || ty.isa() || + ty.isa() || ty.isa() || + ty.isa(); } static mlir::LogicalResult verify(fir::ConvertOp &op) { @@ -1755,16 +1756,8 @@ result.addTypes(eleTy); } -/// Get the element type of a reference like type; otherwise null -static mlir::Type elementTypeOf(mlir::Type ref) { - return llvm::TypeSwitch(ref) - .Case( - [](auto type) { return type.getEleTy(); }) - .Default([](mlir::Type) { return mlir::Type{}; }); -} - mlir::ParseResult fir::LoadOp::getElementOf(mlir::Type &ele, mlir::Type ref) { - if ((ele = elementTypeOf(ref))) + if ((ele = fir::dyn_cast_ptrEleTy(ref))) return mlir::success(); return mlir::failure(); } diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp --- a/flang/lib/Optimizer/Dialect/FIRType.cpp +++ b/flang/lib/Optimizer/Dialect/FIRType.cpp @@ -200,15 +200,15 @@ mlir::Type dyn_cast_ptrEleTy(mlir::Type t) { return llvm::TypeSwitch(t) - .Case( - [](auto p) { return p.getEleTy(); }) + .Case([](auto p) { return p.getEleTy(); }) .Default([](mlir::Type) { return mlir::Type{}; }); } mlir::Type dyn_cast_ptrOrBoxEleTy(mlir::Type t) { return llvm::TypeSwitch(t) - .Case( - [](auto p) { return p.getEleTy(); }) + .Case([](auto p) { return p.getEleTy(); }) .Case([](auto p) { auto eleTy = p.getEleTy(); if (auto ty = fir::dyn_cast_ptrEleTy(eleTy)) @@ -864,7 +864,7 @@ void FIROpsDialect::registerTypes() { addTypes(); + LLVMPointerType, PointerType, RealType, RecordType, ReferenceType, + SequenceType, ShapeType, ShapeShiftType, ShiftType, SliceType, + TypeDescType, fir::VectorType>(); } diff --git a/flang/test/Fir/fir-ops.fir b/flang/test/Fir/fir-ops.fir --- a/flang/test/Fir/fir-ops.fir +++ b/flang/test/Fir/fir-ops.fir @@ -707,3 +707,18 @@ // CHECK: fir.slice %{{.*}}, %{{.*}}, %{{.*}} substr %{{.*}}, %{{.*}} : (index, index, index, index, index) -> !fir.slice<1> return } + +// Test load, store, coordinate_of with llvmptr type +// CHECK-LABEL: llvm_ptr_load_store_coordinate +// CHECK-SAME: (%[[ARG0:.*]]: !fir.ref>>, !fir.ref>>>>, %[[ARG1:.*]]: !fir.ref>>) +func @llvm_ptr_load_store_coordinate(%arg0: !fir.ref>>, !fir.ref>>>>, %arg1: !fir.ref>>) -> !fir.ref>> { + // CHECK-NEXT: %[[C0:.*]] = arith.constant 0 : i32 + %c0_i32 = arith.constant 0 : i32 + // CHECK-NEXT: %[[LLVMPTR:.*]] = fir.coordinate_of %[[ARG0]], %[[C0]] : (!fir.ref>>, !fir.ref>>>>, i32) -> !fir.llvm_ptr>>> + %0 = fir.coordinate_of %arg0, %c0_i32 : (!fir.ref>>, !fir.ref>>>>, i32) -> !fir.llvm_ptr>>> + // CHECK-NEXT: fir.store %[[ARG1]] to %[[LLVMPTR]] : !fir.llvm_ptr>>> + fir.store %arg1 to %0 : !fir.llvm_ptr>>> + // CHECK-NEXT: fir.load %[[LLVMPTR]] : !fir.llvm_ptr>>> + %1 = fir.load %0 : !fir.llvm_ptr>>> + return %1 : !fir.ref>> +} diff --git a/flang/test/Fir/fir-types.fir b/flang/test/Fir/fir-types.fir --- a/flang/test/Fir/fir-types.fir +++ b/flang/test/Fir/fir-types.fir @@ -55,10 +55,14 @@ // CHECK-LABEL: func private @mem2() -> !fir.ptr // CHECK-LABEL: func private @mem3() -> !fir.heap // CHECK-LABEL: func private @mem4() -> !fir.ref<() -> ()> +// CHECK-LABEL: func private @mem5() -> !fir.llvm_ptr> +// CHECK-LABEL: func private @mem6() -> !fir.llvm_ptr func private @mem1() -> !fir.ref func private @mem2() -> !fir.ptr func private @mem3() -> !fir.heap func private @mem4() -> !fir.ref<() -> ()> +func private @mem5() -> !fir.llvm_ptr> +func private @mem6() -> !fir.llvm_ptr // FIR box types (descriptors) // CHECK-LABEL: func private @box1() -> !fir.box> diff --git a/flang/test/Fir/types-to-llvm.fir b/flang/test/Fir/types-to-llvm.fir --- a/flang/test/Fir/types-to-llvm.fir +++ b/flang/test/Fir/types-to-llvm.fir @@ -176,6 +176,26 @@ // ----- +// Test `!fir.llvm_ptr` conversion. + +func private @foo0(%arg0: !fir.llvm_ptr) +// CHECK-LABEL: foo0 +// CHECK-SAME: !llvm.ptr + +func private @foo1(%arg0: !fir.llvm_ptr>) +// CHECK-LABEL: foo1 +// CHECK-SAME: !llvm.ptr> + +func private @foo2(%arg0: !fir.llvm_ptr>>>) +// CHECK-LABEL: foo2 +// CHECK-SAME: !llvm.ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>> + +func private @foo3(%arg0: !fir.llvm_ptr>) +// CHECK-LABEL: foo3 +// CHECK-SAME: !llvm.ptr> + +// ----- + // Test `!fir.complex` conversion. func private @foo0(%arg0: !fir.complex<2>)