This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine] Fix dbg.declare -> dbg.value conversion before a load instruction
ClosedPublic

Authored by loladiro on Oct 29 2015, 2:49 PM.

Details

Summary

llvm.dbg.value needs the actual loaded value as the first argument, rather than it's address.

Diff Detail

Repository
rL LLVM

Event Timeline

loladiro updated this revision to Diff 38766.Oct 29 2015, 2:49 PM
loladiro retitled this revision from to [InstCombine] Fix dbg.declare -> dbg.value conversion before a load instruction.
loladiro updated this object.
loladiro added a reviewer: aprantl.
loladiro set the repository for this revision to rL LLVM.
aprantl accepted this revision.Oct 30 2015, 11:49 AM
aprantl edited edge metadata.

Interesting. On a first glance, this almost looks like a cut&paste error from the function above it.

[ I was thinking about whether it wouldn't be better to leave it as is and add an additional DW_OP_deref to the DIExpression. This has both the advantage and disadvantage that the lifetime of the address is indefinite, which could lead to more debuggable code because the variable is available for a longer range. It could also lead to more misleading debug info, if the code is performing calculations on the loaded value and the debug info is pointing the an old version of the variable in memory. ]

In cases where the alloca cannot be elided, the dbg.declare describing the alloca will also survive, so it makes no sense to describe the address twice. We should do the same thing we do for stores and just describe the value.

Can you add a comment to the code that indicates that this is now tracking the loaded value instead of the stack slot and why this is preferable?

thanks,
adrian

This revision is now accepted and ready to land.Oct 30 2015, 11:49 AM
loladiro updated this revision to Diff 38998.Nov 2 2015, 4:05 PM
loladiro edited edge metadata.

Found a similar problem a couple lines down, I think this is the correct fix, but do have a look.

loladiro updated this revision to Diff 39001.Nov 2 2015, 4:18 PM

Add comment re tracking the loaded value.

loladiro updated this revision to Diff 39028.Nov 2 2015, 8:15 PM

Small typo in the test case

aprantl added inline comments.Nov 3 2015, 9:03 AM
lib/Transforms/Utils/Local.cpp
1127 ↗(On Diff #39028)

Shouldn't the DW_OP_deref be the first instruction in the instruction stream?

1130 ↗(On Diff #39028)

This is definitely the right thing to do here, but I remember adding code to SelectionDAG to recognize the case where a dbg.value describes an alloca and transform the dbg.value to be indirect (this was before we had DIExpression to express this).

Found it:

SelectionDAGBuilder.cpp:4507

if (N.getNode()) {
  // A dbg.value for an alloca is always indirect.
  bool IsIndirect = isa<AllocaInst>(V) || Offset != 0;
  if (!EmitFuncArgumentDbgValue(V, Variable, Expression, dl, Offset,
                                IsIndirect, N)) {
    SDV = DAG.getDbgValue(Variable, Expression, N.getNode(), N.getResNo(),
                          IsIndirect, Offset, dl, SDNodeOrder);
    DAG.AddDbgValue(SDV, N.getNode(), false);
  }
} else if (!V->use_empty() ) {

You'll need to update this as well.
(I couldn't find the equivalent code in FastISel.cpp:1170ff)

loladiro added inline comments.Nov 4 2015, 2:23 PM
lib/Transforms/Utils/Local.cpp
1127 ↗(On Diff #39028)

Yes, I think you're right. For rome reason I had convinced myself of the opposite, but can't remember why.

1130 ↗(On Diff #39028)

Will do, thanks.

loladiro added inline comments.Nov 4 2015, 2:29 PM
lib/Transforms/Utils/Local.cpp
1130 ↗(On Diff #39028)

Is there any use still for the Offset field of llvm.dbg.value, shouldn't that always be taken care of by DW_OP_bit_piece now? Should I just remove the IsIndirect check completely?

Reminder to look at the latest version of this when you get the chance.

Sorry, this got buried in my inbox. LGTM with the pending changes mentioned inline.

lib/Transforms/Utils/Local.cpp
1127 ↗(On Diff #39028)

The push_back should happen before the append (probably forgot to update the patch?).

1130 ↗(On Diff #39028)

Yes. I have an open long-term-project to audit all remaining uses of Offset and replace them with DIExpressions and eventually remove the field entirely. Same goes for the IsIndirect flag.
Are there other uses remaining in SelectionDAG? Could we already remove it (in a separate commit)?

loladiro added inline comments.Nov 17 2015, 8:50 PM
lib/Transforms/Utils/Local.cpp
1127 ↗(On Diff #39028)

Right, I was waiting to see what to do below.

1130 ↗(On Diff #39028)

No, I think this is the only use. I'll update this patch to remove the AllocaInst case, and we can do the Offset case in a separate commit, making sure that there aren't any test cases which rely on it.

loladiro updated this revision to Diff 40887.Nov 22 2015, 1:25 PM

Ok, this turned out a lot trickier than expected, because some tests were relying on the isIndirect setting for printing correctly (in comments). I updated the comment printing code to account for expressions, which fixed most of that, but there were a few instances in tests where the printed comment disagreed with what was actually in the DWARF (because it wasn't accounting for expressions when printing the comments). I think I fixed most of that, but please take a look at whether everything is still semantically correct. The one test I didn't know what to do with was debug-loc-asan.ll (deleted in this patch to have a full patch that passes tests, but if you let me know how to update it properly, I'll fix it).

Thanks for all the extra work!

there were a few instances in tests where the printed comment disagreed with what was actually in the DWARF

With the recent improvements in llvm-dwarfdump, we can and should just update those testcases to use llc-dwarf | llvm-dwarfdump - --debug-dump=info and check for the expressions.

test/CodeGen/ARM/debug-info-blocks.ll
2 ↗(On Diff #40887)

We should replace this by llc_dwarf | llvm-dwarfdump -debug-dump=info and check for the actual expression there.

test/DebugInfo/Mips/dsr-fixed-objects.ll
58 ↗(On Diff #40887)

where does the extra byte come from?

58 ↗(On Diff #40887)

Where does the extra byte come from? The op_deref?

test/DebugInfo/X86/reference-argument.ll
6 ↗(On Diff #40887)

That comment and the CHECK seem to contradict each other?

test/DebugInfo/X86/vla.ll
3 ↗(On Diff #40887)

Why did you have to remove the check for breg? Ism't the op_deref lowered to one?

loladiro added inline comments.Dec 1 2015, 3:58 AM
test/DebugInfo/Mips/dsr-fixed-objects.ll
58 ↗(On Diff #40887)

Yeah, the IR was missing an DW_OP_deref. Fixing this, then the DWARF will stay the same.

test/DebugInfo/X86/reference-argument.ll
6 ↗(On Diff #40887)

Not sure what to say about that. Both before and after the change

0x00000101:     DW_TAG_formal_parameter [16]
                  DW_AT_location [DW_FORM_block1]	(<0x02> 74 00 )
                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000009f] = "v")
                  DW_AT_decl_file [DW_FORM_data1]	("aggregate-indirect-arg.cpp")
                  DW_AT_decl_line [DW_FORM_data1]	(22)
                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0062 => {0x00000062})

Maybe you can take a look at the radar?

test/DebugInfo/X86/vla.ll
3 ↗(On Diff #40887)

I was mistaken, the DW_OP_breg1 is there.

loladiro updated this revision to Diff 41487.Dec 1 2015, 3:59 AM

Updated testcases as described in my reply to your review comments

The source code that reference-argument.ll was created from is in the debuginfo-tests repository:

class SVal {
public:
  ~SVal() {}
  const void* Data;
  unsigned Kind;
};

void bar(SVal &v) {}
class A {
public:
  void foo(SVal v) { bar(v); }
};

int main() {
  SVal v;
  v.Data = 0;
  v.Kind = 2142;
  A a;
  a.foo(v);
  return 0;
}

[This IR output is highly questionable, because a function argument is described by an dbg.declare() which is not exactly documented behavior.] Anyway, RSI is carrying the pointer to v, which is a DW_TAG_reference_type, so the comment is correct and it should *not* have an extra DW_OP_deref on it.

It looks like current clang is still generating an DW_OP_deref. I assume the right thing to do here is an dbg.value without the DW_OP_deref? If so I'll update this test case to do that and we should look at clang to change that there as well.

Actually, no, I'm confused !62, has type !9, which is the class, not a reference thereto.

Bump, can you shed light on my confusion above?

Ah yes. Checking the comments in the assembler output is highly misleading.
I rewrite the test to use llvm-dwarfdump in r255912. Yes, the address should be indirect.

The test still passes if we replace the sketchy dbg.declare with a dbg.value:

call void @llvm.dbg.value(metadata %class.SVal* %v, i64 0, metadata !62, metadata !DIExpression(DW_OP_deref)), !dbg !61

loladiro updated this revision to Diff 43217.Dec 18 2015, 4:41 AM

Ok, rebased and changed the reference argument test case to use dbg.value

Thanks! Two more inline comments, but otherwise good to go.

lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
953 ↗(On Diff #43217)

This comment is now obsolete.

lib/Transforms/Utils/Local.cpp
1126 ↗(On Diff #43217)

Nitpick: DbgDeclareInst::getExpression() will return an empty DIExpression() and never a nullptr, so the if (DIExpr) should be redundant.

aprantl added inline comments.Dec 18 2015, 8:53 AM
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
4519 ↗(On Diff #43217)

Can you remind me why we are ignoring Offset for the indirection flag here but don't on line 957?

loladiro added inline comments.Dec 18 2015, 8:55 AM
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
4519 ↗(On Diff #43217)

Because I made a mistake. We should ignore it up there as well.

loladiro updated this revision to Diff 43236.Dec 18 2015, 9:09 AM

Update to address the latest two review comments.

Before I commit this, I wanted to point out that this still has the test/DebugInfo/X86/debug-loc-asan.ll test deleted. Thoughts on what to do with that?

Oh right. The correct thing to do would be to recreate the IR from source (assuming that the stuff in Local affects the IR) and update the CHECKs as necessary.

Well, the problem was that running the test case through a recent clang, actually produces very small IR:

; Function Attrs: nounwind sanitize_address uwtable
define i32 @_Z3bari(i32 %y) #0 !dbg !4 {
entry:
  %y.addr = alloca i32, align 4
  store i32 %y, i32* %y.addr, align 4
  call void @llvm.dbg.declare(metadata i32* %y.addr, metadata !11, metadata !12), !dbg !13
  %0 = load i32, i32* %y.addr, align 4, !dbg !14
  %add = add nsw i32 %0, 2, !dbg !15
  ret i32 %add, !dbg !16
}

Ah, found it:
-mllvm -asan-skip-promotable-allocas=0

loladiro updated this revision to Diff 43273.Dec 18 2015, 3:07 PM

Ok, I think I figured it out. The first comment in that test case (checking that it comes in a register)
is wrong, because we don't have a dbg.value for that and was based on the incorrect printing of
debug locations in comments (it might be a separate commit to make sure that dbg.value is actually there,
but that's not in the scope for this commit). Then, the CHECK for DEBUG_VALUE was also wrong, because
it's actually a double dereference. Fix that by just removing that check, since we do check the actual
DWARF later down and that's correct.

aprantl added inline comments.Dec 18 2015, 3:35 PM
test/DebugInfo/X86/debug-loc-asan.ll
12 ↗(On Diff #43273)

This comment needs to be updated now. Otherwise this is good!

loladiro updated this revision to Diff 43281.Dec 18 2015, 4:01 PM

Ok, one final update to the test case, so this should be good to go now.

This revision was automatically updated to reflect the committed changes.