On 2007-09-12, at 14:26, Chris Lattner wrote:
On Sep 12, 2007, at 11:14 AM, Gordon Henriksen wrote:
Hm. Are you sure this is wise? I realize my patch didn't provide
root initialization, but I have that fixed locally. Without
liveness analysis, leaving stack roots uninitialized seems unwise,
since gc points are not entirely predictable from the IR.
I think it is fine. trivially, any front-end that produced a call
to the gcroot intrinsic could emit that intrinsic and a store of
null, so there is no power lost here.
The reason it is useful is for things like this (C syntax):
void foo(object *P) {
gcroot(&P, 0);
... use P ...
}
when converted to LLVM, this turns into the equivalent of:
void foo(object *P) {
P_addr = alloca object*
store P -> P_addr
gcroot(P_addr, 0);
... use *P_addr...
}
With the null'ing property of gcroot, it would clobber the live in
value.
Well, this would also fix that:
P_addr = alloca object*
- store P -> P_addr
gcroot(P_addr, 0);
+ store P -> P_addr
But I'd be more concerned about more complex codes:
void f(object[] ar) {
g();
foreach (object o : ar)
h(o);
}
becomes
void @f({ i32, [0 x %object*] }* %ar) {
entry:
%ar_addr = alloca { i32, [0 x %object*] }*
@llvm.gcroot(%ar_addr, 0)
store %ar -> %ar_addr
%o_addr = alloca %object*
@llvm.gcroot(%o_addr, 0)
store null -> %o_addr ; ****
@g()
tmp.0 = load %ar_addr
tmp.1 = gep %tmp.0, 0, 0
index.0 = load tmp.1
loop:
...
}
Here, the FE must emit the highlighted null initializer separate from
the use, declaration, and scope of o; otherwise, a GC at a safepoint
corresponding to call @g will likely segfault the collector. Of more
concern, the FE must do so before any gc points, which are
implementation-defined. It's that last property which makes this
potentially error-prone.
But upon further musings, I'm actually convinced your new spec is
best. llvm.gcroot should be purely an annotation, with no runtime
component.
• In the case of a liveness-accurate collector:
The initializers are not necessary, so the collector is free to omit
them. The alloca has the same value as if llvm.gcroot were not present.
• In the case of a collector without liveness:
The null initializers are necessary, but the initializer should
immediately follow alloca rather than replacing call @llvm.gcroot.
Effectively, the initial value of the alloca becomes null if and only
if required by the collector. This change enables your alloca-store-
gcroot sequence to behave as desired.
Regardless of the collector, the FE should not rely on the contents
of an uninitialized alloca; it FE should emit initializers if that is
necessary for the source language. The collector should perform a
trivial DSE of the initial basic block to avoid obviously redundant
initializers; the difference is that it can do this reliably, since
it has knowledge of where safe points might occur.
I need to tweak the collector infrastructure slightly, but that's
okay; it's definitely a stronger spec if I comply with it in this
manner, since:
1. The semantics of alloca are entirely preserved by the
llvm.gcroot annotation.
2. The user program's interaction with the collector is even more
robust than before.
— Gordon
_______________________________________________
llvm-commits mailing list
llvm-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits