Yes, and what's wrong with that, if it's transparently done by the compiler?
In this scheme, the caller would pass non-register-sized data "by value" by actually passing a pointer to it. (Importantly, this pointer is register-sized, and so wouldn't necessarily need to be spilled to the stack—unlike caller memory copy, which is always to the stack.)
A callee that can be statically determined to never modify the value, would, under this calling convention, be compiled to code that simply works with the data "through" the pointer that's been placed in its register / on the stack.
A callee that can't be statically determined to never modify the value, would, under this calling convention, generate a memcpy from the pointer onto the stack; where the pointer then goes dead at that point (and so, if the pointer was spilled to the stack by the caller, then the memcpy could be targeted so as to overwrite the pointer on the stack.)
This would be much more efficient under most conditions. Its only inefficiency would come from the situation where the pointer being passed would necessarily be spilled to the stack; and then the callee would be statically guaranteed to make a copy. In that case, you're doing an extra push (for the pointer) that current ABIs avoid by just having the caller do an eager copy.
But this would be quite rare in practice, since this ABI (and the ABIs it replaces) are only for external symbols — the kind whose linkage is fundamentally dynamic (i.e. where the linker-loader could in theory substitute anything it likes for the external symbol with an LD_PRELOAD shim.)
Internal symbols — private static functions — get bespoke compiler-specific ABIs that skip all this enforced caller/callee predetermined role business and just codegen whatever's most efficient on a case-by-case bases, with different callsites getting different monomorphizations or partial inlinings of the callee that distribute the responsibilities differently.
And since these ABIs only matter for external linkage, you have to remember that symbols with external linkage get no "type attribute enforcement" at link-load time, and so your symbol for a function that was originally guaranteed to be a callee-that-always-writes, might be substituted at link-load time for a callee-that-never-writes. In which case, having the pointer on the callee's stack once again becomes handy, rather than useless.
> In fact, I think I’d argue that if you’re passing large structures by value
Not necessarily large structures. More often things like UUIDs—values just large-enough to not fit into a (64-bit) machine register. It's these small memory spills, done in hot loops, that add up. There are huge wins for the cleanliness of e.g. RDBMS engine code, if their various 128-bit to 512-bit column types can be passed by value without necessitating an eager copy.