property lists

Matthew Fluet Matthew Fluet <fluet@CS.Cornell.EDU>
Sat, 2 Dec 2000 20:29:11 -0500 (EST)


> > Second footnote:  The live variable lists are updated during the simplify
> > phase when I verify that the all of the liveness information is correct.
> > Previously, I hadn't needed to do this, I just assumed that the values
> > filled in in backend.fun were correct.  (Steve and I wrestled with this at
> > the end of the summer when we first added the liveness calculation to
> > backend.fun.  It's correct, although in some cases it overly conservative,
> > claiming that variables are live into a block when they don't need to be.)
> 
> Shoot.  If you let me know where it's still conservative, I'll look into it.

Here's where I found some differences in the liveness calculations.  These
programs were all run with  -detect-overflow false  to avoid all of the
overflow blocks.  Unfortunately, I don't see a common error in these
cases.

regression/real.sml

This one is due to a missed CPS optimization:

fun L_1055(x_14390) = 
    case x_14390 of
      false => L_889
    | true => L_889

In MachineOutput, this became a Switch, which was optimized at translation
to a single jump to L_889.  Thus, x_14390 (which became RI(0)) is no
longer live in.


benchmarks/barnes-hut.sml *

There were a number of differences in the liveness.

Here's the problematic CPS functions:

	    fun L_376(x_17179, x_17180) = 
	       let
		  val x_16282 = Word32_fromInt(x_15515)
		  val x_16283 = Word32_fromInt(x_17175)
		  val x_16284 = Word32_andb(x_16282, x_16283)
		  val x_16279 = MLton_eq(x_16284, global_82)
		  fun L_700() = 
		     let
			val x_16286 = Int_add(x_17179, global_12)
		     in
			x_17180
		     end
		  fun L_699() = 
		     let
			val x_16288 = Int_add(x_17179, global_12)
			val x_16289 = Word32_fromInt(env_126)
			val x_16290 = Word32_fromInt(x_16288)
			val x_16287 = Word32_lt(x_16290, global_79)
			fun L_703(x_16291) = 
			   let
			      val x_16293 = Word32_toIntX(x_16291)
			      fun L_704() = 
				 let
				    val x_16295 = Word32_toIntX(x_16291)
				    val x_16296 = Int_add(x_17180, x_16295)
				    val x_16297 = Int_add(x_17179, global_12)
				 in
				    x_16296
				 end
			      fun L_705() = 
				 raise [global_24]
			      val x_16292 = Int_lt(x_16293, global_9)
			   in
			      case x_16292 of
				false => L_704 | true => L_705
			   end
			fun L_701() = 
			   let
			      val x_16298 = Word32_arshift(x_16289, global_78)
			   in
			      L_703(x_16298)
			   end
			fun L_702() = 
			   let
			      val x_16299 = Word32_arshift(x_16289, x_16290)
			   in
			      L_703(x_16299)
			   end
		     in
			case x_16287 of
			  false => L_701 | true => L_702
		     end
	       in
		  case x_16279 of
		    false => L_699 | true => L_700
	       end

The basic issues seems to be with L_704, where barnes-hut.reg shows that
x_16297 is unused, but x_17179 is assigned to RI(5), and the backend
reports that RI(5) is live into L_704.  This is propagated back and the
backend reports that L_703, L_702, and L_701 all have RI(5) live in. 

The same error occurs with L_700, where x_16289 is unused.


benchmarks/mlyacc.sml

      fun L_7055() = 
	 let
	    val x_72292 = Array_length(data_36)
	    fun L_7056() = 
	       let
		  val x_72293 = Array_sub(data_36, x_65181)
	       in
		  L_5885(x_72293)
	       end
	    fun L_7057() = 
	       raise [global_39]
	    val x_72291 = Int_geu(x_65181, x_72292)
	 in
	    case x_72291 of
	      false => L_7056 | true => L_7057
	 end

The variable x_72292 is assigned to RI(2), which is reported as live
into L_7056.


benchmarks/zern.sml

The CPS is a little bit big for this one, so here's the C backend output:

L_278:
/* live: L_278 [RI(3),RI(4),RI(1),RI(2)] */
	RI(5) = Int_sub(RI(3), 1);
	RI(6) = Int_add(RI(4), 1000000);
L_279:
/* live: L_279 [RI(5),RI(2),RI(1)] */
	RI(6) = Int_lt(RI(5), 0);
	BZ(RI(6), L_280)

Note that RI(4) shouldn't really be live into L_278, because 
RI(6) = Int_add(RI(4), 1000000);
is dead code.

Here's the important part of the CPS:

fun L_279(x_5081, x_5082) = 
 let
   fun L_280() = ... (big function, neither x_5081 nor x_5082 is free) ...
   fun L_281() = 
    L_197(global_9)
   val x_5039 = Int_lt(x_5082, global_3)
 in
   case x_5039 of
    false => L_280 | true => L_281
 end
fun L_277() = L_279(x_5037, x_5036)
fun L_278() = 
 let
  val x_5075 = Int_sub(x_5036, global_5)
  val x_5076 = Int_add(x_5037, global_7)
 in
  L_279(x_5076, x_5075)
 end

The issue seems to be that x_5081 is really useless in L_279, but it
wasn't eliminated by the CPS shrinker.  On the otherhand, the register
allocator established that x_5039 and x_5081 could share the same
pseudo-register.