/
codegen.pas
227 lines (202 loc) · 5.29 KB
/
codegen.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
// *****************************
// *** Code-generation API ***
// *****************************
// ***** Register allocation API ******
var cgRegisterUsage: ^Longint;
Var outputfile: Text;
// cgRequestRegister() reserves a register and returns its number.
Var cgRequestRegisterRet: Longint;
Procedure cgRequestRegister();
var i: Longint;
Begin
cgRequestRegisterRet := -1;
i := 0;
while ((cgRegisterUsage[i] = cTrue) AND (i<32)) do begin
i := i+1;
end;
if i < 32 then begin
cgRegisterUsage[i] := cTrue;
cgRequestRegisterRet := i;
end else begin
Writeln('ERROR: Register allocation failed, all registers taken!');
end;
End;
// cgReleaseRegister(i) releases register i
Procedure cgReleaseRegister(i: Longint);
Begin
cgRegisterUsage[i] := cFalse;
End;
// Initialize the register allocation API related variables
Procedure cgRegAllocInit();
Var i: Longint;
Begin
New(cgRegisterUsage);
i := 0;
while i<31 do begin
cgRegisterUsage[i] := cFalse;
i := i + 1;
end;
cgRegisterUsage[0] := cTrue;
cgRegisterUsage[28] := cTrue; // Reserved for Global Variable address pointer
End;
// ***** Code emitting ******
Type
ptCodeline = ^tCodeline;
tCodeline = Record
op: String;
a: Longint;
b: Longint;
c: Longint;
rem: String;
End;
Var cgCodeLines: ^ptCodeLine; // Array
Var pc: Longint;
procedure cgPut(op: String; a: Longint; b: Longint; c: Longint; rem: String);
begin
New(cgCodeLines[PC]);
cgCodeLines[PC]^.op := op;
cgCodeLines[PC]^.a := a;
cgCodeLines[PC]^.b := b;
cgCodeLines[PC]^.c := c;
cgCodeLines[PC]^.rem := rem;
Writeln(op, ', ', a, ', ', b, ', ', c, '; ', rem);
PC := PC + 1;
End;
procedure cgCodegenInit();
Begin
New(cgCodeLines);
PC := 0;
End;
procedure cgCodegenFinish();
Var i: Longint;
Begin
Assign(outputfile, 'out.asm');
Rewrite(outputfile);
i := 0;
While i < PC Do Begin
Writeln(outputfile, cgCodelines[i]^.op, ', ', cgCodelines[i]^.a, ', ', cgCodelines[i]^.b, ', ', cgCodelines[i]^.c, '; ', cgCodelines[i]^.rem);
i := i + 1;
End;
close(outputfile);
End;
// ***** Item API ****
Type
ptItem = ^tItem;
tItem = Record
fMode: Longint; // one of mCONST, mVAR, mREG, mREF
fType: ptType;
fReg: Longint; // reg[reg] + offset -> address
fOffset: Longint;
fValue: Longint;
fOperator: Longint; // Operator token
fls: Longint;
tru: Longint;
end;
var mCONST: Longint;
var mVar: Longint;
var mREG: Longint;
var mREF: Longint;
// Initialize the ITEM API related parts
Procedure cgItemInit();
Begin
mCONST := 1;
mVAR := 2;
mREG := 3;
mREF := 4;
End;
procedure const2Reg(item: ptItem);
Begin
item^.fMode := mREG;
cgRequestRegister;
item^.fReg := cgRequestRegisterRet;
// assumes_ R0 = 0
cgPut('ADDI', item^.fReg, 0, item^.fValue, 'cg Const2Reg');
item^.fValue := 0;
item^.fOffset := 0;
End;
procedure var2Reg(item: ptItem);
Begin
item^.fMode := mREG;
cgRequestRegister;
cgPut('LDW', cgRequestRegisterRet, item^.fReg, item^.fOffset, 'cg var2Reg');
item^.fReg := cgRequestRegisterRet;
End;
procedure ref2Reg(item: ptItem);
Begin
Writeln('var2Reg not yet implemented!');
end;
procedure cgLoad(item: ptItem);
Begin
if item^.fMode = mCONST then begin
const2Reg(item);
end else begin
if item^.fMode = mVAR then begin
var2Reg(item);
end else begin
if item^.fMode = mREF then begin
ref2Reg(item);
end;
end;
end;
End;
procedure cgAssignmentOperator(leftItem: ptItem; rightItem: ptItem);
Begin
if(leftItem^.fType <> rightItem^.fType) then begin
errorMsg('Type mismatch in assignment');
End;
cgLoad(rightItem);
// leftItem must be in VAR_MODE, rightItem must be in REG_MODE
cgPut('STW', rightItem^.fReg, leftItem^.fReg, leftItem^.fOffset, 'assignmentOperator');
cgReleaseRegister(rightItem^.fReg);
End;
// TODO
// cEql -> BNE
// cNeq -> BEQ
// cLss -> BGE
// cGeq -> BLT
// cLeq -> BGT
// cGtr -> BLE
Var branchNegateRet: String;
Procedure branchNegate(operatorSymbol: Longint);
Begin
End;
// Conditional Jump, to be fixed up later
Procedure cJump(item: ptItem);
Begin
branchNegate(item^.fOperator);
cgPut(branchNegateRet, item^.fReg, 0, item^.fls, 'cJump');
cgReleaseRegister(item^.fReg);
item^.fls := PC - 1;// Remember address of branch instruction for later fixup
End;
Var fJumpRet: Longint;
Procedure fJump();
Begin
cgPut('BR', 0,0,0, 'fJump');
fJumpRet := PC - 1;// remember address for later fixup
End;
Procedure fixUp(branchAddress: Longint);
Begin
cgCodeLines[branchAddress]^.c := PC - branchAddress;
cgCodeLines[branchAddress]^.rem := cgCodeLines[branchAddress]^.rem + ' /fixedUp/';
End;
Procedure fixLink(branchAddress: Longint);
Var nextBranchAddress: Longint;
Begin
while(branchAddress <> 0) do begin
nextBranchAddress := cgCodelines[branchAddress]^.c;
fixUp(branchAddress);
branchAddress := nextBranchAddress;
end;
End;
// Initialize Parts of this module
Procedure cgInit();
Begin
cgCodegenInit;
cgRegAllocInit;
cgItemInit;
// cgPut('ADDI', 1,1,2, 'Test');
End;
Procedure cgEnd();
Begin
cgCodegenFinish;
End;