By-value aggregate return in a DSL: spill/GEP/load, or support with ExtractValue?

Hi there,

I’m working on a DSL that allows the return of structs and arrays by value. Since by-value returns are in “registers”, subsequent extraction operations could use ExtractValue (as compared to stack/heap variables, which are all pointers and use GEP). Currently, I just spill them to the stack and then use GEP, but I could detect some common patterns and use ExtractValue instead of Spill/GEP/Load. Is this worth it? Would this actually leave small objects in registers? Do any languages actually do this, or do they all pass pointer-to-outparam? Or if I did just use Spill/GEP/Load, would mem2reg (or some other clever optimization pass) just put small objects back into registers and use ExtractValue for me where possible?

(Note that this is all in-language, not related to ABI limitations. I do have one special case that uses the “C” ABI, and for that one case I am already passing a pointer-to-outparam.)

Thanks in advance!