This is an archive of the discontinued LLVM Phabricator instance.

[flang] add fir.declare codegen support
ClosedPublic

Authored by jeanPerier on Oct 19 2022, 6:01 AM.

Details

Summary

For now, nothing is done about debug info and the fir.declare is simply
replaced by the memref argument. This is done in the PreCGRewrite in
order to avoid requiring adding support for fir.shape codegen, which
would still be useless and undesired at that point.

Diff Detail

Event Timeline

jeanPerier created this revision.Oct 19 2022, 6:01 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 19 2022, 6:01 AM
jeanPerier requested review of this revision.Oct 19 2022, 6:01 AM
clementval accepted this revision.Oct 19 2022, 6:09 AM

Makes sense. LG

This revision is now accepted and ready to land.Oct 19 2022, 6:09 AM

Are the pre-codegen ops enough for carrying the debug info to LLVM dialect? Or would we require lowering the fir.declare op to LLVM at some point when we add debug info? Would an alternative path be for fir.declare to subsume the precodegen dialect ops?

Are the pre-codegen ops enough for carrying the debug info to LLVM dialect? Or would we require lowering the fir.declare op to LLVM at some point when we add debug info? Would an alternative path be for fir.declare to subsume the precodegen dialect ops?

I think it will likely need to go a bit further, but since I do not know how debug info will look like in LLVM IR dialect, I cannot be assertive and I do not want to add a cg fir.declare at that stage just in case. It should really not be hard to add when the need arise, or to even allow fir.shape to be translated to some llvm tuple value in codegen and keep fir.declare until then. It may also actually turnout to be possible to already generate debug info in precodegen, this really depends on what should be generated.

I would be really happy if an LLVM debug info expert could jump in on the debug info task and set the exact requirement and plan for FIR/LLVM dialect here.

Are the pre-codegen ops enough for carrying the debug info to LLVM dialect? Or would we require lowering the fir.declare op to LLVM at some point when we add debug info? Would an alternative path be for fir.declare to subsume the precodegen dialect ops?

I think it will likely need to go a bit further, but since I do not know how debug info will look like in LLVM IR dialect, I cannot be assertive and I do not want to add a cg fir.declare at that stage just in case. It should really not be hard to add when the need arise, or to even allow fir.shape to be translated to some llvm tuple value in codegen and keep fir.declare until then. It may also actually turnout to be possible to already generate debug info in precodegen, this really depends on what should be generated.

I would be really happy if an LLVM debug info expert could jump in on the debug info task and set the exact requirement and plan for FIR/LLVM dialect here.

It has been a few years since I worked on Debug Metadata. For a simple adjustable array like marr in the following example

subroutine sb(marr, n)
  integer :: n
  integer :: marr(n)
end subroutine

the debug generated in LLVM IR has to be something like the following. There is a debug declare for the array marr. The metadata attached to marr will be of kind DILocalVariable whose type will list it as an array and the elements field of the type will point to a range (DISubrange) with fields lowerBound and upperBound. In this case the lowerBound will be 1 and the upperbound will be another variable that has the value loaded from n.

define void @sb_(i64* %marr, i64* %n) #0 {
...
call void @llvm.dbg.declare(metadata i64* %marr, metadata !15, metadata !DIExpression()),
...
}

!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 32, align: 32, elements: !10)
!9 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed)
!10 = !{!11}
!11 = !DISubrange(lowerBound: 1, upperBound: !12)
!12 = distinct !DILocalVariable(name: "z_e_13", scope: !5, file: !3, type: !13, flags: DIFlagArtificial)
!15 = !DILocalVariable(name: "marr", arg: 1, scope: !5, file: !3, line: 1, type: !8)
This revision was automatically updated to reflect the committed changes.

Are the pre-codegen ops enough for carrying the debug info to LLVM dialect? Or would we require lowering the fir.declare op to LLVM at some point when we add debug info? Would an alternative path be for fir.declare to subsume the precodegen dialect ops?

I think it will likely need to go a bit further, but since I do not know how debug info will look like in LLVM IR dialect, I cannot be assertive and I do not want to add a cg fir.declare at that stage just in case. It should really not be hard to add when the need arise, or to even allow fir.shape to be translated to some llvm tuple value in codegen and keep fir.declare until then. It may also actually turnout to be possible to already generate debug info in precodegen, this really depends on what should be generated.

I would be really happy if an LLVM debug info expert could jump in on the debug info task and set the exact requirement and plan for FIR/LLVM dialect here.

It has been a few years since I worked on Debug Metadata. For a simple adjustable array like marr in the following example

