Skip to content

A subscript's shape is pinned for the dataflow analysis but not for a generator reading it as an argument #825

Description

@khatchad

A subscript's shape is pinned against the receiver leak in the dataflow analysis, but a generator that reads the subscript result as an argument queries the points-to set instead and still sees the receiver's allocation. The two disagree about the same value.

Witness

With #824's slice fix in place:

def propagate_direct(node_embeddings, adjacency):
    edge_sources = adjacency[:, 0]
    consume_direct_indices(edge_sources)                       # int32 (30,)   correct
    edge_source_states = tf.gather(node_embeddings, edge_sources)
    consume_direct(edge_source_states)                         # float32 (30, 2, 16)

edge_sources reports (30,) at the sink, which is right. One instruction later tf.gather composes ids.shape + params.shape[1:] and produces (30, 2, 16), which is (30, 2) + (16,). So the gather read the receiver's rank-2 shape for the same value the sink reports as rank 1.

Reading

PythonTensorAnalysisEngine routes subscript results through setCalls, so SetShapeOp replaces predecessor types rather than unioning them and the receiver's pre-subscript shape cannot leak in through the assignment graph. That pin governs TensorTypeAnalysis state, which is what the sink reads.

A generator resolving an argument does not read that state. It calls getShapes on the argument's value, which walks the points-to set, and the points-to set still aliases the subscript result with the receiver's allocation — that aliasing is exactly what the pin exists to neutralize, and it is untouched.

So the pin is applied at one of the two places that consume a subscript result. Any generator that reads a sliced value as an argument sees the unpinned shape.

Scope

This is not specific to tf.gather; it is a property of the pin, so every generator that resolves an argument through the points-to set is affected whenever that argument is a subscript result. tf.gather merely makes it visible, because it composes the argument's rank into its own result rather than only reading extents.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions