Page MenuHomePhabricator

Debug Info: Allow SROAed complex floating point types to be described by constants

Authored by aprantl on Feb 3 2016, 1:19 PM.



When SROA splits up composite types and individual pieces are described by integer constants, we currently default to emitting these constant pieces as unsigned bytes regardless of the encoding of the underlying types. We don't make any attempt to find the correct encoding by finding the underlying element type from the composite type.

In the attached testcase a complex float is split into two 64-bit *integers* (because the target doesn't define a 64-bit double type).
This patch relaxes the assertion in isUnsignedDIType and matches the behavior so complex_float is treated consistent with other composite types.

I agree that trusting the IR to encode integer constants properly is questionable, but it is consistent with what we do for composite types, and apparently we're not doing any better elsewhere:

void DwarfUnit::addConstantFPValue(DIE &Die, const ConstantFP *CFP) {
  // Pass this down to addConstantValue as an unsigned bag of bits.
  addConstantValue(Die, CFP->getValueAPF().bitcastToAPInt(), true);


Diff Detail


Event Timeline

aprantl updated this revision to Diff 46811.Feb 3 2016, 1:19 PM
aprantl retitled this revision from to Debug Info: Allow SROAed complex floating point types to be described by constants.
aprantl updated this object.
aprantl added reviewers: dblaikie, echristo, probinson.
aprantl set the repository for this revision to rL LLVM.
aprantl added a subscriber: llvm-commits.
probinson edited edge metadata.Feb 3 2016, 3:57 PM

Do we test Complex anywhere else? I'm not getting any hits in test/DebugInfo/*.


Huh. So we see udata (0) because the zero value is considered as an integer type rather than a float type? And that's supposed to be the entire 128-bit value?
I wonder if something else weird is going on with _Complex, because on Linux I get DW_AT_location with an expression that describes only one 8-byte piece.


This looks funny, and I don't see a reference to !16 anywhere? Is this possibly the missing other half of the _Complex value?

aprantl added inline comments.Feb 3 2016, 4:06 PM

No this is supposed to be the lower 64 bits of the complex 128-bit value.
In order to reproduce this you need to compile for a target that does not have a native 64-bit double data type. (E.g.: -triple=thumbv7-apple-unknown-macho but not thumbv7-apple-ios)


I am unsure how it could survive given that nothing is referencing it, but this is most likely the DIExpression() of the aggregate complex value before it was SROA'ed.

probinson added inline comments.Feb 3 2016, 5:29 PM

How does the consumer know this DW_AT_const_value is only the lower half? How will it find the upper half?
I brought up the Linux behavior only because it also was not describing the upper half, which makes me think there is some deeper problem with describing Complex values. Sorry, should have made that clear, I am not expecting Linux to trigger the integer thing.

aprantl added inline comments.Feb 4 2016, 8:24 AM

Good catch, this is due to an unrelated bug. In the IR the value is clearly described by DW_OP_bit_piece(0, 64), however, the bit_piece expression doesn't make it into the final DWARF output.

Note that describing only the lower half is correct here as the original source is:

void f(_Complex double c) { c = 0; }

If you change that to become

void f(_Complex double c) { c = 0 + 1*_Complex_I; }

you will get two bit_pieces describing real and imaginary parts. However, in this case, our DWARF backend will sub-optimally decide to emit a single-entry location list (totally different code path) because there is more than one DBG_VALUE.

probinson added inline comments.Feb 4 2016, 9:45 AM

Why is it correct to describe only half the value of the formal parameter? It is 16 bytes wide and all of it has some location or constant value.
The body of the function assigns an integer literal to a complex variable; the integer literal is promoted to double and used for the real part, and the imaginary part is set to zero. C11 says so. Therefore there is a known constant value for all the bits of 'c' and the DWARF should describe all of that value.

aprantl added a comment.EditedFeb 4 2016, 9:56 AM

You're correct, it looks like there is also a bug in SROA / Local that is causing the imaginary part to be dropped:

*** IR Dump After Simplify the CFG ***
; Function Attrs: nounwind optsize
define arm_aapcscc void @f([2 x i64] %c.coerce) #0 !dbg !4 {
  %c = alloca { double, double }, align 8
  %0 = bitcast { double, double }* %c to [2 x i64]*
  store [2 x i64] %c.coerce, [2 x i64]* %0, align 8
  call void @llvm.dbg.declare(metadata { double, double }* %c, metadata !10, metadata !16), !dbg !17
  %c.realp = getelementptr inbounds { double, double }, { double, double }* %c, i32 0, i32 0, !dbg !17
  %c.imagp = getelementptr inbounds { double, double }, { double, double }* %c, i32 0, i32 1, !dbg !17
  store double 0.000000e+00, double* %c.realp, align 8, !dbg !17
  store double 0.000000e+00, double* %c.imagp, align 8, !dbg !17
  ret void, !dbg !17
*** IR Dump After SROA ***
; Function Attrs: nounwind optsize
define arm_aapcscc void @f([2 x i64] %c.coerce) #0 !dbg !4 {
  %c.coerce.fca.0.extract = extractvalue [2 x i64] %c.coerce, 0
  call void @llvm.dbg.value(metadata i64 %c.coerce.fca.0.extract, i64 0, metadata !10, metadata !16), !dbg !17
  %c.coerce.fca.1.extract = extractvalue [2 x i64] %c.coerce, 1
  call void @llvm.dbg.value(metadata i64 %c.coerce.fca.1.extract, i64 0, metadata !10, metadata !18), !dbg !17
  call void @llvm.dbg.declare(metadata { double, double }* undef, metadata !10, metadata !19), !dbg !17
  call void @llvm.dbg.value(metadata i64 0, i64 0, metadata !10, metadata !16), !dbg !17
  ret void, !dbg !17

The basic idea of handling DWARF complex_float the same as float seems okay, but the test isn't going to look right until _Complex in general works right. I'd say it's Eric's call whether you need to shave that yak first.

I found the bug causing the imaginary part to be dropped. LdStHasDebugValue in Local.cpp doesn't take DIExpressions into account, so it thinks the variable is already fully described by the dbg.value describing the lower part.
Working on a patch.

Let's consider ths yak shaved:

commit 9114a54cc7bd33e850ef8e2eb97f6c41880737c1
Author: Adrian Prantl <>
Date: Wed Feb 17 12:05:27 2016 -0800

Debug Info: Teach LdStHasDebugValue() (Local.cpp) about DIExpressions.
This function is used to check whether a dbg.value intrinsic has already
been inserted, but without comparing the DIExpression, it would erroneously
fire on split aggregates and only the first scalar would survive.

Found via
aprantl abandoned this revision.Feb 17 2016, 2:26 PM

I also fixed the other bug in r261168:

DwarfDebug: Don't drop the DIExpression just because a variable is
described by an immediate.

which makes this patch obsolete. (This code path can no longer be triggered).

Thanks for all the feedback!