SECTION "CGE"

GET "b.CGheader"

STATIC
$( /* Version of 11 Sep 87 13:42:08
   */
   dummy = VersionMark
   version = 1*256+9 $);

MANIFEST
$( PendingBufferSize = 10;
   MaxPendingInst = 4;
   pi.size = 10;

   pi.F1Inst=1; pi.F2Inst=2; pi.F4Inst=4; pi.F5Inst=5;
   pi.GenF2=6; pi.F5InstL=7; pi.F5InstLM=8;
   pi.SetRtoRplusLplusK=9;
   pi.SetLabel=10;
   pi.f5InstX=11 $);

MANIFEST
$( sll.loc = 1; sll.reg = 2; sll.offset = 3;
   sll.size = 4 $);

STATIC
$( pendingCount = 0;
   pendingInsts = 0; otherBranch = 0;
   eightBitMask = 0 $);

LET InitPendingInsts() BE
$( pendingInsts, otherBranch := 0, 0;
   pendingLab, pendingCount := Null, 0
$)

AND AddPendingInst(a, b, c, d, e, f, g, h, i) BE
$( pendingInsts := FillBlk(pi.size, pendingInsts,
			       a, b, c, d, e, f, g, h, i);
   pendingCount := pendingCount+1
$)

AND PlantInstructionChain(p, m) BE
$( p := ReverseInPlace(p);
   WHILE p~=0 DO $(
      SWITCHON 1!p INTO
      $( CASE pi.SetLabel:
	    RealSetLabel(2!p);
	    ENDCASE
	 CASE pi.F5Inst:
	    F5Inst(2!p, 3!p, m);
	    ENDCASE
	 CASE pi.F5InstX:
	    F5InstX(2!p, 3!p, m);
	    ENDCASE
	 CASE pi.F4Inst:
	    F4InstM(2!p, 3!p, 4!p, 5!p, m);
	    ENDCASE
	 CASE pi.F2Inst:
	    F2Inst(2!p, 3!p, 4!p, 5!p, 6!p, 7!p, 8!p, 9!p, m);
	    ENDCASE
	 CASE pi.F1Inst:
	    F1Inst(2!p, 3!p, 4!p, 5!p, 6!p, 7!p, 8!p, m);
	    ENDCASE
	 CASE pi.GenF2:
	    GenF2M(2!p, 3!p, 4!p, 5!p, 6!p, m);
	    ENDCASE
	 CASE pi.F5InstL:
	    F5InstL2(2!p, 3!p, m);
	    ENDCASE
	 CASE pi.F5InstLM:
	    F5InstL2(2!p, 3!p, 4!p);
	    ENDCASE
	 CASE pi.SetRtoRplusLplusK:
	    SetRtoRplusLplusKM(2!p, 3!p, 4!p, 5!p, m);
	    ENDCASE
      $);
      p := FreeBlk(p, pi.size) $)
$)

AND PlantCopy(l, m) BE
   PlantInstructionChain(CopyOfList(l, pi.size), m)

AND SameInstruction(p, q) = VALOF
$( IF 1!p~=1!q | 2!p~=2!q | 3!p~=3!q THEN RESULTIS FALSE;
   SWITCHON 1!p INTO
   $( CASE pi.F5Inst:
      CASE pi.F5InstX:
      CASE pi.F5InstL:
	 RESULTIS TRUE
      CASE pi.F2Inst:
	 IF 9!p~=9!q THEN RESULTIS FALSE
      CASE pi.F1Inst:
	 IF 7!p~=7!q | 8!p~=8!q THEN RESULTIS FALSE
      CASE pi.GenF2:
	 IF 6!p~=6!q THEN RESULTIS FALSE
      CASE pi.F4Inst:
      CASE pi.SetRtoRplusLplusK:
	 IF 5!p~=5!q THEN RESULTIS FALSE
      CASE pi.F5InstLM:
	 RESULTIS 4!p=4!q
   $)
$)

