:Title[LRETURN.mc, December 7, 1982  12:44 PM, Masinter];

*--------------------------------------------------------------------
* RETURN
*--------------------------------------------------------------------

   KnowRBase[LTEMP0];
   top level;
   InsSet[LispInsSet, 1];

opRETURN:
   T← (fetch← TSP) - 1, FlipMemBase;
   LTEMP0← Md, fetch← T, T← (FXBACK[ALINK]);
   LTEMP1← Md, T← (PVAR) - T;
   fetch← T, LTEMP3← (rhmask);				* get alink field
   LTEMP2← Md;
   branch[.nquick, R odd], LTEMP2, T← (LTEMP2) - (FXBACK[IVAR]);
   T← (fetch← T) + (FXDIF[DEFLO, IVAR]);
   Q← IVAR, IVAR← Md, T← (fetch← T) + 1;		* new IVAR
   DEFLO← Md, T← (fetch← T) + (FXDIF[PC, DEFHI]);
   T← Md, PVAR← (fetch← T) + (FXDIF[PVAR, PC]);
   T← T and (LTEMP3), memBase← ifuBR;			* new PVAR

:if[FNStats];
   BrHi← T, branch[.+2, R<0], FnStatsPtr;
	branch[.retstat], BrLo← DEFLO;
:else;
   BrHi← T;
   BrLo← DEFLO;
:endif;

   BrLo← DEFLO;
   T← ESP, PCF← Md;
.finishret:
   LEFT← T - Q, memBase← StackBR;
   T← (store← Q) + 1, dbuf← LTEMP0;
   TSP← (store← T) + 1, dbuf← LTEMP1;
   LEFT← (LEFT) rsh 1;
   LEFT← (LEFT) - (add[LeftOffset!, 1]c), NextOpCode;

:if[FNStats];
.retstat:
   DEFHI← T; PCF← Md, call[.storeretstat];	* finish this operation
   T← ESP, branch[.finishret];
:endif;

IFUpause[20,1,StackM2BR,0,opReturn,noNData, 0, 0];



*--------------------------------------------------------------------
* NQUICK cases of return
*--------------------------------------------------------------------

	m[HardReturn, CallUFN];

.nquick:
   T← (PVAR) - (FXBACK[ALINK]);
   T← (fetch← T) + (FXDIF[CLINK, ALINK]);
   LTEMP2← Md, T← (fetch← T) + (FXDIF[BLINK, CLINK]);
   pd← (LTEMP2) - (Md) - 1, branch[.+2, R odd];
	UCodeCheck[BadFrame];
   branch[.+2, alu=0], LTEMP2← (LTEMP2) - 1;
	HardReturn;			* alink#clink

* LTEMP2 is returnee
   T← (LTEMP2) - (FXBACK[FLAGS]);   
   fetch← T;					* flagword
   T← Md;

:if[Debugging];
   LTEMP3← T and (StackMask);
   pd← (LTEMP3) xor (FxtnBlock);
   branch[.+2, alu=0];
	uCodeCheck[BadFrame];
