Generating DWARF information that pretends an outparam is the return value

The Rust compiler defines all functions as returning void, with the
first parameter being an outparam of the declared return type, ie.

fn foo2() -> int { ret 5; }

becomes

define void @_ZN4foo217_5cb557d30658848cE(i64*, { i64, { %tydesc*, i1,
{} } }*) uwtable {
  store i64 5, i64* %0
  ret void
}

I'm working on generating debug information for Rust, and I'm
currently stumped on how to generate DWARF output via LLVM that will
correctly represent this (eg. when exiting from foo2(), I'd like to
see "Value returns is $1 = 5"). I'm generating debug metadata nodes
directly instead of using DIBuilder since it doesn't seem to
encapsulate situations like this. Any thoughts? Apologies if this is
too esoteric for the general LLVM community, but there's a seeming
dearth of information about things like DW_TAG_return_variable on the
wider internet.

Cheers,
Josh

Hi Josh,

I’m working on generating debug information for Rust, and I’m
currently stumped on how to generate DWARF output via LLVM that will
correctly represent this (eg. when exiting from foo2(), I’d like to
see “Value returns is $1 = 5”). I’m generating debug metadata nodes
directly instead of using DIBuilder since it doesn’t seem to
encapsulate situations like this.

So, I assume you figured out how to create metadata nodes for TAG_subprogram and corresponding TAG_subroutine_type. If yes, then the zero’th element of array of types you supply (subroutine_type is encoded as composite type, see http://llvm.org/docs/SourceLevelDebugging.html#format_composite_type) is return type.

Let’s say you have

1
2 int foo() {
3 char c = ‘a’;
4 return 42;
5 }

Try generating following metadata nodes (I am not including all of them here) to describe ‘char’ as the return type of function ‘foo’.

!1 = metadata !{i32 589870, i32 0, metadata !2, metadata !“foo”, metadata !“foo”, metadata !“”, metadata !2, i32 2, metadata !3, i1 false, i1 true, i32 0, i32 0, i32 0, i32 0, i1 f
alse, i32 ()* @foo, null, null} ; [ DW_TAG_subprogram ]

!3 = metadata !{i32 589845, metadata !2, metadata !“”, metadata !2, i32 0, i64 0, i64 0, i32 0, i32 0, i32 0, metadata !4, i32 0, i32 0} ; [ DW_TAG_subroutine_type ]

!8 = metadata !{i32 589860, metadata !0, metadata !“char”, null, i32 0, i64 8, i64 8, i64 0, i32 0, i32 6} ; [ DW_TAG_base_type ]

Next, when you generate metadata nodes for arguments, slide argument numbers by 1. (http://llvm.org/docs/SourceLevelDebugging.html#format_variables)

I have not tried this myself, but I hope it helps.

Hi Josh,

I’m working on generating debug information for Rust, and I’m
currently stumped on how to generate DWARF output via LLVM that will
correctly represent this (eg. when exiting from foo2(), I’d like to
see “Value returns is $1 = 5”). I’m generating debug metadata nodes
directly instead of using DIBuilder since it doesn’t seem to
encapsulate situations like this.

So, I assume you figured out how to create metadata nodes for TAG_subprogram and corresponding TAG_subroutine_type. If yes, then the zero’th element of array of types you supply (subroutine_type is encoded as composite type, see http://llvm.org/docs/SourceLevelDebugging.html#format_composite_type) is return type.

Let’s say you have

1
2 int foo() {
3 char c = ‘a’;
4 return 42;
5 }

Try generating following metadata nodes (I am not including all of them here) to describe ‘char’ as the return type of function ‘foo’.

!1 = metadata !{i32 589870, i32 0, metadata !2, metadata !“foo”, metadata !“foo”, metadata !“”, metadata !2, i32 2, metadata !3, i1 false, i1 true, i32 0, i32 0, i32 0, i32 0, i1 f
alse, i32 ()* @foo, null, null} ; [ DW_TAG_subprogram ]

!3 = metadata !{i32 589845, metadata !2, metadata !“”, metadata !2, i32 0, i64 0, i64 0, i32 0, i32 0, i32 0, metadata !4, i32 0, i32 0} ; [ DW_TAG_subroutine_type ]

!4 = metadata !{metadata !8}

Unfortunately this is what I'm already doing, and it's not working. I
drew inspiration from a disassembly of a program that showed that

struct foo {
  int a; float b; char buf[80];
}

struct foo get_foo(void) {
  foo f = { 5, 2.5 };
  return f;
}

would turn into

define void @get_foo(%struct.foo* sret %agg.result) nounwind ssp {
  ...
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* %3, i64 88, i32 4,
i1 false), !dbg !24
  ret void, !dbg !25
}

with similar metadata to what you wrote. I tried adding the sret
attribute to my generated functions, but there was no change - maybe
it doesn't work for non-structural types.

Cheers,
Josh

Hi Josh,