SECTION "CGG"

GET "b.CGheader"

STATIC $(
   // Version of 14 Apr 86 14:03:03
   dummy = VersionMark;
   Version = 1*256+13 $);

/* 1.4	04 Nov 85 11:02:38
     Don't destroy memory of contents of register before it's loaded.
   1.5	07 Feb 86 11:57:13
     Incorporation of floating point
   1.6	18 Feb 86 16:17:49
     Byte selectors access byte n not 3-n
   1.7	20 Feb 86 12:11:32
     Fields with shift 0 not only do not need to shift, they must not
     (LSR 0 is actually LSR 32)
   1.8	25 Feb 86 11:02:48
     Loading of fields uses a copy held in a register if there is one
     (this is a bug fix as well)
   1.9	03 Mar 86 11:55:06
     CgVecAp (and CgVecSt) failed if one side is of the form x+k with
     a shifted version of x present in a register.
   1.10 07 Mar 86 21:35:28
     k.static.
     Code improvement for !@thing
   1.11 21 Mar 86 12:20:13
     Deferred shifts
   1.12 14 Apr 86 14:03:25
     MoveToAnyRSomeTime (case thing is k.reg) only needs to flush it if
     it's not the target register.
*/

LET FreeReg(r) BE
$( FOR t = tempv TO arg1 BY SSSize DO
      IF (h1!t=k.reg | h1!t=k.shreg) & h3!t=r THEN $(
	 StoreT(t); BREAK $);
   FlushPendingUsesOfReg(r);
   DiscardReg(r, k.reg)
$)

AND FreeWithoutUnlocking(r) BE
$( LET l = Locked(r, k.reg);
   FOR t = tempv TO arg1 BY SSSize DO
      IF (h1!t=k.reg | h1!t=k.shreg) & h3!t=r THEN $(
	 StoreT(t); BREAK $);
   FlushPendingUsesOfReg(r);
   IF l THEN Lock(r, k.reg)
$)

AND MoveToR(r, x) BE
$( MoveToRSomeTime(r, x);
   FlushPendingLoadsForReg(r)
$)

AND LoadArg3ToSomeCR() = VALOF
$( LET arg3 = arg2-SSSize;
   TEST arg3<tempv THEN $(
      LET r = NextR();
      LET b, n = (linkageNotStored -> r.ts, r.p), ssp-3;
      TEST usesFrame THEN
	 n := n*nextStackWord
      ELSE
	 b, n := r.ts, nextStackWord*(n-saveSpaceSize);
      GenF2(f.ldr, r, b, 0, n);
      RESULTIS r $)

   ELSE
      RESULTIS MoveToAnyCR(arg3)
$)

AND MoveToRSomeTime(r, x) BE
$( RemoveFalseIndirection(x);
   $( LET t, ind, n, k = h1!x, h2!x, h3!x, h4!x
      AND b, m = 0, 0;
      LET nx4, kx4 = n*4, k*4;

      IF ind<0 THEN $(
	 LET r = LookFor(x, NotAddr);
	 IF r>=0 THEN t, n := k.reg, r $);

      IF r>0 THEN
	 UNLESS (t=k.reg | t=k.shreg) & n=r THEN FreeWithoutUnlocking(r);

      IF ind>=0 THEN $(
	 r := CompileDS(f.ldr, r, r, x);
	 GOTO l $);

      IF r<0 THEN r := NextR();

      IF t~=k.reg | k~=0 THEN
	 FlushPendingUsesOfReg(r);

      SWITCHON t INTO
      $( CASE k.reg:
	    IF r~=n & RegInPendingList(pendingLoads, n)~=Null
	       THEN FlushPendingLoadsForReg(n);

	    TEST k~=0 THEN
	       SetRtoRplusK(r, n, k)
	    ELSE $(
	       IF n~=r THEN $(
		  DiscardReg(r, k.reg);
		  GenRR(f.mov, r, 0, n);
		  MoveRToR(k.reg, n, k.reg, r) $);
	       GOTO lx $);
	    ENDCASE

	 CASE k.shreg:
	    ShiftRegisterDS(r, n, k/32, k REM 32);
	    ENDCASE

	 CASE k.freg:
	    IF ~loadRegFromFRegOK THEN
	       CGError(OnlyWarning, "Floating point operand to integer operation");
	    DiscardReg(r, k.reg);
	    MoveFRToR(n, r, x);
	    IF k~=0 THEN SetRToRplusK(r, r, k);
	    ENDCASE;

	 CASE k.number:
	    SetRtoK(r, n+k);
	    MoveStoR(k.reg, r, k.number, n+k);
	    GOTO lx

	 CASE k.lab:
	    m, nx4 := n, 0;
	    b := CheckRLLoaded();
	    GOTO la

	 CASE k.glob:
	    b := r.g;
	    GOTO la;

	 CASE k.static:
	    b := CheckRLLoaded();
	    GOTO la;

	 CASE k.loc:
	    TEST usesFrame
	       THEN b, nx4 := r.p, nextStackWord*n
	       ELSE b, nx4 := r.ts, nextStackWord*(n-saveSpaceSize);
	la: DiscardReg(r, k.reg);
	    TEST t=k.lab | b=r.0 THEN
	       GenF2(f.ldr, r, b, m, nx4)
	    ELSE {
	       AddToPendingLoads(r, t, n, 0);
	       IF k~=0 THEN FlushPendingLoadsForReg(r)
	    };

	    TEST k=0 THEN $(
	       MoveStoR(k.reg, r, t, (t=k.lab -> m, n));
	       GOTO lx $)
	    ELSE
	       SetRtoRplusK(r, r, k);
	    ENDCASE

	 CASE k.lvsloc:  // can't happen with no frame
	    nx4 := nextStackWord*n;
	    b := linkageNotStored -> r.ts, r.p;
	    SetRtoRplusK(r, b, nx4+k); ENDCASE

	 CASE k.lvsglob:
	    SetRtoRplusK(r, r.g, nx4+k); ENDCASE

	 CASE k.lvsstatic:
	    b := CheckRLLoaded();
	    SetRtoRplusK(r, b, nx4+k); ENDCASE

	 CASE k.lvslab:
	    b := CheckRLLoaded();
	    SetRtoRplusLplusK(r, b, n, k)
	    ENDCASE

	 CASE k.lvloc:	 // also must have a frame
	    /* IF ~linkageNotStored & (n+k)=TOSoffset THEN $(
		  ShiftRegisterDS(r, r.ts, sh.lsr, 2);
		  GOTO l $);
	       // that needs some extra work doing to ensure
	       // that TOSoffset is correct: ie no pending loads
	       // which will affect it
	    */
	    nx4 := nextStackWord*n;
	    b := linkageNotStored -> r.ts, r.p;
	    GOTO loadit

	 CASE k.lvstatic:
	    b := CheckRLLoaded();
	    GOTO loadit

	 CASE k.lvglob:
	    b := r.g;
    loadit: k := k+n; n := k;
	    m := LookForRegContainingType(t);
	    TEST m=Null THEN $(
	       ShiftRegisterDS(r, b, sh.lsr, 2);
	       m := r $)
	    ELSE
	       n := n-LocInRegister(m);
	    SetRtoRplusK(r, m, n);
	    MoveStoR(k.reg, r, t, k);
	    GOTO lx

	 CASE k.lvlab:
	    $( LET k1 = k&#xe0000000;
	       b := CheckRLLoaded();
	       SetRtoRplusLplusK(r, b, n, kx4);
	       ShiftRegister(r, sh.lsr, 2);
	       IF k1~=0 & k1~=#xe0000000 THEN
		  SetRtoRplusK(r, r, k&#xc0000000) $)
      $);

   l: DiscardReg(r, k.reg);
   lx:h1!x, h2!x, h3!x, h4!x := k.reg, -1, r, 0 $)
$)

AND TypeofField(size, shift) =
   size=8 & (shift REM 8)=0 -> bytefield,
   size<8 & [(size+shift) REM 8]=0 -> lbytefield,
			       genfield

AND GenOpToStore(f, r, b, m, a) BE
   GenOpToStoreDS(f, r, r, b, m, a)

AND GenOpToStoreDS(f, r, s, b, m, a) BE
   TEST f=f.str THEN
      GenF2(f, r, b, m, a)
   ELSE $(
      LET r2 = r;
      LET t, n, o = Null, 0, 0;
      IF f~=f.ldr THEN $(
	 Lock(r, k.reg); Lock(s, k.reg);
	 r2 := NextR() $);

      TEST b=r.p THEN
	 t, n := k.loc, a/nextStackWord
      ELSE TEST b=r.g THEN
	 t, n := k.glob, a/4
      ELSE TEST b=r.l THEN
	 IF m=0 THEN
	    t, n := k.static, a/4
      ELSE
	 t, n, o := k.ireg, b, a/4;

      TEST t~=Null THEN $(
	 AddToPendingLoads(r2, t, n, o);
	 IF t~=k.ireg THEN MoveStoR(k.reg, r2, t, n) $)
      ELSE
	 GenF2(f.ldr, r2, b, m, a);

      IF f~=f.ldr THEN $(
	 FlushPendingLoadsForReg(r2);
	 GenRR(f, r, s, r2);
	 UnLock(r, k.reg); UnLock(s, k.reg) $) $)

AND CompileDS(f, r, s, x) = VALOF
$( LET t, ind, n, k = h1!x, h2!x, h3!x, h4!x;
   LET m, a = ?, ?;
   LET r1 = Null;

   IF ind>=0 THEN $(
      LET b = ?;
      IF ind>=Carmark THEN $(
	 h2!x, h4!x := -1, 0;
	 b := (ind=VACarMark -> MoveToAnyCR(x),
				LoadCarAdd(x));
	 Lock(b, k.reg);
	 IF r<0 THEN r := NextR();  // must be some sort of load
	 IF s<0 THEN s := r;
	 TEST f=f.ld THEN
	    GenCPDT(f, r, b, 0, k/BytesPerWord)
	 ELSE
	    GenOpToStoreDS(f, r, s, b, 0, k);
	 UnLock(b, k.reg);
	 RESULTIS r $);

      m, a := 0, 4*k;
      SWITCHON t INTO
      $( CASE k.lvlab:
	    b, m := CheckRLLoaded(), n;
	    ENDCASE

	 CASE k.lvloc:
	    $( LET v = VEC sssize;
	       h1!v, h2!v, h3!v, h4!v := k.loc, -1, k+n, 0;
	       r1 := IsInARegister(v) $);
	    a := a+nextStackWord*n;
	    b := linkageNotStored -> r.ts, r.p;
	    ENDCASE

	 CASE k.lvstatic:
	 CASE k.lvglob:
	    $( LET v = VEC sssize;
	       h1!v, h2!v, h3!v, h4!v := t+k.glob-k.lvglob, -1, k+n, 0;
	       r1 := IsInARegister(v) $);
	    a := a+4*n; b := t=k.lvglob -> r.g, CheckRLLoaded();
	    ENDCASE

	 DEFAULT:
	    h2!x, h4!x := -1, 0;
	    b := LoadAddress(x);
	    TEST localsSafe
	       THEN FlushPendingStoresExceptLocalsAndIregs()
	       ELSE FlushPendingStores()
	    // Lock(b, k.reg)
      $);

      IF r<0 THEN r := NextR();
      IF s<0 THEN s := r;
      TEST ind=0 THEN
	 TEST f=f.ld THEN
	    GenCPDT(f, r, b, m, a/BytesPerWord)
	 ELSE
	    GenOpToStoreDS(f, r, s, b, m, a)
      ELSE $(
	 LET size = ind/32;
	 LET shift = ind REM 32;
	 LET r2 = r;
	 LET classOfSel = TypeOfField(size, shift);

	 IF f~=f.ldr THEN r2 := NextR();

	 TEST r1=Null & (classOfSel=bytefield | classOfSel=lbytefield) THEN
	 $( GenF2(f.ldrb, r2, b, m, a+shift/8);
	    IF classOfSel~=bytefield THEN
	    $( shift := shift REM 8;
	       IF shift~=0 THEN ShiftRegister(r2, sh.lsr, shift) $) $)
	 ELSE $(
	    LET left = TargetWordSize-size;
	    TEST r1=Null THEN $(
	       GenF2(f.ldr, r2, b, m, a);
	       r1 := r2 $)
	    ELSE
	       FlushPendingLoadsForReg(r1);

	    TEST shift~=0 | (left>8 & left<24) THEN $(
	       LET n = TargetWordSize-size-shift;
	       IF n~=0 THEN
	       $( ShiftRegisterDS(r2, r1, sh.asl, n);
		  r1 := r2 $);
	       ShiftRegisterDS(r2, r1, sh.lsr, left) $)

	    ELSE TEST left<=16 THEN
	       GenF1K(f.bic, r2, r1, ~[(-1)>>left])
	    ELSE
	       GenF1K(f.and, r2, r1, (-1)>>left) $);

	 TEST f=f.ld THEN
	    MoveRtoFR(r2, r, x)
	 ELSE IF f~=f.ldr THEN $(
	    GenRR(f, r, s, r2);
	    DiscardReg(r, k.reg) $);
	 DiscardReg(r2, k.reg) $);

      UnLock(b, k.reg);
      RESULTIS r
   $);

   IF k=0 THEN SWITCHON t INTO
   $( CASE k.loc:  k, m := linkageNotStored -> r.ts, r.p, 0;
		   a := nextStackWord*n; GOTO ll
      CASE k.lab:  k, m, a := CheckRLLoaded(), n, 0; GOTO ll
      CASE k.static:k, m, a := CheckRLLoaded(), 0, 4*n; GOTO ll
      CASE k.glob: k, m := r.g, 0; a := 4*n;
	       ll: GenOpToStoreDS(f, r, s, k, m, a);
	       lm: IF f~=f.cmps THEN
		      TEST f=f.ldr THEN
			 MoveStoR(k.reg, r, t, n)
		      ELSE
			 DiscardReg(r, k.reg);
		   RESULTIS r

      DEFAULT:
   $);

   TEST t=k.number THEN
      TEST f=f.ldr THEN
	 SetRtoK(r, n+k)
      ELSE TEST EightBitsOrFewer(n+k) THEN
	 F1Inst(f, r, s, Null, k+n, Null, 0, m.always)
      ELSE $(
	 LET r2 = ?;
	 Lock(r, k.reg); Lock(s, k.reg);
	 r2 := NextR();
	 SetRtoK(r2, k+n);
	 GenRR(f, r, s, r2);
	 UnLock(r, k.reg); Unlock(s, k.reg) $)

   ELSE $(
      LET b, n = r.p, h5!x;
      StoreT(x);
      IF ~usesFrame THEN b, n := r.ts, n-saveSpaceSize;
      n := n*nextStackWord
      GenOpToStoreDS(f, r, s, b, 0, n) $);

   RESULTIS r
$)

AND CGVecSt() BE
$( LET r = ?;
   loadRegFromFRegOK := TRUE;
   r := LoadArg3ToSomeCR();
   loadRegFromFRegOK := FALSE;
   ReadOp();
   CGVecapOrSt(f.str, r);
   TEST localsSafe THEN
      DiscardNonLocalRegs()
   ELSE
      DiscardNonConstRegs();
   Stack(ssp-2)
$)

AND CGVecap() BE
$( LET op = ?;
   ReadOp();
   op := PeekN();
   TEST op=s.sp | op=s.sg | op=s.sl THEN $(
      LET t = op=s.sp -> k.loc,
	      op=s.sg -> k.glob,
			 k.lab;
      LET n =?;
      ReadOp();
      n := ReadN();
      IF t=k.lab THEN $(
	 LET k = OffsetOfStatic(n);
	 IF k~=Null THEN t, n := k.static, k $);
      CGVecapOrSt(f.ldr, LookForSloc(NotAddr, t, n));
      GenStore(t, n) $)
   ELSE
      CGVecapOrSt(f.ldr, -1)
$)

AND CGVecapOrSt(fn, r) BE
$( // both sides should be reasonably complicated
   // (at least, not a constant)
   LET x, y = arg1, arg2;
   LET f = LoadAddress;
   LET b, ix = ?, ?;
   LET shiftby = 2;
   FlushPendingStores();
   IF h2!arg1>=0 THEN MoveToAnyR(arg1);
   IF h2!arg2>=0 THEN MoveToAnyR(arg2);

   TEST k.lvloc<=h1!arg1<=k.lvlab THEN $(
      f, h1!arg1 := MoveToAnyCR, h1!arg1+k.lvs;
      h4!arg1 := h4!arg1*4 $)

   ELSE TEST k.lvloc<=h1!arg2<=k.lvlab THEN $(
      x, y := arg2, arg1;
      f, h1!arg2 := MoveToAnyCR, h1!arg2+k.lvs;
      h4!arg2 := h4!arg2*4 $)

   ELSE IF LookFor(arg2, ShiftedUp)>=0 THEN $(
      x, y := arg2, arg1;
      IF h1!y~=k.shreg THEN $(
	 h4!y := h4!x+h4!y;
	 h4!x := 0 $) $);

   b := f(x);
   Lock(b, k.reg);
   TEST h1!y=k.shreg & (h4!y)/32=sh.asl THEN
      ix, shiftby := h3!y, shiftby+[(h4!y) REM 32]
   ELSE
      ix := MoveToAnyCR(y);
   Lock(ix, k.reg);
   IF r<0 THEN r := NextR();
   TEST localsSafe THEN $(
      IF fn=f.str THEN FlushPendingLoadsExceptLocals();
      FlushPendingStoresExceptLocalsAndIregs() $)
   ELSE $(
      IF fn=f.str THEN FlushPendingLoads();
      FlushPendingStores() $);

   F2Inst(fn, r, b, 0, ix, f.preup, sh.asl, shiftby, m.always);
   UnLock(b, k.reg); UnLock(ix, k.reg);
   TEST fn=f.ldr THEN
      Lose(r, k.reg)
   ELSE
      Stack(ssp-1)
$)
