So I understand now that calls to llvm.gcroot have to be in the first block. (Might be a good idea to mention this in the GC docs).
For each local variable that is created, there are 5 possible steps.
- Allocate the storage for the variable using alloca().
- Declare the variable as a root via llvm.gcroot.
- Initialize the variable to zero.
- Declare the DWARF debugging info for the variable via llvm.dbg.declare.
- Evaluate the initializer expression for the variable and store it to the variable.
(It might seem that step 3 is redundant, but what if step 5 triggers a garbage collection cycle? We need to insure that the alloca doesn’t contain stack junk if this happens, so we need to zero-initialize all roots before any initializers are run. I’m hoping that the optimizer will eliminate the redundant store if the initializer expression turns out to be trivial.)
My question is this: Is there any constraint on the order of steps 2, 3 and 4? And does step 4 also have to go in the first block?
Another related question: What effect does llvm.gcroot have on optimizations? For example, I assume a variable that has been declared as a root can’t be converted to a register variable. Are there any other impacts I should know about?