Skip to content

[JIT] Assertion Prop Issues and Ideas #74671

@AndyAyersMS

Description

@AndyAyersMS

Tracking issue for work and ideas about Assertion Prop.

Recent work

Not a complete list -- will fill this out over time.

Existing open issues

Not a complete list -- will fill this out over time. Also need to go back through these to see how many are no longer relevant.

Ideas

Local Assertion Prop

Extend local prop to work cross-block. If a block's successor has no other predecessors, the successor can inherit the assertion state. This extends local prop to work across join-free regions.

  • we would want to process blocks in morph in reverse postorder
  • we would need to save/restore assertion states if a block has multiple successors

I worked up a simple-minded prototype of this that just handles the case where the predecessor is BBJ_NONE and successor is join free. It revealed some annoying interaction with VN and CSE, in particular, if we have code like:

;; BB01
  = *this
...
;; BB02 (linear flow from BB01
  (big tree, say runtime lookup, with *this)
...
;; BBxx (not linear flow from BB02)
  (big tree, say runtime lookup, with *this, nominal CSE of the tree in BB02)

Then locally propping a non-null this into BB02 breaks CSE, because the two big trees now have different exception sets (this may in fact happen already if the first tree is in BB01).

Some possible remedies:

  • In general, VN doesn't deal with conditionally generated facts, though one can sometimes play games by introducing artificial definitions before building SSA (or after, if you can update SSA). For instance, in BB01 we could introduce a synthetic non-null def of this below the intial indir, then all CSE uses would see the "non null this" VN. This idea of fake defs is powerful and could possibly be leveraged for many other things. But it might be too costly for us.
  • Run AP before CSE and allow CSE to filter out overly broad exception sets when supported by assertions. I'm not really sure why we run CSE before AP anyways.
  • Don't let local prop clear exception bits, just use the null/non-null prop assertions to impact control flow.

Enhance Assertion Kill/Gen Logic

Currently in local prop, we kill assertions for unaliased locals. This includes killing promoted local asserts when a parent struct is assigned to, and killing parent struct asserts when a promoted field is assigned to. However, this is pessimistic in the common case where a field is assigned a value it already has, eg redundant zeroing of fields:

struct S {... int f; ...}

S s = new S();   // generates s == ZERROBJ
s.f = 0;         // kills s == ZEROBJ

In general, we don't do "gen" for promoted structs and their fields with the same thoroughness that we do "kill" so there is an asymmetry here. Arguably a ZEROOBJ on a promoted struct should inspire zero assertions for all its fields. But we may be better off not generating these quasi-redundant assertions and instead teach the lookup logic to understand parent/child relationships.

I have a prototype for this but will wait for #74384 to finalize first.

Flow dependent prop for address-taken locals

In many cases we may be able to prove that address-takenness is not applicable to a span of local defs and uses, eg the last "use" is the one that causes exposure (say a struct passed by ref).

category:planning
theme:assertion-prop
skill-level:expert
cost:medium
impact:medium

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions