Syntax24b.Scn.Fnt ParcElems Alloc Syntax10.Scn.Fnt Syntax10i.Scn.Fnt Syntax10b.Scn.Fnt (* Amiga NonFPU *) MODULE OPC; (* Code Generator for MC68020. Diplomarbeit Samuel Urech Date: 6.11.92 Current version: 26.2.93 Bug concerning record assignment (projection) in Convert fixed by cn/shml 30 Jun 94 Nil-Check by rd/cn 22.05.95 *) IMPORT SYSTEM, OPT, OPL, OPM, AmigaMathL; CONST (* object modes *) Var = 1; VarPar = 2; Con = 3; Fld = 4; Typ = 5; LProc = 6; XProc = 7; SProc = 8; CProc = 9; IProc = 10; Head = 12; TProc = 13; (* accessibility of objects *) internal = 0; external = 1; externalR = 2; (* structure forms *) Undef = 0; Byte = 1; Bool = 2; Char = 3; SInt = 4; Int = 5; LInt = 6; Real = 7; LReal = 8; Set = 9; String = 10; NilTyp = 11; NoTyp = 12; Pointer = 13; ProcTyp = 14; Comp = 15; (* composite structure forms *) Basic = 1; Array = 2; DynArr = 3; Record = 4; IntSet = { SInt .. LInt }; RealSet = { Real, LReal }; ByteSet = { SInt, Byte, Char, Bool }; WordSet = { Int }; LongSet = { LInt, Set, Pointer, ProcTyp }; (* item modes *) dreg = 0; areg = 1; freg = 2; postinc = 3; predec = 4; regx = 5; abs = 7; imm = 8; immL = 9; pcx = 10; coc = 12; fcoc = 13; (* sizes *) byte = 0; word = 1; long = 2; (* opcodes *) ADD = 13; AND = 12; oR = 8; SUB = 9; BCHG = 1; BCLR = 2; BSET = 3; BTST = 0; ADDI = 6; ANDI = 2; CMPI = 12; EORI = 10; ORI = 0; SUBI = 4; ADDQ = 0; SUBQ = 1; CLR = 2; NEG = 4; NEGX = 0; NOT = 6; TST = 10; BFCHG = 10; BFCLR = 12; BFSET = 14; BFTST = 8; DIVS = 81C0H; DIVU = 80C0H; MULS = 0C1C0H; MULU = 0C0C0H; ASh = 0; LSh = 1; ROt = 3; ROX = 2; JMP = 3BH; JSR = 3AH; PEA = 21H; NBCD = 20H; TAS = 2BH; (* Coprocessor opcodes *) FABS = 18H; FACOS = 1CH; FADD = 22H; FASIN = 0CH; FATAN = 0AH; FATANH = 0DH; FCMP = 38H; FCOS = 1DH; FCOSH = 19H; FDIV = 20H; FETOX = 10H; FETOXM1 = 8; FGETEXP = 1EH; FGETMAN = 1FH; FINT = 1; FINTRZ = 3; FLOG10 = 15H; FLOG2 = 16H; FLOGN = 14H; FLOGNP1 = 6; FMOD = 21H; FMOVE = 0; FMUL = 23H; FNEG = 1AH; FREM = 25H; FSCALE = 26H; FSGLDIV = 24H; FSGLMUL = 27H; FSIN = 0EH; FSINH = 2; FSQRT = 4; FSUB = 28H; FTAN = 0FH; FTANH = 9; FTENTOX = 12H; FTST = 3AH; FTWOTOX = 11H; (* Compare kinds *) eql = 9; neq = 10; lss = 11; leq = 12; gtr = 13; geq = 14; (* Condition Codes *) CC = 4; CS = 5; EQ = 7; false = 1; GE = 12; GT = 14; HI = 2; LE = 15; LS = 3; LT = 13; MI = 11; NE = 6; PL = 10; true = 0; VC = 8; VS = 9; (* Floating Point Condition Codes *) FEQ = 1; FNE = 0EH; FGT = 12H; FNGT = 1DH; FGE = 13H; FNGE = 1CH; FLT = 14H; FNLT = 1BH; FLE = 15H; FNLE = 1AH; Ffalse = 0; Ftrue = 0FH; (* Floating Point Control Registers *) FPCR = 4; FPSR = 2; FPIAR = 1; (* Traps, not used ? *) inxTrap = 8; rngTrap = 9; guardTrap = 18; eqGuardTrap = 19; super = 1; None = -1; VAR FP, SP : OPL.Item; indexCheck, rangeCheck, nilCheck, ptrinit, saveRegs* : BOOLEAN; PROCEDURE Init*( options : SET ); BEGIN indexCheck := 0 IN options; rangeCheck := 2 IN options; nilCheck := 9 IN options; ptrinit := 5 IN options; END Init; PROCEDURE MakeLen*( VAR arr : OPL.Item; n : LONGINT; VAR item : OPL.Item ); (* Makes an item that denotes the length in the n-th dimension of a dynamic array. *) BEGIN (* MakeLen *) item := arr; IF item.nolen = 0 THEN item.bd := arr.bd + 4 * ( n + 1 ); ELSE item.bd := arr.bd + 4 * n; END; (* IF *) item.typ := OPT.linttyp; END MakeLen; PROCEDURE MakeIntConst*( val : LONGINT; typ : OPT.Struct; VAR item : OPL.Item ); (* Makes an immediate item of a given type from a number. *) BEGIN (* MakeIntConst *) item.mode := imm; item.typ := typ; item.bd := val; END MakeIntConst; PROCEDURE MakeVar*( obj : OPT.Object; VAR item : OPL.Item ); (* Makes an item from a variable. *) VAR aregItem : OPL.Item; PROCEDURE GetVarBase( obj : OPT.Object ) : INTEGER; (* Returns the register to which the given variable is relative. *) VAR diff, reg : INTEGER; source, dest : OPL.Item; BEGIN (* GetVarBase *) diff := OPL.level - obj.mnolev; IF diff = 0 THEN reg := FP.reg; ELSE (* follow static link *) reg := OPL.GetAdrReg( ); source.mode := regx; source.typ := OPT.sysptrtyp; source.reg := FP.reg; source.bd := 8; source.inxReg := None; source.offsReg := None; dest.mode := areg; dest.typ := OPT.sysptrtyp; dest.reg := reg; OPL.Move( source, dest ); source.reg := reg; WHILE diff > 1 DO OPL.Move( source, dest ); DEC( diff ); END; (* WHILE *) END; (* IF *) RETURN reg END GetVarBase; BEGIN (* MakeVar *) IF ( obj.mode = VarPar ) & ( obj.typ.comp # DynArr ) THEN item.mode := regx; item.reg := GetVarBase( obj ); item.typ := OPT.sysptrtyp; item.bd := obj.adr; item.inxReg := None; aregItem.mode := areg; aregItem.reg := OPL.GetAdrReg( ); OPL.Move( item, aregItem ); OPL.FreeReg( item ); item.mode := regx; item.reg := aregItem.reg; item.bd := 0; ELSIF obj.mnolev < 0 THEN (* imported variable *) item.mode := abs; item.bd := SYSTEM.LSH( LONG( LONG( -obj.mnolev ) ), 8 ) + obj.adr; ELSIF obj.mnolev = 0 THEN (* global variable *) item.mode := pcx; item.bd := obj.linkadr; ELSE (* local variable *) item.mode := regx; item.reg := GetVarBase( obj ); item.bd := obj.adr; END; (* IF *) item.typ := obj.typ; item.inxReg := None; item.offsReg := None; item.nolen := 0; END MakeVar; PROCEDURE DeRef*( typ : OPT.Struct; VAR item : OPL.Item ); (* Makes a dereferentiation of an item. *) VAR aregItem, dregItem : OPL.Item; inxReg : INTEGER; BEGIN (* DeRef *) aregItem.mode := areg; (* If item is (Ax) with x<6, use Ax again *) IF saveRegs & (item.mode=regx) & (item.reg<14) THEN aregItem.reg:=item.reg ELSE aregItem.reg := OPL.GetAdrReg( ) END; item.typ := OPT.sysptrtyp; inxReg := item.offsReg; OPL.Move( item, aregItem ); IF nilCheck & (~(item.mode=immL)) THEN dregItem.mode:=dreg; dregItem.reg:=OPL.GetReg(); NEW(aregItem.typ);aregItem.typ.size:=4; OPL.Move( aregItem, dregItem); OPL.Trapcc(EQ, 2); OPL.FreeReg(dregItem); END; item.mode := regx; item.typ := typ; item.reg := aregItem.reg; item.bd := 0; item.inxReg := inxReg; (* xsize and scale keep their values *) IF typ.comp = DynArr THEN item.nolen := SHORT( typ.n ) + 1; ELSE item.nolen := 0; END; (* IF *) END DeRef; PROCEDURE StaticTag*( typ : OPT.Struct; VAR tag : OPL.Item ); (* Returns the type tag of a type. *) BEGIN (* StaticTag *) tag.mode := immL; tag.typ := OPT.sysptrtyp; tag.bd := SYSTEM.LSH( LONG( LONG( typ.mno ) ), 8 ) + typ.tdadr; END StaticTag; PROCEDURE MakeTag*( obj : OPT.Object; typ : OPT.Struct; VAR item, tag : OPL.Item ); (* Makes an item that denotes the type tag of the given object and item. *) BEGIN (* MakeTag *) IF item.typ.form = Pointer THEN tag := item; DeRef( OPT.sysptrtyp, tag ); tag.bd := -4; ELSIF ( obj # NIL ) & ( obj.mode = VarPar ) THEN tag.mode := regx; tag.typ := OPT.sysptrtyp; tag.reg := FP.reg; tag.bd := obj.adr + 4; tag.inxReg := None; tag.offsReg := None; ELSE StaticTag( typ, tag ); END; (* IF *) END MakeTag; PROCEDURE MakeConst*( obj : OPT.Object; const : OPT.Const; typ : OPT.Struct; VAR item : OPL.Item ); (* Makes an item from a constant. *) VAR realval : REAL; BEGIN (* MakeConst *) item.typ := typ; CASE typ.form OF Set : MakeIntConst( SYSTEM.VAL( LONGINT, const.setval ), typ, item ); | String : OPL.AllocConst( obj, typ, const.ext^, const.intval2, item ); item.nolen := SHORT( const.intval2 ); | Real : AmigaMathL.Short(const.realval, realval); (* realval := SHORT( const.realval );*) OPL.AllocConst( obj, typ, realval, 4, item ); | LReal : OPL.AllocConst( obj, typ, const.realval, 8, item ); ELSE MakeIntConst( const.intval, typ, item ); END; (* CASE *) END MakeConst; PROCEDURE BaseTypSize( VAR arr, size : OPL.Item; VAR scale : INTEGER ); (* Returns the size of the base type of a dynamic array if the base type is a dynamic array itself. *) VAR i : LONGINT; typ : OPT.Struct; len : OPL.Item; BEGIN (* BaseTypSize *) typ := arr.typ.BaseTyp; WHILE typ.comp = DynArr DO typ := typ.BaseTyp; END; (* WHILE *) IF ( typ.size = 1 ) OR ( typ.size = 2 ) OR ( typ.size = 4 ) OR ( typ.size = 8 ) THEN scale := SHORT( typ.size ); MakeLen( arr, arr.typ.offset, size ); ELSE scale := 1; MakeIntConst( typ.size, OPT.linttyp, size ); MakeLen( arr, arr.typ.offset, len ); OPL.Format12( MULS, len, size ); OPL.FreeReg( len ); END; (* IF *) FOR i := arr.typ.offset - arr.typ.n + 1 TO arr.typ.offset - 1 DO MakeLen( arr, i, len ); OPL.Format12( MULS, len, size ); OPL.FreeReg( len ); END; (* FOR *) END BaseTypSize; PROCEDURE Size( VAR arr, size : OPL.Item; VAR scale : INTEGER ); (* Returns the size of a dynamic array and a scale factor. *) VAR len : OPL.Item; typ : OPT.Struct; BEGIN (* Size *) MakeLen( arr, arr.typ.offset - arr.typ.n, len ); typ := arr.typ.BaseTyp; IF typ.comp = DynArr THEN BaseTypSize( arr, size, scale ); OPL.Format12( MULS, len, size ); OPL.FreeReg( len ); ELSE IF ( typ.size = 1 ) OR ( typ.size = 2 ) OR ( typ.size = 4 ) OR ( typ.size = 8 ) THEN scale := SHORT( typ.size ); size := len; ELSE scale := 1; MakeIntConst( typ.size, OPT.linttyp, size ); OPL.Format12( MULS, len, size ); OPL.FreeReg( len ); END; (* IF *) END; (* IF *) END Size; PROCEDURE ElimIndex( VAR item : OPL.Item ); (* Eliminates the index register in the item. *) VAR newReg : INTEGER; BEGIN (* ElimIndex *) IF item.inxReg # None THEN (* load old address *) newReg := OPL.GetAdrReg( ); OPL.Lea( item, newReg ); item.mode := regx; item.bd := 0; item.reg := newReg; item.inxReg := None; END; (* IF *) END ElimIndex; PROCEDURE SetElem*( VAR item : OPL.Item ); (* Makes a set-element from an integer element and sets the corresponding bit. *) VAR source : OPL.Item; BEGIN (* SetElem *) source := item; item.mode := dreg; item.typ := OPT.settyp; item.reg := OPL.GetReg( ); OPL.Format7( CLR, item ); OPL.Format5( BSET, source, item ); END SetElem; PROCEDURE RoundDown; (* Sets the rounding mode of the coprocessor to -inf. *) VAR temp : OPL.Item; BEGIN (* RoundDown *) MakeIntConst( 20H, OPT.linttyp, temp ); OPL.FMovecr( temp, 0, FPCR ); END RoundDown; PROCEDURE RoundNearest; (* Sets the rounding mode of the coprocessor to nearest. *) VAR temp : OPL.Item; BEGIN (* RoundNearest *) MakeIntConst( 0, OPT.linttyp, temp ); OPL.FMovecr( temp, 0, FPCR ); END RoundNearest; PROCEDURE Convert*( VAR source : OPL.Item; desttyp : OPT.Struct ); (* Converts the given item to desttyp. *) VAR sf, sc, df, dc : SHORTINT; dest : OPL.Item; BEGIN (* Convert *) sf := source.typ.form; sc := source.typ.comp; df := desttyp.form; dc := desttyp.comp; IF df = ProcTyp THEN (* handles assignments of functions to proc vars *) source.typ := desttyp; RETURN END; IF (df = Comp) & (sf = Comp) & (dc = Record) & (sc = Record) THEN (* handles record assignment including projection *) source.typ := desttyp; RETURN END; IF ( sf # Pointer ) & ( ( sf # df ) OR ( sc # dc ) ) THEN IF df IN LongSet THEN IF sf = Char THEN dest.mode := dreg; dest.typ := desttyp; dest.reg := OPL.GetReg( ); OPL.Format7( CLR, dest ); OPL.Move( source, dest ); source := dest; ELSIF sf IN ByteSet + WordSet THEN OPL.Ext( source, long ); ELSIF sf IN RealSet THEN OPL.FLoad( source ); RoundDown; source.typ := desttyp; OPL.Load( source ); RoundNearest; END; (* IF *) ELSIF df IN WordSet THEN IF sf IN LongSet THEN OPL.Load( source ); ELSIF sf = Char THEN dest.mode := dreg; dest.typ := desttyp; dest.reg := OPL.GetReg( ); OPL.Format7( CLR, dest ); OPL.Move( source, dest ); source := dest; ELSIF sf IN ByteSet THEN OPL.Ext( source, word ); ELSIF sf IN RealSet THEN OPL.FLoad( source ); RoundDown; source.typ := desttyp; OPL.Load( source ); RoundNearest; END; (* IF *) ELSIF df IN ByteSet THEN IF sf IN WordSet + LongSet THEN OPL.Load( source ); ELSIF sf IN RealSet THEN OPL.FLoad( source ); RoundDown; source.typ := desttyp; OPL.Load( source ); RoundNearest; END; (* IF *) ELSIF df IN RealSet THEN OPL.FLoad( source ); END; (* IF *) source.typ := desttyp; END; (* IF *) END Convert; PROCEDURE GetDynArrVal*( VAR item : OPL.Item ); (* Returns an item containing the actual value of a dynamic array. *) BEGIN (* GetDynArrVal *) IF item.nolen = 0 THEN DeRef( OPT.sysptrtyp, item ); ELSE INC( item.bd, LONG( item.nolen ) * 4 ); item.nolen := 0; item.typ := OPT.sysptrtyp; item.inxReg := item.offsReg; item.offsReg := None; END; (* IF *) END GetDynArrVal; PROCEDURE GetDynArrAdr( VAR item, adr : OPL.Item ); (* Returns an item containing the address of a dynamic array. *) VAR adrReg : OPL.Item; BEGIN (* GetDynArrAdr *) adr.typ := OPT.sysptrtyp; adr.nolen := 0; IF item.nolen = 0 THEN IF item.offsReg # None THEN DeRef( OPT.sysptrtyp, item ); adr.mode := areg; adr.reg := OPL.GetAdrReg( ); OPL.Lea( item, adr.reg ); ELSE adr.mode := item.mode; adr.reg := item.reg; adr.bd := item.bd; adr.inxReg := None; adr.offsReg := None; END; ELSE adr.mode := item.mode; adr.reg := item.reg; adr.bd := item.bd + item.nolen * 4; adr.inxReg := item.offsReg; adr.xsize := item.xsize; adr.scale := item.scale; adr.offsReg := None; adrReg.mode := areg; adrReg.typ := OPT.sysptrtyp; adrReg.reg := OPL.GetAdrReg( ); OPL.Lea( adr, adrReg.reg ); adr := adrReg; END; (* IF *) END GetDynArrAdr; PROCEDURE MakeField*( VAR item : OPL.Item; offset : LONGINT; typ : OPT.Struct ); (* Increments the address of item by offset and sets its type to typ. *) BEGIN (* MakeField *) OPL.LoadExternal( item ); INC( item.bd, offset ); item.typ := typ; END MakeField; PROCEDURE MakeIndex*( VAR index, res : OPL.Item ); (* Makes an indexed item from an item and an index. res := res[ index ]. The generated item has always got an index register or an offset register. *) VAR baseTyp : OPT.Struct; sizeItem, chkItem, offset : OPL.Item; size : LONGINT; scale : INTEGER; BEGIN (* MakeIndex *) baseTyp := res.typ.BaseTyp; size := baseTyp.size; OPL.LoadExternal( res ); IF ( res.typ.comp # DynArr ) & ( index.mode = imm ) THEN INC( res.bd, size * index.bd ); ELSE ElimIndex( res ); IF index.typ.form = SInt THEN Convert( index, OPT.inttyp ); END; IF ( ( index.mode # imm ) OR ( index.bd # 0 ) ) & (indexCheck) THEN IF res.typ.comp = DynArr THEN MakeLen( res, res.typ.offset - res.typ.n, chkItem ); Convert( index, OPT.linttyp ); ELSE MakeIntConst( res.typ.n - 1, index.typ, chkItem ); END; (* IF *) OPL.Chk( index, chkItem ); (* OPL.FreeReg( chkItem ); *) (* Need this for CHK opti *) END; (* IF *) OPL.Load( index ); IF baseTyp.comp # Basic THEN IF baseTyp.comp = DynArr THEN Convert( index, OPT.linttyp ); BaseTypSize( res, sizeItem, scale ); OPL.Format12( MULS, sizeItem, index ); OPL.FreeReg( sizeItem ); ELSE IF ( size = 1 ) OR ( size = 2 ) OR ( size = 4 ) OR ( size = 8 ) THEN scale := SHORT( size ); ELSE scale := 1; MakeIntConst( size, index.typ, sizeItem ); IF index.typ.form = LInt THEN OPL.Format12( MULS, sizeItem, index ); ELSE OPL.Format11( MULS, sizeItem, index ); END; (* IF *) OPL.FreeReg( sizeItem ); END; (* IF *) END; (* IF *) size := 1; ELSE scale := SHORT( size ); END; (* IF *) IF baseTyp.comp = DynArr THEN IF res.offsReg # None THEN offset.mode := dreg; offset.typ := OPT.linttyp; offset.reg := res.offsReg; OPL.Format2( ADD, offset, index ); END; (* IF *) res.offsReg := index.reg; ELSE IF res.typ.comp = DynArr THEN GetDynArrVal( res ); ElimIndex( res ); END; (* IF *) res.inxReg := index.reg; END; (* IF *) IF index.typ.form = LInt THEN res.xsize := 1; ELSE res.xsize := 0; END; (* IF *) CASE scale OF 1 : res.scale := 0; | 2 : res.scale := 1; | 4 : res.scale := 2; | 8 : res.scale := 3; END; (* CASE *) END; (* IF *) res.typ := baseTyp; END MakeIndex; PROCEDURE MakeProc*( obj : OPT.Object; subcl : SHORTINT; VAR item : OPL.Item ); (* Makes an item from a procedure object. *) BEGIN (* MakeProc *) IF obj.mode = XProc THEN (* external procedure *) item.mode := immL; item.typ := OPT.sysptrtyp; item.bd := SYSTEM.LSH( LONG( LONG( -obj.mnolev ) ), 8 ) + obj.adr; item.offsReg := None; ELSIF obj.mode = TProc THEN (* receiver is on top of the stack *) IF obj.link.mode = VarPar THEN item.mode := regx; item.typ := OPT.sysptrtyp; item.reg := SP.reg; item.bd := 4; item.inxReg := None; item.offsReg := None; ELSE item.mode := regx; item.typ := OPT.sysptrtyp; item.reg := SP.reg; item.bd := 0; item.inxReg := None; item.offsReg := None; DeRef( OPT.sysptrtyp, item ); item.bd := -4; END; (* IF *) DeRef( OPT.sysptrtyp, item ); IF subcl = super THEN item.bd := OPL.BaseTypeOffs + 4 * ( obj.link.typ.BaseTyp.extlev - 1 ); DeRef( OPT.sysptrtyp, item ); END; (* IF *) item.bd := OPL.MethodOffs - 4 * ( obj.adr DIV 10000H + 1 ); ELSE MakeIntConst( obj.linkadr, OPT.linttyp, item ); END; (* IF *) END MakeProc; PROCEDURE MakePostInc( typ : OPT.Struct; VAR item : OPL.Item ); (* Makes a post-increment item from the given item. *) VAR dest : OPL.Item; BEGIN (* MakePostInc *) IF item.mode # postinc THEN IF ( item.mode = regx ) & ( item.bd = 0 ) & ( item.inxReg = None ) & ~ ( item.reg IN { FP.reg, SP.reg } ) THEN item.mode := postinc; item.typ := typ; ELSE dest.mode := postinc; dest.typ := typ; dest.reg := OPL.GetAdrReg( ); OPL.Lea( item, dest.reg ); item := dest; END; END; END MakePostInc; PROCEDURE MakeSPPredec( VAR res : OPL.Item ); (* Makes a pre-decrement item with the stack pointer. *) BEGIN (* MakeSPPredec *) res.mode := predec; res.reg := SP.reg; res.typ := SP.typ; END MakeSPPredec; PROCEDURE MakeCocItem*( trueCond : INTEGER; VAR res : OPL.Item ); (* Makes a coc item with the true-condition trueCond. *) BEGIN (* MakeCocItem *) res.mode := coc; res.typ := OPT.booltyp; res.bd := OPL.TFConds( trueCond ); (* leave tJump and fJump unchanged! *) END MakeCocItem; PROCEDURE MakeFCocItem*( trueCond : INTEGER; VAR res : OPL.Item ); (* Makes an fcoc item with the true-condition trueCond. *) BEGIN (* MakeFCocItem *) res.mode := fcoc; res.typ := OPT.booltyp; res.bd := OPL.TFFConds( trueCond ); (* leave tJump and fJump unchanged! *) END MakeFCocItem; PROCEDURE Swap( x : SET ) : INTEGER; (* Writes bits 15 to 0 to the positions 0 to 15 of the result. Used for MOVEM. *) VAR y : SET; i : INTEGER; BEGIN (* Swap *) y := { }; FOR i := 0 TO 15 DO IF i IN x THEN INCL( y, 15 - i ); END; END; (* FOR *) RETURN SHORT( SYSTEM.VAL( LONGINT, y ) ) END Swap; PROCEDURE SwappedFloats( x : SET ) : INTEGER; (* Writes bits 23 to 16 to the positions 0 to 7 of the result. Used for FMOVEM. *) VAR y : SET; i : INTEGER; BEGIN (* SwappedFloats *) y := { }; FOR i := 16 TO 23 DO IF i IN x THEN INCL( y, 23 - i ); END; END; (* FOR *) RETURN SHORT( SYSTEM.VAL( LONGINT, y ) ) END SwappedFloats; PROCEDURE Floats( x : SET ) : INTEGER; (* Writes bits 16 to 23 to the positions 0 to 7 of the result. Used for FMOVEM. *) VAR y : SET; i : INTEGER; BEGIN (* Floats *) y := { }; FOR i := 16 TO 23 DO IF i IN x THEN INCL( y, i - 16 ); END; END; (* FOR *) RETURN SHORT( SYSTEM.VAL( LONGINT, y ) ) END Floats; PROCEDURE PushRegs*( regs : SET ); (* Pushes the given registers onto the stack. *) VAR sppredec : OPL.Item; regList : INTEGER; BEGIN (* PushRegs *) MakeSPPredec( sppredec ); regList := Swap( regs ); IF regList # 0 THEN OPL.Movem( 0, regList, sppredec ); END; (* IF *) regList := Floats( regs ); IF regList # 0 THEN OPL.FMovem( 0, regList , sppredec ); END; (* IF *) END PushRegs; PROCEDURE PopRegs*( regs : SET ); (* Pops the given registers from the stack. *) VAR sppostinc : OPL.Item; regList : INTEGER; BEGIN (* PopRegs *) sppostinc.mode := postinc; sppostinc.reg := SP.reg; sppostinc.typ := SP.typ; regList := SwappedFloats( regs ); IF regList # 0 THEN OPL.FMovem( 1, regList, sppostinc ); END; (* IF *) regList := SHORT( SYSTEM.VAL( LONGINT, regs ) ); IF regList # 0 THEN OPL.Movem( 1, regList, sppostinc ); END; (* IF *) END PopRegs; PROCEDURE TrueJump*( VAR expression : OPL.Item; VAR label : OPL.Label ); (* Generates a conditional branch to the given label with the true condition. *) BEGIN (* TrueJump *) IF expression.mode = imm THEN IF expression.bd # 0 THEN OPL.Jump( true, label ); END; (* IF *) ELSIF expression.mode = coc THEN OPL.Jump( SHORT( expression.bd DIV 10000H ), label ); ELSIF expression.mode = fcoc THEN OPL.FJump( SHORT( expression.bd DIV 10000H ), label ); ELSE OPL.Load( expression ); OPL.Format7( TST, expression ); OPL.Jump( NE, label ); END; (* IF *) OPL.DefineLabel( expression.fJump ); END TrueJump; PROCEDURE FalseJump*( VAR expression : OPL.Item; VAR label : OPL.Label ); (* Generates a conditional branch to the given label with the false condition. *) BEGIN (* FalseJump *) IF expression.mode = imm THEN IF expression.bd = 0 THEN OPL.Jump( true, label ); END; (* IF *) ELSIF expression.mode = coc THEN OPL.Jump( SHORT( expression.bd MOD 10000H ), label ); ELSIF expression.mode = fcoc THEN OPL.FJump( SHORT( expression.bd MOD 10000H ), label ); ELSE OPL.Load( expression ); OPL.Format7( TST, expression ); OPL.Jump( EQ, label ); END; (* IF *) OPL.DefineLabel( expression.tJump ); END FalseJump; PROCEDURE MoveBlock( scale : INTEGER; VAR size, source, dest : OPL.Item ); (* Moves a block of data of length size from source to dest. *) VAR i : LONGINT; losize : OPL.Item; label : OPL.Label; BEGIN (* MoveBlock *) IF scale = 1 THEN MakePostInc( OPT.sinttyp, source ); MakePostInc( OPT.sinttyp, dest ); ELSIF scale = 2 THEN MakePostInc( OPT.inttyp, source ); MakePostInc( OPT.inttyp, dest ); ELSE MakePostInc( OPT.linttyp, source ); MakePostInc( OPT.linttyp, dest ); END; (* IF *) IF ( size.mode = imm ) & ( size.bd <= 6 ) THEN i := 0; WHILE i < size.bd DO OPL.Move( source, dest ); INC( i ); END; (* WHILE *) ELSE IF size.mode = imm THEN DEC( size.bd ); ELSE OPL.Load( size ); OPL.Format1( SUBQ, 1, size ); END; (* IF *) IF ( ( size.mode = imm ) & ( size.bd <= MAX( INTEGER ) ) ) OR ( size.typ # OPT.linttyp ) THEN OPL.Load( size ); Convert( size, OPT.inttyp ); label := OPL.NewLabel; OPL.DefineLabel( label ); OPL.Move( source, dest ); IF scale = 8 THEN OPL.Move( source, dest ); END; OPL.DBcc( false, size.reg, label ); ELSE OPL.Load( size ); losize.mode := dreg; losize.typ := OPT.inttyp; losize.reg := OPL.GetReg( ); OPL.Move( size, losize ); OPL.Swap( size ); label := OPL.NewLabel; OPL.DefineLabel( label ); OPL.Move( source, dest ); IF scale = 8 THEN OPL.Move( source, dest ); END; OPL.DBcc( false, losize.reg, label ); OPL.DBcc( false, size.reg, label ); END; (* IF *) END; (* IF *) END MoveBlock; PROCEDURE Assign*( VAR source, dest : OPL.Item ); (* Generates code for the assignment dest := source. *) VAR size : LONGINT; length, src : OPL.Item; label : OPL.Label; scale : INTEGER; BEGIN (* Assign *) Convert( source, dest.typ ); size := source.typ.size; OPL.LoadAdr( dest ); IF source.mode = freg THEN OPL.FMove( source, dest ); ELSIF source.typ.form = Real THEN OPL.Move( source, dest ); ELSIF source.typ.form = LReal THEN OPL.LoadAdr( source ); OPL.LoadExternal( source ); OPL.LoadExternal( dest ); source.typ := OPT.linttyp; dest.typ := OPT.linttyp; OPL.Move( source, dest ); INC( source.bd, 4 ); INC( dest.bd, 4 ); OPL.Move( source, dest ); DEC( dest.bd, 4 ); dest.typ := OPT.lrltyp; ELSIF source.mode IN { coc, fcoc } THEN src.mode := imm; src.typ := OPT.booltyp; label := OPL.NewLabel; IF source.mode = coc THEN OPL.Jump( SHORT( source.bd MOD 10000H ), source.fJump ); ELSE OPL.FJump( SHORT( source.bd MOD 10000H ), source.fJump ); END; OPL.DefineLabel( source.tJump ); src.bd := 1; OPL.Move( src, dest ); OPL.Jump( true, label ); OPL.DefineLabel( source.fJump ); src.bd := 0; OPL.Move( src, dest ); OPL.DefineLabel( label ); ELSIF ( size = 1 ) OR ( size = 2 ) OR ( size = 4 ) THEN OPL.Move( source, dest ); ELSE (* complex data structure *) IF source.typ.comp = DynArr THEN Size( source, length, scale ); GetDynArrVal( source ); ELSE IF size MOD 4 = 0 THEN scale := 4; MakeIntConst( size DIV 4, OPT.linttyp, length ); ELSIF size MOD 2 = 0 THEN scale := 2; MakeIntConst( size DIV 2, OPT.linttyp, length ); ELSE scale := 1; MakeIntConst( size, OPT.linttyp, length ); END; (* IF *) END; (* IF *) MoveBlock( scale, length, source, dest ); END; (* IF *) END Assign; PROCEDURE MoveDynArrStack*( formalTyp : OPT.Struct; offset : LONGINT; VAR item : OPL.Item ); (* Moves the address and the length(s) of the given item to (offset, A7). *) VAR source, dest, adr, length, len1 : OPL.Item; typ : OPT.Struct; i, dim : LONGINT; lengthMade : BOOLEAN; BEGIN (* MoveDynArrStack *) dim := formalTyp.n + 1; typ := item.typ; dest.mode := regx; dest.typ := OPT.linttyp; dest.reg := SP.reg; dest.bd := offset; dest.inxReg := None; IF typ.comp = DynArr THEN source := item; GetDynArrAdr( source, adr ); ELSE adr.mode := areg; adr.typ := OPT.sysptrtyp; adr.reg := OPL.GetAdrReg( ); OPL.Lea( item, adr.reg ); END; OPL.Move( adr, dest ); i := typ.offset - typ.n; WHILE ( typ.comp = DynArr ) & ( dim > 1 ) DO INC( dest.bd, 4 ); MakeLen( item, i, length ); OPL.Move( length, dest ); INC( i ); DEC( dim ); typ := typ.BaseTyp; formalTyp := formalTyp.BaseTyp; END; (* WHILE *) WHILE dim > 1 DO INC( dest.bd, 4 ); IF typ.form = String THEN MakeIntConst( item.nolen, OPT.linttyp, length ); ELSE MakeIntConst( typ.n, OPT.linttyp, length ); END; (* IF *) OPL.Move( length, dest ); INC( i ); DEC( dim ); typ := typ.BaseTyp; formalTyp := formalTyp.BaseTyp; END; (* WHILE *) IF ( formalTyp.comp = DynArr ) & ( formalTyp.BaseTyp = OPT.bytetyp ) THEN IF typ.comp = DynArr THEN lengthMade := TRUE; MakeLen( item, i, length ); INC( i ); DEC( dim ); typ := typ.BaseTyp; WHILE typ.comp = DynArr DO MakeLen( item, i, len1 ); OPL.Format12( MULS, len1, length ); INC( i ); DEC( dim ); typ := typ.BaseTyp; END; (* WHILE *) ELSE lengthMade := FALSE; END; (* IF *) IF typ.form = String THEN MakeIntConst( item.nolen, OPT.linttyp, len1 ); ELSE MakeIntConst( typ.size, OPT.linttyp, len1 ); END; (* IF *) IF lengthMade THEN IF len1.bd > 1 THEN OPL.Format12( MULS, len1, length ); END; ELSE length := len1; END; (* IF *) ELSIF typ.comp = DynArr THEN MakeLen( item, i, length ); ELSIF typ.form = String THEN MakeIntConst( item.nolen, OPT.linttyp, length ); ELSE MakeIntConst( typ.n, OPT.linttyp, length ); END; (* IF *) INC( dest.bd, 4 ); OPL.Move( length, dest ); END MoveDynArrStack; PROCEDURE MoveAdrStack*( offset : LONGINT; VAR item : OPL.Item ); (* Moves the address of the given item to (offset, SP). *) VAR dest, adrReg : OPL.Item; BEGIN (* MoveAdrStack *) dest.mode := regx; dest.typ := OPT.sysptrtyp; dest.reg := SP.reg; dest.bd := offset; dest.inxReg := None; dest.offsReg := None; adrReg.mode := areg; adrReg.typ := OPT.sysptrtyp; adrReg.reg := OPL.GetAdrReg( ); OPL.Lea( item, adrReg.reg ); OPL.Move( adrReg, dest ); END MoveAdrStack; PROCEDURE MoveStack*( offset : LONGINT; VAR item : OPL.Item ); (* Moves the given item to (offset, SP). *) VAR dest : OPL.Item; BEGIN (* MoveStack *) dest.mode := regx; dest.typ := item.typ; dest.reg := SP.reg; dest.bd := offset; dest.inxReg := None; dest.offsReg := None; Assign( item, dest ); END MoveStack; PROCEDURE Copy*( VAR source, dest : OPL.Item ); (* Generates code for COPY( source, dest ). dest may not be bigger than 32kB. *) VAR destlen : OPL.Item; label : OPL.Label; src, dst : OPL.Item; BEGIN (* Copy *) src := source; dst := dest; IF src.typ.comp = DynArr THEN GetDynArrVal( src ); END; (* IF *) IF dst.typ.comp = DynArr THEN MakeLen( dst, 0, destlen ); GetDynArrVal( dst ); OPL.Load( destlen ); OPL.Format1( SUBQ, 2, destlen ); ELSE MakeIntConst( dst.typ.n - 2, OPT.linttyp, destlen ); OPL.Load( destlen ); END; (* IF *) MakePostInc( OPT.chartyp, src ); MakePostInc( OPT.chartyp, dst ); label := OPL.NewLabel; OPL.DefineLabel( label ); OPL.Move( src, dst ); OPL.DBcc( EQ, destlen.reg, label ); MakeIntConst( 0, OPT.chartyp, src ); OPL.Move( src, dst ); END Copy; PROCEDURE Decrement*( VAR designator, expression : OPL.Item ); (* Decrements the value of designator by expression *) BEGIN (* Decrement *) IF expression.mode = imm THEN IF ( expression.bd >= 0 ) & ( expression.bd <= 8 ) THEN OPL.Format1( SUBQ, SHORT( expression.bd ), designator ); ELSE OPL.Format6( SUBI, expression.bd, designator ); END; (* IF *) ELSE OPL.Format2( SUB, expression, designator ); END; (* IF *) END Decrement; PROCEDURE Increment*( VAR designator, expression : OPL.Item ); (* Increments the value of designator by expression *) BEGIN (* Increment *) IF expression.mode = imm THEN IF ( expression.bd >= 0 ) & ( expression.bd <= 8 ) THEN OPL.Format1( ADDQ, SHORT( expression.bd ), designator ); ELSE OPL.Format6( ADDI, expression.bd, designator ); END; (* IF *) ELSE OPL.Format2( ADD, expression, designator ); END; (* IF *) END Increment; PROCEDURE Include*( VAR set, element : OPL.Item ); (* set := set + { element } *) VAR temp : OPL.Item; BEGIN (* Include *) temp := set; IF element.mode = imm THEN OPL.Format4( BSET, element.bd, temp ); ELSE OPL.Format5( BSET, element, temp ); END; (* IF *) OPL.Move( temp, set ); END Include; PROCEDURE Exclude*( VAR set, element : OPL.Item ); (* set := set - { element } *) VAR temp : OPL.Item; BEGIN (* Exclude *) temp := set; IF element.mode = imm THEN OPL.Format4( BCLR, element.bd, temp ); ELSE OPL.Format5( BCLR, element, temp ); END; (* IF *) OPL.Move( temp, set ); END Exclude; PROCEDURE EnterMod*; (* Generates code for the entry into the module. *) BEGIN (* EnterMod *) OPL.SetEntry( 0, OPL.pc ); OPL.Enter( 0 ); END EnterMod; PROCEDURE CopyDynArrs( par : OPT.Object ); (* Copys the dynamic arrays which are value-parameters to the stack. *) VAR source, dest, ptr, size, negsize, newSP : OPL.Item; scale : INTEGER; BEGIN (* CopyDynArrs *) WHILE par # NIL DO OPL.usedRegs := { }; IF ( par.typ.comp = DynArr ) & ( par.mode = Var ) THEN MakeVar( par, source ); Size( source, size, scale ); OPL.Load( size ); GetDynArrVal( source ); IF scale = 1 THEN (* align size to 4 bytes *) OPL.Format1( ADDQ, 3, size ); OPL.Format13( ASh, -2, size ); scale := 4; ELSIF scale = 2 THEN OPL.Format1( ADDQ, 1, size ); OPL.Format13( ASh, -1, size ); scale := 4; END; (* IF *) negsize.mode := dreg; negsize.typ := OPT.linttyp; negsize.reg := OPL.GetReg( ); OPL.Move( size, negsize ); OPL.Format7( NEG, negsize ); newSP.mode := regx; newSP.typ := OPT.sysptrtyp; newSP.reg := SP.reg; newSP.bd := 0; newSP.inxReg := negsize.reg; IF size.typ.form = LInt THEN newSP.xsize := 1; ELSE newSP.xsize := 0; END; newSP.scale := OPL.Scale( scale ); OPL.Lea( newSP, SP.reg ); dest.mode := areg; dest.typ := OPT.sysptrtyp; dest.reg := OPL.GetAdrReg( ); OPL.Move( SP, dest ); dest.mode := regx; dest.typ := par.typ; dest.bd := 0; dest.inxReg := None; MoveBlock( scale, size, source, dest ); ptr.mode := regx; ptr.typ := OPT.sysptrtyp; ptr.reg := FP.reg; ptr.bd := par.adr; ptr.inxReg := None; OPL.Move( SP, ptr ); END; (* IF *) par := par.link; END; (* WHILE *) END CopyDynArrs; PROCEDURE EnterProc*( proc : OPT.Object ); (* Generates code for the entry into a procedure. If ptrinit is set, the whole local variable area is initialized. *) VAR source, dest, losize, hisize, adrReg : OPL.Item; dsize, i : LONGINT; label : OPL.Label; BEGIN (* EnterProc *) OPL.DefineLabel( proc.linkadr ); IF proc.adr # -1 THEN OPL.SetEntry( SHORT( proc.adr MOD 10000H ), OPL.pc ); END; (* IF *) dsize := proc.conval.intval; OPL.Enter( -dsize ); IF ptrinit THEN MakeIntConst( 0, OPT.linttyp, source ); dest.mode := regx; dest.typ := OPT.linttyp; dest.reg := SP.reg; dest.bd := 0; dest.inxReg := None; dest.offsReg := None; IF dsize > 8 THEN (* old was 24 *) adrReg.mode := areg; adrReg.typ := OPT.sysptrtyp; adrReg.reg := OPL.GetAdrReg( ); OPL.Move( SP, adrReg ); adrReg.mode := postinc; IF dsize > 20 THEN (* if the constant is small, the code will be shorter, but slower; 20 is the shortest way *) IF dsize > 4 * MAX( INTEGER ) THEN MakeIntConst( ( dsize DIV 4 - 1 ) DIV 10000H, OPT.inttyp, hisize ); OPL.Load( hisize ); MakeIntConst( ( dsize DIV 4 - 1 ) MOD 10000H, OPT.inttyp, losize ); OPL.Load( losize ); label := OPL.NewLabel; OPL.DefineLabel( label ); OPL.Move( source, adrReg ); OPL.DBcc( false, losize.reg, label ); OPL.DBcc( false, hisize.reg, label ); ELSE MakeIntConst( dsize DIV 4 - 1, OPT.inttyp, losize ); OPL.Load( losize ); label := OPL.NewLabel; OPL.DefineLabel( label ); OPL.Move( source, adrReg ); OPL.DBcc( false, losize.reg, label ); END; (* IF *) ELSE FOR i := 1 TO (dsize DIV 4) DO OPL.Move( source, adrReg ); END; END; ELSE FOR i := 1 TO dsize DIV 4 DO OPL.Move( source, dest ); INC( dest.bd, 4 ); END; (* FOR *) END; (* IF *) END; (* IF *) CopyDynArrs( proc.link ); END EnterProc; PROCEDURE Return*( proc : OPT.Object; withRes : BOOLEAN; VAR result : OPL.Item ); (* Generates code for returning from a procedure or a module (proc = NIL). result contains the value that has to be returned in D0 or FP0, if withRes is TRUE. D0 and FP0 can be used because all registers are free. *) VAR d0, fp0 : OPL.Item; BEGIN (* Return *) IF withRes THEN IF proc.typ.form IN RealSet THEN (* result is returned in FP0 *) IF ( result.mode # freg ) OR ( result.reg # 16 ) THEN fp0.mode := freg; fp0.reg := 16; fp0.typ := proc.typ; OPL.FMove( result, fp0 ); END; (* IF *) ELSIF ( result.mode # dreg ) OR ( result.reg # 0 ) THEN d0.mode := dreg; d0.reg := 0; d0.typ := proc.typ; Assign( result, d0 ); (* Assign, not Move because of BOOLEAN return values. *) END; (* IF *) END; (* IF *) OPL.Return; END Return; PROCEDURE WriteStaticLink*( obj : OPT.Object ); (* Writes the static link of the given object to (A7) if necessary. *) VAR source, dest : OPL.Item; diff : INTEGER; BEGIN (* WriteStaticLink *) IF ( obj # NIL ) & ( obj.mnolev > 0 ) & ( obj.mode = LProc ) THEN (* static link needed *) diff := OPL.level - obj.mnolev; IF diff = 0 THEN (* local procedure *) source := FP; ELSE source.mode := regx; source.typ := OPT.sysptrtyp; source.reg := FP.reg; source.bd := 8; source.inxReg := None; source.offsReg := None; IF diff > 1 THEN dest.mode := areg; dest.typ := OPT.sysptrtyp; dest.reg := OPL.GetAdrReg( ); OPL.Move( source, dest ); source.reg := dest.reg; WHILE diff > 2 DO OPL.Move( source, dest ); DEC( diff ); END; (* WHILE *) END; (* IF *) END; (* IF *) MoveStack( 0, source ); END; (* IF *) END WriteStaticLink; PROCEDURE Call*( VAR item : OPL.Item; obj : OPT.Object ); (* Calls the given procedure. *) BEGIN (* Call *) IF ( obj # NIL ) & ( obj.mode = CProc ) THEN OPL.WriteCProc( obj^.conval^.ext ); ELSIF item.mode = imm THEN OPL.Bsr( item.bd ); obj.linkadr := item.bd; ELSE DeRef( OPT.sysptrtyp, item ); OPL.Format15( JSR, item ); END; (* IF *) END Call; PROCEDURE GetResult*( typ : OPT.Struct; VAR res : OPL.Item ); (* Returns the result of a function call. *) VAR d0, fp0 : OPL.Item; BEGIN (* GetResult *) IF typ.form IN RealSet THEN IF 16 IN OPL.usedRegs THEN fp0.mode := freg; fp0.typ := typ; fp0.reg := 16; res.mode := freg; res.typ := typ; res.reg := OPL.GetFReg( ); OPL.FMove( fp0, res ); ELSE res.mode := freg; res.typ := typ; res.reg := 16; INCL( OPL.usedRegs, 16 ); END; (* IF *) ELSIF 0 IN OPL.usedRegs THEN res.mode := dreg; res.typ := typ; res.reg := OPL.GetReg( ); d0.mode := dreg; d0.typ := typ; d0.reg := 0; OPL.Move( d0, res ); ELSE res.mode := dreg; res.typ := typ; res.reg := 0; INCL( OPL.usedRegs, 0 ); END; (* IF *) END GetResult; PROCEDURE TypeTest*( VAR item : OPL.Item; typ : OPT.Struct; guard, equal : BOOLEAN ); (* Generates code for a type test. If equal is true, the two types have to be equal, if guard is true, a Trap is generated if the test fails. If both are false, only the condition codes are set. *) VAR tag : OPL.Item; savedRegs : SET; BEGIN (* TypeTest *) savedRegs := OPL.usedRegs; IF ~ equal THEN DeRef( OPT.sysptrtyp, item ); INC( item.bd, LONG( LONG( OPL.BaseTypeOffs + 4 * typ.extlev ) ) ); END; (* IF *) OPL.Load( item ); StaticTag( typ, tag ); OPL.Cmp( tag, item ); IF equal THEN OPL.Trapcc( NE, eqGuardTrap ); ELSIF guard THEN OPL.Trapcc( NE, guardTrap ); ELSE MakeCocItem( EQ, item ); END; (* IF *) OPL.usedRegs := savedRegs; END TypeTest; PROCEDURE Case*( VAR expression : OPL.Item; lo, hi : LONGINT; VAR label : OPL.Label; VAR jtAdr : LONGINT ); (* Generates the initializing part of a case statement and allocates the jump table. label denotes the else part of the case statement, jtAdr is the address of the jump table. *) VAR loItem, jumpTabEntry, jumpAddress : OPL.Item; jumpTab : ARRAY OPM.MaxCaseRange OF INTEGER; BEGIN (* Case *) OPL.Load( expression ); IF expression.typ.form IN ByteSet THEN Convert( expression, OPT.inttyp ); END; MakeIntConst( lo, expression.typ, loItem ); OPL.Format2( SUB, loItem, expression ); OPL.Format6( CMPI, hi - lo, expression ); OPL.Jump( HI, label ); OPL.AllocBytes( jumpTab, 2 * ( hi - lo + 1 ), jtAdr ); jumpTabEntry.mode := pcx; jumpTabEntry.typ := OPT.inttyp; jumpTabEntry.bd := jtAdr - OPL.ConstSize - OPL.dsize; jumpTabEntry.inxReg := expression.reg; IF expression.typ.size = 4 THEN jumpTabEntry.xsize := 1; ELSE jumpTabEntry.xsize := 0; Convert( expression, OPT.inttyp ); END; (* IF *) jumpTabEntry.scale := 1; (* 2 bytes *) OPL.Load( jumpTabEntry ); jumpAddress.mode := pcx; jumpAddress.typ := OPT.sysptrtyp; jumpAddress.bd := 0; jumpAddress.inxReg := jumpTabEntry.reg; jumpAddress.xsize := 0; (* word *) jumpAddress.scale := 1; (* *2 *) OPL.Format15( JMP, jumpAddress ); END Case; PROCEDURE AddToSP*( data : LONGINT ); (* Subtracts the immediate value 'data' from the stack pointer. *) (* no ADDQ/SUBQ, new OPL does it in a better way *) VAR source : OPL.Item; BEGIN (* AddToSP *) IF data > 0 THEN (*IF data < 8 THEN OPL.Format1( ADDQ, SHORT( data ), SP ); ELSE*) MakeIntConst( data, OPT.linttyp, source ); OPL.Format3( ADD, source, SP.reg ); (*END; (* IF *)*) ELSIF data < 0 THEN data := -data; (*IF data < 8 THEN OPL.Format1( SUBQ, SHORT( data ), SP ); ELSE*) MakeIntConst( data, OPT.linttyp, source ); OPL.Format3( SUB, source, SP.reg ); (*END; (* IF *)*) END; (* IF *) END AddToSP; PROCEDURE Test*( VAR item : OPL.Item ); (* Tests a boolean item and makes a coc item. fcoc items are left unchanged. *) BEGIN (* Test *) IF ( item.mode # coc ) & ( item.mode # fcoc ) THEN OPL.Load( item ); OPL.Format7( TST, item ); MakeCocItem( NE, item ); END; (* IF *) END Test; PROCEDURE UpTo*( VAR low, high, res : OPL.Item ); (* set constructor res := { low .. high }. *) VAR chkItem, leftShift, rightShift : OPL.Item; BEGIN (* UpTo *) res.mode := dreg; res.typ := OPT.settyp; res.reg := OPL.GetReg( ); IF rangeCheck THEN MakeIntConst( OPM.MaxSet, high.typ, chkItem ); IF low.mode # imm THEN OPL.Chk( low, chkItem ); END; IF high.mode # imm THEN OPL.Chk( high, chkItem ); END; END; (* IF *) rightShift.mode := dreg; rightShift.typ := high.typ; rightShift.reg := OPL.GetReg( ); leftShift.mode := dreg; leftShift.typ := high.typ; leftShift.reg := OPL.GetReg( ); OPL.Moveq( OPM.MaxSet, rightShift.reg ); OPL.Format2( SUB, high, rightShift ); OPL.Move( rightShift, leftShift ); OPL.Format2( ADD, low, leftShift ); OPL.Moveq( -1, res.reg ); OPL.Format14( LSh, 1, leftShift, res ); OPL.Format14( LSh, 0, rightShift, res ); OPL.FreeReg( high ); OPL.FreeReg( low ); OPL.FreeReg( leftShift ); OPL.FreeReg( rightShift ); END UpTo; PROCEDURE Abs*( VAR item : OPL.Item ); (* Generates code for the calculation of the absolute value of the given item. *) VAR label : OPL.Label; BEGIN (* Abs *) IF item.typ.form IN RealSet THEN OPL.Format8( FABS, item, item ); ELSE OPL.Load( item ); label := OPL.NewLabel; OPL.Format7( TST, item ); OPL.Jump( GE, label ); OPL.Format7( NEG, item ); OPL.DefineLabel( label ); END; (* IF *) END Abs; PROCEDURE Adr*( VAR item : OPL.Item ); (* Generates code for the calculation of the address of the given item. *) VAR reg : INTEGER; adr : OPL.Item; BEGIN (* Adr *) IF item.typ.comp = DynArr THEN GetDynArrAdr( item, adr ); item := adr; ELSIF item.mode IN { regx, pcx } THEN reg := OPL.GetAdrReg( ); OPL.Lea( item, reg ); item.mode := areg; item.reg := reg; ELSIF item.mode = abs THEN item.mode := immL; ELSE HALT( 94 ); END; (* IF *) item.typ := OPT.sysptrtyp; END Adr; PROCEDURE Cap*( VAR item : OPL.Item ); (* Generates code for the calculation of CAP( item ). For characters only. *) BEGIN (* Cap *) OPL.Load( item ); OPL.Format4( BCLR, 5, item ); END Cap; PROCEDURE Neg*( VAR item : OPL.Item ); (* Generates code for the calculation of -item. *) BEGIN (* Neg *) IF item.typ.form IN RealSet THEN OPL.Format8( FNEG, item, item ); ELSIF item.typ.form = Set THEN OPL.Load( item ); OPL.Format7( NOT, item ); ELSE OPL.Load( item ); OPL.Format7( NEG, item ); END; (* IF *) END Neg; PROCEDURE Not*( VAR item : OPL.Item ); (* Generates code for the calculation of ~ item. For Booleans only. *) VAR tcond, fcond : LONGINT; BEGIN (* Not *) IF ( item.mode = coc ) OR ( item.mode = fcoc ) THEN tcond := item.bd DIV 10000H; fcond := item.bd MOD 10000H; item.bd := 10000H * fcond + tcond; ELSE OPL.Load( item ); OPL.Format7( TST, item ); MakeCocItem( EQ, item ); END; (* IF *) END Not; PROCEDURE Odd*( VAR item : OPL.Item ); (* Generates code for the calculation of ODD( item ). *) BEGIN (* Odd *) OPL.Load( item ); OPL.Format4( BTST, 0, item ); MakeCocItem( NE, item ); END Odd; PROCEDURE Plus*( typ : OPT.Struct; VAR source, dest : OPL.Item ); (* Generates code for the addition dest := dest + source. *) BEGIN (* Plus *) OPL.AssertDestReg( typ, source, dest ); IF typ.form = Set THEN OPL.Format2( oR, source, dest ); ELSIF typ.form IN RealSet THEN OPL.Format8( FADD, source, dest ); ELSE OPL.Format2( ADD, source, dest ); END; (* IF *) OPL.FreeReg( source ); END Plus; PROCEDURE Minus*( typ : OPT.Struct; VAR source, dest : OPL.Item ); (* Generates code for the subtraktion dest := dest - source. *) BEGIN (* Minus *) IF typ.form = Set THEN OPL.Load( dest ); OPL.Load( source ); OPL.Format7( NOT, source ); OPL.Format2( AND, source, dest ); ELSIF typ.form IN RealSet THEN OPL.FLoad( dest ); OPL.Format8( FSUB, source, dest ); ELSE OPL.Load( dest ); OPL.Format2( SUB, source, dest ); END; (* IF *) OPL.FreeReg( source ); END Minus; PROCEDURE Mul*( typ : OPT.Struct; VAR source, dest : OPL.Item ); (* Generates code for the multiplication dest := dest * source. *) BEGIN (* Mul *) OPL.AssertDestReg( typ, source, dest ); IF typ.form = Set THEN OPL.Format2( AND, source, dest ); ELSIF typ.form IN RealSet THEN OPL.Format8( FMUL, source, dest ); ELSIF typ.form = SInt THEN Convert( source, OPT.inttyp ); Convert( dest, OPT.inttyp ); OPL.Format11( MULS, source, dest ); ELSIF typ.form = Int THEN OPL.Format11( MULS, source, dest ); ELSIF typ.form = LInt THEN Convert( source, OPT.linttyp ); Convert( dest, OPT.linttyp ); OPL.Format12( MULS, source, dest ); END; (* IF *) OPL.FreeReg( source ); END Mul; PROCEDURE Divide*( typ : OPT.Struct; VAR source, dest : OPL.Item ); (* Generates code for the division dest := dest / source. *) BEGIN (* Divide *) IF typ.form = Set THEN OPL.Load( dest ); OPL.Eor( source, dest ); ELSE OPL.Format8( FDIV, source, dest ); END; (* IF *) OPL.FreeReg( source ); END Divide; PROCEDURE Div*( VAR source, dest : OPL.Item ); (* Generates code for the integer division dest := dest DIV source. *) VAR label : OPL.Label; remainder : OPL.Item; BEGIN (* Div *) OPL.Load( dest ); Convert( dest, OPT.linttyp ); IF source.typ.form = LInt THEN remainder.mode := dreg; remainder.reg := OPL.GetReg( ); remainder.typ := OPT.linttyp; OPL.Divsl( source, remainder, dest ); OPL.Format4( BTST, 31, remainder ); ELSE Convert( source, OPT.inttyp ); OPL.Format11( DIVS, source, dest ); OPL.Format4( BTST, 31, dest ); END; (* IF *) label := OPL.NewLabel; OPL.Jump( EQ, label ); OPL.Format1( SUBQ, 1, dest ); OPL.DefineLabel( label ); OPL.FreeReg( source ); END Div; PROCEDURE Mod*( VAR source, dest : OPL.Item ); (* Generates code for the remainder dest := dest MOD source.*) VAR label : OPL.Label; remainder : OPL.Item; BEGIN (* Mod *) OPL.Load( source ); (* because it is used twice and may be a pc-item. *) OPL.Load( dest ); Convert( dest, OPT.linttyp ); IF source.typ.form = LInt THEN remainder.mode := dreg; remainder.typ := OPT.linttyp; remainder.reg := OPL.GetReg( ); OPL.Divsl( source, remainder, dest ); dest := remainder; OPL.Format4( BTST, 31, dest ); ELSE Convert( source, OPT.inttyp ); OPL.Format11( DIVS, source, dest ); OPL.Swap( dest ); OPL.Format4( BTST, 15, dest ); END; (* IF *) label := OPL.NewLabel; OPL.Jump( EQ, label ); OPL.Format2( ADD, source, dest ); OPL.DefineLabel( label ); OPL.FreeReg( source ); END Mod; PROCEDURE Mask*( mask : LONGINT; VAR dest : OPL.Item ); (* Generates code for the calculation of dest := dest & ~mask. Used for MOD. *) BEGIN (* Mask *) OPL.Load( dest ); OPL.Format6( ANDI, mask, dest ); END Mask; PROCEDURE In*( VAR element, set, dest : OPL.Item ); (* Generates code for the calculation of dest := element IN set. *) BEGIN (* In *) IF element.mode = imm THEN OPL.Format4( BTST, element.bd, set ); ELSE OPL.Format5( BTST, element, set ); END; (* IF *) MakeCocItem( NE, dest ); END In; PROCEDURE LoadCC*( VAR item : OPL.Item ); (* If item.mode is coc or fcoc, the item is loaded into a data register. *) VAR temp : OPL.Item; BEGIN (* LoadCC *) IF item.mode IN { coc, fcoc } THEN temp := item; item.mode := dreg; item.typ := OPT.booltyp; item.reg := OPL.GetReg( ); Assign( temp, item ); END; (* IF *) END LoadCC; PROCEDURE Compare*( kind : SHORTINT; VAR left, right, res : OPL.Item ); (* Compares left and right and generates a coc- or fcoc-item. *) VAR tCond : INTEGER; dreg1, dreg2 : OPL.Item; begLabel, endLabel : OPL.Label; BEGIN (* Compare *) IF left.typ.form IN RealSet THEN OPL.Format8( FCMP, right, left ); CASE kind OF eql : tCond := FEQ; | neq : tCond := FNE; | lss : tCond := FLT; | leq : tCond := FLE; | gtr : tCond := FGT; | geq : tCond := FGE; END; (* CASE *) MakeFCocItem( tCond, res ); ELSE IF ( left.typ.comp IN { Array, DynArr } ) OR ( left.typ.form = String ) THEN IF left.typ.comp = DynArr THEN GetDynArrVal( left ); END; MakePostInc( OPT.chartyp, left ); IF right.typ.comp = DynArr THEN GetDynArrVal( right ); END; MakePostInc( OPT.chartyp, right ); dreg1.mode := dreg; dreg1.typ := OPT.chartyp; dreg1.reg := OPL.GetReg( ); dreg2.mode := dreg; dreg2.typ := OPT.chartyp; dreg2.reg := OPL.GetReg( ); begLabel := OPL.NewLabel; endLabel := OPL.NewLabel; OPL.DefineLabel( begLabel ); OPL.Move( left, dreg1 ); OPL.Move( right, dreg2 ); OPL.Cmp( dreg2, dreg1 ); OPL.Jump( NE, endLabel ); OPL.Format7( TST, dreg1 ); OPL.Jump( NE, begLabel ); OPL.DefineLabel( endLabel ); OPL.Cmp( dreg2, dreg1 ); ELSE IF right.typ = OPT.niltyp THEN Convert( right, OPT.sysptrtyp ); END; LoadCC( left ); LoadCC( right ); OPL.Cmp( right, left ); END; (* IF *) IF ( left.typ.form = Char ) OR ( left.typ.comp IN { Array, DynArr } ) OR ( left.typ.form = String ) THEN CASE kind OF eql : tCond := EQ; | neq : tCond := NE; | lss : tCond := CS; | leq : tCond := LS; | gtr : tCond := HI; | geq : tCond := CC; END; (* CASE *) ELSE CASE kind OF eql : tCond := EQ; | neq : tCond := NE; | lss : tCond := LT; | leq : tCond := LE; | gtr : tCond := GT; | geq : tCond := GE; END; (* CASE *) END; (* IF *) MakeCocItem( tCond, res ); END; (* IF *) END Compare; PROCEDURE Shift*( opcode : INTEGER; VAR shift, dest : OPL.Item ); (* Generates code for the calculation of ASH( dest, shift ), SYSTEM.LSH( dest, shift ) and SYSTEM.ROT( dest, shift ). *) VAR elseLabel, endLabel : OPL.Label; BEGIN (* Shift *) IF shift.mode = imm THEN IF shift.bd # 0 THEN IF ( shift.bd >= -8 ) & ( shift.bd <= 8 ) THEN OPL.Format13( opcode, SHORT( shift.bd ), dest ); ELSE IF shift.bd < 0 THEN MakeIntConst( -shift.bd, OPT.inttyp, shift ); OPL.Format14( opcode, 0, shift, dest ); ELSE MakeIntConst( shift.bd, OPT.inttyp, shift ); OPL.Format14( opcode, 1, shift, dest ); END; (* IF *) END; (* IF *) END; (* IF *) ELSE (* shift must be tested, because the machine instructions only take positive shifts. *) elseLabel := OPL.NewLabel; endLabel := OPL.NewLabel; OPL.Load( shift ); OPL.Load( dest ); OPL.Format7( TST, shift ); OPL.Jump( LT, elseLabel ); OPL.Format14( opcode, 1, shift, dest ); OPL.Jump( true, endLabel ); OPL.DefineLabel( elseLabel ); OPL.Format7( NEG, shift ); OPL.Format14( opcode, 0, shift, dest ); OPL.DefineLabel( endLabel ); END; (* IF *) END Shift; PROCEDURE Trap*( nr : INTEGER ); (* Generates code for a trap. *) BEGIN (* Trap *) OPL.Trapcc( true, nr ); END Trap; PROCEDURE RunTime( nr : INTEGER ); (* Calls the given run-time routine. *) VAR proc : OPL.Item; BEGIN (* RunTime *) proc.mode := abs; proc.typ := OPT.sysptrtyp; proc.bd := SYSTEM.LSH( LONG( 255 ), 8 ) + nr; OPL.Format15( JSR, proc ); END RunTime; PROCEDURE PtrCheck( typ : OPT.Struct ); VAR ptrTab : ARRAY 1 OF LONGINT; nofptrs : INTEGER; BEGIN (* PtrCheck *) nofptrs := 0; OPL.FindPtrs( typ, 0, ptrTab, nofptrs ); IF nofptrs > 0 THEN OPM.err( -303 ) END; END PtrCheck; PROCEDURE New*( VAR designator, tag : OPL.Item ); (* Generates the code for calling NEW( designator ). *) VAR sppredec, res : OPL.Item; savedRegs : SET; BEGIN (* New *) savedRegs := OPL.usedRegs; PushRegs( savedRegs ); MakeSPPredec( sppredec ); OPL.Move( tag, sppredec ); RunTime( 0 ); AddToSP( 4 ); GetResult( OPT.sysptrtyp, res ); PopRegs( savedRegs ); OPL.Move( res, designator ); END New; PROCEDURE SYSNew*( VAR designator, size : OPL.Item ); (* Generates the code for calling SYSTEM.NEW( designator, size ). *) VAR sppredec, res : OPL.Item; savedRegs : SET; BEGIN (* SYSNew *) PtrCheck( designator.typ.BaseTyp ); savedRegs := OPL.usedRegs; PushRegs( savedRegs ); MakeSPPredec( sppredec ); Convert( size, OPT.linttyp ); OPL.Move( size, sppredec ); RunTime( 1 ); AddToSP( 4 ); GetResult( OPT.sysptrtyp, res ); PopRegs( savedRegs ); OPL.Move( res, designator ); END SYSNew; PROCEDURE SYSMove*( VAR sourceAdr, destAdr, length : OPL.Item ); (* Generates code for SYSTEM.MOVE( sourceAdr, destAdr, length ). *) VAR source, dest : OPL.Item; BEGIN (* SYSMove *) source.mode := areg; source.typ := OPT.linttyp; source.reg := OPL.GetAdrReg( ); Convert( sourceAdr, OPT.linttyp ); OPL.Move( sourceAdr, source ); source.mode := postinc; source.typ := OPT.sinttyp; dest.mode := areg; dest.typ := OPT.linttyp; dest.reg := OPL.GetAdrReg( ); Convert( destAdr, OPT.linttyp ); OPL.Move( destAdr, dest ); dest.mode := postinc; dest.typ := OPT.sinttyp; MoveBlock( 1, length, source, dest ); END SYSMove; PROCEDURE SYSGet*( VAR adr, dest : OPL.Item ); (* Generates code for SYSTEM.GET( adr, dest ). *) VAR adrReg : OPL.Item; BEGIN (* SYSGet *) adrReg.mode := areg; adrReg.typ := OPT.linttyp; adrReg.reg := OPL.GetAdrReg( ); OPL.Move( adr, adrReg ); adrReg.mode := regx; adrReg.bd := 0; adrReg.typ := dest.typ; adrReg.inxReg := None; Assign( adrReg, dest ); END SYSGet; PROCEDURE SYSPut*( VAR source, address : OPL.Item ); (* Generates code for SYSTEM.PUT( source, address ). *) VAR adrReg : OPL.Item; BEGIN (* SYSPut *) adrReg.mode := areg; adrReg.typ := OPT.linttyp; adrReg.reg := OPL.GetAdrReg( ); address.typ := OPT.sysptrtyp; OPL.Move( address, adrReg ); adrReg.mode := regx; adrReg.typ := source.typ; adrReg.bd := 0; adrReg.inxReg := None; Assign( source, adrReg ); END SYSPut; PROCEDURE SYSGetReg*( VAR dest, sourceReg : OPL.Item ); (* Generates code for SYSTEM.GETREG( sourceReg, dest ). *) BEGIN (* SYSGetReg *) sourceReg.reg := SHORT( sourceReg.bd ); sourceReg.typ := dest.typ; IF ( sourceReg.bd >= 0 ) & ( sourceReg.bd <= 7 ) THEN sourceReg.mode := dreg; OPL.Move( sourceReg, dest ); ELSIF ( sourceReg.bd >= 8 ) & ( sourceReg.bd <= 15 ) THEN sourceReg.mode := areg; OPL.Move( sourceReg, dest ); ELSIF ( sourceReg.bd >= 16 ) & ( sourceReg.bd <= 23 ) THEN sourceReg.mode := freg; OPL.FMove( sourceReg, dest ); ELSE OPM.err( 220 ); END; (* IF *) END SYSGetReg; PROCEDURE SYSPutReg*( VAR source, destReg : OPL.Item ); (* Generates code for SYSTEM.PUTREG( destReg, source ). *) BEGIN (* SYSPutReg *) destReg.reg := SHORT( destReg.bd ); IF ( destReg.bd >= 0 ) & ( destReg.bd <= 7 ) THEN destReg.mode := dreg; OPL.Move( source, destReg ); ELSIF ( destReg.bd >= 8 ) & ( destReg.bd <= 15 ) THEN destReg.mode := areg; OPL.Move( source, destReg ); ELSIF ( destReg.bd >= 16 ) & ( destReg.bd <= 23 ) THEN destReg.mode := freg; OPL.FMove( source, destReg ); ELSE OPM.err( 220 ); END; (* IF *) END SYSPutReg; PROCEDURE SYSBit*( VAR adr, bitnr, res : OPL.Item ); (* Generates code for SYSTEM.BIT( adr, bitnr ). *) VAR adrItem : OPL.Item; BEGIN (* SYSBit *) adrItem.mode := areg; adrItem.reg := OPL.GetAdrReg( ); adrItem.typ := OPT.sysptrtyp; adr.typ := OPT.sysptrtyp; OPL.Move( adr, adrItem ); adrItem.mode := regx; adrItem.bd := 0; adrItem.inxReg := None; IF bitnr.mode = imm THEN OPL.Format4( BTST, bitnr.bd, adrItem ); ELSE OPL.Format5( BTST, bitnr, adrItem ); END; (* IF *) MakeCocItem( NE, res ); END SYSBit; BEGIN (* OPC *) FP.mode := areg; FP.typ := OPT.sysptrtyp; FP.reg := 14; SP.mode := areg; SP.typ := OPT.sysptrtyp; SP.reg := 15; saveRegs:=TRUE END OPC.