Question on SIL begin_access

Hi SIL experts,

The begin_access doc says:

The operand must be a root address derivation:
a function argument,
an alloc_stack instruction,
a project_box instruction,
a global_addr instruction,
a ref_element_addr instruction, or
another begin_access instruction.

Does it mean that begin_access cannot be used on struct_element_addr when I'm writing an element to an aggregate, and should be used on the entire struct buffer instead? If that's the case, why can the operand be a ref_element_addr?

@Andrew_Trick or @John_McCall can answer in a lot more detail than I can, but the basic idea is that class properties have individual identity and struct properties don't. This is in line with the idea of mutating methods—remember, formally a struct mutation is copy-in/copy-out (or maybe move-in/move-out some day).

On a very practical level, too, the run-time checking for exclusivity violations would be a lot more expensive if it broke structs down into their individual fields, and it would still have to treat structs as aggregates for mutating methods (and inout access in general).

2 Likes

I like @jrose's explanation. Additionally...

A begin_access certainly can operate on a struct_element_addr, but only if it's nested within the "real" formal access. That happens after inlining @inout parameters. The top-level begin_access must be reachable via a straightforward SSA use-def walk.

We must be able to identify the object being formally accessed and all accesses to shared mutable state need to be precisely identified. So, if you declare a class property with a struct type, we need to recognize that accessing a member of that struct is actually an access of that class property. The struct does not have a separate identity. It's a semantic property but also a physical property.

1 Like

Thanks everyone!