ACSE 2.0.3
Advanced Compiler System for Education
Loading...
Searching...
No Matches
target_transform.c
Go to the documentation of this file.
1
4
5#include <stdarg.h>
6#include <stdbool.h>
7#include <stddef.h>
8#include <stdint.h>
9#include "target_transform.h"
10#include "codegen.h"
11#include "list.h"
12#include "target_info.h"
13
14#define RD(i) (i->rDest->ID)
15#define RS1(i) (i->rSrc1->ID)
16#define RS2(i) (i->rSrc2->ID)
17#define IMM(i) (i->immediate)
18
19#define SYSCALL_ID_PRINT_INT 1
20#define SYSCALL_ID_READ_INT 5
21#define SYSCALL_ID_EXIT_0 10
22#define SYSCALL_ID_PRINT_CHAR 11
23
24
26 t_program *program, t_listNode *prev, t_instruction *instr)
27{
28 program->instructions =
29 listInsertAfter(program->instructions, prev, (void *)instr);
30 if (prev == NULL)
31 return program->instructions;
32 return prev->next;
33}
34
35
37{
38 t_listNode *res = NULL;
39 va_list args;
40 t_regID cur;
41
42 va_start(args, regObj);
43 cur = va_arg(args, t_regID);
44 while (cur != REG_INVALID) {
45 res = listInsert(res, INT_TO_LIST_DATA(cur), -1);
46 cur = va_arg(args, t_regID);
47 }
48 va_end(args);
49
51 regObj->mcRegWhitelist = res;
52}
53
54
56{
57 switch (opcode) {
58 case OPC_ADDI:
59 case OPC_SUBI:
60 case OPC_ANDI:
61 case OPC_ORI:
62 case OPC_XORI:
63 case OPC_MULI:
64 case OPC_DIVI:
65 case OPC_REMI:
66 case OPC_SLLI:
67 case OPC_SRLI:
68 case OPC_SRAI:
69 case OPC_SEQI:
70 case OPC_SNEI:
71 case OPC_SLTI:
72 case OPC_SLTIU:
73 case OPC_SGEI:
74 case OPC_SGEIU:
75 case OPC_SGTI:
76 case OPC_SGTIU:
77 case OPC_SLEI:
78 case OPC_SLEIU:
79 return true;
80 }
81 return false;
82}
83
84
86{
87 switch (orig) {
88 case OPC_ADDI:
89 return OPC_ADD;
90 case OPC_SUBI:
91 return OPC_SUB;
92 case OPC_ANDI:
93 return OPC_AND;
94 case OPC_ORI:
95 return OPC_OR;
96 case OPC_XORI:
97 return OPC_XOR;
98 case OPC_MULI:
99 return OPC_MUL;
100 case OPC_DIVI:
101 return OPC_DIV;
102 case OPC_REMI:
103 return OPC_REM;
104 case OPC_SLLI:
105 return OPC_SLL;
106 case OPC_SRLI:
107 return OPC_SRL;
108 case OPC_SRAI:
109 return OPC_SRA;
110 case OPC_SEQI:
111 return OPC_SEQ;
112 case OPC_SNEI:
113 return OPC_SNE;
114 case OPC_SLTI:
115 return OPC_SLT;
116 case OPC_SLTIU:
117 return OPC_SLTU;
118 case OPC_SGEI:
119 return OPC_SGE;
120 case OPC_SGEIU:
121 return OPC_SGEU;
122 case OPC_SGTI:
123 return OPC_SGT;
124 case OPC_SGTIU:
125 return OPC_SGTU;
126 case OPC_SLEI:
127 return OPC_SLE;
128 case OPC_SLEIU:
129 return OPC_SLEU;
130 }
131 return orig;
132}
133
134
135bool isInt12(int immediate)
136{
137 return immediate < (1 << 11) && immediate >= -(1 << 11);
138}
139
140
142{
143 t_listNode *curi = program->instructions;
144
145 while (curi) {
146 t_listNode *transformedInstrLnk = curi;
147 t_instruction *instr = curi->data;
148
150 curi = curi->next;
151 continue;
152 }
153
154 if (instr->opcode == OPC_ADDI && instr->rSrc1->ID == REG_0) {
155 if (!isInt12(instr->immediate)) {
156 curi = addInstrAfter(program, curi, genLI(NULL, RD(instr), IMM(instr)));
157 removeInstructionAt(program, transformedInstrLnk);
158 }
159
160 } else if (instr->opcode == OPC_MULI || instr->opcode == OPC_DIVI ||
161 instr->opcode == OPC_REMI || !isInt12(instr->immediate)) {
162 t_regID reg = getNewRegister(program);
163 int newOpc = getMatchingNonImmediateOpcode(instr->opcode);
164 curi = addInstrAfter(program, curi, genLI(NULL, reg, IMM(instr)));
165 curi = addInstrAfter(program, curi,
166 genInstruction(NULL, newOpc, RD(instr), RS1(instr), reg, NULL, 0));
167 removeInstructionAt(program, transformedInstrLnk);
168
169 } else if (instr->opcode == OPC_SLLI || instr->opcode == OPC_SRLI ||
170 instr->opcode == OPC_SRAI) {
171 instr->immediate = (unsigned)(instr->immediate) & 0x1F;
172 }
173
174 curi = curi->next;
175 }
176}
177
178
180{
181 t_listNode *curi = program->instructions;
182
183 while (curi) {
184 t_listNode *transformedInstrLnk = curi;
185 t_instruction *instr = curi->data;
186
187 if (instr->opcode == OPC_SUBI) {
188 instr->opcode = OPC_ADDI;
189 instr->immediate = -instr->immediate;
190
191 } else if (instr->opcode == OPC_SEQ || instr->opcode == OPC_SNE ||
192 instr->opcode == OPC_SEQI || instr->opcode == OPC_SNEI) {
193 if (instr->opcode == OPC_SEQ || instr->opcode == OPC_SNE)
194 curi = addInstrAfter(
195 program, curi, genSUB(NULL, RD(instr), RS1(instr), RS2(instr)));
196 else
197 curi = addInstrAfter(
198 program, curi, genADDI(NULL, RD(instr), RS1(instr), -IMM(instr)));
199 if (instr->opcode == OPC_SEQ || instr->opcode == OPC_SEQI)
200 curi = addInstrAfter(
201 program, curi, genSLTIU(NULL, RD(instr), RD(instr), 1));
202 else
203 curi = addInstrAfter(
204 program, curi, genSLTU(NULL, RD(instr), REG_0, RD(instr)));
205 removeInstructionAt(program, transformedInstrLnk);
206
207 } else if ((instr->opcode == OPC_SGTI && IMM(instr) == INT32_MAX) ||
208 (instr->opcode == OPC_SGTIU && (uint32_t)IMM(instr) == UINT32_MAX)) {
209 curi = addInstrAfter(program, curi, genLI(NULL, RD(instr), 0));
210 removeInstructionAt(program, transformedInstrLnk);
211
212 } else if (instr->opcode == OPC_SGE || instr->opcode == OPC_SGEU ||
213 instr->opcode == OPC_SGEI || instr->opcode == OPC_SGEIU ||
214 instr->opcode == OPC_SGTI || instr->opcode == OPC_SGTIU ||
215 instr->opcode == OPC_SLE || instr->opcode == OPC_SLEU) {
216 if (instr->opcode == OPC_SGE) {
217 instr->opcode = OPC_SLT;
218 } else if (instr->opcode == OPC_SGEI) {
219 instr->opcode = OPC_SLTI;
220 } else if (instr->opcode == OPC_SGEU) {
221 instr->opcode = OPC_SLTU;
222 } else if (instr->opcode == OPC_SGEIU) {
223 instr->opcode = OPC_SLTIU;
224 } else if (instr->opcode == OPC_SGTI) {
225 instr->opcode = OPC_SLTI;
226 instr->immediate += 1;
227 } else if (instr->opcode == OPC_SGTIU) {
228 instr->opcode = OPC_SLTIU;
229 instr->immediate += 1;
230 } else {
231 t_instrArg *tmp = instr->rSrc1;
232 instr->rSrc1 = instr->rSrc2;
233 instr->rSrc2 = tmp;
234 if (instr->opcode == OPC_SLE)
235 instr->opcode = OPC_SLT;
236 else if (instr->opcode == OPC_SLEU)
237 instr->opcode = OPC_SLTU;
238 }
239 curi =
240 addInstrAfter(program, curi, genXORI(NULL, RD(instr), RD(instr), 1));
241
242 } else if ((instr->opcode == OPC_SLEI && IMM(instr) == INT32_MAX) ||
243 (instr->opcode == OPC_SLEIU && (uint32_t)IMM(instr) == UINT32_MAX)) {
244 curi = addInstrAfter(program, curi, genLI(NULL, RD(instr), 1));
245 removeInstructionAt(program, transformedInstrLnk);
246
247 } else if (instr->opcode == OPC_SLEI) {
248 instr->opcode = OPC_SLTI;
249 instr->immediate += 1;
250
251 } else if (instr->opcode == OPC_SLEIU) {
252 instr->opcode = OPC_SLTIU;
253 instr->immediate += 1;
254
255 } else if (instr->opcode == OPC_SGT || instr->opcode == OPC_SGTU) {
256 t_instrArg *tmp;
257 if (instr->opcode == OPC_SGT)
258 instr->opcode = OPC_SLT;
259 else if (instr->opcode == OPC_SGTU)
260 instr->opcode = OPC_SLTU;
261 tmp = instr->rSrc1;
262 instr->rSrc1 = instr->rSrc2;
263 instr->rSrc2 = tmp;
264
265 } else if (instr->opcode == OPC_SW_G) {
266 // We always force the temporary argument of SW instructions to be T6.
267 // This solves two problems. First, as T6 is never used by register
268 // allocation, we can freely use global SW instructions to generate stores
269 // to spilled registers. The other problem this solves is that the
270 // register allocation is not aware of the fact that the register used for
271 // the first operand must be different than the register of the temporary
272 // operand; by forcing T6 here we avoid the assignment of the two to the
273 // same register by construction.
275 }
276
277 curi = curi->next;
278 }
279}
280
281
282void fixSyscalls(t_program *program)
283{
284 t_listNode *curi = program->instructions;
285
286 while (curi) {
287 t_listNode *transformedInstrLnk = curi;
288 t_instruction *instr = curi->data;
289
290 if (instr->opcode != OPC_CALL_EXIT_0 &&
291 instr->opcode != OPC_CALL_READ_INT &&
292 instr->opcode != OPC_CALL_PRINT_INT &&
293 instr->opcode != OPC_CALL_PRINT_CHAR) {
294 curi = curi->next;
295 continue;
296 }
297
298 // Load syscall ID in a7.
299 int func;
300 if (instr->opcode == OPC_CALL_EXIT_0)
301 func = SYSCALL_ID_EXIT_0;
302 else if (instr->opcode == OPC_CALL_PRINT_INT)
304 else if (instr->opcode == OPC_CALL_READ_INT)
305 func = SYSCALL_ID_READ_INT;
306 else // if (instr->opcode == OPC_CALL_PRINT_CHAR)
308 t_regID rFunc = getNewRegister(program);
309 curi = addInstrAfter(program, curi, genLI(NULL, rFunc, func));
310
311 // Load argument in a0, if there is one.
312 t_regID rArg;
313 if (instr->rSrc1) {
314 rArg = getNewRegister(program);
315 t_instruction *tmp = genADDI(NULL, rArg, RS1(instr), 0);
316 curi = addInstrAfter(program, curi, tmp);
317 } else {
318 rArg = REG_INVALID;
319 }
320
321 // Generate an ECALL.
322 t_regID rd;
323 if (instr->rDest)
324 rd = getNewRegister(program);
325 else
326 rd = REG_INVALID;
327 t_instruction *ecall =
328 genInstruction(NULL, OPC_ECALL, rd, rFunc, rArg, NULL, 0);
329 curi = addInstrAfter(program, curi, ecall);
330 if (ecall->rDest)
332 if (ecall->rSrc1)
334 if (ecall->rSrc2)
336
337 // Move a0 (result) to the destination register if needed.
338 if (instr->rDest)
339 curi = addInstrAfter(program, curi, genADDI(NULL, RD(instr), rd, 0));
340
341 // Remove the old call instruction.
342 removeInstructionAt(program, transformedInstrLnk);
343
344 curi = curi->next;
345 }
346}
347
348
350{
351 fixPseudoInstructions(program);
352 fixSyscalls(program);
354}
Code generation functions.
t_instruction * genXORI(t_program *program, t_regID rd, t_regID rs1, int immediate)
Definition codegen.c:133
t_instruction * genSUB(t_program *program, t_regID rd, t_regID rs1, t_regID rs2)
Definition codegen.c:52
t_instruction * genSLTU(t_program *program, t_regID rd, t_regID rs1, t_regID rs2)
Definition codegen.c:185
t_instruction * genLI(t_program *program, t_regID rd, int immediate)
Definition codegen.c:350
t_instruction * genSLTIU(t_program *program, t_regID rd, t_regID rs1, int immediate)
Definition codegen.c:239
t_instruction * genADDI(t_program *program, t_regID rd, t_regID rs1, int immediate)
Definition codegen.c:103
struct t_listNode * next
Definition list.h:40
void * data
Pointer to the data associated to this node.
Definition list.h:44
t_listNode * listInsertAfter(t_listNode *list, t_listNode *listPos, void *data)
Definition list.c:44
t_listNode * listInsert(t_listNode *list, void *data, int pos)
Definition list.c:86
#define INT_TO_LIST_DATA(data)
Convert an integer from a list data pointer.
Definition list.h:33
t_listNode * deleteList(t_listNode *list)
Definition list.c:189
A node belonging a list.
Definition list.h:39
t_listNode * instructions
List of instructions.
Definition program.h:100
t_listNode * mcRegWhitelist
Definition program.h:66
t_instrArg * rSrc1
First source argument (or NULL if none).
Definition program.h:74
t_instrArg * rSrc2
Second source argument (or NULL if none).
Definition program.h:75
int immediate
Immediate argument.
Definition program.h:76
t_regID ID
The register identifier.
Definition program.h:63
t_instrArg * rDest
Destination argument (or NULL if none).
Definition program.h:73
int opcode
Instruction opcode.
Definition program.h:72
t_regID getNewRegister(t_program *program)
Definition program.c:398
#define REG_INVALID
Constant used for invalid register identifiers.
Definition program.h:31
#define REG_0
Constant identifying a register whose value is always zero.
Definition program.h:33
void removeInstructionAt(t_program *program, t_listNode *instrLi)
Definition program.c:361
t_instruction * genInstruction(t_program *program, int opcode, t_regID rd, t_regID rs1, t_regID rs2, t_label *label, int immediate)
Definition program.c:338
int t_regID
Type for register identifiers.
Definition program.h:28
void doTargetSpecificTransformations(t_program *program)
@ OPC_SGTU
@ OPC_ECALL
@ OPC_SGTI
@ OPC_CALL_EXIT_0
@ OPC_SW_G
@ OPC_MULI
@ OPC_DIV
Definition target_info.h:94
@ OPC_SLTU
@ OPC_SLT
@ OPC_SRL
Definition target_info.h:97
@ OPC_XORI
@ OPC_ADDI
@ OPC_SGT
@ OPC_SEQI
@ OPC_OR
Definition target_info.h:91
@ OPC_SUB
Definition target_info.h:89
@ OPC_SGEIU
@ OPC_XOR
Definition target_info.h:92
@ OPC_SLTIU
@ OPC_CALL_PRINT_CHAR
@ OPC_SGTIU
@ OPC_CALL_READ_INT
@ OPC_SLTI
@ OPC_SNE
@ OPC_SRLI
@ OPC_SRA
Definition target_info.h:98
@ OPC_SLL
Definition target_info.h:96
@ OPC_SLEU
@ OPC_ORI
@ OPC_REM
Definition target_info.h:95
@ OPC_SLEI
@ OPC_ANDI
@ OPC_SEQ
@ OPC_ADD
Definition target_info.h:88
@ OPC_SLEIU
@ OPC_SGEI
@ OPC_CALL_PRINT_INT
@ OPC_SNEI
@ OPC_SUBI
@ OPC_DIVI
@ OPC_SRAI
@ OPC_MUL
Definition target_info.h:93
@ OPC_REMI
@ OPC_SLLI
@ OPC_AND
Definition target_info.h:90
@ OPC_SGEU
@ OPC_SLE
@ OPC_SGE
@ REG_A0
Definition target_info.h:55
@ REG_A7
Definition target_info.h:62
@ REG_T6
Definition target_info.h:76
A double-linked list.
Properties of the target machine.
int getMatchingNonImmediateOpcode(int orig)
#define SYSCALL_ID_READ_INT
bool isImmediateArgumentInstrOpcode(int opcode)
void setMCRegisterWhitelist(t_instrArg *regObj,...)
#define RS1(i)
#define IMM(i)
#define RS2(i)
#define SYSCALL_ID_EXIT_0
void fixPseudoInstructions(t_program *program)
void fixUnsupportedImmediates(t_program *program)
t_listNode * addInstrAfter(t_program *program, t_listNode *prev, t_instruction *instr)
#define SYSCALL_ID_PRINT_CHAR
#define SYSCALL_ID_PRINT_INT
#define RD(i)
bool isInt12(int immediate)
void fixSyscalls(t_program *program)
Transformation pass for lowering target machine details.