Commits

Slava Pestov committed a7a9e162986
SILGen: Open code calls of enum case constructors Sema models enum case constructors as ApplyExprs. Formerly SILGen would emit a case constructor function for each enum case, constructing the enum value in the constructor body. ApplyExprs of case constructors were lowered like any other call. This is nice and straightforward but has several downsides: 1) Case constructor functions are very repetitive and trivial, in particular for no-payload cases. They were declared @_transparent and so were inlined at call sites, but for public enums they still had to be emitted into the final object file. 2) If the enum is generic, the substituted type may be loadable even if the unsubstituted type is not, but since the case constructor is polymorphic we had to allocate stack buffers anyway, to pass the payload and result at the right abstration level. This meant that for example Optional.Some(foo) generated less-efficient SIL than the equivalent implicit conversion. 3) We were missing out on peephole optimization opportunities when the payload of an indirect case or address-only enum could be emitted directly into the destination buffer, avoiding a copy. One example would be when an enum payload is the result of calling a function that returns an address-only value indirectly. It appears we had unnecessary copies and takes even with -O. Again, optional implicit conversions special-cased this. This patch implements a new approach where a fully-formed call to a element constructor is handled via a special code path where the 'enum' or 'init_enum_data_addr' / 'inject_enum_addr' instructions are emitted directly. These always work on the substituted type, avoiding stack allocations unless needed. An additional optimization is that the ArgumentSource abstraction is used to delay evaluation of the payload argument until the indirect box or address-only payload was set up. If a element constructor is partially applied, we still emit a reference to the constant as before. It may seem like case constructor functions are at least useful for resilience, but case constructors are transparent, so making them resilient would require a new "transparent but only in this module, and don't serialize the SIL body" declaration. @inline(always) is almost what we need here, but this affect mandatory inlining, only the optimizer, so it would be a regression for non-resilient enums, or usages of resilient enums in the current module. A better approach is to construct resilient enums with a new destructiveInjectEnumTag value witness function, which is coming soon, and the general improvement from that approach is what prompted this patch.