<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/123349>123349</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
Failing to derive NoAlias for non-aliasing stores in a loop
</td>
</tr>
<tr>
<th>Labels</th>
<td>
llvm:optimizations
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
bjope
</td>
</tr>
</table>
<pre>
Consider this IR:
```
define dso_local void @bar(ptr noalias nocapture noundef %p, i16 noundef %nr) {
entry:
%cmp45 = icmp sgt i16 %nr, 0
tail call void @llvm.assume(i1 %cmp45)
br label %for.body
for.body:
%a = phi i16 [ 0, %entry ], [ %add, %for.body ]
%mul = mul nsw nuw i16 %a, %nr
%gep = getelementptr inbounds i32, ptr %p, i16 %mul
; mul2 = (a + 1) * nr
%or = or disjoint i16 %a, 1
%mul2 = mul nsw nuw i16 %or, %nr
%gep2 = getelementptr inbounds i32, ptr %p, i16 %mul2
store i32 7, ptr %gep
store i32 9, ptr %gep2
%add = add nuw nsw i16 %a, 4
%cmp = icmp samesign ult i16 %a, 60
br i1 %cmp, label %for.body, label %for.cond.cleanup
for.cond.cleanup:
ret void
}
```
If running `opt -passes='aa-eval' -print-all-alias-modref-info` we see that %gep and %gep2 id detected as "MayAlias".
(This also happens if replacing the "or disjoint" by "add nsw nuw".)
I did try to manually rewrite the IR a bit. Given that a>=0 and nr>0 I think we can rewrite
```
; mul2 = (a + 1) * nr
%or = or disjoint i16 %a, 1
%mul2 = mul nsw nuw i16 %or, %nr
```
as
```
; mul2 = (a * nr) + nr
%mul = mul nsw nuw i16 %a, %nr
%mul2 = add nsw nuw i16 %mul, %nr
```
And then it looks like we would derive "NoAlias" when the IR looks like this instead:
```
define dso_local void @foo(ptr noalias nocapture noundef %p, i16 noundef %nr) {
entry:
%cmp45 = icmp sgt i16 %nr, 0
tail call void @llvm.assume(i1 %cmp45)
br label %for.body
for.body:
%a = phi i16 [ 0, %entry ], [ %add, %for.body ]
%mul = mul nsw nuw i16 %a, %nr
%gep = getelementptr inbounds i32, ptr %p, i16 %mul
; mul2 = (a * nr) + nr
%mul2 = add nsw nuw i16 %mul, %nr
%gep2 = getelementptr inbounds i32, ptr %p, i16 %mul2
store i32 7, ptr %gep
store i32 9, ptr %gep2
%add = add nuw nsw i16 %a, 4
%cmp = icmp samesign ult i16 %a, 60
br i1 %cmp, label %for.body, label %for.cond.cleanup
for.cond.cleanup:
ret void
}
```
So there seems to be a bit of inconsistency in the analysis, making it sensitive to what the IR looks like.
Here is a C level reproducer:
```
void large(int *p, int nr) {
__builtin_assume(nr > 0);
#pragma clang loop unroll(disable)
for (int a = 0; a < 64; a+=2) {
p[a * nr] = 7;
p[(a + 1) * nr] = 9;
}
}
```
Compiled with `-emit-llvm -O3 -g0` we get IR similar to @bar above:
```
define dso_local void @csource(ptr nocapture noundef writeonly %p, i32 noundef %nr) local_unnamed_addr #0 {
entry:
%cmp = icmp sgt i32 %nr, 0
tail call void @llvm.assume(i1 %cmp)
%0 = zext nneg i32 %nr to i64
br label %for.body
for.cond.cleanup:
ret void
for.body:
%indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
%1 = mul nuw nsw i64 %indvars.iv, %0
%arrayidx = getelementptr inbounds nuw i32, ptr %p, i64 %1
store i32 7, ptr %arrayidx, align 4
%2 = or disjoint i64 %indvars.iv, 1
%3 = mul nuw nsw i64 %2, %0
%arrayidx4 = getelementptr inbounds nuw i32, ptr %p, i64 %3
store i32 9, ptr %arrayidx4, align 4
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 2
%cmp1 = icmp samesign ult i64 %indvars.iv, 62
br i1 %cmp1, label %for.body, label %for.cond.cleanup
}
declare void @llvm.assume(i1 noundef) #1
attributes #0 = { nofree norecurse nosync nounwind memory(argmem: write, inaccessiblemem: write) uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
```
Which according to aa-eval is identified as:
```
Function: csource: 2 pointers, 1 call sites
MayAlias: i32* %arrayidx, i32* %arrayidx4
```
Given that it is possible to derive NoAlias for `@foo` above then I think it should be possible for `@bar` as well. And if that is solved I guess we would be able to see that the stores in the `@csource` test case as well.
It is at least a bit unfortunate that the C code is lowered into IR that doesn't satisfy alias analysis in the sense that we can derive that the stores are safe to reorder (or execute in parallel). Btw, if unrolling the loop we do get 64 pointers that has NoAlias, so there isn't even aliasing between iterations.
PS. Context for this problem is that I've been analysing downstream regressions after https://github.com/llvm/llvm-project/pull/119365 . This might be one part of the puzzle, but real problem seem to be that we drop knowledge about "nsw" after LoopStrenghtReduce. I suspect that if we can't derive NoAlias before loop-reduce, then it is even harder for loop-reduce/scev-expander to reason about "nsw" when generating reassociations.
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzsWNtu4zjSfhrmpiBDony88IWdTP4_wJ4ws8BeBpRYkjmhSIGk7LifflHUwU6cZLobCywWu40GzJDFYh2_qpLwXtUGccsWe7Z4uBNdOFi3LX63Ld4VVp6399Z4JdFBOCgPT7-yfMfS-H-ZDv_TncRKGQTp7bO2pdBwtEoCm6eFcIyv2-DAWKGV8GBsKdrQOQRjOyOxAsYXLeP3oLLl9Z5xjG-ArfYs3aEJ7ty_DHRWNu18ASx_AFU2Lfg6xNvDrXtII2EQSkMp9EUcrY_NTHjfNcj4WmUTL8Y38UrhQIsCNR1U1s3IBL26018XKUSUoD2o_vHFHlJ6nPFFlBfY4iH-vdhHaimH05FVJBh4NZ2O3OjX-BOY7jSqJIZrxo3ENbaRuMaAGhs0gSysTEHW86ByTldo79q2_Ss9j3xPL_HIhfG1AMb3kEWD8x1cXrIuklgHUvnfrTLhjVTZlfj8M_mt-0gB_tMa8MjFB-uQCGF1RVpjS6eXw83bQz75TsooAP2SrCTztWbzq1C7CjTRICUMdPqtIZbpGD5TUNH2bSy93yytkbNSozBdewm0N7tDwDkMMY6JavXwLgFZunuqwHXGKFMDW6a2DZC0wnv0LH9gfCVEgkehGV9B0jplQiK0TmJOJo2VDqtEmcqyZQonBI8I4SDCGG3CyMlvSoLEgGVACcID4_zP4rwjRozzGQnD138nsBDaWziItkXjQVXgsNWiJAHDAeneVVgxzqE402b0SB9BkV_MzEFFkEoCpVaw0AjTCa3P4PDkVMDI9OlXEFCoMIP_U0c0vQ6C5b-w_CGNWhjH8l9SeCI8My-kaynMyOOdVf-tiXItiPDfJVkUKIq2vxLth6BlYnnlhmv0-ERAlu52RpILDKgA2toXD1q9IBn4ZDtNMePUMbr9L3aMFjgdopOi464uxVqjjA8o5FBwvqfaVNb-r9r8Z1SbT0P1e6PvX1RHviwj_5V15DdLCeliDWg8IW2BPaiCrUCZkhpCH9CUZ1B98goj9NkrT1I14oUQXgXwaLwKlPPBwomA-CbRZxO0_z-9SDUD7kHjETVVC2dlV6K7RYCYYVq4OiaWoTK1671rAlynMgDA83PRKR2UeZ5y0RBa_0IJtGH5SMd43jpRNwJKLUxNYrbQGWe1ZnwtlReFxjF1ASqC_P71PjVTinNa3sNyHteM71n-wN-KQ_9atthPWbB4iNdXF0lGkg8LzkB-LXjvxo-ceW-bVmmUcFLhQH1Bgo0KCSETJH_NIanToeLXGMg3XjVKC0cu69t3EIU94g-AcOlt50qcgPg9AMdCa40-X1Iy57dQHJk-d8aIBuWzkJKsnaefQ_Q7gM75TwP06GPGF2nk-g1fAxiD9YUtGUgt598B43-Ugx-CvTLyKJyfqeMF9ZfzP0T9y7WZwdfwRQXILvg_ohbxv2Yx3E4nqHNOnJV8_QpwI15_ALo97-yLzn3kTltCEzZO0MlvW6uPZJ16rPwz3fhnKs1_Xqf8i0IxsX-n1K2nbmvIRxryq3DPPqsmH11c8puykv1cXelBhtK_1MLh56k0JHQPXHnW3xIhOFV0Af2QzNQQrPZgbOWQIMJh2TlPK382ZWRyUkZCg411Z8JDVzfYsHzX40iP-aIs0XtVkPOuzzbQnQKhNnWdjTKJxlro5IhlsC45KRkOjPM4H_GU2lHGubFJcKJtlamTRlwRBNfhQOODKF-S1tnQcyq6qkKXePUNJ_L1QBuoSoWkbLvp6HW9TJbzt-cVCkJJPxExvi8bS96j1eu6X1Sv3vWrpnntF97jtOD96nW9Grl3Bt-8XaNBp8p4HH351iXZ5JKm86F1tnbo-zZa60KULxdXvXXQSWntMHTOXHz1lWM-rFb_OKjyAKIsrZNxTLQwjK3UGiiJJqhKxbHztiA9dqYMyhp6ZqxB-Q44tAQZ6GJ3kvUFwKuAPqbENLoSv01M8917OLrdnd_KfjVvqkDitrbXnLQYZp9h8Olbh2U6TCzLtK-x_fQ0DqbUQB3i4FTghdflZiFcvOnhhFrPgMYvVQ0CePBWH1HCE9QdOXCawqiXG4SaZnxqyyKA-bGh658YrbhMIaAPUAqP04PDRB4fEwE0Ch-GNrEzlXWhMyJcPXAPpZWxxdP2hA4l9WqWWo5IIi16w_gqgBdB-eoM_QA3tpajZNRUDlyH0X2w7XtNCJy8qKKmDq2TGNs16wBfsewCEsdWOKE1asY3M9iHU_R2NTR944eK2AeeEKSNTdJyPkVU_-hBeJhG2nvwY_-sBoWQAiNqQxwLDCeMUzI6QfHqB1P-7bcZ3FsTqBqQm-MM3DpLyUNmi289Mb46IhTEYTCNqUHak_HBoWjAYcxY4guiCujgEEIbw5s_Mv5Yq3DoillpG8YfCbSHH0Kz37EMjD-2HTW8j1m2yZcLmEH8ltOo-hAoeqxBMlscBsg6bfftm444XHQBHAo9CU0DxDA_jA6TzrbwYuxJo6wpFG0XIur6E0FSL_GfrG1_Cw5NfQi_Io0AM3gC3_kWyzBEeDW4P1r4XXoVWFE1Jr8lLt4n8cZvE8r3HjmIGBNk6jeUj77EY4KvrTDxszeFj_DW3Agbv11EPBWBvEBk3pZq8Oqd3OZyk2_EHW6zVb7K-Hy13NwdtmK9nPMiX2wWqw2fy_larlerjHNRrFZymaV3astTvkizbJXN8w3fzDJc4XqV5Zs0F5s5Ipun2AilZ7HqWlffKe873GY8z-ebu1jAffykz3n0cb6zbVCN-tbLRtVg8XDnttHzRVd7quDKB3_hGFTQuH0USg9I_AGGGWuSKbAvCCKiQe86p7c_HHxREU_h1-ty3PJ_BgAA__8WWYBT">