0,0 → 1,434 |
(* |
BSD 2-Clause License |
|
Copyright (c) 2018, 2019, Anton Krotov |
All rights reserved. |
*) |
|
MODULE REG; |
|
|
CONST |
|
N = 16; |
|
R0* = 0; R1* = 1; R2* = 2; |
R8* = 8; R9* = 9; R10* = 10; R11* = 11; |
|
NVR = 32; |
|
|
TYPE |
|
OP1 = PROCEDURE (arg: INTEGER); |
OP2 = PROCEDURE (arg1, arg2: INTEGER); |
OP3 = PROCEDURE (arg1, arg2, arg3: INTEGER); |
|
REGS* = POINTER TO RECORD |
|
regs*: SET; |
stk*: ARRAY N OF INTEGER; |
top*: INTEGER; |
pushed*: INTEGER; |
|
vregs*: SET; |
offs: ARRAY NVR OF INTEGER; |
size: ARRAY NVR OF INTEGER; |
|
push, pop: OP1; |
mov, xch: OP2; |
load, save: OP3 |
|
END; |
|
|
PROCEDURE push (R: REGS); |
VAR |
i, reg: INTEGER; |
|
BEGIN |
reg := R.stk[0]; |
INCL(R.regs, reg); |
R.push(reg); |
FOR i := 0 TO R.top - 1 DO |
R.stk[i] := R.stk[i + 1] |
END; |
DEC(R.top); |
INC(R.pushed) |
END push; |
|
|
PROCEDURE pop (R: REGS; reg: INTEGER); |
VAR |
i: INTEGER; |
|
BEGIN |
FOR i := R.top + 1 TO 1 BY -1 DO |
R.stk[i] := R.stk[i - 1] |
END; |
R.stk[0] := reg; |
EXCL(R.regs, reg); |
R.pop(reg); |
INC(R.top); |
DEC(R.pushed) |
END pop; |
|
|
PROCEDURE InStk (R: REGS; reg: INTEGER): INTEGER; |
VAR |
i, n: INTEGER; |
|
BEGIN |
i := 0; |
n := R.top; |
WHILE (i <= n) & (R.stk[i] # reg) DO |
INC(i) |
END; |
|
IF i > n THEN |
i := -1 |
END |
|
RETURN i |
END InStk; |
|
|
PROCEDURE GetFreeReg (R: REGS): INTEGER; |
VAR |
i: INTEGER; |
|
BEGIN |
i := 0; |
WHILE (i < N) & ~(i IN R.regs) DO |
INC(i) |
END; |
|
IF i = N THEN |
i := -1 |
END |
|
RETURN i |
END GetFreeReg; |
|
|
PROCEDURE Put (R: REGS; reg: INTEGER); |
BEGIN |
EXCL(R.regs, reg); |
INC(R.top); |
R.stk[R.top] := reg |
END Put; |
|
|
PROCEDURE PopAnyReg (R: REGS): INTEGER; |
VAR |
reg: INTEGER; |
|
BEGIN |
reg := GetFreeReg(R); |
ASSERT(reg # -1); |
ASSERT(R.top < LEN(R.stk) - 1); |
ASSERT(R.pushed > 0); |
pop(R, reg) |
|
RETURN reg |
END PopAnyReg; |
|
|
PROCEDURE GetAnyReg* (R: REGS): INTEGER; |
VAR |
reg: INTEGER; |
|
BEGIN |
reg := GetFreeReg(R); |
IF reg = -1 THEN |
ASSERT(R.top >= 0); |
reg := R.stk[0]; |
push(R) |
END; |
|
Put(R, reg) |
|
RETURN reg |
END GetAnyReg; |
|
|
PROCEDURE GetReg* (R: REGS; reg: INTEGER): BOOLEAN; |
VAR |
free, n: INTEGER; |
res: BOOLEAN; |
|
|
PROCEDURE exch (R: REGS; reg1, reg2: INTEGER); |
VAR |
n1, n2: INTEGER; |
|
BEGIN |
n1 := InStk(R, reg1); |
n2 := InStk(R, reg2); |
R.stk[n1] := reg2; |
R.stk[n2] := reg1; |
R.xch(reg1, reg2) |
END exch; |
|
|
BEGIN |
IF reg IN R.regs THEN |
Put(R, reg); |
res := TRUE |
ELSE |
n := InStk(R, reg); |
IF n # -1 THEN |
free := GetFreeReg(R); |
IF free # -1 THEN |
Put(R, free); |
exch(R, reg, free) |
ELSE |
push(R); |
free := GetFreeReg(R); |
ASSERT(free # -1); |
Put(R, free); |
IF free # reg THEN |
exch(R, reg, free) |
END |
END; |
res := TRUE |
ELSE |
res := FALSE |
END |
END |
|
RETURN res |
END GetReg; |
|
|
PROCEDURE Exchange* (R: REGS; reg1, reg2: INTEGER): BOOLEAN; |
VAR |
n1, n2: INTEGER; |
res: BOOLEAN; |
|
BEGIN |
res := FALSE; |
|
IF reg1 # reg2 THEN |
n1 := InStk(R, reg1); |
n2 := InStk(R, reg2); |
|
IF (n1 # -1) & (n2 # -1) THEN |
R.stk[n1] := reg2; |
R.stk[n2] := reg1; |
R.xch(reg2, reg1); |
res := TRUE |
ELSIF (n1 # -1) & (reg2 IN R.regs) THEN |
R.stk[n1] := reg2; |
INCL(R.regs, reg1); |
EXCL(R.regs, reg2); |
R.mov(reg2, reg1); |
res := TRUE |
ELSIF (n2 # -1) & (reg1 IN R.regs) THEN |
R.stk[n2] := reg1; |
EXCL(R.regs, reg1); |
INCL(R.regs, reg2); |
R.mov(reg1, reg2); |
res := TRUE |
END |
ELSE |
res := TRUE |
END |
|
RETURN res |
END Exchange; |
|
|
PROCEDURE Drop* (R: REGS); |
BEGIN |
INCL(R.regs, R.stk[R.top]); |
DEC(R.top) |
END Drop; |
|
|
PROCEDURE BinOp* (R: REGS; VAR reg1, reg2: INTEGER); |
BEGIN |
IF R.top > 0 THEN |
reg1 := R.stk[R.top - 1]; |
reg2 := R.stk[R.top] |
ELSIF R.top = 0 THEN |
reg1 := PopAnyReg(R); |
reg2 := R.stk[R.top] |
ELSIF R.top < 0 THEN |
reg2 := PopAnyReg(R); |
reg1 := PopAnyReg(R) |
END |
END BinOp; |
|
|
PROCEDURE UnOp* (R: REGS; VAR reg: INTEGER); |
BEGIN |
IF R.top >= 0 THEN |
reg := R.stk[R.top] |
ELSE |
reg := PopAnyReg(R) |
END |
END UnOp; |
|
|
PROCEDURE PushAll* (R: REGS); |
BEGIN |
WHILE R.top >= 0 DO |
push(R) |
END |
END PushAll; |
|
|
PROCEDURE Lock* (R: REGS; reg, offs, size: INTEGER); |
BEGIN |
ASSERT(reg IN R.vregs); |
ASSERT(offs # 0); |
R.offs[reg] := offs; |
IF size = 0 THEN |
size := 8 |
END; |
R.size[reg] := size |
END Lock; |
|
|
PROCEDURE Release* (R: REGS; reg: INTEGER); |
BEGIN |
ASSERT(reg IN R.vregs); |
R.offs[reg] := 0 |
END Release; |
|
|
PROCEDURE Load* (R: REGS; reg: INTEGER); |
VAR |
offs: INTEGER; |
|
BEGIN |
ASSERT(reg IN R.vregs); |
offs := R.offs[reg]; |
IF offs # 0 THEN |
R.load(reg, offs, R.size[reg]) |
END |
END Load; |
|
|
PROCEDURE Save* (R: REGS; reg: INTEGER); |
VAR |
offs: INTEGER; |
|
BEGIN |
ASSERT(reg IN R.vregs); |
offs := R.offs[reg]; |
IF offs # 0 THEN |
R.save(reg, offs, R.size[reg]) |
END |
END Save; |
|
|
PROCEDURE Store* (R: REGS); |
VAR |
i: INTEGER; |
|
BEGIN |
FOR i := 0 TO NVR - 1 DO |
IF i IN R.vregs THEN |
Save(R, i) |
END |
END |
END Store; |
|
|
PROCEDURE Restore* (R: REGS); |
VAR |
i: INTEGER; |
|
BEGIN |
FOR i := 0 TO NVR - 1 DO |
IF i IN R.vregs THEN |
Load(R, i) |
END |
END |
END Restore; |
|
|
PROCEDURE Reset* (R: REGS); |
VAR |
i: INTEGER; |
|
BEGIN |
FOR i := 0 TO NVR - 1 DO |
IF i IN R.vregs THEN |
R.offs[i] := 0 |
END |
END |
END Reset; |
|
|
PROCEDURE GetVarReg* (R: REGS; offs: INTEGER): INTEGER; |
VAR |
i, res: INTEGER; |
|
BEGIN |
res := -1; |
i := 0; |
WHILE i < NVR DO |
IF (i IN R.vregs) & (R.offs[i] = offs) THEN |
res := i; |
i := NVR |
END; |
INC(i) |
END |
|
RETURN res |
END GetVarReg; |
|
|
PROCEDURE GetAnyVarReg* (R: REGS): INTEGER; |
VAR |
i, res: INTEGER; |
|
BEGIN |
res := -1; |
i := 0; |
WHILE i < NVR DO |
IF (i IN R.vregs) & (R.offs[i] = 0) THEN |
res := i; |
i := NVR |
END; |
INC(i) |
END |
|
RETURN res |
END GetAnyVarReg; |
|
|
PROCEDURE Create* (push, pop: OP1; mov, xch: OP2; load, save: OP3; regs, vregs: SET): REGS; |
VAR |
R: REGS; |
i: INTEGER; |
|
BEGIN |
NEW(R); |
|
R.regs := regs; |
R.pushed := 0; |
R.top := -1; |
|
R.push := push; |
R.pop := pop; |
R.mov := mov; |
R.xch := xch; |
R.load := load; |
R.save := save; |
|
R.vregs := vregs; |
|
FOR i := 0 TO NVR - 1 DO |
R.offs[i] := 0; |
R.size[i] := 0 |
END |
|
RETURN R |
END Create; |
|
|
END REG. |