<div dir="ltr">Hello everyone,<div><br></div><div>I think I have found an gvn / alias analysis related bug, but before opening an issue on the tracker I wanted to see if I am missing something. I have the following testcase:</div><div><br></div><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><font face="monospace, monospace">define spir_kernel void @test(<2 x i32*> %in1, <2 x i32*> %in2, i32* %out) {<br></font><font face="monospace, monospace">entry:<br></font><font face="monospace, monospace">  ; Just some temporary storage<br></font><font face="monospace, monospace">  %tmp.0 = alloca i32<br></font><font face="monospace, monospace">  %tmp.1 = alloca i32<br></font><font face="monospace, monospace">  %tmp.i = insertelement <2 x i32*> undef, i32* %tmp.0, i32 0<br></font><font face="monospace, monospace">  %tmp = insertelement <2 x i32*> %tmp.i, i32* %tmp.1, i32 1<br></font><font face="monospace, monospace">  ; Read from in1 and in2<br></font><font face="monospace, monospace">  %in1.v = call <2 x i32> @llvm.masked.gather.v2i32(<2 x i32*> %in1, i32 1, <2 x i1> <i1 true, i1 true>, <2 x i32> undef) #1<br></font><font face="monospace, monospace">  %in2.v = call <2 x i32> @llvm.masked.gather.v2i32(<2 x i32*> %in2, i32 1, <2 x i1> <i1 true, i1 true>, <2 x i32> undef) #1<br></font><font face="monospace, monospace">  ; Store in1 to the allocas<br></font><font face="monospace, monospace">  call void @llvm.masked.scatter.v2i32(<2 x i32> %in1.v, <2 x i32*> %tmp, i32 1, <2 x i1> <i1 true, i1 true>);<br></font><font face="monospace, monospace">  ; Read in1 from the allocas<br></font><font face="monospace, monospace">  %tmp.v.0 = call <2 x i32> @llvm.masked.gather.v2i32(<2 x i32*> %tmp, i32 1, <2 x i1> <i1 true, i1 true>, <2 x i32> undef) #1<br></font><font face="monospace, monospace">  ; Store in2 to the allocas<br></font><font face="monospace, monospace">  call void @llvm.masked.scatter.v2i32(<2 x i32> %in2.v, <2 x i32*> %tmp, i32 1, <2 x i1> <i1 true, i1 true>);<br></font><font face="monospace, monospace">  ; Read in2 from the allocas<br></font><font face="monospace, monospace">  %tmp.v.1 = call <2 x i32> @llvm.masked.gather.v2i32(<2 x i32*> %tmp, i32 1, <2 x i1> <i1 true, i1 true>, <2 x i32> undef) #1<br></font><font face="monospace, monospace">  ; Store in2 to out for good measure<br></font><font face="monospace, monospace">  %tmp.v.1.0 = extractelement <2 x i32> %tmp.v.1, i32 0<br></font><font face="monospace, monospace">  %tmp.v.1.1 = extractelement <2 x i32> %tmp.v.1, i32 1<br></font><font face="monospace, monospace">  store i32 %tmp.v.1.0, i32* %out<br></font><font face="monospace, monospace">  %out.1 = getelementptr i32, i32* %out, i32 1<br></font><font face="monospace, monospace">  store i32 %tmp.v.1.1, i32* %out.1<br></font><font face="monospace, monospace">  ret void<br></font><font face="monospace, monospace">}</font></blockquote></div><div><font face="monospace, monospace"><br></font></div><div><font face="arial, helvetica, sans-serif">It uses a masked scatter operation to store a value to the two allocas and then uses a masked gather operation to read that same value. This is done twice in a row, with two different values. If I run this code through the GVN pass, the second gather (</font><font face="monospace, monospace">%tmp.v.1</font><font face="arial, helvetica, sans-serif">) will be deemed to be the same as the first gather (</font><font face="monospace, monospace">%tmp.v.0</font><font face="arial, helvetica, sans-serif">) and it will be removed. After some debugging, I realized that this is happening because the Memory Dependence Analysis returns </font><font face="monospace, monospace">%tmp.v.0</font><font face="arial, helvetica, sans-serif"> as the Def dependency for </font><font face="monospace, monospace">%tmp.v.1, </font><font face="arial, helvetica, sans-serif">even though the scatter call in between changes the value stored at </font><font face="monospace, monospace">%tmp. </font><font face="arial, helvetica, sans-serif">This, in turn, is happening because the alias analysis is returning NoModRef for the </font><font face="monospace, monospace">%tmp.v.1</font><font face="arial, helvetica, sans-serif"> and second scatter callsites. T</font><span style="font-family:arial,helvetica,sans-serif">he resulting IR produces the wrong result:</span></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><font face="monospace, monospace">define spir_kernel void @test(<2 x i32*> %in1, <2 x i32*> %in2, i32* %out) {<br></font><font face="monospace, monospace">entry:<br></font><font face="monospace, monospace">  %tmp.0 = alloca i32<br></font><font face="monospace, monospace">  %tmp.1 = alloca i32<br></font><font face="monospace, monospace">  %tmp.i = insertelement <2 x i32*> undef, i32* %tmp.0, i32 0<br></font><font face="monospace, monospace">  %tmp = insertelement <2 x i32*> %tmp.i, i32* %tmp.1, i32 1<br></font><font face="monospace, monospace">  %in1.v = call <2 x i32> @llvm.masked.gather.v2i32(<2 x i32*> %in1, i32 1, <2 x i1> <i1 true, i1 true>, <2 x i32> undef) #1<br></font><font face="monospace, monospace">  %in2.v = call <2 x i32> @llvm.masked.gather.v2i32(<2 x i32*> %in2, i32 1, <2 x i1> <i1 true, i1 true>, <2 x i32> undef) #1<br></font><font face="monospace, monospace">  call void @llvm.masked.scatter.v2i32(<2 x i32> %in1.v, <2 x i32*> %tmp, i32 1, <2 x i1> <i1 true, i1 true>)<br></font><font face="monospace, monospace">  %tmp.v.0 = call <2 x i32> @llvm.masked.gather.v2i32(<2 x i32*> %tmp, i32 1, <2 x i1> <i1 true, i1 true>, <2 x i32> undef) #1<br></font><font face="monospace, monospace">  call void @llvm.masked.scatter.v2i32(<2 x i32> %in2.v, <2 x i32*> %tmp, i32 1, <2 x i1> <i1 true, i1 true>)<br></font><font face="monospace, monospace">  ; The call to masked.gather is gone and now we are using the old value (%tmp.v.0)<br></font><font face="monospace, monospace">  %tmp.v.1.0 = extractelement <2 x i32> %tmp.v.0, i32 0<br></font><font face="monospace, monospace">  %tmp.v.1.1 = extractelement <2 x i32> %tmp.v.0, i32 1<br></font><font face="monospace, monospace">  store i32 %tmp.v.1.0, i32* %out<br></font><font face="monospace, monospace">  %out.1 = getelementptr i32, i32* %out, i32 1<br></font><font face="monospace, monospace">  store i32 %tmp.v.1.1, i32* %out.1<br></font><font face="monospace, monospace">  ret void<br></font><font face="monospace, monospace">}</font></blockquote><div> </div><div style="font-family:arial,helvetica,sans-serif"><div style="font-family:arial,sans-serif"><span style="font-family:arial,helvetica,sans-serif">The old value read from </span><font face="monospace, monospace">%tmp</font><font face="arial, helvetica, sans-serif"> is used, instead of the new one. </font><span style="font-family:arial,helvetica,sans-serif">I tested this code using `opt -gvn`, with LLVM 3.8.1. I also tried tip (84cb7f4) with the same result.</span></div></div></div><div><br></div><div><font face="arial, helvetica, sans-serif">I should mention that if I replace the second scatter with stores, the issue persists. The only way to avoid it is to replace all scatter/gather intrinsics with equivalent sets of store/load, in which case the MemDep returns the correct dependencies and the GVN pass will not remove the second set of loads.</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">So, my question is, is this a bug or am I doing something that I shouldn't be in the IR? And if it is a bug, is it the AA analyses that return the wrong result (I presume so) or should GVN handle such cases differently?</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">Best regards,</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">Chris</font></div></div>