<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/61169>61169</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            EarlyCSE drops debug info for pointer values derived from arguments
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            debuginfo,
            llvm:optimizations
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          jryans
      </td>
    </tr>
</table>

<pre>
    The `EarlyCSE` pass removes debug value info for portions of the `oid` pointer
array, even though these values must be available since they derive from
function arguments. The `SROA` pass just before this also seems to drop some
value info for the same variable.

## Versions

* Clang: version 17.0.0 (https://github.com/llvm/llvm-project.git 87cf39aa349b83ae3b7d16c30ac7a8ffa0ad098c)
* LLDB: version 17.0.0git (git@github.com:llvm/llvm-project.git revision c820e60844ee1e5f084dd7761576bd0bd4927264)

## Compiler Explorer

* [Optimisation pipeline view using x86-64 Clang trunk (may change over time)](https://godbolt.org/z/h7dbaWozP)

## Program source

```c
struct object_id {
  int algo;
};

struct object {
  struct object_id oid;
};

struct entry {
  struct object *item;
};

int example(int n, struct entry *ent0, struct entry *ent1) {
  const struct object_id *(oid[2]);
  struct object_id mb_oid;

  if (n) {
    oid[0] = &mb_oid;
    oid[1] = &ent0->item->oid;
  } else {
    int swap = 0;
    oid[swap] = &ent0->item->oid;
    oid[1 - swap] = &ent1->item->oid;
  }
  return oid[0]->algo;
}
```

## Debug info view

```
$ clang -fno-discard-value-names -fno-inline -g -O1 -c -o example-O1.o
$ llvm-dwarfdump -n example example-O1.o
0x00000032: DW_TAG_subprogram
 DW_AT_low_pc      (0x0000000000000000)
 DW_AT_high_pc     (0x0000000000000015)
              DW_AT_frame_base (DW_OP_reg6 RBP)
              DW_AT_call_all_calls      (true)
 DW_AT_name        ("example")
              DW_AT_decl_line (13)
              DW_AT_prototyped  (true)
              DW_AT_type (0x000000a7 "int")
              DW_AT_external    (true)
$ llvm-dwarfdump -n oid example-O1.o
0x00000072: DW_TAG_variable
 DW_AT_location    (0x00000000:
                 [0x0000000000000011, 0x0000000000000013): DW_OP_reg0 RAX, DW_OP_piece 0x8)
 DW_AT_name        ("oid")
              DW_AT_decl_line   (14)
 DW_AT_type        (0x000000f7 "const object_id*[2]")
```

Location for `oid` is missing for most of the function, and the location that is
present only covers part of the array.

## IR before `EarlyCSE`

```llvm
if.then: ; preds = %entry
  call void @llvm.dbg.value(metadata ptr undef, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64))
  %0 = load ptr, ptr %ent0, align 8
  call void @llvm.dbg.value(metadata ptr %0, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64))
  br label %if.end

if.else:                                          ; preds = %entry
  call void @llvm.dbg.value(metadata i32 0, "swap", metadata !DIExpression())
  %1 = load ptr, ptr %ent0, align 8
  call void @llvm.dbg.value(metadata ptr %1, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64))
  %2 = load ptr, ptr %ent1, align 8
  call void @llvm.dbg.value(metadata ptr %2, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64))
 %oid.sroa.0.0.sroa.speculate.load.if.else = load i32, ptr %1, align 4
  br label %if.end
```

## IR after `EarlyCSE`

```llvm
if.then: ; preds = %entry
  call void @llvm.dbg.value(metadata ptr undef, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64))
  call void @llvm.dbg.value(metadata ptr poison, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64))
  br label %if.end

if.else:                                          ; preds = %entry
  call void @llvm.dbg.value(metadata i32 0, "swap", metadata !DIExpression())
  %0 = load ptr, ptr %ent0, align 8
  call void @llvm.dbg.value(metadata ptr %0, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64))
  call void @llvm.dbg.value(metadata ptr poison, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64))
 %oid.sroa.0.0.sroa.speculate.load.if.else = load i32, ptr %0, align 4
  br label %if.end
```

## IR diff before and after `EarlyCSE`

```diff
@@ -1,14 +1,12 @@
 if.then: ; preds = %entry
   call void @llvm.dbg.value(metadata ptr undef, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64))
-  %0 = load ptr, ptr %ent0, align 8
-  call void @llvm.dbg.value(metadata ptr %0, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64))
+  call void @llvm.dbg.value(metadata ptr poison, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64))
   br label %if.end

 if.else:                                          ; preds = %entry
   call void @llvm.dbg.value(metadata i32 0, "swap", metadata !DIExpression())
- %1 = load ptr, ptr %ent0, align 8
-  call void @llvm.dbg.value(metadata ptr %1, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64))
-  %2 = load ptr, ptr %ent1, align 8
-  call void @llvm.dbg.value(metadata ptr %2, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64))
- %oid.sroa.0.0.sroa.speculate.load.if.else = load i32, ptr %1, align 4
+ %0 = load ptr, ptr %ent0, align 8
+  call void @llvm.dbg.value(metadata ptr %0, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64))
+ call void @llvm.dbg.value(metadata ptr poison, "oid", metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64))
+ %oid.sroa.0.0.sroa.speculate.load.if.else = load i32, ptr %0, align 4
 br label %if.end
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsWVtv2zzS_jX0zUCCRMmSfOELO04-FMiHFHmLt3tnUNJIZlciBZJyk_76BSnLh9jNoZssgsUKbSJLM8NnDnxmYjKteS0Q52S6JNPVhPVmI9X8h3pkQk9yWT7Ov20QSBJcM9U8Xv11TZIAOqY1KGzlFjWUmPc1bFnTI3BRSaikgk4qw6XQICswgwHJS6cruTCoSLAiwYIpxR4JvQLcogCzkX29sfIaB4Ma2l4byBHYlvGG5Q2C5qJAK_QIJSq-RaiUbAd7VS8Kuy4wVfctCqN92OH_6_5uscf-Y7BaSWUtcQ2s0RI0YqvBSCiV7EDLFgerT3yz_mjWWoiKW0j-ILb7SSNCI_gblbYBOH21gKuGiZpEC9gOAhCmfuAHQGi2MabTJFoQekPoTc3Nps_9QraE3jTNdvzldUr-wML4NTeQpUUVzRiL4lmeRQyjPC3DpIgCVqQsqyoWsDKYZQWhswOE29vV8hyBNUdoVnND4uBo8Wjxu8UVbrkzUGQ0wCTI4hgxxGkVZHFZpmkSTtMkL4O8jGc0pUl8QHEcqSvZdrxBBdcPXSPVWBoHvGS6vOsMb7lmLrcd77DhAmHL8Sf0mosaHrLES-IhumBUL_5pnWnZIxQbJmoEuUUFhrdoQUxX5-GWZS4b40tVE3rzi9CbTVrm7Lv89fUy7K9K1oq1oGWvCjwRSILhXzF81kb1hQGZ28iteQkkXQ5vALgwwJpakmj3iKSrw_25-rHumV27w160g8Kox9-aAUIX3GD7jB0LGR9Y2zVIaGY_CbuDT83TBQoT_OZ5SOjsGEEhhTbn7hC6IDSzTk2X1OVstodywfs2X58EYIxwZStBPFkSYLAbkOkKSLQCQpMnBg5C4ZGQdcsj0bUNkv19qkHSFWCj8XQpGyP9k3XORnBhAfvy1WvsUYEH54rhs-DGW4WmV-IoBlb6rA5Pq_nCHlg56nfEaPfixU0wKsRQuM3pVUJ6JdcFU6XnmNUTrEU9vODC7WyvBu8uBK8AT47F5t2FvjxYc3RU_mSqKvu2A0-Mchfkg4fAXRG1vLf6vv62-L-17vNu2MO7qKy-rxff1o38ue4KcBeh2ah6uPZ0sFPY8HozalxQCKcHhZNr0K4Ua3GdM1szNFt9X999XSusE7hffn1WsWBNs7b_7Y3e4zWqx6cIbXxHZUIzQul-_9Jn1yixaNYuIYRmYfSsbKekkeaxw_ICjgvyVvQ4XiwFQikX5iVQ-GBQCdZccvhyYUhePlMU6XFRjC39SUkUQ-d5mmHbPS7gtGLT5VkhhJYOz566qA4AhtQHcL_4hxUdnnQcC4TgIXs5q3Y7vzqjTimMn1p1aYGz8q9cdgai3lOuJeiRmg_LXiSM2zGEdoA6DINcQ8u16-D2RSut-WFiHEc5GwkmSvdsnwizYQb4brjqFGoUBqRoHqGwjV5Dx9TekhsyL81oX-7HGfB0vr3IY24KGhpg5ZsNCps0Ei2hU1jqHQNPXZvb9zXWNLC11Udip--Xee07zrPDCRpWMsOgMwp6UWJlXT1K4xXsRQgNV1-uH6yn2sVkxxS3t3__v6WQ2s66rrzsj2HSOpQBodPAAWwkK-1yVsiuOgB2OqzhtYDsD6Bb6--A3II-h54raFiOjV2FVz6K8mQUqXzbbW0mXn29S8p4RGF02vXgF70-y0j4oRkJP7CW6DPIw38bOf2oWiJ0KnnpayWZ_XtnuNEdFn3DDPrWH39XUAcHeUSPHDzyLn6xQp-Zm77cA6sMqv9y3nkDjk5yPXD9_2jkTTTy-Yn9c5fGO7BC8H6sUPKqGmcSO_S8miWs4u5RHJA4AM9yVRgDoUt3R2F4sQP4ai75JGTi_UGxe59ljCF0-Ykq_iU2hPenw_8MH3pvH6veXCIfNFd5fzBYvRn7R01W3seMVnbXvHnPv3WrfVyPs0g-y57fhfIDGt2LfW5SzqNyFs3YBOdhkqZZMgvT2WQzZ0mFJU5TzEqasJDlMWVJkOO0mCVBXAUTPqcBjYIoiMIsTsKZH-ZpmFRBWiXFLCvykMQBtow3vousVPWEa93jPAnDZDZxsLQ716LUnVFxUckhrIRSN1ZHC-kOFn65bxW0fTldTdTcfYWU97W2aePa6MMShpsG52M7didF4xHY0eGXO-Iaj7CGU6rSHVMdDqYmvWrmbzvyIfTGeagJvXFO_isAAP__bWsA9w">