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

    <tr>
        <th>Summary</th>
        <td>
            InstCombine drops debug value info for start of live range
        </td>
    </tr>

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

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

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

<pre>
    The `InstCombine` pass loses track of the value of variable `hc` before the
`if` conditional. It appears to be because the `urem` operation is moved
after the conditional, but it should be possible to extend the value expression
of `hc` to do that at debug time and preserve full debug coverage for the
variable

## Versions

* Clang: version 17.0.0 (https://github.com/llvm/llvm-project.git 7de0804ea3290e5e43ce38567b4056a34ccad551)
* 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/6ba9o3PE9)

## Program source

```c
#include <stddef.h>
#include <stdlib.h>
#include <string.h>

extern unsigned long branch_table_sz;
extern struct branch **branch_table;

struct branch {
  const char *name;
};

unsigned int hc_str(const char *s, size_t len);

struct branch *lookup_branch(const char *name);

struct branch *new_branch(const char *name)
{
  unsigned int hc = hc_str(name, strlen(name)) % branch_table_sz;
  struct branch *b = lookup_branch(name);

  if (b)
    exit(1);

 branch_table[hc] = b;
  return b;
}
```

## Debug info view

```
$ clang -fno-discard-value-names -fno-inline -g -O1 -c -o example-O1.o
$ llvm-dwarfdump -n hc example-O1.o
0x0000005a: DW_TAG_variable
              DW_AT_location    (0x0000005f:
 [0x000000000000003f, 0x000000000000005e): DW_OP_breg1 RDX+0, DW_OP_stack_value)
              DW_AT_name        ("hc")
 DW_AT_decl_line   (18)
              DW_AT_type        (0x000000b7 "unsigned int")
$ llvm-dwarfdump --debug-line example-O1.o
Address Line   Column File   ISA Discriminator Flags
------------------ ------ ------ ------ --- ------------- -------------
0x0000000000000000 17      0      1   0             0  is_stmt
0x000000000000000d     18 33      1   0             0  is_stmt prologue_end
0x0000000000000012 18     20      1   0             0
0x0000000000000020     18     49      1 0             0
0x000000000000002a     19     21      1   0 0  is_stmt
0x0000000000000032     21      6      1   0             0 is_stmt
0x0000000000000035     21      6      1   0 0
0x0000000000000037     18     20      1   0             0 is_stmt
0x000000000000003a     18     47      1   0 0
0x000000000000003f     24      2      1   0             0 is_stmt
0x0000000000000049     24     19      1   0 0
0x0000000000000051     25      2      1   0             0 is_stmt
0x000000000000005e     22      3      1   0             0 is_stmt
0x0000000000000068     22      3      1   0             0  is_stmt end_sequence
```

The source line after the definition of `hc` (`hc = ...`) is line 19, which is
mapped to address `0x2a`. The value location range for `hc` does not start until
`0x3f` (after the conditional).

## IR before `InstCombine`

```llvm
define dso_local ptr @new_branch(ptr noundef %name) local_unnamed_addr {
entry:
  call void @llvm.dbg.value(metadata ptr %name, "name", metadata !DIExpression())
  %call = call i64 @strlen(ptr noundef %name)
  %call1 = call i32 @hc_str(ptr noundef %name, i64 noundef %call)
  %conv = zext i32 %call1 to i64
  %0 = load i64, ptr @branch_table_sz, align 8
  %rem = urem i64 %conv, %0
  %conv2 = trunc i64 %rem to i32
  call void @llvm.dbg.value(metadata i32 %conv2, "hc", metadata !DIExpression())
  %call3 = call ptr @lookup_branch(ptr noundef %name)
  call void @llvm.dbg.value(metadata ptr %call3, "b", metadata !DIExpression())
  %tobool = icmp ne ptr %call3, null
  br i1 %tobool, label %if.then, label %if.end

if.then: ; preds = %entry
  call void @exit(i32 noundef 1)
 unreachable

if.end:                                           ; preds = %entry
  %1 = load ptr, ptr @branch_table, align 8
  %idxprom = zext i32 %conv2 to i64
  %arrayidx = getelementptr inbounds ptr, ptr %1, i64 %idxprom
  store ptr null, ptr %arrayidx, align 8
  ret ptr null
}
```

## IR after `InstCombine`

