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.