AND CommonSequence(p) = VALOF
$( WHILE SameInstruction(pendingInsts, otherBranch) DO $(
      LET q = pendingInsts;
      pendingInsts := !pendingInsts;
      !q := p; p := q;
      otherBranch := FreeBlk(otherBranch, pi.size) $);
   IF (CGDebugMode&db.cs)~=0 THEN
      PrintList(p, pi.size, "common", ":", "*n")
   RESULTIS p
$)

AND LabelInPendingInsts(p) = VALOF
$( IF Assoc(pi.SetLabel, 1, p)=Null THEN RESULTIS FALSE;

   WHILE p~=0 DO $(
      IF 1!p~=pi.SetLabel THEN RESULTIS TRUE;
      p := !p $);
   RESULTIS FALSE
$)

AND FirstPendingInst(a, b, c, d, e) =
	 1!pendingInsts=a &
	 (b=Null | 2!pendingInsts=b) &
	 (c=Null | 3!pendingInsts=c) &
	 (d=Null | 4!pendingInsts=d) &
	 (e=Null | 5!pendingInsts=e)

AND FlushPendingInsts(m, atLab) BE
$( LET pl = pendingLab;
   LET dc = deadCode;
   LET mcopy = m;
   LET plantAtEnd = 0;
   LET labAtEnd, otherCaseLab = Null, Null;

   IF pendingLab=Null THEN RETURN;
   IF (CGDebugMode&db.cs)~=0 THEN $(
      WriteF("FlushPI %x8 %n op %n lab %n*n", m, atLab, op, pendingLab);
      PrintList(pendingInsts, pi.size, "pending", ":", "*n");
      PrintList(otherBranch, pi.size, "other", ":", "*n") $);

   IF atLab & m=Null &
      FirstPendingInst(pi.F5InstL, pendingLab, f.b, Null, Null) THEN $(
      LET q = pendingInsts;
      pendingInsts := !pendingInsts;
      plantAtEnd := q; !q := 0;
      m := pendingMask $);

   deadCode := Alive;
   pendingLab := Null;
   m := ComplementCondition(m);

   IF plantAtEnd=0 & m~=m.always &
      ([FirstPendingInst(pi.F5InstL, Null, f.b, Null, Null) &
	LabelFlagged(pl, lab.onlyonejump)] |

       FirstPendingInst(pi.F1Inst, f.mov, r.pc, r.pc, r.b) |

       FirstPendingInst(pi.F1Inst, f.movs, r.pc, 0, r.14) |

       FirstPendingInst(pi.F2Inst, f.ldr, r.pc, r.pc, Null) |

       FirstPendingInst(pi.GenF2, f.ldr, r.pc, Null, Null) |

       FirstPendingInst(pi.F4Inst, f.ldm, r.p, f4.plpc, Null)) THEN $(
      LET l = 2!pendingInsts;
      LET o = otherBranch;
      IF 1!pendingInsts~=pi.F5InstL THEN l := -2;
      IF l<0 | ValueOfLabel(l)=Null THEN $(
	 otherBranch:= l<0 -> pendingInsts,
			      FreeBlk(pendingInsts, pi.size);
	 pendingInsts := o;
	 pendingCount := LengthOfList(o);
	 pendingLab, pendingMask := l, m;
	 RETURN $) $);

   IF otherBranch~=0 THEN $(
      // see whether there are common sets of instructions
      // between the two sequences.
      LET plantAtStart = 0;
      LET p = plantAtEnd;

      IF atLab THEN plantAtEnd := CommonSequence(plantAtEnd);

      pendingInsts := ReverseInPlace(pendingInsts);
      otherBranch := ReverseInPlace(otherBranch);
      plantAtStart := CommonSequence(0);

      pendingInsts := ReverseInPlace(pendingInsts);
      otherBranch := ReverseInPlace(otherBranch);

      PlantInstructionChain(plantAtStart, m.always);

      TEST LengthOfList(otherBranch)<=MaxPendingInst &
	   ~LabelInPendingInsts(otherBranch) THEN $(
	 PlantInstructionChain(otherBranch, pendingMask);
	 IF plantAtEnd~=p THEN
	    TEST pl<0 & LengthOfList(plantAtEnd)=1 &
		 1!plantAtEnd=pi.F5InstL THEN $(
	       PlantCopy(plantAtEnd, pendingMask);
	       m := m.always $)
	    ELSE $(
	       m := ComplementCondition(pendingMask);
	       labAtEnd := NextLabel() $) $)

      ELSE $(
	 otherCaseLab := NextLabel();
	 F5InstL2(otherCaseLab, f.b, ComplementCondition(pendingMask));
	 PlantInstructionChain(otherBranch, m.always);
	 IF plantAtEnd~=p THEN $(
	    PlantCopy(plantAtEnd, m.always);
	    m := m.always $) $)
   $);

   TEST pl>=0 & m=m.always THEN
      F5InstL2(pl, f.b, pendingMask)

   ELSE IF LengthOfList(pendingInsts)>MaxPendingInst |
	   LabelInPendingInsts(pendingInsts) THEN $(
      TEST labAtEnd~=Null THEN
	 F5InstL2(labAtEnd, f.b, PendingMask)
      ELSE IF pl>=0 THEN
	 F5InstL2(pl, f.b, PendingMask);
      m := m.always $);

   IF otherCaseLab~=Null THEN RealSetLabel(otherCaseLab);
   PlantInstructionChain(pendingInsts, m);

   plantAtEnd := ReverseInPlace(plantAtEnd);
   IF labAtEnd~=Null THEN SetLabel(labAtEnd);
   PlantInstructionChain(plantAtEnd, m.always);
   IF mcopy=Null & labAtEnd~=Null & pl>=0 THEN
      f5InstL2(pl, f.b, pendingMask);

   pendingCount := 0;
   otherBranch, pendingInsts := 0, 0;
   deadCode := dc
$)