:endif;

   pd← T and (rhmask);
   branch[.+2, alu=0], T← (LTEMP2) - (FXBACK[NEXT]);
	HardReturn;			* usecnt of returnee # 0

   fetch← T, T← FreeStackBlock;
   LTEMP3← fetch← Md;			* LTEMP3 points to returnee's next
   pd← T xor (Md);			* T ← flags
   branch[.+2, alu#0], T← IVAR;
	branch[DORETURN];

* check for contiguous BF

   pd← T xor (LTEMP3);			* is IVAR=returnee's next?
   branch[.+2, alu=0], T← (PVAR) - (FXBACK[BLINK]);
	HardReturn;
   fetch← T;
   T← Md;
   fetch← T;
   T← Md;
   pd← T and (rhmask);
   branch[DORETURN, alu=0];
     HardReturn;

DORETURN:	* do return to LTEMP2
   T← (PVAR) - (FXBACK[BFLAGS]);
   fetch← T, T← add[BfResidual!, rhmask!]c;
   pd← T and Md;
   branch[.freefx, alu=0], T← IVAR;


:if[Debugging];

.checkfreebf:
   T← (PVAR) - (FXBACK[ALINK]);
   fetch← T;
   LTEMP3← Md;
   branch[.+2, R odd], LTEMP3;
	UCodeCheck[ShouldBeSlowFrame];
   T← (PVAR) - (FXBACK[BLINK]);

:else;

.checkfreebf:
   T← (PVAR) - (FXBACK[BLINK]);

:endif;

   fetch← T, T← (rhmask);
   LTEMP3← fetch← Md;					* get bf flags
   LTEMP4← Md, pd← T and Md;
   branch[.nqnz, alu#0], T← (LTEMP3) + (2c);

:if[Debugging];
   T← (LTEMP3) + 1;
   T← (fetch← T) + 1;
   pd← (IVAR) - (Md);
   branch[.+2, alu=0];
	uCodeCheck[IVARWRONG];
:endif;

   T← T - (IVAR);
   IVAR← (store← IVAR) + 1, dbuf← FreeStackBlock;
   store← IVAR, dbuf← T, branch[.clresid];

.nqnz:	* leave BF alone, just decrement use count
   T← (LTEMP4) - 1;
   store← LTEMP3, dbuf← T, branch[.clresid];

.clresid:
   T← (PVAR) - (FXBACK[BFLAGS]);

:if[Debugging];
   fetch← T;
   LTEMP3← Md;
   pd←(LTEMP3) and (BFResidual);
   branch[.+2, alu#0];
	uCodeCheck[StackBad];
   nop;
:endif;

.freefx:				* make from T to ESP into a free block
   ESP← (ESP) - T;
   T← (store← T) + 1, dbuf← FreeStackBlock;
   store← T, dbuf← ESP;

   PVAR← LTEMP2;

*--------------------------------------------------------------------
RTN2:	* return to frame at PVAR with LTEMP0,,LTEMP1
*--------------------------------------------------------------------

   memBase← StackBR;
:if[Debugging];
   T← (PVAR) - (FXBACK[FLAGS]);
   fetch← T;
   T← Md;
   T← T and (StackMask);
   pd← T xor (FxtnBlock);
   branch[.+2, alu=0];
	uCodeCheck[BadFrame];
:endif;

   T← (PVAR) - (FXBACK[IVAR]);
   T← (fetch← T) + (FXDIF[NEXT,IVAR]);
   IVAR← Md, fetch← T;
   ESP← Md;
   TSP← Md, fetch← Md;

.extend:
   ESP← (fetch← ESP) + 1;
   T← Md;
   pd← T xor (FreeStackBlock);
   branch[.+2, alu#0], T← ESP← (fetch← ESP) - 1;
	ESP← (ESP) + (Md), branch[.extend];

   T← (T - (TSP)) rsh 1;
   branch[.+2, carry], LEFT← T - (LeftOffset);
	uCodeCheck[noStackAtPunt];

   T← (PVAR) - (FXBACK[FLAGS]);
   fetch← T;
   LTEMP2← Md;
   pd← (LTEMP2) and (FXInCall);
   branch[.retcall, alu#0], pd← (LTEMP2) and (FXNoPushReturn);
   branch[.nopush, alu#0], Q← TSP;
   T← (store← Q) + 1, dbuf← LTEMP0;
   TSP← (store← T) + 1, dbuf← LTEMP1;
   branch[.retfe2, R>=0], Left← (Left) - 1;
	uCodeCheck[NoStackAtPunt];


.nopush:
   LTEMP2← (LTEMP2) and not (FXNoPushReturn);
   store← T, dbuf← LTEMP2;			* turn off no pushbit
   
.retfe2:
   T← (PVAR) - (FXBACK[IVAR]);
   T← (fetch← T) + (FXDIF[DEFLO, IVAR]);
   IVAR← Md, T← (fetch← T) + 1;
   DEFLO← Md, T← (fetch← T) + (FXDIF[PC, DEFHI]);
   DEFHI← Md, fetch← T, T← (rhmask);
   DEFHI← (DEFHI) and T, memBase← ifuBR;
   BrHi← DEFHI;
   BrLo← DEFLO;
   PCF← Md;

:if[FNStats];
   branch[.+2, R<0], FnStatsPtr;
   call[.storeretstat];
   NextOpCode;

:else;
   nop;
   NextOpCode;
:endif;

.retcall:
   LTEMP2← (LTEMP2) and not (FXInCall);
   store← T, dbuf← LTEMP2;
   T← (TSP) - 1;
   T← (fetch← T) - 1;
   DEFLO← Md, T← (fetch← T) - 1;
   DEFHI← Md, T← (fetch← T) - 1;
   NARGS← Md; fetch← T;
:if[Debugging];
   pd← DEFHI;
   branch[.+2, alu=0], LTEMP0← Md;
	uCodeCheck[BadRetCall];
   pd← (LTEMP0) xor (SmallHi);
   branch[.+2, alu=0];
	uCodeCheck[BadRetCall];
:endif;
   TSP← T, branch[RESTARTCALL0];