home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 2
/
goldfish_vol2_cd1.bin
/
files
/
dev
/
obero
/
oberon-a
/
source
/
oc
/
och.mod
< prev
next >
Wrap
Text File
|
1994-08-08
|
58KB
|
1,822 lines
(***************************************************************************
$RCSfile: OCH.mod $
Description: Code selection for statements
Created by: fjc (Frank Copeland)
$Revision: 4.11 $
$Author: fjc $
$Date: 1994/08/03 11:47:56 $
Copyright © 1990-1993, ETH Zuerich
Copyright © 1993-1994, Frank Copeland
This module forms part of the OC program
See OC.doc for conditions of use and distribution
Log entries are at the end of the file.
***************************************************************************)
MODULE OCH;
(*
** $C= CaseChk $I= IndexChk $L+ LongAdr $N= NilChk
** $P- PortableCode $R= RangeChk $S= StackChk $T= TypeChk
** $V= OvflChk $Z= ZeroVars
*)
IMPORT SYS := SYSTEM, OCG, OCS, OCT, OCC, OCI, OCE;
(* --- Exported declarations -------------------------------------------- *)
TYPE
LabelRange * = RECORD
low *, high * : LONGINT; label * : INTEGER
END; (* LabelRange *)
(* --- Local declarations ----------------------------------------------- *)
CONST
(* Symbols *)
null = OCS.null; times = OCS.times; slash = OCS.slash; div = OCS.div;
mod = OCS.mod; and = OCS.and; plus = OCS.plus; minus = OCS.minus;
or = OCS.or; eql = OCS.eql; neq = OCS.neq; lss = OCS.lss;
leq = OCS.leq; gtr = OCS.gtr; geq = OCS.geq; not = OCS.not;
(* object modes *)
Var = OCG.Var; VarX = OCG.VarX; VarR = OCG.VarR; Ind = OCG.Ind;
IndX = OCG.IndX; IndR = OCG.IndR; RegI = OCG.RegI; RegX = OCG.RegX;
Lab = OCG.Lab; LabI = OCG.LabI; Abs = OCG.Abs; Con = OCG.Con;
Push = OCG.Push; Pop = OCG.Pop; Coc = OCG.Coc; Reg = OCG.Reg;
Fld = OCG.Fld; LProc = OCG.LProc; XProc = OCG.XProc; TProc = OCG.TProc;
FProc = OCG.FProc; Mod = OCG.Mod; LibCall = OCG.LibCall;
RList = OCG.RList; VarArgMode = OCG.VarArg;
regSet = {VarR, IndR, Reg};
(* structure forms *)
Undef = OCT.Undef; Byte = OCT.Byte; Bool = OCT.Bool; Char = OCT.Char;
SInt = OCT.SInt; Int = OCT.Int; LInt = OCT.LInt; Real = OCT.Real;
LReal = OCT.LReal; Set = OCT.Set; String = OCT.String;
NilTyp = OCT.NilTyp; NoTyp = OCT.NoTyp; Pointer = OCT.Pointer;
ProcTyp = OCT.ProcTyp; Array = OCT.Array; DynArr = OCT.DynArr;
Record = OCT.Record; BPointer = OCT.BPointer; CPointer = OCT.CPointer;
BSet = OCT.BSet; WSet = OCT.WSet; PtrTyp = OCT.PtrTyp;
CPtrTyp = OCT.CPtrTyp; BPtrTyp = OCT.BPtrTyp; Word = OCT.Word;
Longword = OCT.Longword; TagTyp = OCT.TagTyp;
caseSet = {Char, SInt, Int, LInt};
ptrSet = {Pointer, CPointer, BPointer};
uptrSet = {CPointer, BPointer};
intSet = {SInt, Int, LInt};
byteSet = {Undef, Bool, Byte, Char, SInt, BSet};
wordSet = {Int, WSet, Word};
lwordSet =
{ LInt, Real, LReal, Set, NilTyp, Pointer, ProcTyp, BPointer, CPointer,
PtrTyp, CPtrTyp, BPtrTyp, Longword };
(* CPU Registers *)
D0 = 0; D1 = 1; D2 = 2; D7 = 7;
A0 = 8; A1 = 9; A2 = 10; A3 = 11; A4 = 12; A5 = 13; A6 = 14; A7 = 15;
BP = A4; FP = A5; SP = A7;
DataRegs = {D0 .. D7};
AdrRegs = {A0 .. A7};
(* Data sizes *)
B = 1; W = 2; L = 4;
VAR
returnFound : BOOLEAN;
(* CONST mname = "OCH"; *)
(* --- Procedure declarations ------------------------------------------- *)
(*------------------------------------*)
PROCEDURE setCC (VAR x : OCT.Item; cc : LONGINT);
BEGIN (* setCC *)
x.typ := OCT.booltyp; x.mode := Coc; x.a0 := cc; x.a1 := 0; x.a2 := 0
END setCC;
(*------------------------------------*)
PROCEDURE FJ * (VAR loc : INTEGER);
(* CONST pname = "FJ"; *)
BEGIN (* FJ *)
(* OCG.TraceIn (mname, pname); *)
OCC.PutWord (OCC.BRA); OCC.PutWord (loc); loc := OCC.pc - 2
(* ;OCG.TraceOut (mname, pname); *)
END FJ;
(*------------------------------------*)
PROCEDURE CFJ * (VAR x : OCT.Item; VAR loc : INTEGER);
(* CONST pname = "CFJ"; *)
VAR op : INTEGER;
BEGIN (* CFJ *)
(* OCG.TraceIn (mname, pname); *)
IF x.typ.form = Bool THEN
IF x.mode = Con THEN
IF x.a0 = 0 THEN setCC (x, OCC.F) ELSE setCC (x, OCC.T) END
ELSIF x.mode # Coc THEN
OCC.PutF1 (OCC.TST, B, x); OCI.Unload (x); setCC (x, OCC.NE)
END
ELSE
OCS.Mark (120); setCC (x, OCC.EQ)
END;
IF x.a0 # OCC.T THEN
IF x.a0 = OCC.F THEN op := OCC.BRA
ELSE op := OCC.Bcc + (OCC.invertedCC (x.a0) * 100H);
END;
OCC.PutWord (op); OCC.PutWord (x.a2); loc := OCC.pc - 2
ELSE
loc := x.a2
END;
OCC.FixLink (x.a1)
(* ;OCG.TraceOut (mname, pname); *)
END CFJ;
(*------------------------------------*)
PROCEDURE BJ * (loc : INTEGER);
(* CONST pname = "BJ"; *)
VAR dest : INTEGER;
BEGIN (* BJ *)
(* OCG.TraceIn (mname, pname); *)
dest := loc - OCC.pc - 2;
IF dest < -128 THEN OCC.PutWord (OCC.BRA); OCC.PutWord (dest)
ELSE OCC.PutWord (SYS.LOR (OCC.BRA, SYS.AND (dest, 0FFH)))
END
(* ;OCG.TraceOut (mname, pname); *)
END BJ;
(*------------------------------------*)
PROCEDURE CBJ * (VAR x : OCT.Item; loc : INTEGER);
(* CONST pname = "CBJ"; *)
VAR op, dest : INTEGER;
BEGIN (* CBJ *)
(* OCG.TraceIn (mname, pname); *)
IF x.typ.form = Bool THEN
IF x.mode = Con THEN
IF x.a0 = 0 THEN setCC (x, OCC.F) ELSE setCC (x, OCC.T) END
ELSIF x.mode # Coc THEN
OCC.PutF1 (OCC.TST, B, x); OCI.Unload (x); setCC (x, OCC.NE)
END
ELSE
OCS.Mark (120); setCC (x, OCC.EQ)
END;
IF x.a0 # OCC.T THEN
IF x.a0 = OCC.F THEN op := OCC.BRA
ELSE op := OCC.Bcc + (OCC.invertedCC (x.a0) * 100H);
END;
dest := loc - OCC.pc - 2;
IF dest < -128 THEN OCC.PutWord (op); OCC.PutWord (dest)
ELSE OCC.PutWord (SYS.LOR (op, SYS.AND (dest, 0FFH)))
END
END;
OCC.FixLinkWith (x.a2, loc); OCC.FixLink (x.a1)
(* ;OCG.TraceOut (mname, pname); *)
END CBJ;
(*------------------------------------*)
PROCEDURE ModulePrologue * ();
(* CONST pname = "ModulePrologue"; *)
VAR rc1, rc2 : OCT.Item;
BEGIN (* ModulePrologue *)
(* OCG.TraceIn (mname, pname); *)
OCC.StartPrologue ();
(* Save initial stack pointer *)
OCC.PutWord (2C4FH); (* MOVE.L A7, A6 *)
(* Call OberonSys initialisation code *)
OCC.PutWord (4EB9H);
OCC.PutLongRef (0, OCT.OberonSysINIT); (* JSR OberonSysINIT *)
(* Branch to module initialisation code *)
OCC.PutWord (OCC.BSR);
OCC.PutWordRef (0, OCT.InitSymbol); (* BSR InitSymbol *)
(* Set return code to 0 (clean exit) *)
rc1.mode := Con; rc1.a0 := 0; rc1.typ := OCT.linttyp;
rc2.mode := Lab; rc2.a0 := OCT.returnCode; rc2.a1 := 4;
rc2.typ := OCT.linttyp; rc2.symbol := OCT.OberonSysVAR;
OCC.Move (L, rc1, rc2); (* MOVE.L #0,OberonSys.returnCode *)
(* Jump to final cleanup code *)
OCC.PutWord (4EF9H);
OCC.PutLongRef (0, OCT.OberonSysCLEANUP); (* JMP OberonSysCLEANUP *)
OCC.EndCodeHunk ()
(* ;OCG.TraceOut (mname, pname); *)
END ModulePrologue;
(*------------------------------------*)
PROCEDURE StartProcedure * (proc : OCT.Object);
(* CONST pname = "StartProcedure"; *)
BEGIN (* StartProcedure *)
(* OCG.TraceIn (mname, pname); *)
IF OCC.level = 1 THEN OCC.StartCodeHunk (FALSE) END
(* ;OCG.TraceOut (mname, pname); *)
END StartProcedure;
(*------------------------------------*)
PROCEDURE LoadBP (saveBP : BOOLEAN);
(* CONST pname = "LoadBP"; *)
BEGIN (* LoadBP *)
(* OCG.TraceIn (mname, pname); *)
IF saveBP THEN OCC.PutWord (2F0CH) END; (* MOVE.L BP,-(SP) *)
OCC.PutWord (49F9H);
OCC.PutLongRef (0, OCT.VarSymbol) (* LEA Module_VAR, BP *)
(* ;OCG.TraceOut (mname, pname); *)
END LoadBP;
(*------------------------------------*)
PROCEDURE CopyDynArray (adr : LONGINT; typ : OCT.Struct; dsize : LONGINT);
(* CONST pname = "CopyDynArray"; *)
VAR size, len, desc, ptr1, ptr2, tos, x : OCT.Item;
moveSize : INTEGER; moveWords, oddSize : BOOLEAN; R : SET;
(*------------------------------------*)
PROCEDURE DynArrSize (typ : OCT.Struct);
(* CONST pname = "DynArrSize"; *)
BEGIN (* DynArrSize *)
(* OCG.TraceIn (mname, pname); *)
IF typ.form = DynArr THEN
DynArrSize (typ.BaseTyp);
IF len.mode = Undef THEN
desc.mode := Var; desc.lev := OCC.level; desc.a0 := adr + typ.adr;
len.mode := Reg; len.a0 := D0; OCC.Move (L, desc, len);
desc.typ := OCT.linttyp; len.typ := OCT.linttyp
ELSE
IF desc.mode = Var THEN desc.a0 := adr + typ.adr;
ELSE desc.a1 := adr + typ.adr;
END;
OCE.Op (times, len, desc, TRUE)
END
ELSE
size.mode := Con; size.typ := OCT.linttyp; size.a0 := typ.size
END
(* ;OCG.TraceOut (mname, pname); *)
END DynArrSize;
BEGIN (* CopyDynArray *)
(* OCG.TraceIn (mname, pname); *)
IF OCS.saveRegs OR OCS.saveAllRegs THEN OCS.Mark (345) END;
R := OCC.RegSet; len.mode := Undef;
(* load total length of dyn array *)
DynArrSize (typ);
(* calculate size in bytes *)
oddSize := ODD (size.a0);
moveWords := ~oddSize & ((size.a0 MOD 4) # 0);
IF size.a0 > 1 THEN
OCE.Op (times, len, size, FALSE)
END;
IF oddSize THEN
x.mode := Con; x.a0 := 0; x.typ := OCT.inttyp;
OCC.Bit (OCC.BTST, x, len); (* BTST #0, <len> *)
OCC.PutWord (6702H); (* BEQ.S 1$ *)
OCC.PutF7 (OCC.ADDQ, L, 1, len) (* ADDQ.L #1, <len> *)
END; (* 1$ *)
size := len;
IF OCS.stackCheck THEN
x.mode := Lab; x.a0 := 0; x.a1 := 4; x.symbol := OCT.OberonSysSTACKCHK;
OCC.PutF3 (OCC.JSR, x) (* JSR STACKCHK *)
END;
(* adjust stack pointer *)
tos.mode := Reg; tos.a0 := SP;
OCC.PutF5 (OCC.SUB, L, size, tos); (* SUBA.L <size>, A7 *)
(* decrement counter *)
x.mode := Con; x.typ := OCT.inttyp;
IF ~oddSize THEN
(* adjust counter for copy loop *)
IF moveWords THEN x.a0 := 1 ELSE x.a0 := 2 END;
OCC.Shift (OCC.ASR, L, x, size); (* ASR.L #?, <size> *)
END;
OCC.PutF7 (OCC.SUBQ, L, 1, size); (* SUBQ.L #1, <size> *)
ptr1.mode := Ind; ptr1.a0 := adr; ptr1.a1 := 0; ptr1.a2 := -1;
ptr1.lev := OCC.level; ptr1.typ := OCT.notyp;
x := ptr1; x.mode := Var;
OCI.LoadAdr (ptr1); ptr1.mode := Pop; (* LEA adr(A5), An *)
OCC.Move (L, tos, x); (* MOVE.L A7, adr(A5) *)
OCC.GetAReg (ptr2); OCC.Move (L, tos, ptr2); (* MOVE.L A7, Am *)
ptr2.mode := Pop;
IF oddSize THEN moveSize := B
ELSIF moveWords THEN moveSize := W
ELSE moveSize := L
END;
OCC.Move (moveSize, ptr1, ptr2); (* 2$ MOVE.? (An)+,(Am)+ *)
OCC.PutWord (OCC.DBF + SHORT (size.a0));
OCC.PutWord (-4); (* DBF <size>, 2$ *)
OCC.FreeRegs (R)
(* ;OCG.TraceOut (mname, pname); *)
END CopyDynArray;
(*------------------------------------*)
PROCEDURE StartProcBody * (proc : OCT.Object; dsize : LONGINT);
(* CONST pname = "StartProcBody"; *)
CONST
(* Register numbers in *reverse* order. *)
D0 = 15; D1 = 14; D2 = 13; D7 = 8;
A0 = 7; A1 = 6; A2 = 5; A4 = 3; A5 = 2; A6 = 1;
VAR
par : OCT.Object; x, y : OCT.Item; count : LONGINT;
usesA4, usesA5 : BOOLEAN; savedRegs : SET;
BEGIN (* StartProcBody *)
(* OCG.TraceIn (mname, pname); *)
(*proc.a1 := OCC.pc;*)
OCC.StartProcedure (proc);
IF OCS.stackCheck THEN
IF OCS.saveAllRegs THEN OCC.PutWord (2F00H) END; (* MOVE.L D0,-(A7) *)
x.mode := Con; x.a0 := dsize; x.typ := OCT.linttyp;
y.mode := Reg; y.a0 := 0; (* D0 *)
OCC.Move (L, x, y);
x.mode := Lab; x.a0 := 0; x.a1 := 4; x.symbol := OCT.OberonSysSTACKCHK;
OCC.PutF3 (OCC.JSR, x);
IF OCS.saveAllRegs THEN OCC.PutWord (201FH) END; (* MOVE.L (A7)+,D0 *)
END;
usesA4 := ((proc.mode = XProc)
OR ((proc.mode = TProc) & (proc.visible = OCT.Exp)))
& ~OCS.longVars;
usesA5 := (OCC.level # 1) OR (dsize # 0) OR OCI.IsParam (proc.link);
IF usesA4 THEN LoadBP (TRUE) END;
IF usesA5 THEN
IF (dsize > 0) & OCS.zeroVars THEN
OCC.PutWord (4E55H); OCC.PutWord (0); (* LINK A5,#0 *)
(* Clear all procedure variables. *)
count := dsize DIV 4; (* clear longwords initially *)
IF count > 0 THEN
IF count < 5 THEN (* inline the loop *)
WHILE count > 0 DO
OCC.PutWord (42A7H); (* CLR.L -(A7) *)
DEC (count)
END;
ELSE
IF OCS.saveAllRegs THEN OCC.PutWord (2F00H) (* MOVE.L D0,-(A7) *)
END;
OCC.PutWord (303CH);
OCC.PutWord (SHORT (count) - 1); (* MOVE.W #count-1,D0 *)
OCC.PutWord (42A7H); (* 1$ CLR.L -(A7) *)
OCC.PutWord (OCC.DBF);
OCC.PutWord (-4); (* DBF.W D0,1$ *)
IF OCS.saveAllRegs THEN OCC.PutWord (201FH) (* MOVE.L (A7)+,D0 *)
END;
END
END;
IF (dsize MOD 4) # 0 THEN (* Assuming dsize is a multiple of 2 *)
OCC.PutWord (4267H) (* CLR.W -(A7) *)
END
ELSE
OCC.PutWord (4E55H);
OCC.PutWord (-SHORT (dsize)) (* LINK A5,#<-dsize> *)
END
END; (* IF *)
IF OCS.saveRegs OR OCS.saveAllRegs THEN
savedRegs := {A6..A2,D7..D2};
IF OCS.saveAllRegs THEN savedRegs := savedRegs + {A0,A1,D0,D1} END;
IF usesA4 THEN EXCL (savedRegs, A4) END;
IF usesA5 THEN EXCL (savedRegs, A5) END;
OCC.PutWord (48E7H); (* MOVEM.L savedRegs,-(A7) *)
OCC.PutWord (SYS.VAL (INTEGER, SHORT (savedRegs)))
END;
IF OCS.copyDynArray THEN
par := proc.link;
WHILE par # NIL DO
(* code for dynamic array value parameters *)
IF (par.typ.form = DynArr) & (par.mode = Var) THEN
CopyDynArray (par.a0, par.typ, dsize)
END;
par := par.link
END
END;
returnFound := FALSE
(* ;OCG.TraceOut (mname, pname); *)
END StartProcBody;
(*------------------------------------*)
PROCEDURE EndProcBody *
(proc : OCT.Object; psize, L0 : INTEGER; vars : BOOLEAN);
(* CONST pname = "EndProcBody"; *)
VAR op : OCT.Item; usesA4, usesA5 : BOOLEAN; savedRegs : SET;
BEGIN (* EndProcBody *)
(* OCG.TraceIn (mname, pname); *)
usesA4 := ((proc.mode = XProc)
OR ((proc.mode = TProc) & (proc.visible = OCT.Exp)))
& ~OCS.longVars;
usesA5 := (OCC.level # 1) OR vars OR OCI.IsParam (proc.link);
IF usesA4 THEN
(* Don't count return address, frame pointer or global var base *)
DEC (psize, 12)
ELSE
(* Don't count return address or frame pointer *)
DEC (psize, 8)
END;
(* Insert trap for missing RETURN in function procedures. *)
IF (proc.typ # OCT.notyp) & OCS.returnCheck THEN
IF returnFound THEN OCC.Trap (OCC.ReturnCheck)
ELSE OCS.Mark (335)
END
END;
OCC.FixLink (L0); (* Fix up RETURN branches *)
IF OCS.saveRegs OR OCS.saveAllRegs THEN
savedRegs := {D2..D7,A2..A6};
IF OCS.saveAllRegs THEN savedRegs := savedRegs + {D0,D1,A0,A1} END;
IF usesA4 THEN EXCL (savedRegs, A4) END;
IF usesA5 THEN EXCL (savedRegs, A5) END;
OCC.PutWord (4CDFH); (* MOVEM.L (A7)+,savedRegs *)
OCC.PutWord (SYS.VAL (INTEGER, SHORT (savedRegs)))
END;
IF usesA5 THEN OCC.PutWord (4E5DH) END; (* UNLK A5 *)
IF usesA4 THEN OCC.PutWord (285FH) END; (* MOVEA.L (A7)+, A4 *)
IF psize > 0 THEN
OCC.PutWord (2F57H); OCC.PutWord (psize); (* MOVE.L (SP),psize(SP) *)
IF psize <= 8 THEN
op.mode := Reg; op.a0 := SP;
OCC.PutF7 (OCC.ADDQ, L, psize, op) (* ADDQ #<psize>,SP *)
ELSE
OCC.PutWord (4FEFH); OCC.PutWord (psize) (* LEA psize(SP),SP *)
END
END;
OCC.PutWord (OCC.RTS);
IF OCC.level = 1 THEN OCC.EndCodeHunk () END
(* ;OCG.TraceOut (mname, pname); *)
END EndProcBody;
(*------------------------------------*)
PROCEDURE StartModuleBody * (VAR dsize : LONGINT; VAR L0 : INTEGER);
(* CONST pname = "StartModuleBody"; *)
VAR
op1, op2, op3 : OCT.Item; modno : INTEGER; module : OCT.Module;
count : LONGINT;
BEGIN (* StartModuleBody *)
(* OCG.TraceIn (mname, pname); *)
OCC.StartCodeHunk (TRUE);
IF ~OCS.longVars THEN LoadBP (FALSE) END;
(* Check if module already initialised *)
op1.mode := Var; op1.lev := 0; op1.a0 := dsize;
OCC.PutF1 (OCC.TST, B, op1);
(* If so, return *)
L0 := 0; op2.mode := Coc; op2.a0 := OCC.EQ; op2.a1 := 0; op2.a2 := 0;
op2.typ := OCT.booltyp; CFJ (op2, L0);
IF OCS.garbageCollect & OCC.GlobalPtrs () THEN
op1.mode := Lab; op1.a0 := OCT.GCVars; op1.a1 := 4;
op1.symbol := OCT.OberonSysVAR;
op2.mode := Lab; op2.a0 := 0; op2.a1 := 4; op2.symbol := OCT.GCSymbol;
OCC.Move (L, op1, op2);
op2.mode := LabI; OCC.Move (L, op2, op1)
END;
IF (dsize > 0) & OCS.zeroVars THEN
(* Clear all global variables. *)
OCC.GetAReg (op1);
IF OCS.longVars THEN
op2.mode := Lab; op2.a0 := 0; op2.a1 := 4;
op2.symbol := OCT.VarSymbol;
OCC.PutF2 (OCC.LEA, op2, op1.a0) (* LEA Module_VAR,An *)
ELSE
op2.mode := Reg; op2.a0 := BP;
OCC.Move (L, op2, op1) (* MOVE.L A4,An *)
END;
op1.mode := Pop; count := dsize DIV 4; (* clear longwords initially *)
IF count > 0 THEN
IF count < 5 THEN (* inline the loop *)
WHILE count > 0 DO OCC.PutF1 (OCC.CLR, L, op1); DEC (count) END;
ELSE
IF count > 65536 THEN OCS.Mark (312); count := 65536 END;
op3.mode := Con; op3.a0 := count - 1; op3.typ := OCT.inttyp;
OCC.GetDReg (op2);
OCC.Move (W, op3, op2); (* MOVE.W #count,Dn *)
OCC.PutF1 (OCC.CLR, L, op1); (* 1$ CLR.L (An)+ *)
OCC.PutWord (OCC.DBF + SHORT (op2.a0));
OCC.PutWord (-4); (* DBF.W Dn,1$ *)
OCC.FreeReg (op2)
END
END;
IF (dsize MOD 4) # 0 THEN (* Assuming dsize is a multiple of 2 *)
OCC.PutF1 (OCC.CLR, W, op1) (* CLR.W (An)+ *)
END;
OCC.FreeReg (op1)
END;
(* Set initialisation flag *)
op1.mode := Var; op1.lev := 0; op1.a0 := dsize; OCC.PutF3 (OCC.ST, op1);
(* Increment dsize to account for initFlag variable *)
INC (dsize, OCG.BoolSize); IF ODD (dsize) THEN INC (dsize) END;
IF OCT.nofGmod > 0 THEN
IF ~OCS.longVars THEN
(* Save variable base pointer *)
OCC.PutWord (2F0CH) (* MOVE.L BP,-(SP) *)
END;
(* Call init code of imported modules *)
op1.mode := Lab; op1.a0 := 0; op1.a1 := 4; modno := 0;
WHILE modno < OCT.nofGmod DO
module := OCT.GlbMod [modno];
IF module.visible = OCT.Exp THEN
op1.symbol := module.symbol; OCC.PutF3 (OCC.JSR, op1)
END;
INC (modno)
END;
IF ~OCS.longVars THEN
(* Restore variable base pointer *)
OCC.PutWord (285FH) (* MOVEA.L (A7)+, A4 *)
END
END
(* ;OCG.TraceOut (mname, pname); *)
END StartModuleBody;
(*------------------------------------*)
PROCEDURE EndModuleBody * (L0 : INTEGER);
(* CONST pname = "EndModuleBody"; *)
VAR op1, op2 : OCT.Item;
BEGIN (* EndModuleBody *)
(* OCG.TraceIn (mname, pname); *)
OCC.FixLink (L0);
OCC.PutWord (OCC.RTS);
OCC.EndCodeHunk ()
(* ;OCG.TraceOut (mname, pname); *)
END EndModuleBody;
(*------------------------------------*)
PROCEDURE CompareParLists * (x, y : OCT.Object);
(* CONST pname = "CompareParLists"; *)
VAR xt, yt : OCT.Struct;
BEGIN (* CompareParLists *)
(* OCG.TraceIn (mname, pname); *)
WHILE x # NIL DO
IF y # NIL THEN
xt := x.typ; yt := y.typ;
WHILE (xt.form = DynArr) & (yt.form = DynArr) DO
xt := xt.BaseTyp; yt := yt.BaseTyp
END;
IF x.mode # y.mode THEN
OCS.Mark (115)
ELSIF xt # yt THEN
IF (xt.form = ProcTyp) & (yt.form = ProcTyp) THEN
CompareParLists (xt.link, yt.link)
ELSE
OCS.Mark (115)
END
END;
y := y.link
ELSE
OCS.Mark (116)
END;
x := x.link
END; (* WHILE *)
IF (y # NIL) & (y.mode <= Ind) & (y.a0 >= 0) THEN OCS.Mark (117) END
(* ;OCG.TraceOut (mname, pname); *)
END CompareParLists;
(*------------------------------------*)
PROCEDURE Leng (VAR x : OCT.Item; L0 : LONGINT);
(* CONST pname = "Leng"; *)
VAR y : OCT.Item;
BEGIN (* Leng *)
(* OCG.TraceIn (mname, pname); *)
IF x.mode = Push THEN y.mode := Abs; y.a0 := L0; OCC.PutF3 (OCC.PEA, y)
ELSE y.mode := Con; y.a0 := L0; y.typ := OCT.linttyp; OCC.Move (L, y, x)
END
(* ;OCG.TraceOut (mname, pname); *)
END Leng;
(*------------------------------------*)
PROCEDURE DynArrBnd (
ftyp : OCT.Struct; VAR ap : OCT.Item; varpar : BOOLEAN);
(* CONST pname = "DynArrBnd"; *)
VAR
f : INTEGER; x, y, z, desc : OCT.Item; atyp : OCT.Struct;
adr : LONGINT; freeY : BOOLEAN;
BEGIN (* DynArrBnd *)
(* OCG.TraceIn (mname, pname); *)
(* ftyp.form = DynArr *)
x.mode := Push; x.a0 := SP; atyp := ap.typ;
IF varpar & (ftyp.BaseTyp = OCT.bytetyp) THEN
IF atyp.form # DynArr THEN Leng (x, atyp.size)
ELSE
adr := atyp.adr; OCI.DescItem (desc, ap.desc, adr);
atyp := atyp.BaseTyp; freeY := FALSE;
IF atyp.form = DynArr THEN
OCC.GetDReg (y); OCC.Move (L, desc, y);
OCI.UpdateDesc (desc, adr); freeY := TRUE;
y.typ := OCT.linttyp;
REPEAT
OCI.DescItem (desc, ap.desc, atyp.adr);
OCE.Op (times, y, desc, FALSE);
atyp := atyp.BaseTyp
UNTIL atyp.form # DynArr;
ELSE
y := desc
END;
IF atyp.size > 1 THEN
z.mode := Con; z.a0 := atyp.size; z.typ := OCT.linttyp;
OCE.Op (times, y, z, FALSE)
END;
OCC.Move (L, y, x);
IF freeY THEN OCI.Unload (y) ELSE OCI.UnloadDesc (ap) END
END
ELSE
desc.mode := Undef;
LOOP
f := atyp.form;
IF f = Array THEN Leng (x, atyp.n)
ELSIF f = DynArr THEN
OCI.DescItem (desc, ap.desc, atyp.adr);
OCC.Move (L, desc, x); OCI.UpdateDesc (desc, atyp.adr)
ELSE OCS.Mark (66)
END;
ftyp := ftyp.BaseTyp; atyp := atyp.BaseTyp;
IF ftyp.form # DynArr THEN
IF ftyp # atyp THEN OCS.Mark (67) END;
EXIT
END
END; (* LOOP *)
OCI.UnloadDesc (ap)
END
(* ;OCG.TraceOut (mname, pname); *)
END DynArrBnd;
(*------------------------------------*)
PROCEDURE ExtendStack (size : LONGINT);
VAR sp, x : OCT.Item;
BEGIN (* ExtendStack *)
sp.mode := Reg; sp.a0 := SP;
IF ODD (size) THEN INC (size) END;
IF size <= 8 THEN
OCC.PutF7 (OCC.SUBQ, L, size, sp)
ELSE
x.mode := RegI; x.a0 := SP; x.a1 := -size;
OCC.PutF2 (OCC.LEA, x, sp.a0)
END
END ExtendStack;
(*------------------------------------*)
PROCEDURE moveBW (VAR src, dst : OCT.Item; extend : BOOLEAN);
(* CONST pname = "moveBW"; *)
VAR x, zero : OCT.Item;
BEGIN (* moveBW *)
(* OCG.TraceIn (mname, pname); *)
IF src.mode = Con THEN
OCC.Move (W, src, dst)
ELSE
IF ~extend THEN
zero.mode := Con; zero.a0 := 0; zero.typ := OCT.wordtyp;
END;
IF (dst.mode IN regSet) & (dst.a0 IN DataRegs) THEN
IF ~extend THEN OCC.Move (W, zero, dst) END;
OCC.Move (B, src, dst);
IF extend THEN OCI.EXT (W, dst.a0) END
ELSE
IF extend THEN
OCI.Load (src); OCI.EXT (W, src.a0)
ELSE
x := src; OCC.GetDReg (src);
OCC.Move (W, zero, src); OCC.Move (B, x, dst); OCI.Unload (x)
END;
OCC.Move (W, src, dst)
END
END
(* ;OCG.TraceOut (mname, pname); *)
END moveBW;
(*------------------------------------*)
PROCEDURE moveBL (VAR src, dst : OCT.Item; extend : BOOLEAN);
(* CONST pname = "moveBL"; *)
VAR x, zero : OCT.Item;
BEGIN (* moveBL *)
(* OCG.TraceIn (mname, pname); *)
IF src.mode = Con THEN
OCC.Move (L, src, dst)
ELSE
IF ~extend THEN
zero.mode := Con; zero.a0 := 0; zero.typ := OCT.wordtyp;
END;
IF (dst.mode IN regSet) & (dst.a0 IN DataRegs) THEN
IF ~extend THEN OCC.Move (L, zero, dst) END;
OCC.Move (B, src, dst);
IF extend THEN OCI.EXT (W, dst.a0); OCI.EXT (L, dst.a0) END
ELSE
IF extend THEN
OCI.Load (src); OCI.EXT (W, src.a0); OCI.EXT (L, src.a0)
ELSE
x := src; OCC.GetDReg (src);
OCC.Move (L, zero, src); OCC.Move (B, x, src); OCI.Unload (x)
END;
OCC.Move (L, src, dst)
END
END
(* ;OCG.TraceOut (mname, pname); *)
END moveBL;
(*------------------------------------*)
PROCEDURE moveWL (VAR src, dst : OCT.Item; extend : BOOLEAN);
(* CONST pname = "moveWL"; *)
VAR x, zero : OCT.Item;
BEGIN (* moveWL *)
(* OCG.TraceIn (mname, pname); *)
IF src.mode = Con THEN
OCC.Move (L, src, dst)
ELSE
IF ~extend THEN
zero.mode := Con; zero.a0 := 0; zero.typ := OCT.wordtyp;
END;
IF (dst.mode IN regSet) & (dst.a0 IN DataRegs) THEN
IF ~extend THEN OCC.Move (L, zero, dst) END;
OCC.Move (W, src, dst);
IF extend THEN OCI.EXT (L, dst.a0) END
ELSE
IF extend THEN
OCI.Load (src); OCI.EXT (L, src.a0)
ELSE
x := src; OCC.GetDReg (src);
OCC.Move (L, zero, src); OCC.Move (W, x, src); OCI.Unload (x)
END;
OCC.Move (L, src, dst)
END
END
(* ;OCG.TraceOut (mname, pname); *)
END moveWL;
(*------------------------------------*)
(*
Moves size bytes from src to dst.
*)
PROCEDURE moveBlock (VAR src, dst : OCT.Item; size : LONGINT);
(* CONST pname = "moveBlock"; *)
VAR
x, y : OCT.Item; numRegs, i, s : INTEGER; lw : LONGINT; R : SET;
useMOVEM, freeDst : BOOLEAN;
BEGIN (* moveBlock *)
(* OCG.TraceIn (mname, pname); *)
freeDst := FALSE;
(* size must be even, but it may be zero *)
IF ODD (size) THEN OCS.Mark (957); INC (size) END;
IF size = 2 THEN OCC.Move (W, src, dst)
ELSIF size = 4 THEN OCC.Move (L, src, dst)
ELSIF size > 0 THEN
R := {D0 .. D7} - OCC.RegSet; numRegs := 0; i := D0;
WHILE i <= D7 DO IF i IN R THEN INC (numRegs) END; INC (i) END;
IF (size MOD 4) = 2 THEN useMOVEM := ((numRegs * 2) >= size); s := W
ELSE useMOVEM := ((numRegs * 4) >= size); s := L
END;
IF useMOVEM THEN
(* Calculate which registers are needed *)
numRegs := SHORT (size DIV s); i := 0;
WHILE numRegs > 0 DO
WHILE ~(i IN R) DO INC (i) END;
INC (i); DEC (numRegs)
END;
(* Discard the rest *)
WHILE i <= D7 DO EXCL (R, i); INC (i) END;
(* Reserve the registers *)
OCC.RegSet := OCC.RegSet + R;
(* Finally ... *)
x.mode := RList; x.a0 := SYS.VAL (LONGINT, R);
OCC.Move (s, src, x); (* MOVEM.s <src>,Dx-Dy *)
OCC.Move (s, x, dst); (* MOVEM.s Dx-Dy,<dst> *)
(* Free registers. *)
OCC.RegSet := OCC.RegSet - R;
ELSE
OCI.LoadAdr (src); src.mode := Pop;
IF dst.mode = Push THEN
ExtendStack (size);
y.mode := Reg; y.a0 := dst.a0;
OCC.GetAReg (dst); OCC.Move (L, y, dst);
dst.mode := Pop; dst.a1 := 0;
freeDst := TRUE
ELSE OCI.LoadAdr (dst); dst.mode := Pop
END;
lw := size DIV 4;
IF lw > 65536 THEN
x.mode := Con; x.a0 := lw; x.typ := OCT.linttyp;
OCI.Load (x); (* MOVE.L #<size>,Dc *)
OCC.Move (L, src, dst); (* 1$ MOVE.L (As)+,(Ad)+ *)
OCC.PutF7 (OCC.SUBQ, L, 1, x); (* SUBQ.L #1,Dc *)
OCC.PutWord (66FAH); (* BNE 1$ *)
ELSIF lw > 1 THEN
IF lw > 32768 THEN DEC (lw, 65536) END;
x.mode := Con; x.a0 := lw - 1; x.typ := OCT.inttyp;
OCI.Load (x); (* MOVE.W #<size>,Dc *)
OCC.Move (L, src, dst); (* 1$ MOVE.L (As)+,(Ad)+ *)
OCC.PutWord (OCC.DBF + SHORT (x.a0));
OCC.PutWord (-4) (* DBF.W Dc, 1$ *)
ELSIF lw = 1 THEN
OCC.Move (L, src, dst)
END;
IF (size MOD 4) = 2 THEN OCC.Move (W, src, dst) END;
IF freeDst THEN OCC.FreeReg (dst) END
END
END
(* ;OCG.TraceOut (mname, pname); *)
END moveBlock;
(*------------------------------------*)
PROCEDURE Assign * (VAR dst, src : OCT.Item; param : BOOLEAN);
(* CONST pname = "Assign"; *)
VAR f, g, op, L0, reg : INTEGER; s, vsz : LONGINT;
y, z, tag, tdes : OCT.Item; p, q : OCT.Struct; R : SET;
freeDst : BOOLEAN;
(*------------------------------------*)
PROCEDURE IntToReal ();
(* CONST pname = "IntToReal"; *)
CONST SPFlt = -36;
VAR r0, base, br : OCT.Item; R : SET; f : INTEGER;
BEGIN (* IntToReal *)
(* OCG.TraceIn (mname, pname); *)
IF src.mode = Con THEN src.typ := OCT.linttyp END;
f := src.typ.form;
r0.mode := Reg; r0.a0 := D0; br.mode := Reg; br.a0 := A6;
base.mode := Lab; base.a0 := OCT.mathBase; base.a1 := 4;
base.symbol := OCT.OberonSysVAR;
OCC.LoadRegParams1 (R, src);
IF f = SInt THEN OCI.EXT (W, D0); f := Int END;
IF f = Int THEN OCI.EXT (L, D0) END;
OCC.Move (L, base, br);
br.mode := RegI; br.a1 := SPFlt; OCC.PutF3 (OCC.JSR, br);
OCC.RestoreRegisters (R, src);
OCC.Move (L, src, dst)
(* ;OCG.TraceOut (mname, pname); *)
END IntToReal;
BEGIN (* Assign *)
(* OCG.TraceIn (mname, pname); *)
IF dst.rdOnly THEN OCS.Mark (324) END;
f := dst.typ.form; g := src.typ.form;
IF dst.mode = Con THEN OCS.Mark (56) END;
CASE f OF
Undef :
|
Byte :
IF (g = String) & (src.a1 <= 2) THEN
src.a0 := src.a2; src.typ := OCT.chartyp; g := Char
END;
IF g IN byteSet THEN OCC.Move (B, src, dst)
ELSE OCS.Mark (113)
END
|
Word :
IF (g = String) & (src.a1 <= 2) THEN
src.a0 := src.a2; src.typ := OCT.chartyp; g := Char
END;
IF g IN wordSet THEN OCC.Move (W, src, dst)
ELSIF g IN byteSet THEN moveBW (src, dst, g = SInt)
ELSE OCS.Mark (113)
END
|
Longword :
IF (g = String) & (src.a1 <= 2) THEN
src.a0 := src.a2; src.typ := OCT.chartyp; g := Char
END;
IF g IN lwordSet THEN OCC.Move (L, src, dst)
ELSIF g IN wordSet THEN moveWL (src, dst, g = Int)
ELSIF g IN byteSet THEN moveBL (src, dst, g = SInt)
ELSE OCS.Mark (113)
END
|
Bool :
IF src.mode = Coc THEN
IF (dst.mode IN regSet) & (dst.a0 IN AdrRegs) THEN
y := dst; OCC.GetDReg (dst)
ELSE y.mode := Undef
END;
IF
((src.a1 = 0) & (src.a2 = 0)) OR (src.a0 IN {OCC.T, OCC.F})
THEN
op := OCC.Scc + (SHORT (src.a0) * 100H); OCC.PutF3 (op, dst)
ELSE
op := OCC.Bcc + (OCC.invertedCC (src.a0) * 100H);
OCC.PutWord (op); OCC.PutWord (src.a2); (* Bcc 1$ *)
src.a2 := OCC.pc - 2; OCC.FixLink (src.a1);
z := dst; OCC.PutF3 (OCC.ST, z); (* ST <dst> *)
L0 := OCC.pc; OCC.PutWord (6000H); (* BRA.S 2$ *)
OCC.FixLink (src.a2);
z := dst; OCC.PutF3 (OCC.SF, z); (* 1$ SF <dst> *)
OCC.PatchWord (L0, OCC.pc - L0 - 2); (* 2$ *)
END;
IF y.mode # Undef THEN
OCC.Move (L, dst, y); OCI.Unload (dst) (*OCI.Unload (y)*)
END
ELSIF g = Bool THEN
IF src.mode = Con THEN
IF (dst.mode IN regSet) & (dst.a0 IN AdrRegs) THEN
y := dst; OCC.GetDReg (dst)
ELSE y.mode := Undef
END;
IF src.a0 = 0 THEN op := OCC.SF ELSE op := OCC.ST END;
OCC.PutF3 (op, dst);
IF y.mode # Undef THEN
OCC.Move (L, dst, y); OCI.Unload (dst) (*OCI.Unload (y)*)
END
ELSE
OCC.Move (B, src, dst)
END
ELSE OCS.Mark (113)
END
|
Char, SInt :
IF (g = String) & (src.a1 <= 2) THEN
src.a0 := src.a2; src.typ := OCT.chartyp; g := Char
END;
IF (g = f) OR (g = Byte) THEN OCC.Move (B, src, dst)
ELSE OCS.Mark (113)
END
|
Int :
IF g IN {Int, Word} THEN OCC.Move (W, src, dst)
ELSIF g = SInt THEN moveBW (src, dst, TRUE)
ELSE OCS.Mark (113)
END
|
LInt :
IF g IN {LInt, Longword} THEN OCC.Move (L, src, dst)
ELSIF g = Int THEN moveWL (src, dst, TRUE)
ELSIF g = SInt THEN moveBL (src, dst, TRUE)
ELSE OCS.Mark (113)
END
|
BSet, WSet, Set :
IF g = f THEN OCC.Move (src.typ.size, src, dst)
ELSIF (g IN {BSet, WSet, Set}) & (src.mode = Con) THEN
IF (f = BSet) & ((src.a0 < -128) OR (src.a0 > 255)) THEN
OCS.Mark (113)
ELSIF (f = WSet) & ((src.a0 < -32768) OR (src.a0 > 65535)) THEN
OCS.Mark (113)
ELSE
OCC.Move (dst.typ.size, src, dst)
END
ELSE OCS.Mark (113)
END
|
Real :
IF g = Real THEN OCC.Move (L, src, dst)
ELSIF g IN intSet THEN IntToReal ()
ELSE OCS.Mark (113)
END
|
LReal :
IF g = LReal THEN OCC.Move (L, src, dst)
ELSIF g = Real THEN OCC.Move (L, src, dst)
ELSIF g IN intSet THEN IntToReal ()
ELSE OCS.Mark (113)
END
|
Pointer :
IF (dst.typ = src.typ) OR (g = NilTyp) THEN
p := dst.typ.BaseTyp;
IF p = NIL THEN OCS.Mark (966); HALT (966) END;
IF p.form = DynArr THEN
IF param THEN
IF g = NilTyp THEN
WHILE (p # NIL) & (p.form = DynArr) DO
OCC.Move (L, src, dst);
p := p.BaseTyp
END;
OCC.Move (L, src, dst);
ELSIF src.mode = RList THEN
ExtendStack (p.size); dst.mode := RegI; dst.a1 := 0;
OCC.Move (L, src, dst)
ELSE
IF src.mode IN {Ind, IndX, RegI, RegX} THEN
INC (src.a1, p.adr)
ELSE
INC (src.a0, p.adr)
END;
WHILE (p # NIL) & (p.form = DynArr) DO
OCC.Move (L, src, dst);
IF src.mode IN {Ind, IndX, RegI, RegX} THEN DEC (src.a1, 4)
ELSE DEC (src.a0, 4)
END;
p := p.BaseTyp
END;
OCC.Move (L, src, dst)
END
ELSE
IF g = NilTyp THEN
IF dst.mode = RList THEN
R := SYS.VAL (SET, dst.a0); reg := D0; dst.mode := Reg;
WHILE reg <= A7 DO
IF reg IN R THEN
dst.a0 := reg; OCC.Move (L, src, dst)
END;
INC (reg)
END
ELSE
WHILE (p # NIL) & (p.form = DynArr) DO
OCC.Move (L, src, dst);
IF dst.mode IN {Ind, IndX, RegI, RegX} THEN INC (dst.a1, 4)
ELSE INC (dst.a0, 4)
END;
p := p.BaseTyp
END;
OCC.Move (L, src, dst)
END
ELSIF (src.mode = RList) OR (dst.mode = RList) THEN
OCC.Move (L, src, dst)
ELSE
moveBlock (src, dst, dst.typ.size)
END
END;
ELSE OCC.Move (L, src, dst)
END
ELSIF g = Pointer THEN
p := dst.typ.BaseTyp; q := src.typ.BaseTyp;
IF (p.form = Record) & (q.form = Record) THEN
WHILE (q # p) & (q # NIL) DO q := q.BaseTyp END;
IF q # NIL THEN OCC.Move (L, src, dst)
ELSE OCS.Mark (113)
END
ELSE OCS.Mark (113)
END
ELSE OCS.Mark (113)
END
|
CPointer :
IF (dst.typ = src.typ) OR (g IN {CPtrTyp, NilTyp}) THEN
OCC.Move (L, src, dst)
ELSIF g = CPointer THEN
p := dst.typ.BaseTyp; q := src.typ.BaseTyp;
IF p = q THEN
OCC.Move (L, src, dst)
ELSIF (p.form = Record) & (q.form = Record) THEN
WHILE (q # p) & (q # NIL) DO q := q.BaseTyp END;
IF q # NIL THEN OCC.Move (L, src, dst)
ELSE OCS.Mark (113)
END
ELSE OCS.Mark (113)
END
ELSE OCS.Mark (113)
END
|
BPointer :
IF (dst.typ = src.typ) OR (g = NilTyp) THEN
OCC.Move (L, src, dst)
ELSE OCS.Mark (113)
END
|
PtrTyp :
IF (g IN {Pointer, PtrTyp, NilTyp}) THEN
OCC.Move (L, src, dst)
ELSE OCS.Mark (113)
END
|
CPtrTyp :
IF (g IN {CPointer, CPtrTyp, NilTyp}) THEN
OCC.Move (L, src, dst)
ELSE OCS.Mark (113)
END
|
BPtrTyp :
IF (g IN {BPointer, BPtrTyp, NilTyp}) THEN
OCC.Move (L, src, dst)
ELSE OCS.Mark (113)
END
|
Array :
IF ~(dst.mode IN ptrSet) THEN
IF dst.typ = src.typ THEN
moveBlock (src, dst, dst.typ.size)
ELSIF (g = String) & (dst.typ.BaseTyp = OCT.chartyp) THEN
freeDst := FALSE;
IF dst.mode = Push THEN
ExtendStack (dst.typ.size);
y.mode := Reg; y.a0 := dst.a0;
OCC.GetAReg (dst); OCC.Move (L, y, dst);
dst.mode := RegI; dst.a1 := 0;
freeDst := TRUE
END;
z.mode := Con; z.typ := OCT.inttyp; z.a0 := src.a1 - 1;
vsz := dst.typ.n - 1; IF z.a0 > vsz THEN OCS.Mark (114) END;
OCI.CopyString (src, dst, z);
IF freeDst THEN OCC.FreeReg (dst) END
ELSE
OCS.Mark (113)
END
ELSE
OCS.Mark (904)
END
|
DynArr :
IF param THEN (* formal parameter is open array *)
IF (dst.mode = VarR) OR (dst.mode = IndR) THEN
(* Register parameter, address only *)
IF
(dst.typ.BaseTyp = OCT.bytetyp)
OR ((g = String) & (dst.typ.BaseTyp.form = Char))
OR ((g IN {Array, DynArr})
& (src.typ.BaseTyp = dst.typ.BaseTyp))
THEN
IF (g = String) & (dst.typ.BaseTyp.form = Char) THEN
IF src.a1 = 2 THEN OCC.AllocStringFromChar (src) END;
IF src.a1 = 1 THEN (* Pass NIL for an empty string *)
src.mode := Con; src.a0 := 0;
OCC.Move (L, src, dst)
ELSE
OCI.MoveAdr (src, dst)
END
ELSE
OCI.MoveAdr (src, dst)
END;
ELSE
OCS.Mark (59)
END
ELSE
IF (g = String) & (dst.typ.BaseTyp.form = Char) THEN
Leng (dst, src.a1);
IF src.a1 < 3 THEN OCC.AllocStringFromChar (src) END
ELSIF src.mode >= Abs THEN
OCS.Mark (59)
ELSE
DynArrBnd (dst.typ, src, FALSE)
END;
IF (g = DynArr) OR (src.mode IN {Ind, IndX}) THEN
OCI.MoveAdr (src, dst)
ELSE
OCC.PutF3 (OCC.PEA, src)
END
END
ELSE
OCS.Mark (113)
END
|
Record :
IF (dst.mode IN regSet) (*& (src.typ.size > PtrSize)*) THEN
OCS.Mark (904)
ELSE
IF dst.typ # src.typ THEN
IF g = Record THEN
q := src.typ.BaseTyp;
WHILE (q # NIL) & (q # dst.typ) DO q := q.BaseTyp END;
IF q = NIL THEN OCS.Mark (113) END
ELSE
OCS.Mark (113)
END
END;
IF
OCS.typeCheck & ~param
& ( ( (dst.mode = Ind) OR (dst.mode = RegI))
& ((dst.obj = OCC.wasderef) & (dst.a2 = Pointer))
(* p^ := *)
OR (dst.mode = Ind) & (dst.obj # NIL) & (dst.obj # OCC.wasderef))
(* varpar := *)
THEN
R := OCC.RegSet; tag := dst;
IF dst.obj = OCC.wasderef THEN tag.a1 := -4
ELSE tag.mode := Var; INC (tag.a0, 4)
END;
tdes.mode := LabI; tdes.a0 := 0; tdes.a1 := 4;
tdes.symbol := dst.typ.symbol;
OCC.PutF5 (OCC.CMP, L, tdes, tag);
OCC.TrapCC (OCC.TypeCheck, OCC.NE);
OCC.FreeRegs (R)
END;
moveBlock (src, dst, dst.typ.size)
END
|
ProcTyp :
IF (dst.typ = src.typ) OR (g = NilTyp) THEN
OCC.Move (L, src, dst)
ELSIF src.mode = XProc THEN
(* procedure dest to proc. variable, check compatibility *)
IF dst.typ.BaseTyp = src.typ THEN
CompareParLists (dst.typ.link, src.obj.link);
OCI.MoveAdr (src, dst)
ELSE OCS.Mark (118)
END
ELSIF src.mode = LProc THEN OCS.Mark (119)
ELSIF src.mode = TProc THEN OCS.Mark (331)
ELSIF src.mode = FProc THEN OCS.Mark (341)
ELSE OCS.Mark (111)
END
|
TagTyp :
IF (f = g) OR (g = NilTyp) THEN
OCC.Move (L, src, dst)
ELSE
OCS.Mark (111)
END
|
NoTyp, NilTyp : OCS.Mark (111)
|
ELSE
OCS.Mark (1016); OCS.Mark (f)
END; (* CASE f *)
OCI.Unload (src)
(* ;OCG.TraceOut (mname, pname); *)
END Assign;
(*------------------------------------*)
PROCEDURE RegsUsed ( fpar : OCT.Object ) : SET;
VAR result : SET;
BEGIN (* RegsUsed *)
result := {};
WHILE fpar # NIL DO
IF fpar.mode IN {VarR, IndR, VarArgMode} THEN
INCL (result, fpar.a0)
END;
fpar := fpar.link
END;
RETURN result
END RegsUsed;
(*------------------------------------*)
PROCEDURE PrepCall *
( VAR x : OCT.Item;
VAR fpar : OCT.Object;
VAR mask : SET );
(* CONST pname = "PrepCall"; *)
BEGIN (* PrepCall *)
(* OCG.TraceIn (mname, pname); *)
mask := OCC.AllRegs;
IF x.mode IN {LProc, XProc, FProc} THEN
fpar := x.obj.link
ELSIF (x.mode = LibCall) OR (x.mode = TProc) THEN
fpar := x.obj.link.link;
IF x.mode = LibCall THEN
mask := OCC.ScratchRegs + RegsUsed (fpar)
END;
ELSIF (x.typ # NIL) & (x.typ.form = ProcTyp) THEN
fpar := x.typ.link
ELSE
OCS.Mark (121); fpar := NIL; x.typ := OCT.undftyp
END
(* ;OCG.TraceOut (mname, pname); *)
END PrepCall;
(*------------------------------------*)
PROCEDURE VarArg *
( VAR ap : OCT.Item; fpo : OCT.Object;
VAR stackload : LONGINT; load : BOOLEAN );
(* CONST pname = "VarArg"; *)
VAR fp, reg : OCT.Item;
BEGIN (* VarArg *)
(* OCG.TraceIn (mname, pname); *)
fp.mode := Push; fp.a0 := A7; fp.typ := fpo.typ; fp.rdOnly := FALSE;
Assign (fp, ap, TRUE); INC (stackload, fp.typ.size);
IF load THEN
fp.mode := Reg; reg.mode := Reg; reg.a0 := fpo.a0;
OCC.ReserveReg (SHORT (reg.a0));
OCC.Move (L, fp, reg)
END;
(* ;OCG.TraceOut (mname, pname); *)
END VarArg;
(*------------------------------------*)
PROCEDURE RegParam (VAR ap : OCT.Item; fpo : OCT.Object);
(* CONST pname = "RegParam"; *)
VAR fp, t : OCT.Item; q : OCT.Struct; f, g : INTEGER;
BEGIN (* RegParam *)
(* OCG.TraceIn (mname, pname); *)
fp.mode := fpo.mode; fp.a0 := fpo.a0; fp.typ := fpo.typ;
fp.rdOnly := FALSE; f := fp.typ.form; g := ap.typ.form;
IF fpo.mode = IndR THEN (* VAR parameter *)
IF ap.mode >= Con THEN OCS.Mark (122)
ELSIF ap.rdOnly THEN OCS.Mark (324)
END;
IF fp.typ.form = DynArr THEN
IF
(fp.typ.BaseTyp = OCT.bytetyp)
OR ((ap.typ.form IN {Array, DynArr})
& (fp.typ.BaseTyp = ap.typ.BaseTyp))
THEN
OCI.MoveAdr (ap, fp)
ELSE
OCS.Mark (111)
END
ELSIF (fp.typ.form = Record) & (ap.typ.form = Record) THEN
q := ap.typ; WHILE (q # fp.typ) & (q # NIL) DO q := q.BaseTyp END;
IF q # NIL THEN
OCI.MoveAdr (ap, fp)
ELSE
OCS.Mark (111)
END
ELSIF
(ap.typ = fp.typ)
OR ((f = Byte) & (g IN {Char, SInt, BSet}))
OR ((f = Word) & (g IN wordSet))
OR ((f = Longword) & (g IN lwordSet))
OR ((f = PtrTyp) & (g IN {Pointer, PtrTyp}))
OR ((f = CPtrTyp) & (g IN {CPointer, CPtrTyp}))
OR ((f = BPtrTyp) & (g IN {BPointer, BPtrTyp}))
THEN
OCI.MoveAdr (ap, fp)
ELSE OCS.Mark (123)
END;
OCI.Unload (ap)
ELSE
Assign (fp, ap, TRUE)
END;
OCC.ReserveReg (SHORT (fp.a0))
(* ;OCG.TraceOut (mname, pname); *)
END RegParam;
(*------------------------------------*)
PROCEDURE Param * (VAR ap : OCT.Item; fpo : OCT.Object);
(* CONST pname = "Param"; *)
VAR
fp, t : OCT.Item; q : OCT.Struct; freeFp : BOOLEAN; f, g : INTEGER;
s : LONGINT;
BEGIN (* Param *)
(* OCG.TraceIn (mname, pname); *)
IF (fpo.mode = VarR) OR (fpo.mode = IndR) THEN RegParam (ap, fpo)
ELSE
fp.mode := Push; fp.a0 := SP; fp.typ := fpo.typ; fp.rdOnly := FALSE;
f := fpo.typ.form; g := ap.typ.form;
IF fpo.mode = Ind THEN (* VAR parameter *)
IF ap.mode >= Con THEN OCS.Mark (122)
ELSIF ap.rdOnly THEN OCS.Mark (324)
END;
IF fp.typ.form = DynArr THEN
DynArrBnd (fp.typ, ap, TRUE);
IF (ap.typ.form = DynArr) OR (ap.mode IN {Ind, IndX}) THEN
OCI.MoveAdr (ap, fp)
ELSE OCC.PutF3 (OCC.PEA, ap)
END;
OCI.Unload (ap)
ELSIF (fp.typ.form = Record) & (ap.typ.form = Record) THEN
q := ap.typ; WHILE (q # fp.typ) & (q # NIL) DO q := q.BaseTyp END;
IF q # NIL THEN
IF (ap.mode = Ind) & (ap.obj # NIL) & (ap.obj # OCC.wasderef) THEN
(* actual parameter is a VAR parameter *)
ap.mode := Var; INC (ap.a0, 4); OCC.Move (L, ap, fp);
IF ap.mode = Var THEN DEC (ap.a0, 4) ELSE DEC (ap.a1, 4) END;
OCC.Move (L, ap, fp)
ELSIF
((ap.mode = Ind) OR (ap.mode = RegI)) & (ap.obj = OCC.wasderef)
THEN
(* actual parameter is a dereferenced pointer *)
IF ap.a2 = Pointer THEN
ap.a1 := -4; OCC.Move (L, ap, fp);
ap.a1 := 0; OCI.MoveAdr (ap, fp)
ELSIF ap.a2 IN uptrSet THEN
t.mode := Lab; t.a0 := 0; t.a1 := 4;
t.symbol := ap.typ.symbol;
OCC.PutF3 (OCC.PEA, t); OCI.MoveAdr (ap, fp)
ELSE
OCS.Mark (111)
END
ELSE
t.mode := Lab; t.a0 := 0; t.a1 := 4; t.symbol := ap.typ.symbol;
OCC.PutF3 (OCC.PEA, t); OCC.PutF3 (OCC.PEA, ap)
END
ELSE
OCS.Mark (111)
END;
OCI.Unload (ap)
ELSIF
(ap.typ = fp.typ)
OR ((f = Byte) & (g IN {Char, SInt, BSet}))
OR ((f = Word) & (g IN wordSet))
OR ((f = Longword) & (g IN lwordSet))
OR ((f = PtrTyp) & (g IN {Pointer, PtrTyp}))
OR ((f = CPtrTyp) & (g IN {CPointer, CPtrTyp}))
OR ((f = BPtrTyp) & (g IN {BPointer, BPtrTyp}))
THEN
IF ap.mode IN {Ind, IndX} THEN OCI.MoveAdr (ap, fp)
ELSE OCC.PutF3 (OCC.PEA, ap)
END;
OCI.Unload (ap)
ELSE
OCS.Mark (123)
END
ELSE
(*
freeFp := FALSE;
IF fp.typ.form IN {Array, Record} THEN
fp.mode := Reg;
IF fp.typ.size <= 8 THEN
s := fp.typ.size; IF ODD (s) THEN INC (s) END;
OCC.PutF7 (OCC.SUBQ, L, s, fp)
ELSE
t.mode := RegI; t.a0 := SP; t.a1 := -fp.typ.size;
IF ODD (t.a1) THEN DEC (t.a1) END;
OCC.PutF2 (OCC.LEA, t, fp.a0)
END;
OCC.GetAReg (t); OCC.Move (L, fp, t);
fp.mode := RegI; fp.a0 := t.a0; fp.a1 := 0;
freeFp := TRUE
END;
*)
Assign (fp, ap, TRUE);
(*IF freeFp THEN OCI.Unload (fp) END*)
END
END
(* ;OCG.TraceOut (mname, pname); *)
END Param;
(*------------------------------------*)
PROCEDURE Receiver * (VAR x : OCT.Item; rcvr : OCT.Object);
(* CONST pname = "Receiver"; *)
VAR y : OCT.Item;
BEGIN (* Receiver *)
(* OCG.TraceIn (mname, pname); *)
y := x;
IF (y.typ.form IN ptrSet) & (rcvr.mode = Ind) THEN OCE.DeRef (y) END;
Param (y, rcvr)
(* ;OCG.TraceOut (mname, pname); *)
END Receiver;
(*------------------------------------*)
PROCEDURE Call * (VAR x : OCT.Item);
(* CONST pname = "Call"; *)
VAR y, z : OCT.Item;
BEGIN (* Call *)
(* OCG.TraceIn (mname, pname); *)
IF x.mode = LProc THEN
IF x.lev > 0 THEN
y.mode := Var; y.typ := OCT.linttyp;
IF x.lev = OCC.level THEN
y.lev := x.lev; y.a0 := 0; OCC.PutF3 (OCC.PEA, y)
ELSE
y.lev := x.lev + 1; y.a0 := 8; z.mode := Push; z.a0 := SP;
OCC.Move (L, y, z)
END
END;
OCC.PutWord (OCC.BSR); OCC.PutWordRef (0, x.symbol)
ELSIF x.mode IN {XProc, FProc} THEN
IF x.lev = 0 THEN
OCC.PutWord (OCC.BSR); OCC.PutWordRef (0, x.symbol)
ELSE
OCC.PutF3 (OCC.JSR, x)
END
ELSIF (x.mode < Con) & (x.typ # OCT.undftyp) THEN (* procedure variable *)
y := x; y.typ := OCT.ptrtyp; OCC.GetAReg (x);
IF OCS.nilCheck THEN
OCI.Load (y); (* MOVE.L x,Dn *)
OCC.PutWord (6602H); (* BNE 1$ *)
OCC.PutWord (OCC.TRAP + OCC.NilCheck); (* TRAP #NilCheck *)
END; (* 1$ *)
OCC.Move (L, y, x); OCI.Unload (y); x.mode := RegI;
x.a1 := 0; OCC.PutF3 (OCC.JSR, x); x.typ := x.typ.BaseTyp
ELSE
OCS.Mark (121)
END
(* ;OCG.TraceOut (mname, pname); *)
END Call;
(*-------------------------------------------*)
PROCEDURE CallLibCall * (VAR x, rcvr : OCT.Item; stackload : LONGINT);
(* CONST pname = "CallLibCall"; *)
VAR y, sp : OCT.Item;
BEGIN (* CallLibCall *)
(* OCG.TraceIn (mname, pname); *)
(* x.mode = LibCall *)
y.mode := Reg; y.a0 := A6; OCC.Move (L, rcvr, y);
y.mode := RegI; y.a1 := x.a0; OCC.PutF3 (OCC.JSR, y);
IF stackload > 0 THEN
IF stackload <= 8 THEN
sp.mode := Reg; sp.a0 := SP;
OCC.PutF7 (OCC.ADDQ, L, stackload, sp)
ELSE
sp.mode := RegI; sp.a0 := SP; sp.a1 := stackload;
OCC.PutF2 (OCC.LEA, sp, SP)
END;
END;
(* ;OCG.TraceOut (mname, pname); *)
END CallLibCall;
(*------------------------------------*)
PROCEDURE CallTypeBound * (VAR x, rcvr : OCT.Item);
(* CONST pname = "CallTypeBound"; *)
VAR y, z : OCT.Item;
BEGIN (* CallTypeBound *)
(* OCG.TraceIn (mname, pname); *)
(* x.mode = TProc *)
IF x.a2 < 0 THEN (* Super-call, call directly *)
x.lev := -x.obj.link.typ.mno;
IF x.lev = 0 THEN
OCC.PutWord (OCC.BSR); OCC.PutWordRef (0, x.symbol)
ELSE
x.mode := XProc; OCC.PutF3 (OCC.JSR, x)
(*OCC.PutWord (OCC.JSR); OCC.PutLongRef (0, x.symbol)*)
END
ELSE
y := rcvr; IF y.typ.form = Pointer THEN OCE.DeRef (y) END;
IF (y.mode IN {RegI, Ind}) & (y.obj = OCC.wasderef) & (y.a2 = Pointer)
THEN
(* rcvr is dereferenced pointer *)
IF y.mode = Ind THEN OCC.GetAReg (z)
ELSE z.mode := Reg; z.a0 := y.a0
END;
y.a1 := -4; OCC.Move (L, y, z);
z.mode := RegI; z.a1 := -x.obj.a0 * 4;
y.mode := Reg; y.a0 := z.a0; y.a1 := 0;
OCC.Move (L, z, y); y.mode := RegI; OCC.PutF3 (OCC.JSR, y)
ELSIF (y.mode = Ind) & (rcvr.obj # OCC.wasderef) THEN
(* rcvr is record variable parameter *)
y.mode := Var; INC (y.a0, 4); OCC.GetAReg (z); OCC.Move (L, y, z);
z.mode := RegI; z.a1 := -x.obj.a0 * 4;
y.mode := Reg; y.a0 := z.a0; y.a1 := 0;
OCC.Move (L, z, y); y.mode := RegI; OCC.PutF3 (OCC.JSR, y)
ELSE
(* rcvr is record variable *)
x.lev := -x.obj.link.typ.mno;
IF x.lev = 0 THEN
OCC.PutWord (OCC.BSR); OCC.PutWordRef (0, x.symbol)
ELSE
x.mode := XProc; OCC.PutF3 (OCC.JSR, x)
END
END
END
(* ;OCG.TraceOut (mname, pname); *)
END CallTypeBound;
(*------------------------------------*)
PROCEDURE Result * (VAR x : OCT.Item; typ : OCT.Struct);
(* CONST pname = "Result"; *)
VAR res : OCT.Item; R : SET; reg : INTEGER;
BEGIN (* Result *)
(* OCG.TraceIn (mname, pname); *)
IF
(typ.form = Pointer) & (typ.BaseTyp # NIL) & (typ.BaseTyp.form = DynArr)
THEN
res.mode := RList; R := {}; reg := D0;
WHILE (reg * 4) < typ.size DO INCL (R, reg); INC (reg) END;
res.a0 := SYS.VAL (LONGINT, R)
ELSE
res.mode := Reg; res.a0 := D0
END;
res.typ := typ; res.rdOnly := FALSE;
Assign (res, x, FALSE);
returnFound := TRUE
(* ;OCG.TraceOut (mname, pname); *)
END Result;
(*------------------------------------*)
PROCEDURE CaseIn * (VAR x : OCT.Item; VAR L0 : INTEGER);
(* CONST pname = "CaseIn"; *)
BEGIN (* CaseIn *)
(* OCG.TraceIn (mname, pname); *)
IF ~(x.typ.form IN caseSet) THEN OCS.Mark (125) END;
OCI.Load (x); OCC.UnReserveReg (SHORT (x.a0)); L0 := 0; FJ (L0)
(* ;OCG.TraceOut (mname, pname); *)
END CaseIn;
(*------------------------------------*)
PROCEDURE CaseOut *
( VAR x : OCT.Item;
L0, L1, L2, n : INTEGER;
VAR tab : ARRAY OF LabelRange);
(* CONST pname = "CaseOut"; *)
VAR labItem, y, z : OCT.Item; i, L3 : INTEGER;
BEGIN (* CaseOut *)
(* OCG.TraceIn (mname, pname); *)
labItem.mode := Con; labItem.typ := x.typ; i := 0;
OCC.FixLink (L0); (* fixup jump from case expression *)
WHILE i < n DO
IF tab [i].low = tab [i].high THEN
y := x; labItem.a0 := tab [i].low; OCE.Op (neq, y, labItem, FALSE);
CBJ (y, tab [i].label)
ELSE
L3 := 0; y := x; labItem.a0 := tab [i].low;
OCE.Op (geq, y, labItem, FALSE); CFJ (y, L3); z := x;
labItem.a0 := tab [i].high; OCE.Op (gtr, z, labItem, FALSE);
CBJ (z, tab [i].label); OCC.fixup (L3)
END;
INC (i)
END;
BJ (L2); (* jump to code for else part *)
OCC.FixLink (L1); (* fixup jumps from individual cases *)
(* ;OCG.TraceOut (mname, pname); *)
END CaseOut;
(*------------------------------------*)
PROCEDURE BeginFor *
( VAR control, low, high, step : OCT.Item; VAR L0, L1 : INTEGER );
(* CONST pname = "BeginFor"; *)
VAR f, g, h, i : INTEGER; x, y : OCT.Item;
BEGIN (* BeginFor *)
(* OCG.TraceIn (mname, pname); *)
f := control.typ.form; g := low.typ.form; h := high.typ.form;
i := step.typ.form;
IF (f IN intSet) & (g IN intSet) & (h IN intSet) & (i IN intSet) THEN
IF low.mode = Con THEN
IF (f = Int) & (g = LInt) THEN OCS.Mark (317)
ELSIF (f = SInt) & (g # SInt) THEN OCS.Mark (317)
END;
low.typ := control.typ
END;
IF high.mode = Con THEN
IF (f = Int) & (h = LInt) THEN OCS.Mark (317)
ELSIF (f = SInt) & (h # SInt) THEN OCS.Mark (317)
END;
high.typ := control.typ
ELSE OCI.Load (high)
END;
IF (f = Int) & (i = LInt) THEN OCS.Mark (317)
ELSIF (f = SInt) & (i # SInt) THEN OCS.Mark (317)
END;
step.typ := control.typ;
IF (low.mode = Con) & (high.mode = Con) THEN
IF (step.a0 > 0) & (high.a0 < low.a0) THEN OCS.Mark (318)
ELSIF (step.a0 < 0) & (low.a0 < high.a0) THEN OCS.Mark (318)
END
END;
x := control; Assign (x, low, FALSE);
L0 := OCC.pc; x := control; y := high;
IF high.mode = Con THEN
IF step.a0 > 0 THEN OCE.Op (leq, x, y, FALSE);
ELSE OCE.Op (geq, x, y, FALSE);
END;
CFJ (x, L1)
ELSE
IF step.a0 > 0 THEN OCE.Op (geq, y, x, FALSE);
ELSE OCE.Op (leq, y, x, FALSE);
END;
CFJ (y, L1)
END;
END
(* ;OCG.TraceOut (mname, pname); *)
END BeginFor;
(*------------------------------------*)
PROCEDURE EndFor *
( VAR control, step : OCT.Item; L0, L1 : INTEGER );
(* CONST pname = "EndFor"; *)
BEGIN (* EndFor *)
(* OCG.TraceIn (mname, pname); *)
IF step.a0 > 0 THEN OCC.PutF5 (OCC.ADD, step.typ.size, step, control)
ELSE
step.a0 := -step.a0; OCC.PutF5 (OCC.SUB, step.typ.size, step, control)
END;
(*IF OCS.overflowCheck THEN OCC.PutWord (OCC.TRAPV) END;*)
BJ (L0); OCC.FixLink (L1)
(* ;OCG.TraceOut (mname, pname); *)
END EndFor;
END OCH.
(***************************************************************************
$Log: OCH.mod $
Revision 4.11 1994/08/03 11:47:56 fjc
- Changed error codes.
- Implemented SaveRegs switch, changed code generated for
SaveAllRegs switch.
Revision 4.10 1994/07/26 18:37:11 fjc
*** empty log message ***
Revision 4.9 1994/07/25 00:52:13 fjc
- Implemented stack checking.
Revision 4.8 1994/07/23 16:04:26 fjc
- Changed Assign() to sign- or zero-extend values assigned
to WORD and LONGWORD variables.
- Changed PrepCall() to generate a register mask.
Revision 4.7 1994/07/22 14:17:15 fjc
- Changed to handle FProc objects.
- Changed code generated for procedure entry and exit to
implement the $A compiler switch.
- Changed parameter passing code to save A4 if necessary.
- Renamed procedure call procedures.
Revision 4.6 1994/07/10 13:27:21 fjc
- Commented out trace code.
- Changed code generated for module prologue.
- Added check for $G compiler switch before creating GC data.
- Fixed register allocation bug in RegParam().
Revision 4.5 1994/06/19 20:44:37 fjc
- Fixing passing empty strings to register parameters
broke the passing of non-empty strings. What a
maroon :-(.
- Calling type-bound procedures through CPointers
was always broken.
Revision 4.4 1994/06/17 17:50:57 fjc
- Implemented TagTyp.
- Fixed bug passing short strings to LIBCALLs.
Revision 4.3 1994/06/06 18:36:15 fjc
- Implemented varargs for LibCall procedures:
- Created VarArg() to push one argument;
- Created RestoreStack() to pop parameters off the stack.
Revision 4.2 1994/06/05 22:45:21 fjc
- Changed to use new symbol table format.
- Fixed bug allowing any constant to be assigned to a set.
Revision 4.1 1994/06/01 09:33:44 fjc
- Bumped version number
***************************************************************************)