AND SetLabel(l) BE
   TEST PendingLab~=Null
      THEN AddPendingInst(pi.SetLabel, l)
      ELSE RealSetLabel(l)

AND ShiftValue(shiftType, shiftBy, r2) =
  // shiftBy is positive if the shift is by a constant,
  // negative if by the value of a register (= -regno)
   shiftType=Null -> r2,
   shiftBy>=0 -> r2+shiftType+(shiftBy<<7),
		 r2+shiftType+#x10+((-shiftBy)<<8)

AND LogBase2(n) = VALOF
$( LET i = 0;
   WHILE (n&1)=0 DO n, i := n>>1, i+1;
   RESULTIS i
$)

AND F5Inst(opcode, offset, mask) BE
   IF deadCode~=Dead THEN $(
      IF pendingLab~=Null THEN
	 TEST pendingCount<PendingBufferSize THEN $(
	    AddPendingInst(pi.F5Inst, opcode, offset);
	    RETURN $)
	 ELSE
	    FlushPendingInsts(Null, FALSE);

      PutWord(opcode+mask+(([offset-LocCtr-8]>>2)&#x00ffffff))
$)


AND F5InstX(opcode, sym, mask) BE
   IF deadCode~=Dead THEN $(
      IF pendingLab~=Null THEN
	 TEST pendingCount<PendingBufferSize THEN $(
	    AddPendingInst(pi.F5InstX, opcode, sym);
	    RETURN $)
	 ELSE
	    FlushPendingInsts(Null, FALSE);

      AddXRelocatedLoc(locCtr, sym, RelWord+RelPCRel+RelSymbol);
      PutWord(opcode+mask)
$)

AND F4Inst(opcode, base, RegList, wb.dir.prepost.pc) BE
   F4InstM(opcode, base, RegList, wb.dir.prepost.pc, m.always)

AND F4InstM(opcode, base, regList, wb.dir.prepost.pc, mask) BE
   IF deadCode~=Dead THEN $(
      IF pendingLab~=Null THEN
	 TEST pendingCount<PendingBufferSize THEN $(
	    AddPendingInst(pi.F4Inst, opcode, base, regList,
				      wb.dir.prepost.pc);
	    RETURN $)
	 ELSE
	    FlushPendingInsts(Null, FALSE);

   PutWord(opcode+mask+wb.dir.prepost.pc+(base<<16)+regList)
$)

AND F2Inst(opcode, reg, base, offset, r2,
	   prepost, shiftType, shiftBy, mask) BE
   IF deadCode~=Dead THEN $(
      LET addrType = ?;
      IF pendingLab~=Null THEN
	 TEST pendingCount<PendingBufferSize THEN $(
	    AddPendingInst(pi.F2Inst, opcode, reg, base, offset, r2,
				      prepost, shiftType, shiftBy);
	    RETURN $)
	 ELSE
	    FlushPendingInsts(Null, FALSE);

      TEST r2~=Null THEN $(
	 addrType := #x2000000
	 offset := ShiftValue(shiftType, shiftBy, r2) $)

      ELSE TEST offset<0 THEN
	 addrType, offset := f.down, -offset
      ELSE
	 addrType := f.up;

      IF ~(0<=offset<=f2.max.offset) THEN $(
	 CGError(FALSE, "F2Inst: offset %n", offset);
	 offset := 0 $);

      PutWord(mask+opcode+prepost+addrType+(base<<16)+
	      (reg<<12)+offset) $)

AND PackUp(offset) =
   offset=0 -> 0, VALOF
   $( LET lsbit = offset&(-offset);
      LET shift = 0;
      TEST lsbit>2 THEN $(
	 shift := 32-[LogBase2(lsbit) & (-2)];
	 TEST shift=32 THEN
	    shift := 0
	 ELSE
	    offset := offset>>(32-shift) $)
      ELSE $(
	 LET n = offset;
	 WHILE (n&#xc0000000)~=0 DO $(
	    n := n<<2; shift := shift+2 $);
	 offset := RotateRight(offset, 32-shift) $);

      IF offset>=#x100 THEN $(
	 CGError(FALSE, "F1Inst: Offset %x8 will not fit in 8 bits",
			RotateRight(offset, shift));
	 offset := 0 $);

      RESULTIS offset + (shift<<7)
   $)

AND F1Inst(opcode, reg, base, r2, offset, shiftType, shiftBy, m) BE
   IF deadCode~=Dead THEN $(
      LET addrType = ?
      IF pendingLab~=Null THEN
	 TEST m=m.always & pendingCount<PendingBufferSize THEN $(
	    AddPendingInst(pi.F1Inst, opcode, reg, base, r2,
				      offset, shiftType, shiftBy);
	    RETURN $)
	 ELSE
	    FlushPendingInsts(Null, FALSE);

      TEST r2=Null THEN $(
	 addrType := #x2000000;
	 offset := PackUp(offset) $)
      ELSE $(
	 addrType:= 0;
	 offset := ShiftValue(shiftType, shiftBy, r2) $);

      PutWord(m+opcode+addrType+(base<<16)+offset+(reg<<12)) $)

AND GenF1K(f, r, s, k) BE
$( LET e = EightBitsOrFewer(k);
   LET m = eightBitMask;
   TEST e THEN
      F1Inst(f, r, s, Null, k, Null, 0, m.always)
   ELSE TEST (f=f.add | f=f.sub | f=f.orr | f=f.eor | f=f.bic) &
	     EightBitsOrFewer(k&~m) THEN $(
      GenF1K(f, r, s, k&m);
      GenF1K(f, r, r, k&~m) $)
   ELSE $(
      SetRtoK(r.0, k);
      r0Offset := Null;
      GenRR(f, r, s, r.0) $)
$)

AND CompareAgainstK(r, k, cm) BE {
   LET e = EightBitsOrFewer(k);
   LET m = eightBitMask;
   LET unsigned = cm=m.gtu | cm=m.geu | cm=m.ltu | cm=m.leu;
   TEST e THEN
      F1Inst(f.cmps, r, r, Null, k, Null, 0, m.always)
   ELSE TEST k<0 & ~unsigned & EightBitsOrFewer(-k) THEN
      F1Inst(f.cmns, r, r, Null, -k, Null, 0, m.always)
   ELSE TEST ~unsigned & k>0 & EightBitsOrFewer(k&~m) THEN
      TEST cm=m.eq | cm=m.ne THEN {
	 GenF1K(f.sub, r.0, r, k&m);
	 GenF1K(f.subs, r.0, r.0, k&~m);
	 r0Offset := Null }
      ELSE {
	 F1Inst(f.subs, r.0, r, Null, k&m, Null, 0, m.always);
	 F1Inst(f.subs, r.0, r.0, Null, k&~m, Null, 0, m.ge);
	 r0Offset := Null }
   ELSE TEST unsigned & EightBitsOrFewer(k&~m) THEN {
      F1Inst(f.subs, r.0, r, Null, k&m, Null, 0, m.always);
      F1Inst(f.subs, r.0, r.0, Null, k&~m, Null, 0, m.geu);
      r0Offset := Null }
   ELSE {
      SetRtoK(r.0, k);
      r0Offset := Null;
      GenRR(f.cmps, r, r, r.0) } }

AND GenRR(f, r, s, r2) BE
   F1Inst(f, r, s, r2, 0, Null, 0, m.always)

AND GenF2(f, r, base, lab, offset) BE
$( IF pendingLab~=Null THEN
      TEST pendingCount<PendingBufferSize THEN $(
	 AddPendingInst(pi.GenF2, f, r, base, lab, offset);
	 RETURN $)
      ELSE
	 FlushPendingInsts(Null, FALSE);
   GenF2M(f, r, base, lab, offset, m.always)
$)

AND GenF2M(f, r, base, lab, offset, m) BE
   TEST lab~=0 THEN $(
      LET laboffset = ValueOfLabel(lab);
      LET fop = (f&#xf00)~=0;
      IF laboffset~=Null & fop THEN
	 laboffset := laboffset/BytesPerWord
      /* Yeuch!!  Floating point offsets are scaled */
      TEST laboffset=Null THEN $(
	 addref(LocCtr, (fop -> 6, 2), lab)
	 F2Inst(f, r, base, offset, Null, f.pre, Null, 0, m) $)
      ELSE F2Inst(f, r, base, offset+laboffset,
			Null, f.pre, Null, 0, m) $)

   ELSE $(
      LET max = f2.max.offset;
      IF (op&#xf00)~=0 THEN max := #xff;
      IF ~(-max<=offset<=max) THEN $(
	 LET o = [offset/(max+1)]*(max+1);
	 SetRtoRplusKM(r.0, base, o, m);
	 offset := offset-o;
	 r0Offset := Null;
	 base := r.0 $);
      F2Inst(f, r, base, offset, Null, f.pre, Null, 0, m) $)

AND CallSub(sr) BE
$( DiscardReg(r.14, k.reg);
   GenRR(f.mov, r.14, 0, r.pc);
   SetRtoRplusK(r.pc, r.gb, sr)
$)

AND SetRtoRplusLplusK(r, s, l, k) BE
   TEST s=r.l THEN $(
      // IF s is rl, I assert that l will always be a label
      // whose value (relative to rl) is known.
      LET n = Assoc(l, 1, staticLabels);
      TEST n=Null THEN
	 CGError(FALSE, "SetRtoRplusLplusK: unset label %n*n", l)
      ELSE
	 SetRtoRplusK(r, s, k+(3!n)) $)

   ELSE $(
      IF pendingLab~=Null THEN
	 TEST pendingCount<PendingBufferSize THEN $(
	    AddPendingInst(pi.SetRToRplusLplusK, r, s, l, k);
	    RETURN $)
	 ELSE
	    FlushPendingInsts(Null, FALSE);
      SetRToRplusLplusKM(r, s, l, k, m.always) $)

AND SetRToRPlusLplusKM(r, s, l, k, m) BE
$( AddRef(locCtr, 1, l);
   SetRToRplusKM(r, s, k, m)
$)

AND SetRtoRplusKM(r, s, k, m) BE
   TEST EightBitsOrFewer(k) THEN
      F1Inst(f.add, r, s, Null, k, Null, 0, m)
   ELSE TEST EightBitsOrFewer(-k) THEN
      F1Inst(f.sub, r, s, Null, -k, Null, 0, m)
   ELSE $(
      BackTrace();
      CGError(FALSE, "SetRtoRplusKM: offset %n out of range", k) $)

AND SetRtoRplusK(r, s, k) BE
$( LET m, mn = ?, ?;
   eightBitMask := 255;
   IF EightBitsOrFewer(k) THEN $(
      GenF1K(f.add, r, s, k); RETURN $);
   m := eightBitMask;

   IF EightBitsOrFewer(-k) THEN $(
      GenF1K(f.sub, r, s, -k); RETURN $);
   mn := eightBitMask;

   TEST EightBitsOrFewer(k&~m) THEN
      GenF1K(f.add, r, s, k)
   ELSE TEST EightBitsOrFewer((-k)&~mn) THEN
      GenF1K(f.sub, r, s, -k)
   ELSE TEST r~=s THEN $(
      SetRtoK(r, k);
      GenRR(f.add, r, r, s) $)
   ELSE $(
      SetRtoK(r.0, k);
      r0Offset := Null;
      GenRR(f.add, r, r, r.0) $)
$)

AND SetRtoK(r, k) BE
$( LET m = ?;
   eightBitMask := 255;
   IF EightBitsOrFewer(k) THEN $(
      GenF1K(f.mov, r, 0, k); RETURN $);
   m := eightBitMask;

   TEST EightBitsOrFewer(~k) THEN
      GenF1K(f.mvn, r, 0, ~k)
   ELSE TEST EightBitsOrFewer(k&~m) THEN $(
      GenF1K(f.mov, r, 0, k&m)
      GenF1K(f.add, r, r, k&~m) $)
   ELSE TEST GlobalConstant(k)~=0 THEN
      GenF2(f.ldr, r, r.g, 0, GlobalConstant(k))
   ELSE TEST usesRL THEN $(
      CheckRLLoaded();
      GenF2(f.ldr, r, r.l, 0, staticDataSize+Fdata(k)) $)
   ELSE
      GenF2(f.ldr, r, r.pc, LocalConstLab, Fdata(k))
$)

AND GenF(f, r, x) BE
   GenFDS(f, r, r, x)

AND GenFDS(f, r, s, x) BE
$( LET n, k = h3!x, h4!x;
   IF f~=f.cmps & f~=f.cmns THEN
      FlushPendingUsesOfReg(r);
   Lock(r, k.reg); Lock(s, k.reg);
   SWITCHON Class(x, TRUE) INTO
   $( CASE shiftedrtype:
	 F1Inst(f, r, s, n, Null, k/32, k REM 32, m.always);
	 ENDCASE

      CASE lockedrtype:
	 IF k=0 & h2!x<0 THEN $(
	    GenRR(f, r, s, n);
	    ENDCASE $)

      CASE rtype:
	 $( LET r2 = k=0 -> MoveToAnyCR(x),
			    MoveToAnyR(x);
	    GenRR(f, r, s, r2) $);
	 ENDCASE

      CASE ktype:
	 GenF1K(f, r, s, n+k);
	 ENDCASE

      DEFAULT:
	 CompileDS(f, r, s, x) $);

   UnLock(r, k.reg); UnLock(s, k.reg)
$)

AND InsertCount(sr) BE
$( countFlag := FALSE;
   TEST sr=sr.entrycount
      THEN SetRtoRplusK(r.pc, r.gb, sr)
      ELSE F5InstL(m.always, countLabel, f.bl);

   PutWord(0)
$)

AND EightBitsOrFewer(n) = VALOF
$( LET bits = 0;
   eightBitMask := 255;
   TEST n=0
      THEN RESULTIS TRUE
   ELSE TEST (n&3)=0 THEN $(
      WHILE (n&3)=0 DO $(
	 n := n>>2;
	 eightBitMask := eightBitMask<<2 $);
      RESULTIS 0<n<256 $)
   ELSE $(
      WHILE (n&#xc0000000)~=0 DO $(
	 IF bits=8 THEN RESULTIS FALSE;
	 n := n<<2;
	 eightBitMask := (eightBitMask>>2)|#xc0000000;
	 bits := bits+2 $);
      RESULTIS 0<n<256 $)
$)

AND ShiftRegisterDS(r, s, sh, n) BE
   F1Inst(f.mov, r, 0, s, 0, sh, n, m.always)

AND ShiftRegister(r, sh, n) BE
   F1Inst(f.mov, r, 0, r, 0, sh, n, m.always)

AND MaskOutTagBits(r) BE
   F1Inst(f.bic, r, r, Null, #xff000000, sh.asl, 0, m.always)

AND TransferredLabel(l) = l=0 -> 0, VALOF
$( LET p = Assoc(l, 1, transferLabs);
   IF p=Null THEN RESULTIS l;
   l := 2!p
$) REPEAT

AND Jump(l) BE
   IF deadCode~=Dead THEN $(
      IF l~=0 THEN l := TransferredLabel(l);
      TEST l=0 THEN
	 TEST usesFrame & ~linkageNotStored THEN
	    TEST compactCode THEN
	       CondJump(m.always, exitLab)
	    ELSE $(
	       GenRR(f.mov, r.ts, 0, r.p);
	       F4Inst(f.ldm, r.p, f4.pblpc, f.postup+f.pc) $)
	 ELSE GenRR(f.movs, r.pc, 0, r.14)

      ELSE $(
	 SaveStateForLab(l);
	 pendingJump := l $) $)

AND CondJump(m, l) BE CondJump2(m, l, TRUE)

AND CondJump2(m, l, updateSavedState) BE
$( IF l~=0 THEN l := TransferredLabel(l);
   TEST l=0 THEN
      TEST usesFrame & ~linkageNotStored THEN
	 F5InstL(m, exitLab, f.b)
      ELSE TEST pendingLab~=Null &
		m=ComplementCondition(pendingMask) &
		pendingCount<PendingBufferSize THEN
	 F1Inst(f.movs, r.pc, 0, r.14, 0, Null, 0, m.always)
      ELSE
	 F1Inst(f.movs, r.pc, 0, r.14, 0, Null, 0, m)
   ELSE $(
      IF updateSavedState THEN SaveStateForLab(l);
      F5InstL(m, l, f.b) $)
$)

AND F5InstL(m, l, f) BE
$( LET n = ValueOfLabel(l);
   TEST m~=m.always THEN $(
      TEST pendingMask=m & l=pendingLab THEN
	 FlushPendingInsts(m, FALSE)
      ELSE TEST pendingLab~=Null &
		m=ComplementCondition(pendingMask) &
		pendingCount<PendingBufferSize &
		PeekN() = s.lab THEN $(
	 AddPendingInst(pi.F5InstLM, l, f, m);
	 RETURN $)
      ELSE
	 FlushPendingInsts(Null, FALSE);

      IF n<0 THEN $(
	 pendingLab, pendingMask := l, m;
	 pendingCount := 0;
	 RETURN $) $)

   ELSE IF pendingLab~=Null THEN
      TEST pendingCount<PendingBufferSize THEN $(
	 AddPendingInst(pi.F5InstL, l, f);
	 RETURN $)
      ELSE
	 FlushPendingInsts(Null, FALSE);

   F5InstL2(l, f, m)
$)

AND F5InstL2(l, f, m) BE
$( LET n = ValueOfLabel(l);
   FlagLabel(l, lab.jumpedto);
   TEST n<0 THEN $(
      AddRef(locCtr, 5, l);
      F5Inst(f, 0, m) $)
   ELSE
      F5Inst(f, n, m)
$)

AND MultiplyInst(fn, rd, rm, rs, rn) BE
   F4Inst(fn, rd, rm+#x90+(rs<<8)+(fn=f.mla->rn, 0), 0)

AND CheckDelayedJump() BE
   IF pendingJump~=0 THEN $(
      LET d = deadCode;
      deadCode := Alive;
      CondJump2(m.always, pendingJump, FALSE);
      pendingJump := 0;
      deadCode := d $)

AND GlobalConstant(n) = VALOF
$( // See whether n is a constant addressible through
   // (negative offsets from) rg, returning the offset
   // if so.  Currently, there are none such
   RESULTIS 0
$)
