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

    <tr>
        <th>Summary</th>
        <td>
            inconsistent argument attributes in calls to similar library functions
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

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

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

<pre>
    This issue was prompted by a discussion in [D129224](https://reviews.llvm.org/D129224) of applying attributes to arguments of calls to known library functions.  It shows that the middle end doesn't apply such attributes entirely consistently which, at a minimum, can be confusing.  Separately, it also shows that the middle end doesn't optimize all three functions in the test case equivalently.  Compiling the following test case with `opt -O2`
```
declare i64 @atol(i8*)
declare i64 @strlen(i8*)
declare i64 @strtol(i8*, i8**, i32)

define i64 @f1(i8* %p, i8* %pd) {
  %t0 = load i8, i8* %p
  %n = call i64 @atol(i8* %p)
  %t1 = load i8, i8* %p
  %d = sub i8 %t1, %t0
  store i8 %d, i8* %pd
  ret i64 %n
}

define i64 @f2(i8* %p, i8* %pd) {
  %t0 = load i8, i8* %p
  %n = call i64 @strlen(i8* %p)
  %t1 = load i8, i8* %p
  %d = sub i8 %t1, %t0
  store i8 %d, i8* %pd
  ret i64 %n
}

define i64 @f3(i8* %p, i8* %pd) {
  %t0 = load i8, i8* %p
  %n = call i64 @strtol(i8* %p, i8** null, i32 0)
  %t1 = load i8, i8* %p
  %d = sub i8 %t1, %t0
  store i8 %d, i8* %pd
  ret i64 %n
}
```
produces the output below.  In it the attributes applied to the first argument at each call site are different even though all three functions have the same access semantics (they all read a string pointed by the first argument, up to the terminating nul), as are the attributes applied to the first argument in the declaration of `strtol` and those in `atol` and `strlen`.

```; ModuleID = 'a.ll'
source_filename = "a.ll"

; Function Attrs: mustprogress nofree nounwind readonly willreturn
declare i64 @atol(i8* nocapture) local_unnamed_addr #0

; Function Attrs: argmemonly mustprogress nofree nounwind readonly willreturn
declare i64 @strlen(i8* nocapture) local_unnamed_addr #1

; Function Attrs: mustprogress nofree nounwind willreturn
declare i64 @strtol(i8* readonly, i8** nocapture, i32) local_unnamed_addr #2

; Function Attrs: mustprogress nofree nounwind willreturn
define i64 @f1(i8* nocapture readonly %p, i8* nocapture writeonly %pd) local_unnamed_addr #2 {
  %n = tail call i64 @atol(i8* nocapture %p)
  store i8 0, i8* %pd, align 1
  ret i64 %n
}

; Function Attrs: argmemonly mustprogress nofree nounwind willreturn
define i64 @f2(i8* nocapture readonly %p, i8* nocapture writeonly %pd) local_unnamed_addr #3 {
  %n = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) %p)
  store i8 0, i8* %pd, align 1
  ret i64 %n
}

; Function Attrs: mustprogress nofree nounwind willreturn
define i64 @f3(i8* nocapture readonly %p, i8* nocapture writeonly %pd) local_unnamed_addr #2 {
  %t0 = load i8, i8* %p, align 1
  %n = tail call i64 @strtol(i8* nocapture nonnull %p, i8** null, i32 0)
  %t1 = load i8, i8* %p, align 1
  %d = sub i8 %t1, %t0
  store i8 %d, i8* %pd, align 1
  ret i64 %n
}

attributes #0 = { mustprogress nofree nounwind readonly willreturn }
attributes #1 = { argmemonly mustprogress nofree nounwind readonly willreturn }
attributes #2 = { mustprogress nofree nounwind willreturn }
attributes #3 = { argmemonly mustprogress nofree nounwind willreturn }
```
I would expect the first argument in each of the three calls to be annotated with the same attributes: `nocapture nonnull noundef dereferenceable(1)`.  In the `strlen` case `nocapture` might be implied by `argmemonly` but that's both subtle and (as far as I can see) not documented in the manual.

I would also expect all three functions to be optimized equivalently, and in particular, `f1` to the same IL as `f3` (even though `f3` might set `errno` and `f1` need not).
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzVWE1v4zYQ_TXyhVhDlmzZPviQrLFAgBY9tPcFJVE2W4pU-RE3_fV9Q9myHTuJd7MNWiBwRGk4fHwcvhmyNPXT6retdEw6FwTbccc6a9rOi5qVT4yzWroqOCeNZlKzZHa_nmTLLJsms3WSLbbedy7J75LsC_6seJRi58ZKPbZjYzd4dbDOlsw0jHedepJ6w7j3VpbBC8e8YdxuQiu0d2RTcaXi2z-02WmmZGm5fWJN0JUHCjdm7MEztzU7WG25x49graxrJZjQNauNcDrJ5r4fjblQbU_HwzjSCnyo4Ew6jzYau62stkn2GZaYdCu1bENL7YprVgoyboIDdAz_q-i45R4-yECig3LmJkSm87KVfwv0ULCyQhznRfRSR2D0GNWh759BPnIVAWLYz1gWqYg9MmuMUmYXW0OHnfRblhQphmGffsnwlKTrJL2jh_4vNmtRKW4Fk8WUJdOUe6OwlHKRZFjH5VUb5y1w3GB15gvk9A_9c54NHQ_dG6mH3s3k0JMl2awbusdWTRGUzO_7joze-ZQl-Zopw-toeGp-YqajFUXVtQnvh1qe-p3c5LeOVi6U-Nx3I9OI62DlvCFy4uf6-Xz2Nlb4HheQ7rmZr18hKfsgks5X_H9HU_5xNF1G0zHumQ5K7YOfpf9VAs_lAfpfh4qUGTJjgu-ChwJCbEh5NekdfThRVNJZiXwBzY7KJC0E6aDpJKiCQ4Ija056dAXYWjaNsPRdPAoSPhM226uyuOWPIvp1vEXfCsgcc6Ll0PHKYT4LfHyKXa0AlRx0WNLFzki9T2OXsIil0B0ge2Eh-dxTN6wYrROlAhehftNs9yLeCyOnGVBOA7f7QClSxpESMF_oNSXUopej_fvekDZekY5Pw_u4Rvk9-xkLpMTDOkYGEgsfU5DNe0tngq3E10bCCzHW22S9TXbmE66-7Hlmd5ghZXLWBucRAhtLPGvT0GpoEzRyTR0ZNprypVQKIRWsfjOnoHfFO5gK2ncKDfU1aMJWf-V1bYEuT9_GBYpb0cbBfwjEZwJ3A8jJO8l7G9Apa4d5nMvJEeUhob4A9r0rfQn2hVw9QDoyfy65R4OdxfYfLOpXwD-T5153PZfq5UR-HOZZrhrUMb1IA9jjSm40m9ycZt4Xm2-Qmv2rpOa3kXqxL4IGTPzXlMugbFZE5a4ELxXicDGJ6fTDOX8P0fmHRu-rxcUlH68uzfWIPyzODys_rqJ6byXyHUt_kncpS_TJbH7_zRmADX7PPU4Gj-9ILy85z26D-7aj_JtRXvP5rMx7YDsTVM3EX52o_Au1TKzcUMDEIikWZsPxHIdirrXxnGqsePI8FmkDetqoGPEyUg-ycl1OqPqJxSa5PK2J-nPuqUd62crNlmpUJtu-NkPJR4XVQBYZAU88naNQcqw0wItI9kr0dVe2QLXXcEtF30M89DsRSwHMEAf4KjICz_v6DtVn4OqsQjvwGS8D9qReq2d76g43AfXZKT9uER1H6bhFfRtQIMRNVlDKxSz2VWek-eEnQkufcvqEOZzW0sP7nh2HrYaWsFabk2qz96oFgGCmmPB4JFaTYrZYzPNsMh3Vq7xe5ks-8hJcraQ-3pqclvhDtAL5ECEOMwT-yyucUbBqdX51tEEAhXJcmRYNuj_a__uEEP8dVKIZb6gcHmbFfDodbVfzdFpMq-lCpEW-FPV8OZ_wKpvms2ZWNIvlcqQ4zi1ulczuUflqsesvuagKnq1HcpWlWZbOswK_xSwfLxfLWV6UZcZni6zJFxBcnDKkGq6zRnYVIZVh4_BRgYbjXdeIOwdtEyIOB_88YCHsqnWiNHYUR15F5P8AUgD6NA">