<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">