IntInf asserts

Matthew Fluet Matthew Fluet <fluet@CS.Cornell.EDU>
Fri, 2 Nov 2001 12:55:56 -0500 (EST)


Can someone argue why the following asserts are in IntInf.c:

	assert(frontier == (pointer)&bp->limbs[bp->card - 1]);

Compiling with -g and with all of the CPS simplifications off and all of
the SSA simplifications on causes smith-normal-form.sml to raise the above
assertion in IntInf_doNeg.

A couple of things to note:  with all of the inlining off, the primitive
IntInf functions all live in their own SSA function.  So, you see stuff
like:


fun operatorTilde_0 (x_1583) = L_1486()
  L_1486 ()
    x_1585 = #2 x_1583
    x_1586 = #1 x_1583
    x_1584 = IntInf_neg (x_1586, x_1585)
    x_1584
fun bigNegate_2 (env_103, x_1267) = L_1244()
  L_1244 ()
    L_1254 (isSmall_0 (x_1267)) None
  L_1254 (x_1277)
    case x_1277 of
      false => L_1253 | true => L_1249
  L_1253 ()
    L_1252 (bigSize_0 (x_1267)) None
  L_1252 (x_1275)
    x_1276 = (global_1, x_1275)
    L_1251 (operatorPlusQues_0 (x_1276)) None
  L_1251 (x_1274)
    L_1250 (allocate_0 (x_1274))
  L_1250 (x_1272)
    x_1273 = (x_1267, x_1272)
    operatorTilde_0 (x_1273)
  L_1249 ()
    L_1248 (toWord_0 (x_1267)) None
  L_1248 (x_1270)
    x_1271 = MLton_eq (x_1270, global_5119)
    case x_1271 of
      false => L_1247 | true => L_1245
  L_1247 ()
    x_1269 = (global_5118, x_1270)
    L_1246 (operatorMinus_0 (x_1269)) None
  L_1246 (x_1268)
    fromWord_0 (x_1268)
  L_1245 ()
    env_103

The allocation for the intInf result and the actual call to the primitive
intInf function are separated by an SSA function call.

Ahh... I think I see.  We're not flattening the argument to
operatorTilde_0, so there really is an additional allocation going on
there.  And that seems to remind me of something that came up before...:


From: "Stephen Weeks" <sweeks@intertrust.com>
Date: Tue, 27 Jun 2000 18:52:19 -0700 (PDT)
To: MLton@research.nj.nec.com
Subject: safe for space ... and IntInf

> Is this restriction currently in place (I.e., are we safe for space
now)?

Yes.  Right now, the flattener never changes tail calls into non-tail
calls.   However, other Cps simplification passes, like useless.fun,
do turn tail calls into nontail calls.  I think useless is ok because
it has the one-way property (you can only coerce something that's
useful into something that's useless, but not vice versa).

Your mail also came at a fortunate time, as I was trying to track down 
a seg fault I was getting in the smith-normal-form regression test.
For stress testing, I turned off all the cps simplify passes (except
for poly equal) and ran the regressions.  smith-normal-form failed
with a seg fault when compiled normally, and failed with an assertion
failure in IntInf_do_neg when compiled -g.  The assertion failure was
right at the beginning, checking that the frontier is in the expected
place.
	assert(frontier == (pointer)&bp->limbs[bp->card - 1]);
I'd been tracking this bug for a couple hours when I received your
mail about the flattener.  Do you see the connection? :-)  As a
reminder, here is the code for bigNegate

	 fun bigNegate (arg: bigInt): bigInt =
		if Prim.isSmall arg
		      then let val argw = Prim.toWord arg
			   in if argw = badw
				 then negBad
				 else Prim.fromWord (Word.- (0w2, argw))
			   end
		      else Prim.~ (arg, allocate (1 + bigSize arg))

The problem is, when the flattener is turned off, there is an
allocation in between the call to allocate and the Prim.~ call.  The
argument tuple allocation screws everything up.  So, we are relying on 
the flattener for correctness of the IntInf implementation.  Any ideas 
on how to improve the implementation to remove this reliance, or at
least put an assert somewhere to avoid falling prey to this bug again?

From: "Stephen Weeks" <sweeks@intertrust.com>
Date: Tue, 27 Jun 2000 19:26:18 -0700 (PDT)
To: MLton@research.nj.nec.com
Subject: Re: safe for space ... and IntInf

> The bignum code pretty much has to depend on the fact that certain temporaries
> are allocate JUST before the call so that it can shrink them back to their
> desired size.  Only the last thing allocated can be shrunk.  I'm glad I put
> the assert in the code.

me too.

> One solution (a hack) would be to handle the flatening of Prim.??? args
> specially.  I.e., Prim.??? takes its arguments flattened out.  This corresponds
> to reality, so it isn't SO crazy.

Prim args are flattened even with the flattener turned off.  The
problem is that there is a lambda wrapped around the primitive that
coerces from the tuplized representation to the flattened one.  It is
this lambda which either has to be flattened (or inlined).

> Well, we could make the Prim guys curried (yuck). 

This doesn't help either, for the reason given above, and because
currying, without optimization, causes an allocation for the
intermediate closure.

I'm inclined to leave the problem be -- but I'd at least like to put a 
reminder or assert somewhere to avoid tracking down this bug next time 
I do stress testing.

******

Well, I'm putting a comments in SSA shrink..fun and CPS shrink.fun to this
effect.