Skip to content

Commit

Permalink
Megapatch: Fix allocation sinking.
Browse files Browse the repository at this point in the history
Finding cycles in heap nodes now seems to work correctly.  Nodes that
are updated should also be handled better.  This work required a
number of changes and refactorings, including:

  * We now emit PHI nodes for every unrolled instruction that is not
    completely loop invariant.  Before, we didn't emit a PHI node for an
    instruction `i` if the `rename[i]` did occur before the LOOP marker.
    That was plain wrong.  As a counter example see tests
    Bc/Jit000[1-3].hs

  * This leads to many PHI nodes being emitted initially, but DCE
    removes most of them.

  * PHI nodes are now also properly treated as parallel assignments
    in the IR interpreter.  The codegen still needs updating.

  * When looking for cycles in heap nodes we now treat PHIs as separate
    nodes and don't try looking through them.  This is needed because
    the second argument of a PHI node may be another PHI node.  We can
    actually have full loops.

  * When a PHI node is updated, do not try to sink any of the nodes
    reachable from that PHI node.  We're basically performing a write
    into values from a previous loop iteration, so we probably can't
    optimise that any better.

  * All tests but one are passing.  The failing one,
    Bench/SumSquare1.hs, is failing due to GC occurring in the middle of
    the IR interpreter.  The fix will be to use proper HEAPCHECK guard
    IR instructions.  That'll come next.
  • Loading branch information
nominolo committed Sep 24, 2011
1 parent d769ef4 commit d980d70
Show file tree
Hide file tree
Showing 11 changed files with 852 additions and 108 deletions.
17 changes: 16 additions & 1 deletion includes/HeapInfo.h
Expand Up @@ -9,10 +9,20 @@ void growHeapInfoBuffer_(JitState *J, Word needed);
void growHeapInfoMapBuffer_(JitState *J, Word needed);
u4 newHeapInfo(JitState *J, IRRef1 ref, InfoTable *info);
u4 cloneHeapInfo(JitState *J, IRRef1 ref, u2 orig);
HeapInfo *getHeapInfo(JitState *J, IRRef ref);
void printHeapInfo(FILE *file, JitState *J);
void heapSCCs(JitState *J);

INLINE_HEADER HeapInfo *
getHeapInfo(JitState *J, IRIns *ir)
{
switch (ir->o) {
case IR_NEW:
LC_ASSERT(ir->op2 < J->cur.nheap);
return &J->cur.heap[ir->op2];
default:
LC_ASSERT(0); return NULL;
}
}

INLINE_HEADER void growHeapInfoBuffer(JitState *J, Word needed)
{
Expand Down Expand Up @@ -40,5 +50,10 @@ setHeapInfoField(Fragment *F, HeapInfo *hp, u4 field, TRef tr)
F->heapmap[hp->mapofs + field] = (HeapEntry)tref_ref(tr);
}

INLINE_HEADER int
isLoopVariant(JitState *J, IRRef ref)
{
return (ref < J->cur.nloop && irt_getphi(J->cur.ir[ref].t));
}

#endif
10 changes: 10 additions & 0 deletions includes/IR.h
Expand Up @@ -7,6 +7,10 @@ typedef u2 IRRef1; /* One stored reference */
typedef u4 IRRef2; /* Two stored references */
typedef u4 IRRef; /* Used to pass around references */

#define mkIRRef2(r1, r2) ((r1) | ((r2) << 16))
#define irref2_ref1(r) ((u2)(r))
#define irref2_ref2(r) ((u2)((r) >> 16))

/*
* LuaJIT IR
*
Expand Down Expand Up @@ -209,6 +213,7 @@ enum {
};

#define irref_islit(ref) ((ref) < REF_BIAS)
#define irref_int(ref) ((int)((ref) - REF_BIAS))

#define IRT(o, t) (cast(u4, ((o) << 8) | (t)))

Expand Down Expand Up @@ -236,4 +241,9 @@ static LC_AINLINE int ir_sideeff(IRIns *ir)
return ((irt_isguard(ir->t)) || (ir_mode[ir->o] & IRM_S));
}

static LC_AINLINE int ir_issunken(IRIns *ir)
{
return !irt_getmark(ir->t);
}

#endif /* _LAMBDACHINE_IR_H */
31 changes: 30 additions & 1 deletion includes/Jit.h
Expand Up @@ -91,6 +91,7 @@ typedef struct _Fragment {
IRRef nins; // Next IR instruction
IRRef nk; // Lowest IR literal
IRRef nloop; // Reference to LOOP instruction (if any)
u2 nphis; // Number of PHI nodes (only needed by IR interpreter)

Word *kwords; // Constant words
u4 nkwords;
Expand Down Expand Up @@ -255,8 +256,8 @@ LC_FASTCALL void optUnrollLoop(JitState *J);
LC_FASTCALL void optDeadCodeElim(JitState *J);
LC_FASTCALL void optDeadAssignElim(JitState *J);
LC_FASTCALL TRef optForward(JitState *J);
LC_FASTCALL void compactPhis(JitState *J);

LC_FASTCALL IRRef findPhiTwin(JitState *J, IRRef ref);
void growIRBufferTop(JitState *J);

int irEngine(Capability *cap, Fragment *F);
Expand Down Expand Up @@ -299,4 +300,32 @@ INLINE_HEADER void traceError(JitState *J, int n)
exit(n);
}

LC_FASTCALL IRRef findPhi_aux(JitState *J, IRRef ref);

// Find the corresponding PHI node for the given target reference.
//
// Returns a non-zero result iff [ref] is shadowed by a PHI node.
// The result is a reference to the PHI node itself.
INLINE_HEADER IRRef
findPhi(JitState *J, IRRef ref)
{
if (ref < REF_BIAS || ref >= J->cur.nloop || !irt_getphi(J->cur.ir[ref].t))
return 0;

return findPhi_aux(J, ref);
}

// Find the corresponding twin of a referenced involved in a PHI node.
//
// Returns a non-zero result iff [ref] is a PHI node. The returned
// reference is the PHI twin (i.e., the second argument to the PHI
// node).
INLINE_HEADER IRRef
findPhiTwin(JitState *J, IRRef ref)
{
IRRef ref2 = findPhi(J, ref);
return ref != 0 ? J->cur.ir[ref2].op2 : 0;
}


#endif

0 comments on commit d980d70

Please sign in to comment.