[llvm-dev] sret read after unwind

Philip Reames via llvm-dev
2021-12-06T21:51:46Z

I think this is an interesting problem.

I'd probably lean towards the use of a separate attribute, but not
strongly so.

The example which makes me prefer the separate attribute would be a
function with an out-param.  It's very unlikely that an out-param will
be read on the exception path.  Being able to perform DSE for such out
params seems quite interesting.

However, I'll note that the same problem can be framed as an escape
problem.  That is, we have an annotation not that a value is dead on the
exception path, but that it hasn't been captured on entry to the
routine.  Then, we can apply local reasoning to show that the first
store can't be visible to may_unwind, and eliminate it.

I'd want to give the escape framing more thought as that seems
potentially more general.  Does knowing that an argument does not point
to escaped memory on entry help on all of your motivating examples?

Philip

On 12/4/21 2:39 AM, Nikita Popov via llvm-dev wrote:
> Hi,
>
> Consider the following IR:
>
> declare void @may_unwind()
> define void @test(i32* noalias sret(i32) %out) {
>     store i32 0, i32* %out
>     call void @may_unwind()
>     store i32 1, i32* %out
>     ret void
> }
>
> Currently, we can't remove the first store as dead, because the
> @may_unwind() call may unwind, and the caller might read %out at that
> point, making the first store visible.
>
> Similarly, it prevents call slot optimization in the following
> example, because the call may unwind and make an early write to the
> sret argument visible:
>
> declare void @may_unwind(i32*)
> declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i1)
> define void @test(i32* noalias sret(i32) %arg) {
>     %tmp = alloca i32
>     call void @may_unwind(i32* nocapture %tmp)
>     %tmp.8 = bitcast i32* %tmp to i8*
>     %arg.8 = bitcast i32* %arg to i8*
>     call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %arg.8, i8* align
> 4 %tmp.8, i64 4, i1 false)
>     ret void
> }
>
> I would like to address this in some form. The easiest way would be to
> change LangRef to specify that sret arguments cannot be read on unwind
> paths. I think that matches how sret arguments are generally used.
>
> Alternatively, this could be handled using a separate attribute that
> can be applied to any argument, something along the lines of "i32*
> nounwindread sret(i32) %arg". The benefit would be that this is
> decoupled from sret ABI semantics and could potentially be inferred
> (e.g. if the function is only ever used with call and not invoke, this
> should be a given).
>
> Any thoughts on this? Is this a problem worth solving, and if yes,
> would a new attribute be preferred over restricting sret semantics?
>
> Regards,
> Nikita
>
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20211206/84a0620b/attachment.html>