[llvm-dev] Intrinsics InstrReadMem memory properties

Doerfert, Johannes via llvm-dev llvm-dev at lists.llvm.org
Wed Jul 24 15:57:40 PDT 2019


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<mailto: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<mailto: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<mailto:llvm-dev-bounces at lists.llvm.org>> on behalf of Son Tuan VU
> > via llvm-dev <llvm-dev at lists.llvm.org<mailto: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<mailto:jdoerfert at anl.gov>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190724/ee77ee48/attachment.html>


More information about the llvm-dev mailing list