[llvm-dev] RFC: Add guard intrinsics to LLVM

Andrew Trick via llvm-dev llvm-dev at lists.llvm.org
Mon Feb 22 23:05:20 PST 2016


> On Feb 22, 2016, at 10:26 PM, Sanjoy Das <sanjoy at playingwithpointers.com> wrote:
> 
> Assuming everyone is on the same page, here's a rough high level agenda:
> 
> 
> # step A: Introduce an `interposable` function attribute
> 
> We can bike shed on the name and the exact specification, but the
> general idea is that you cannot do IPA / IPO over callsites calling
> `interposable` functions without inlining them.  This attribute will
> (usually) have to be used on function bodies that can deoptimize (e.g. has a
> side exit / guard it in); but also has more general use cases.

+1

> # step B: Introduce a `side_exit` intrinsic
> 
> Specify an `@llvm.experimental.side_exit` intrinsic, polymorphic on the
> return type:

I didn’t know intrinsics could be polymorphic on the return type.

> - Consumes a "deopt" continuation, and replaces the current physical
>   stack frame with one or more interpreter frames (implementation
>   provided by the runtime).
> - Calls to this intrinsic must be `musttail` (verifier will check this)
> - We'll have some minor logic in the inliner such that when inlining @f into @g
>   in
> 
>     define i32 @f() {
>       if (X) return side_exit() [ "deopt"(X) ];
>       return i32 20;
>     }
> 
>     define i64 @g() {
>       if (Y) {
>         r = f() [ "deopt"(Y) ];
>         print(r);
>     }
> 
>   We get
> 
>     define i64 @g() {
>       if (Y) {
>         if (X) return side_exit() [ "deopt"(Y, X) ];
>         print(20);
>       }
>     }
> 
>   and not
> 
>     define i64 @g() {
>       if (Y) {
>         r = X ? (side_exit() [ "deopt"(Y, X) ]) : 20;
>         print(r);
>     }

I understand why you’re doing this: explicitly model the resume-at-return path. But…

- It’s a bit awkward vs. side_exit(); unreachable, as evidenced by inlining.

- It would be nice to be able to model frequent OSR points as branch-to-unreachable because it may lead to better optimization, codegen, and compile time. I don’t think those are really fundamental problems though aside from adding a large number of return block users, but it may be work to find all of the small performance issues.

- Do you think this will make sense for all return argument conventions, including sret?

(I actually think this is a great approach, I’m just playing Devil’s advocate here.)

> # step C: Introduce a `guard_on` intrinsic
> 
> Will be based around what was discussed / is going to be discussed on
> this thread.
> 
> 
> (I think Philip was right in suggesting to split out a "step B" that
> only introduces a `side_exit` intrinsic.  We *will* have to specify
> them, since we'd like to optimize some after we've lowered guards into
> explicit control flow, and for that we need a specification of side
> exits.)

+1

-Andy

> 
> 
> # aside: non-managed languages and guards
> 
> Chandler raised some points on IRC around making `guard_on` (and
> possibly `side_exit`?) more generally applicable to unmanaged
> languages; so we'd want to be careful to specify these in a way that
> allows for implementations in an unmanaged environments (by function
> cloning, for instance).
> 
> -- Sanjoy



More information about the llvm-dev mailing list