[llvm-dev] Intrinsics InstrReadMem memory properties

Son Tuan VU via llvm-dev llvm-dev at lists.llvm.org
Thu Jul 25 01:53:08 PDT 2019


So I removed the 'tail' from the call and try out different properties:
- IntrNoMem: memset() and the intrinsic are both optimized away as expected
- IntrWriteMem: memset() optimized away by DSE but the intrinsic isn't. I
would expect both to be removed, since the intrinsic is now also a dead
store.
- IntrReadMem: memset() and the intrinsic are both optimized away
*unexpectedly* (CSE removes the intrinsic, then InstCombine removes
memset). The latter is understandable, but why the intrinsic gets optimized
in the first place?
- IntrArgMemOnly: none gets optimized away as expected
- ReadOnly<0>: none gets optimized away as expected
- ReadNone<0> / WriteOnly<0>: none gets optimized *unexpectedly*

Am I missing something here or there are indeed bugs here? Btw, can you
tell me how and why 'tail' changes the optimizer behavior?

Thanks a lot for your explanation!

Son Tuan Vu


On Thu, Jul 25, 2019 at 12:57 AM Doerfert, Johannes <jdoerfert at anl.gov>
wrote:

> Does the behavior change if you remove the tail from the call to your
> intrinsic?
>
> I can later look in more detail.
>
> Get Outlook for Android <https://aka.ms/ghei36>
>
> ------------------------------
> *From:* Son Tuan VU <sontuan.vu119 at gmail.com>
> *Sent:* Wednesday, July 24, 2019 6:51:10 PM
> *To:* Doerfert, Johannes
> *Cc:* llvm-dev
> *Subject:* Re: [llvm-dev] Intrinsics InstrReadMem memory properties
>
> Ok, now I think I've found a bug:
>
> Consider this C code:
> void bar(int b) {
>   int a[10];
>   memset(a, b, 10);
> }
>
> which generates this IR code:
> define dso_local void @bar(i32 %b) #0 {
> entry:
>   %b.addr = alloca i32, align 4
>   %a = alloca [10 x i32], align 16
>   store i32 %b, i32* %b.addr, align 4
>   %arraydecay = getelementptr inbounds [10 x i32], [10 x i32]* %a, i64 0,
> i64 0
>   %0 = bitcast i32* %arraydecay to i8*
>   %1 = load i32, i32* %b.addr, align 4
>   %2 = trunc i32 %1 to i8
>   call void @llvm.memset.p0i8.i64(i8* align 16 %0, i8 %2, i64 10, i1
> false)
>   ret void
> }
>
> Now I have a pass that inserts an intrinsic with IntrReadMem into the IR:
> define dso_local void @bar(i32 %b) #0 {
> entry:
>   %b.addr = alloca i32, align 4
>   %a = alloca [10 x i32], align 16
>   store i32 %b, i32* %b.addr, align 4
>   %arraydecay = getelementptr inbounds [10 x i32], [10 x i32]* %a, i64 0,
> i64 0
>   %0 = bitcast i32* %arraydecay to i8*
>   %1 = load i32, i32* %b.addr, align 4
>   %2 = trunc i32 %1 to i8
>   call void @llvm.memset.p0i8.i64(i8* align 16 %0, i8 %2, i64 10, i1 false)
> *  tail call void @mem_read_test(i8* %0)*
>   ret void
> }
>
> ; Function Attrs: nounwind readonly
> declare void @mem_read_test(i8*) #2
>
> However, the call to memset() still got optimized away by DSE. What am I
> missing here? Or this is indeed a bug in DSE?
>
> Son Tuan Vu
>
>
> On Wed, Jul 24, 2019 at 6:47 PM Doerfert, Johannes <jdoerfert at anl.gov>
> wrote:
>
>> You are on the right track. Addresses could get exposed in various ways,
>> a probably non-exclusive list is:
>>  - passed as arguments
>>  - communicated through a global
>>  - via I/O, or more general, system calls. This includes all forms of
>>    synchronization, e.g., inter-lane communication.
>>  - transitively passed by any of the means above, e.g., the address of a
>>    pointer to the object could be exposed.
>>
>> So if we take the example below and add:
>>   bar(&A[50]);
>> just before the call to unknown, we have to assume A is known to unknown
>> now, at least if we do not have information about bar that would suggest
>> otherwise.
>>
>>
>> On 07/24, Son Tuan VU wrote:
>> > Hi Johannes,
>> >
>> > Thanks for your reply. I now see more clearly how things work with these
>> > properties. However, what would be an object whose address is
>> potentially
>> > known by a callee? I suppose the intrinsic arguments and global
>> variable?
>> >
>> > So IIUC, if not restricted by *only properties, an intrinsic could
>> access
>> > to:
>> > - only its arguments if IntrArgMemOnly specified,
>> > - its arguments and the global variable as well if Intr*Mem (other than
>> > IntrNoMem) specified.
>> >
>> > Please tell me if I'm correct or not!
>> >
>> > Thanks again,
>> >
>> >
>> >
>> > On Wed, Jul 24, 2019, 17:27 Doerfert, Johannes <jdoerfert at anl.gov>
>> wrote:
>> >
>> > > Hi Son Tuan Vu,
>> > >
>> > > if not restricted by *writeonly*, *readonly*, or *readnone*
>> (basically), a
>> > > call can access any object for which the
>> > > callee could potentially know the address. That means, if the address
>> of
>> > > an object cannot be known to the callee,
>> > > it cannot access that object. An example is given below. Thus, a dead
>> > > store can be eliminated if the memory cannot
>> > > be read by any subsequent operation. If you think there is a bug,
>> could
>> > > you provide a reproducer?
>> > >
>> > > Example:
>> > >
>> > > void unknown();
>> > > void foo() {
>> > >    int *A = malloc(100 * sizeof(A[0]));
>> > >    int B[100];
>> > >   for (int i = 0; i < 100; i++)
>> > >     A[i] = B[i] = i;
>> > >
>> > >   // The addresses/objects A and B are not known to the unknown
>> function
>> > > and the stores above can be removed.
>> > >   unknown();
>> > >
>> > >   free(A);
>> > > }
>> > >
>> > > I hope this helps,
>> > >   Johannes
>> > >
>> > >
>> > > ________________________________________
>> > > From: llvm-dev <llvm-dev-bounces at lists.llvm.org> on behalf of Son
>> Tuan VU
>> > > via llvm-dev <llvm-dev at lists.llvm.org>
>> > > Sent: Wednesday, July 24, 2019 08:20
>> > > To: llvm-devmemory
>> > > Subject: [llvm-dev] Intrinsics InstrReadMem memory properties
>> > >
>> > > Hello,
>> > >
>> > > According to include/llvm/IR/Intrinsics.td, InstrReadMem property
>> > > indicates that the intrinsic only reads from and does not write to
>> memory.
>> > >
>> > > Does this mean that it can read anywhere in the memory? Because we
>> already
>> > > have 'InstrArgMemOnly' for intrinsics which only access memory that
>> its
>> > > argument(s) point(s) to.
>> > >
>> > > If 'InstrReadMem' really means read from anywhere in the memory, this
>> > > should imply that,  if there's an intrinsic having this property
>> *after* a
>> > > dead store, the latter should not be eliminated by optimizations?
>> > >
>> > > This is not the current behavior of LLVM though, so it seems that my
>> > > guesses are wrong... But at least, can someone show me the mistake
>> here?
>> > >
>> > > Thanks for your time,
>> > >
>> > > Son Tuan Vu
>> > >
>>
>> --
>>
>> Johannes Doerfert
>> Researcher
>>
>> Argonne National Laboratory
>> Lemont, IL 60439, USA
>>
>> jdoerfert at anl.gov
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190725/599e5e12/attachment-0001.html>


More information about the llvm-dev mailing list