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

Reply via email to