```llvm
define dso_local ptr @new_branch(ptr noundef %name) local_unnamed_addr {
entry:
  call void @llvm.dbg.value(metadata ptr %name, "name", metadata !DIExpression())
  %call = call i64 @strlen(ptr noundef nonnull dereferenceable(1) %name)
  %call1 = call i32 @hc_str(ptr noundef %name, i64 noundef %call)
  %0 = load i64, ptr @branch_table_sz, align 8
 call void @llvm.dbg.value(metadata i64 poison, "hc", metadata !DIExpression(DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_stack_value))
  %call3 = call ptr @lookup_branch(ptr noundef %name)
  call void @llvm.dbg.value(metadata ptr %call3, "b", metadata !DIExpression())
  %tobool.not = icmp eq ptr %call3, null
  br i1 %tobool.not, label %if.end, label %if.then

if.then:                                          ; preds = %entry
  call void @exit(i32 noundef 1)
  unreachable

if.end: ; preds = %entry
  %conv = zext i32 %call1 to i64
  %rem = urem i64 %conv, %0
  call void @llvm.dbg.value(metadata i64 %rem, "hc", metadata !DIExpression(DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_stack_value))
  call void @llvm.dbg.value(metadata i64 %rem, "hc", metadata !DIExpression(DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_stack_value))
  %1 = load ptr, ptr @branch_table, align 8
  %arrayidx = getelementptr inbounds ptr, ptr %1, i64 %rem
  store ptr null, ptr %arrayidx, align 8
  ret ptr null
}
```

## IR diff before and after `InstCombine`