subroutine sb(marr, n)
  integer :: n
  integer :: marr(n)
end subroutine

the debug generated in LLVM IR has to be something like the following. There is a debug declare for the array marr. The metadata attached to marr will be of kind DILocalVariable whose type will list it as an array and the elements field of the type will point to a range (DISubrange) with fields lowerBound and upperBound. In this case the lowerBound will be 1 and the upperbound will be another variable that has the value loaded from n.

define void @sb_(i64* %marr, i64* %n) #0 {
...
call void @llvm.dbg.declare(metadata i64* %marr, metadata !15, metadata !DIExpression()),
...
}

!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 32, align: 32, elements: !10)
!9 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed)
!10 = !{!11}
!11 = !DISubrange(lowerBound: 1, upperBound: !12)
!12 = distinct !DILocalVariable(name: "z_e_13", scope: !5, file: !3, type: !13, flags: DIFlagArtificial)
!15 = !DILocalVariable(name: "marr", arg: 1, scope: !5, file: !3, line: 1, type: !8)

Thanks @kiranchandramohan for the illustration. Currently, is there a way to generate DIExpression metadata and llvm.dbg calls in the LLVM MLIR dialect ? I found this file in MLIR [1], but I am not sure it can generate a lot on top of location information. If not, before we can do anything in FIR about this, something will have to be added (extending LLVM dialect or maybe even adding a DIExpression dialect in MLIR).

[1] https://github.com/llvm/llvm-project/blob/main/mlir/lib/Target/LLVMIR/DebugTranslation.h

peixin added a subscriber: peixin.Oct 21 2022, 12:02 AM

Will fir.declare be used for procedure pointer, too? I am looking at the procedure pointer. It seems the codegen has been supported (check the following example). Should the lowering support be delayed until HLFIR is ready? It seems that fir.declare only targets on Fortran variables as HighLevelFIR.md mentioned.

func.func private @foo(!fir.ref<(!fir.ref<i32>) -> f32>)

func.func @func() -> ((!fir.ref<i32>) -> f32) {
  %0 = fir.alloca (!fir.ref<i32>) -> f32
  %1 = fir.load %0 : !fir.ref<(!fir.ref<i32>) -> f32>
  fir.call @foo(%0) : (!fir.ref<(!fir.ref<i32>) -> f32>) -> ()
  return %1 : (!fir.ref<i32>) -> f32
}

Will fir.declare be used for procedure pointer, too? I am looking at the procedure pointer. It seems the codegen has been supported (check the following example). Should the lowering support be delayed until HLFIR is ready? It seems that fir.declare only targets on Fortran variables as HighLevelFIR.md mentioned.

func.func private @foo(!fir.ref<(!fir.ref<i32>) -> f32>)

func.func @func() -> ((!fir.ref<i32>) -> f32) {
  %0 = fir.alloca (!fir.ref<i32>) -> f32
  %1 = fir.load %0 : !fir.ref<(!fir.ref<i32>) -> f32>
  fir.call @foo(%0) : (!fir.ref<(!fir.ref<i32>) -> f32>) -> ()
  return %1 : (!fir.ref<i32>) -> f32
}

Yes, fir.declare will support them. I do not see huge reason to wait though. I think however that the FIR design intention was rather to use fir.ref<fir.boxproc<FunctType>> to abstract the detail of what procedure are in lowering.
Also, I think procedure pointers will deserve a small doc to summarize in what kind of context they should appear, what are the constraints and what will be done in lowering.

Will fir.declare be used for procedure pointer, too? I am looking at the procedure pointer. It seems the codegen has been supported (check the following example). Should the lowering support be delayed until HLFIR is ready? It seems that fir.declare only targets on Fortran variables as HighLevelFIR.md mentioned.

func.func private @foo(!fir.ref<(!fir.ref<i32>) -> f32>)

func.func @func() -> ((!fir.ref<i32>) -> f32) {
  %0 = fir.alloca (!fir.ref<i32>) -> f32
  %1 = fir.load %0 : !fir.ref<(!fir.ref<i32>) -> f32>
  fir.call @foo(%0) : (!fir.ref<(!fir.ref<i32>) -> f32>) -> ()
  return %1 : (!fir.ref<i32>) -> f32
}

Yes, fir.declare will support them. I do not see huge reason to wait though. I think however that the FIR design intention was rather to use fir.ref<fir.boxproc<FunctType>> to abstract the detail of what procedure are in lowering.
Also, I think procedure pointers will deserve a small doc to summarize in what kind of context they should appear, what are the constraints and what will be done in lowering.

Got it. Thanks a lot.