```diff
@@ -1,26 +1,26 @@
 define dso_local ptr @new_branch(ptr noundef %name) local_unnamed_addr {
 entry:
   call void @llvm.dbg.value(metadata ptr %name, "name", metadata !DIExpression())
-  %call = call i64 @strlen(ptr noundef %name)
+ %call = call i64 @strlen(ptr noundef nonnull dereferenceable(1) %name)
 %call1 = call i32 @hc_str(ptr noundef %name, i64 noundef %call)
-  %conv = zext i32 %call1 to i64
   %0 = load i64, ptr @branch_table_sz, align 8
-  %rem = urem i64 %conv, %0
-  %conv2 = trunc i64 %rem to i32
- call void @llvm.dbg.value(metadata i32 %conv2, "hc", metadata !DIExpression())
+  call void @llvm.dbg.value(metadata i64 poison, "hc", metadata !DIExpression(DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_stack_value))
   %call3 = call ptr @lookup_branch(ptr noundef %name)
   call void @llvm.dbg.value(metadata ptr %call3, "b", metadata !DIExpression())
- %tobool = icmp ne ptr %call3, null
-  br i1 %tobool, label %if.then, label %if.end
+  %tobool.not = icmp eq ptr %call3, null
+  br i1 %tobool.not, label %if.end, label %if.then

 if.then: ; preds = %entry
   call void @exit(i32 noundef 1)
 unreachable

 if.end:                                           ; preds = %entry
+  %conv = zext i32 %call1 to i64
+  %rem = urem i64 %conv, %0
+  call void @llvm.dbg.value(metadata i64 %rem, "hc", metadata !DIExpression(DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_stack_value))
+  call void @llvm.dbg.value(metadata i64 %rem, "hc", metadata !DIExpression(DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_stack_value))
   %1 = load ptr, ptr @branch_table, align 8
-  %idxprom = zext i32 %conv2 to i64
- %arrayidx = getelementptr inbounds ptr, ptr %1, i64 %idxprom
+  %arrayidx = getelementptr inbounds ptr, ptr %1, i64 %rem
   store ptr null, ptr %arrayidx, align 8
   ret ptr null
 }
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsOltv2zjWv4Z5OZAhURfLD3lw4uZDgH7oYLaY2TeDEimbU4nUkJTr9NcvSEqWb3HiJu1iihUCRybP_Ryei2SiNV8Jxm5ReofSxQ3pzFqq27_UExH6ppD06fbzmgHKwkehzb1sCi4YykJoidZQS800GEXKLyArMGsGG1J3zH7ZEMVJUTvcdWlRClZJxSwUChconKMs5JXdKKWg3HApSD2BRwOkbRlRGoyEgkHBStJph2dpdYo1Fkm2TBGLBFxDIzeMeqqkMkw54D2yCN9D0RngBvRadjW1hFupNbcSGglsa5igexqwbauY1lwKT1ZWoyJGApVg1sQAMUBZ0a3A8IYBERQsGlMbBlVX1_1mKTdMkRWDSqpR_8FCvTX8J44RjuEPpixrfbg1h_uaiBWK57DxABBNJ-EkBITztTGtRvEc4QeEH1bcrLtiUsoG4Ye63gz_glbJv1hpJituYEpZmIcJIzGehSxlSVyyOE-zaZGEaUbipCwJTdMI4dkowsePi7tTCSw5hPMVNygJ95jH8-eYK7bhjkCZ45BlYZ4kjEUsrcI8oXQ6zaJ0mhU0LGgyw1OcJaMU-5a6l03La6bgw7atpWLq2GQovfvUGt5w7aOl5S2ruWCw4ewrdJqLFWzzLMgSb10wqhNfrDINeYJyTcSKgfWfc7EVIl2cmlvSQtZmItUK4YdvCD9kBZnJ-LcPs_Ni_6bkSpEGtOxUeRgBWej_yh0CF2XdUQYovteGUlZN1ij-8Mx2zYsL24qL1f62-7TBrwR0wuUCCrUUKygUEeV6aWyELvU3FN8dAGujutL0UICwtfU-yg7efx6BT_tNsIdUG2tmZYkI0uxhThdHVHYScmFgXS61UQjnhyS0Peuaf2NLAzUT1vwXRcHzWsovXbv0Cyf0nEgvExHs60sUeqV2qh9pAyhejEp5pHtrZ6dFPlDBM0A4fdY9cOqZwlE-1vK8XgC8srFf7AQGAGBbbhDOozPwBz5P79YlSheOX7EnkmKmU2Jvybr2MNrPnJGFy51cVNKd1bOHZEBIoHSHN6iEDCjXJVE0cJk8sIpqv8GFO_nBCoJPEQQlBDbzk6atWfApmsiRmktX9CtRFe2aFgJhHXQKGm5Dd6XEpsTFn8vP8_9bHuZ1OLgWfy7nn5e1LH0yArDG3lGpbELxWCi9G5aHK65sQByvpt6Ljvun35aFYqsIfl_8G-G70ML7ZW1I-WXpDHLg2WPJrLGGFYRzhPG6RBiPOB6MsrJeOls6sCi_SNQ8tftEBw2KKSCM90_BPqdzXghcOQ0c41NnzCm1JRs-ernuZd01Ah54bb89_msOC65LxRsuiJEKHmqy6gtscHLBc__gHFh_HcbEeEE09cqH_l803sJug-ulNo15hgb1iDnE8cs0oFWylquOLZmg5wlG2BKzF35eqPOoPUKPnswG9NchEw_tsXC0z_slI8T4ACl73hCXyaTPk3lG6ni6r_IFi73AmRxYbvoazpVnmXhY_J2cey_1ZKLZKzin3j44fRvn1J983ONfiN6LZLL8tWR2h4AJutTs746Jkl0oNna88V0YuLwyzg-UVVy4AQL2u3-bFu29q3KTycTSwzM7hTj8aGaz7tc1L9fA-_zS2ImG2rmB9DkKZWG4xQRl4QQ-74aOXV1Qruu008KOLZVMg5AGtCHKQCcMr3dqhdu46mV7Zv6ZTc5U2Mffh6HsZMA7W21dL--WnG0YUC1dMauhNQpQEh60QXZNyE5QZnuKtO84nJb1shP2O11ai4wNIRNGPY1VEEpS17CRnFrilv2EFqtJX8fyhhlCiSGe-8Dh3pYVf4vttx0UwtHi8cM42OHcN1QDM4RTx8861t3wLLF8dz3YeYWO0KM9_Bhb_F1Tdxb_3rHZW7aoR2Sl2Diq39jWeKoDLyMt-h5s2Hd7hLoNfD-45rhjxPdAar4SkO9hK9Y4fDtle_U9d2_VNDwSCjtgOzGVA7RFtELF-EofDmpZsr0T-97jehfGow967Y_b38uuvC7sHMde5OI7JDaykNKHHS-bFgQ7oSy6uh4wCgU8GvHsdk0KVtslXk3M2sbq4dquD_CfA1Q8BxTfQasY1Y49wqk_gefs0E8B1k-D5cZHA9AJxUi5Pn6g0TOPjxrDi9dlmRBOozHGW3uwzsb4-QDndNsq2ZyeJhfNJ6eJKEWeON06-BUzrGYNE8ay46KwVtAHIuA0Gk70yGyczGyqdZFn3TniDFzOiKyYGTFePzs9_t4Xsv8l9msTu5BC-Ed3ilVM2fbBh5Obf39q3v_-XP7anJsl0Equpbgi4_qJ8uPHP_5_aU8NU8YiePncwPdhOQx14wB6DB7ji-BH8-ovkeAntnvbJXn29zVJ3uKeS-rncv_5RP9O2feKivBySXgx0V_T-Ly2dbniaHiq_5Sj8csq9raK_7YSbs30XynflFfVMJ0RQa8q5xa3X0pClIQQWJVwBgjfDXduoxfzRxV9OK76P7PsB28c6BC--7GNww_pG4Lr8uabuozgirwbXDMzBj9xZrRu_nXbpffql35ewxRcPREHbxyJbQB8T5PmEN-nT4NXT-TvMJLDe8_kgwVfmXUG8NcljmvP5z-ptfmVdYM39G3BlY9qgnd-VDNE6Lu1jt_VO55pHuG0e7yhtzGdxTNyw26jbJrjPMvj9GZ9m-RpHEfJjBRxmBMaJtmsIAXOGS1ncVpMb_gtDnEcxmEeJck0SidlOJthFrEqygpchNgmmIbweuKiUqrVDde6Y7dZhLPoxuUz7X44hrF7MctFJX1MIozdI6V4zoU2Zd-tYozSxY26da91i26lbcBzbfTIwHBTs9u9Fheokq3uf0fl35K4XwRUUvVvQmQFNd8w_87kplP17XU_hUL4wamlEX5wmv0nAAD___BmPY4">