ACSE 2.0.3
Advanced Compiler System for Education
Loading...
Searching...
No Matches
cfg.c
Go to the documentation of this file.
1
3
4#include <assert.h>
5#include <stdlib.h>
6#include "cfg.h"
7#include "target_info.h"
8#include "target_asm_print.h"
9#include "errors.h"
10
11
12static bool compareCFGRegAndRegID(void *a, void *b)
13{
14 t_cfgReg *cfgReg = (t_cfgReg *)a;
15 t_regID id = *((t_regID *)b);
16
17 if (cfgReg == NULL)
18 return false;
19 return cfgReg->tempRegID == id;
20}
21
22/* Alloc a new control flow graph register object. If a register object
23 * referencing the same identifier already exists, returns the pre-existing
24 * object. */
25static t_cfgReg *createCFGRegister(t_cfg *graph, t_instrArg *arg)
26{
27 // Test if a register with the same identifier is already present.
28 t_listNode *elementFound =
29 listFindWithCallback(graph->registers, &arg->ID, compareCFGRegAndRegID);
30
31 t_cfgReg *result;
32 if (elementFound) {
33 // It's there: just use it.
34 result = (t_cfgReg *)elementFound->data;
35 } else {
36 // If it's not there it needs to be created.
37 result = malloc(sizeof(t_cfgReg));
38 if (result == NULL)
39 fatalError("out of memory");
40 result->tempRegID = arg->ID;
41 result->mcRegWhitelist = NULL;
42 // Insert it in the list of registers
43 graph->registers = listInsert(graph->registers, result, -1);
44 }
45
46 // Copy the machine register allocation constraint, or compute the
47 // intersection between the register allocation constraint sets.
48 if (arg->mcRegWhitelist) {
49 if (result->mcRegWhitelist == NULL) {
51 } else {
52 t_listNode *thisReg = result->mcRegWhitelist;
53 while (thisReg) {
54 t_listNode *nextReg = thisReg->next;
55 if (!listFind(arg->mcRegWhitelist, thisReg->data)) {
56 result->mcRegWhitelist =
57 listRemoveNode(result->mcRegWhitelist, thisReg);
58 }
59 thisReg = nextReg;
60 }
61 if (result->mcRegWhitelist == NULL)
62 fatalError("bug: unsatisfiable register constraints on t%d", arg->ID);
63 }
64 }
65
66 return result;
67}
68
69
70static t_bbNode *newBBNode(t_instruction *instr)
71{
72 t_bbNode *result = malloc(sizeof(t_bbNode));
73 if (result == NULL)
74 fatalError("out of memory");
75 for (int i = 0; i < CFG_MAX_DEFS; i++)
76 result->defs[i] = NULL;
77 for (int i = 0; i < CFG_MAX_USES; i++)
78 result->uses[i] = NULL;
79 result->instr = instr;
80 result->in = NULL;
81 result->out = NULL;
82 result->parent = NULL;
83 return result;
84}
85
88static void deleteBBNode(t_bbNode *node)
89{
90 if (node == NULL)
91 return;
92 deleteList(node->in);
93 deleteList(node->out);
94 free(node);
95}
96
97static void bbNodeComputeDefUses(t_bbNode *node)
98{
99 t_cfg *graph = node->parent->parent;
100 t_instruction *instr = node->instr;
101
102 // Create or lookup CFG register objects for all arguments.
103 t_cfgReg *regDest = NULL;
104 t_cfgReg *regSource1 = NULL;
105 t_cfgReg *regSource2 = NULL;
106 if (instr->rDest != NULL)
107 regDest = createCFGRegister(graph, instr->rDest);
108 if (instr->rSrc1 != NULL)
109 regSource1 = createCFGRegister(graph, instr->rSrc1);
110 if (instr->rSrc2 != NULL)
111 regSource2 = createCFGRegister(graph, instr->rSrc2);
112
113 // Fill the def/use sets for this node.
114 int defIdx = 0;
115 if (regDest)
116 node->defs[defIdx++] = regDest;
117 int useIdx = 0;
118 if (regSource1)
119 node->uses[useIdx++] = regSource1;
120 if (regSource2)
121 node->uses[useIdx++] = regSource2;
122}
123
124
128{
129 t_basicBlock *result = malloc(sizeof(t_basicBlock));
130 if (result == NULL)
131 fatalError("out of memory");
132 result->pred = NULL;
133 result->succ = NULL;
134 result->nodes = NULL;
135 result->parent = NULL;
136 return result;
137}
138
142{
143 if (block == NULL)
144 return;
145
146 deleteList(block->pred);
147 deleteList(block->succ);
148
149 t_listNode *curNode = block->nodes;
150 while (curNode != NULL) {
151 t_bbNode *curCFGNode = (t_bbNode *)curNode->data;
152 deleteBBNode(curCFGNode);
153 curNode = curNode->next;
154 }
155
156 deleteList(block->nodes);
157 free(block);
158}
159
164{
165 // Do not insert if the block is already inserted in the list of predecessors.
166 if (listFind(block->pred, pred) == NULL) {
167 block->pred = listInsert(block->pred, pred, -1);
168 pred->succ = listInsert(pred->succ, block, -1);
169 }
170}
171
176{
177 // Do not insert if the node is already inserted in the list of successors.
178 if (listFind(block->succ, succ) == NULL) {
179 block->succ = listInsert(block->succ, succ, -1);
180 succ->pred = listInsert(succ->pred, block, -1);
181 }
182}
183
185{
186 t_bbNode *newNode = newBBNode(instr);
187 block->nodes = listInsert(block->nodes, newNode, -1);
188 newNode->parent = block;
189 bbNodeComputeDefUses(newNode);
190 return newNode;
191}
192
194 t_basicBlock *block, t_instruction *instr, t_bbNode *ip)
195{
196 t_listNode *listIP = listFind(block->nodes, ip);
197 if (listIP == NULL)
198 fatalError("bug: invalid basic block node; corrupt CFG?");
199
200 t_bbNode *newNode = newBBNode(instr);
201 block->nodes = listInsertBefore(block->nodes, listIP, newNode);
202 newNode->parent = block;
203 bbNodeComputeDefUses(newNode);
204 return newNode;
205}
206
208 t_basicBlock *block, t_instruction *instr, t_bbNode *ip)
209{
210 t_listNode *listIP = listFind(block->nodes, ip);
211 if (listIP == NULL)
212 fatalError("bug: invalid basic block node; corrupt CFG?");
213
214 t_bbNode *newNode = newBBNode(instr);
215 block->nodes = listInsertAfter(block->nodes, listIP, newNode);
216 newNode->parent = block;
217 bbNodeComputeDefUses(newNode);
218 return newNode;
219}
220
221
222static t_cfg *newCFG(void)
223{
224 t_cfg *result = malloc(sizeof(t_cfg));
225 if (result == NULL)
226 fatalError("out of memory");
227 result->blocks = NULL;
228 result->registers = NULL;
229 // Create the dummy ending block.
230 result->endingBlock = newBasicBlock();
231 result->endingBlock->parent = result;
232 return result;
233}
234
235void deleteCFG(t_cfg *graph)
236{
237 t_listNode *curNode;
238 if (graph == NULL)
239 return;
240
241 curNode = graph->blocks;
242 while (curNode) {
243 t_basicBlock *curBlock = (t_basicBlock *)curNode->data;
244 deleteBasicBlock(curBlock);
245 curNode = curNode->next;
246 }
247 deleteList(graph->blocks);
249
250 curNode = graph->registers;
251 while (curNode) {
252 t_cfgReg *curReg = (t_cfgReg *)curNode->data;
253 deleteList(curReg->mcRegWhitelist);
254 free(curReg);
255 curNode = curNode->next;
256 }
257 deleteList(graph->registers);
258
259 free(graph);
260}
261
266{
267 t_basicBlock *block = newBasicBlock();
268 graph->blocks = listInsert(graph->blocks, block, -1);
269 block->parent = graph;
270 return block;
271}
272
273static t_basicBlock *cfgSearchLabel(t_cfg *graph, t_label *label)
274{
275 if (label == NULL)
276 return NULL;
277
278 t_basicBlock *bblock = NULL;
279 t_listNode *curNode = graph->blocks;
280 while (curNode != NULL) {
281 bblock = (t_basicBlock *)curNode->data;
282
283 // Check the first node of the basic block. If its instruction has a label,
284 // check if it's the label we are searching for.
285 t_bbNode *curCFGNode = (t_bbNode *)bblock->nodes->data;
286 if ((curCFGNode->instr)->label != NULL) {
287 if ((curCFGNode->instr)->label->labelID == label->labelID)
288 // Found!
289 break;
290 }
291
292 curNode = curNode->next;
293 }
294
295 return bblock;
296}
297
298
299static bool instrIsStartingNode(t_instruction *instr)
300{
301 return instr->label != NULL;
302}
303
304static bool instrIsEndingNode(t_instruction *instr)
305{
306 return isExitInstruction(instr) || isJumpInstruction(instr);
307}
308
309static void cfgComputeTransitions(t_cfg *graph)
310{
311 // This function is the continuation of programToCFG(), where after creating
312 // the blocks in the CFG we need to construct the transitions between them.
313 // After the basic block construction, all branch instructions are now
314 // found at the end of (some of the) basic blocks. The algorithm for adding
315 // the transitions simply consists of searching for every branch, and adding
316 // the correct outgoing edges to its basic block.
317 t_listNode *curNode = graph->blocks;
318 while (curNode != NULL) {
319 t_basicBlock *curBlock = (t_basicBlock *)curNode->data;
320
321 // Get the last instruction in the basic block.
322 t_listNode *lastNode = listGetLastNode(curBlock->nodes);
323 t_bbNode *lastCFGNode = (t_bbNode *)lastNode->data;
324 t_instruction *lastInstr = lastCFGNode->instr;
325
326 // If the instruction is return-like or exit-like, by definition the next
327 // block is the ending block because it stops the program/subroutine.
328 if (isExitInstruction(lastInstr)) {
329 bbAddSucc(curBlock, graph->endingBlock);
330 bbAddPred(graph->endingBlock, curBlock);
331 continue;
332 }
333
334 // All branch/jump instructions may transfer control to the code
335 // indicated by their label argument, so add edges appropriately.
336 if (isJumpInstruction(lastInstr)) {
337 if (lastInstr->addressParam == NULL)
338 fatalError("bug: malformed jump instruction with no label in CFG");
339 t_basicBlock *jumpBlock = cfgSearchLabel(graph, lastInstr->addressParam);
340 if (jumpBlock == NULL)
341 fatalError("bug: malformed jump instruction with invalid label in CFG");
342 bbAddPred(jumpBlock, curBlock);
343 bbAddSucc(curBlock, jumpBlock);
344 }
345
346 // Additionally, conditional jumps may also not be taken, and in that
347 // case the execution continues to the next instruction.
348 // As the order of the blocks in the block list reflects the order of
349 // the instructions in the program, we can rely on this property to fetch
350 // the correct block for this fallthrough case.
351 if (!isUnconditionalJump(lastInstr)) {
352 t_listNode *nextNode = curNode->next;
353 if (nextNode != NULL) {
354 // The current basic block has a successor in the list, all is fine
355 t_basicBlock *nextBlock = nextNode->data;
356 bbAddSucc(curBlock, nextBlock);
357 bbAddPred(nextBlock, curBlock);
358 } else {
359 // If this is the last basic block in the list, the next block is
360 // the ending block (which exists outside the list).
361 bbAddSucc(curBlock, graph->endingBlock);
362 bbAddPred(graph->endingBlock, curBlock);
363 }
364 }
365
366 curNode = curNode->next;
367 }
368}
369
371{
372 t_cfg *result = newCFG();
373
374 // Generate each basic block, by splitting the list of instruction at each
375 // terminator instruction or labeled instruction. Labeled instructions are
376 // instructions with a label assigned to them. Terminator instructions are
377 // branch-like instructions: branches themselves, but also any instruction
378 // used for subroutine return.
379 // The `bblock' variable contains a basic block we are adding instructions
380 // to, or NULL if we have just found the end of the last basic block and we
381 // are not sure whether to insert a new one. When `bblock' is NULL, a new
382 // block is created lazily at the next instruction found. This ensures no
383 // empty blocks are created.
384 t_basicBlock *bblock = NULL;
385 t_listNode *curNode = program->instructions;
386 while (curNode != NULL) {
387 t_instruction *curInstr = (t_instruction *)curNode->data;
388
389 // If the instruction node needs to be at the beginning of a basic block
390 // (= is labeled) or if `bblock' is NULL (because the last instruction was
391 // a terminator) then create a new basic block.
392 if (instrIsStartingNode(curInstr) || bblock == NULL)
393 bblock = cfgCreateBlock(result);
394
395 // Add the instruction to the end of the current basic block.
396 t_bbNode *curCFGNode = bbInsertInstruction(bblock, curInstr);
397
398 // If the instruction is a basic block terminator, set `bblock' to NULL
399 // to stop inserting nodes into it.
400 if (instrIsEndingNode(curInstr))
401 bblock = NULL;
402
403 curNode = curNode->next;
404 }
405
406 // Now all the blocks have been created, we need to add the edges between
407 // blocks, which is done in the cfgComputeTransitions() function.
408 cfgComputeTransitions(result);
409 return result;
410}
411
412
413void cfgToProgram(t_program *program, t_cfg *graph)
414{
415 // Erase the old code segment.
416 program->instructions = deleteList(program->instructions);
417
418 // Iterate through all the instructions in all the basic blocks (in order)
419 // and re-add them to the program.
420 t_listNode *curBlockNode = graph->blocks;
421 while (curBlockNode != NULL) {
422 t_basicBlock *bblock = (t_basicBlock *)curBlockNode->data;
423 t_listNode *curInnerNode = bblock->nodes;
424 while (curInnerNode != NULL) {
425 t_bbNode *node = (t_bbNode *)curInnerNode->data;
426
427 program->instructions =
428 listInsert(program->instructions, node->instr, -1);
429
430 curInnerNode = curInnerNode->next;
431 }
432 curBlockNode = curBlockNode->next;
433 }
434}
435
436
437int cfgIterateNodes(t_cfg *graph, void *context,
438 int (*callback)(t_bbNode *node, int nodeIndex, void *context))
439{
440 int counter = 0;
441 int exitcode = 0;
442
443 t_listNode *curBlockNode = graph->blocks;
444 while (curBlockNode != NULL) {
445 t_basicBlock *curBlock = (t_basicBlock *)curBlockNode->data;
446
447 t_listNode *curInnerNode = curBlock->nodes;
448 while (curInnerNode != NULL) {
449 t_bbNode *curCFGNode = (t_bbNode *)curInnerNode->data;
450
451 exitcode = callback(curCFGNode, counter, context);
452 if (exitcode != 0)
453 return exitcode;
454
455 counter++;
456 curInnerNode = curInnerNode->next;
457 }
458
459 curBlockNode = curBlockNode->next;
460 }
461 return exitcode;
462}
463
464
466{
467 if (bblock == NULL)
468 return NULL;
469 if (bblock->nodes == NULL)
470 return NULL;
471
472 t_listNode *last = listGetLastNode(bblock->nodes);
473 t_bbNode *lastNode = (t_bbNode *)last->data;
474 return listClone(lastNode->out);
475}
476
478{
479 if (bblock == NULL)
480 return NULL;
481 if (bblock->nodes == NULL)
482 return NULL;
483
484 t_bbNode *firstNode = (t_bbNode *)bblock->nodes->data;
485 return listClone(firstNode->in);
486}
487
488static t_listNode *addElementToSet(t_listNode *set, void *element,
489 bool (*compareFunc)(void *a, void *b), bool *modified)
490{
491 if (element == NULL)
492 return set;
493
494 // Add the element if it's not already in the `set' list.
495 if (listFindWithCallback(set, element, compareFunc) == NULL) {
496 set = listInsert(set, element, -1);
497 if (modified != NULL)
498 (*modified) = true;
499 }
500
501 return set;
502}
503
504static t_listNode *addElementsToSet(t_listNode *set, t_listNode *elements,
505 bool (*compareFunc)(void *a, void *b), bool *modified)
506{
507 // Add all the elements to the set one by one.
508 t_listNode *curNode = elements;
509 while (curNode != NULL) {
510 void *curData = curNode->data;
511 set = addElementToSet(set, curData, compareFunc, modified);
512 curNode = curNode->next;
513 }
514
515 // Return the new list.
516 return set;
517}
518
519static t_listNode *computeLiveInSetEquation(t_cfgReg *defs[CFG_MAX_DEFS],
520 t_cfgReg *uses[CFG_MAX_USES], t_listNode *liveOut)
521{
522 // Initialize live in set as equal to live out set.
523 t_listNode *liveIn = listClone(liveOut);
524
525 // Add all items from set of uses.
526 for (int i = 0; i < CFG_MAX_USES; i++) {
527 if (uses[i] == NULL)
528 continue;
529 if (TARGET_REG_ZERO_IS_CONST && uses[i]->tempRegID == REG_0)
530 continue;
531 liveIn = addElementToSet(liveIn, uses[i], NULL, NULL);
532 }
533
534 // Remove items from set of definitions as long as they are not present in
535 // the set of uses.
536 for (int defIdx = 0; defIdx < CFG_MAX_DEFS; defIdx++) {
537 int found = 0;
538
539 if (defs[defIdx] == NULL)
540 continue;
541 if (TARGET_REG_ZERO_IS_CONST && defs[defIdx]->tempRegID == REG_0)
542 continue;
543
544 for (int useIdx = 0; useIdx < CFG_MAX_USES && !found; useIdx++) {
545 if (uses[useIdx] && uses[useIdx]->tempRegID == defs[defIdx]->tempRegID)
546 found = 1;
547 }
548
549 if (!found)
550 liveIn = listFindAndRemove(liveIn, defs[defIdx]);
551 }
552
553 return liveIn;
554}
555
556/* Re-computes the live registers out of a block by applying the standard
557 * flow equation:
558 * out(block) = union in(block') for all successor block' */
559static t_listNode *cfgComputeLiveOutOfBlock(t_cfg *graph, t_basicBlock *block)
560{
561 // Iterate through all the successor blocks
562 t_listNode *result = NULL;
563 t_listNode *curSuccNode = block->succ;
564 while (curSuccNode != NULL) {
565 t_basicBlock *curSuccessor = (t_basicBlock *)curSuccNode->data;
566
567 if (curSuccessor != graph->endingBlock) {
568 // Update our block's 'out' set by adding all registers 'in' to the
569 // current successor.
570 t_listNode *liveINRegs = bbGetLiveIn(curSuccessor);
571 result = addElementsToSet(result, liveINRegs, NULL, NULL);
572 deleteList(liveINRegs);
573 }
574
575 curSuccNode = curSuccNode->next;
576 }
577
578 return result;
579}
580
581static bool cfgUpdateLivenessOfNodesInBlock(t_cfg *graph, t_basicBlock *bblock)
582{
583 // Keep track of whether we modified something or not.
584 bool modified = false;
585
586 // Start with the last node in the basic block, we will proceed upwards
587 // from there.
588 t_listNode *curLI = listGetLastNode(bblock->nodes);
589 // The live in set of the successors of the last node in the block is the
590 // live out set of the block itself.
591 t_listNode *successorsLiveIn = cfgComputeLiveOutOfBlock(graph, bblock);
592
593 while (curLI != NULL) {
594 // Get the current CFG node.
595 t_bbNode *curNode = (t_bbNode *)curLI->data;
596
597 // Live out of a block is equal to the union of the live in sets of the
598 // successors.
599 curNode->out =
600 addElementsToSet(curNode->out, successorsLiveIn, NULL, &modified);
601 deleteList(successorsLiveIn);
602
603 // Compute the live in set of the block using the set of definition,
604 // uses and live out registers of the block.
605 t_listNode *liveIn =
606 computeLiveInSetEquation(curNode->defs, curNode->uses, curNode->out);
607 curNode->in = addElementsToSet(curNode->in, liveIn, NULL, &modified);
608
609 // Since there are no branches in a basic block, the successors of
610 // the predecessor is just the current block.
611 successorsLiveIn = liveIn;
612
613 // Continue backwards to the previous node.
614 curLI = curLI->prev;
615 }
616
617 deleteList(successorsLiveIn);
618
619 // Return a non-zero value if anything was modified.
620 return modified;
621}
622
623static bool cfgPerformLivenessIteration(t_cfg *graph)
624{
625 bool modified = false;
626 t_listNode *curNode = listGetLastNode(graph->blocks);
627 while (curNode != NULL) {
628 t_basicBlock *curBlock = (t_basicBlock *)curNode->data;
629
630 // Update the liveness informations for the current basic block.
631 if (cfgUpdateLivenessOfNodesInBlock(graph, curBlock))
632 modified = true;
633
634 curNode = curNode->prev;
635 }
636 return modified;
637}
638
640{
641 bool modified;
642 do {
643 modified = cfgPerformLivenessIteration(graph);
644 } while (modified);
645}
646
647
648static void dumpCFGRegister(t_cfgReg *reg, FILE *fout)
649{
650 if (reg->tempRegID == REG_INVALID) {
651 fprintf(fout, "<!UNDEF!>");
652 } else {
653 char *regName = registerIDToString(reg->tempRegID, false);
654 fprintf(fout, "%s", regName);
655 free(regName);
656 }
657}
658
659static void dumpArrayOfCFGRegisters(t_cfgReg **array, int size, FILE *fout)
660{
661 int foundRegs = 0;
662
663 for (int i = 0; i < size; i++) {
664 if (!(array[i]))
665 continue;
666
667 if (foundRegs > 0)
668 fprintf(fout, ", ");
669
670 dumpCFGRegister(array[i], fout);
671 foundRegs++;
672 }
673
674 fflush(fout);
675}
676
677static void dumpListOfCFGRegisters(t_listNode *regs, FILE *fout)
678{
679 if (regs == NULL)
680 return;
681 if (fout == NULL)
682 return;
683
684 t_listNode *currentListNode = regs;
685 while (currentListNode != NULL) {
686 t_cfgReg *curReg = (t_cfgReg *)currentListNode->data;
687 dumpCFGRegister(curReg, fout);
688 if (currentListNode->next != NULL)
689 fprintf(fout, ", ");
690
691 currentListNode = currentListNode->next;
692 }
693 fflush(fout);
694}
695
696static int cfgComputeBBIndex(t_basicBlock *bb)
697{
698 t_cfg *cfg = bb->parent;
699 if (bb == cfg->endingBlock)
700 return listLength(cfg->blocks);
701
702 int res = 1;
703 t_listNode *cur = cfg->blocks;
704 while (cur) {
705 t_basicBlock *bb2 = (t_basicBlock *)cur->data;
706 if (bb2 == bb)
707 return res;
708 res++;
709 cur = cur->next;
710 }
711
712 fatalError("bug: malformed CFG, found basic block not in list");
713}
714
715static void dumpBBList(t_listNode *list, FILE *fout)
716{
717 t_listNode *cur = list;
718 while (cur) {
719 t_basicBlock *bb = (t_basicBlock *)cur->data;
720 fprintf(fout, "%d", cfgComputeBBIndex(bb));
721 cur = cur->next;
722 if (cur)
723 fprintf(fout, ", ");
724 }
725}
726
727static void cfgDumpBB(t_basicBlock *block, FILE *fout, bool verbose)
728{
729 if (block == NULL)
730 return;
731 if (fout == NULL)
732 return;
733
734 fprintf(fout, " Predecessor blocks: {");
735 dumpBBList(block->pred, fout);
736 fprintf(fout, "}\n");
737 fprintf(fout, " Successor blocks: {");
738 dumpBBList(block->succ, fout);
739 fprintf(fout, "}\n");
740
741 int count = 1;
742 t_listNode *elem = block->nodes;
743 while (elem != NULL) {
744 t_bbNode *curCFGNode = (t_bbNode *)elem->data;
745
746 fprintf(fout, " Node %4d: ", count);
747 if (curCFGNode->instr == NULL)
748 fprintf(fout, "(null)");
749 else
750 printInstruction(curCFGNode->instr, fout, false);
751 fprintf(fout, "\n");
752
753 if (verbose) {
754 fprintf(fout, " def = {");
755 dumpArrayOfCFGRegisters(curCFGNode->defs, CFG_MAX_DEFS, fout);
756 fprintf(fout, "}\n");
757 fprintf(fout, " use = {");
758 dumpArrayOfCFGRegisters(curCFGNode->uses, CFG_MAX_USES, fout);
759 fprintf(fout, "}\n");
760
761 fprintf(fout, " in = {");
762 dumpListOfCFGRegisters(curCFGNode->in, fout);
763 fprintf(fout, "}\n");
764 fprintf(fout, " out = {");
765 dumpListOfCFGRegisters(curCFGNode->out, fout);
766 fprintf(fout, "}\n");
767 }
768
769 count++;
770 elem = elem->next;
771 }
772 fflush(fout);
773}
774
775void cfgDump(t_cfg *graph, FILE *fout, bool verbose)
776{
777 if (graph == NULL)
778 return;
779 if (fout == NULL)
780 return;
781
782 fprintf(fout, "# Control Flow Graph dump\n\n");
783
785 fprintf(fout, "%s",
786 "Note: The value of register \'zero\' is immutable.\n"
787 "As a result, it does not appear in the liveness sets.\n\n");
788 }
789
790 fprintf(fout, "Number of basic blocks: %d\n", listLength(graph->blocks));
791 fprintf(
792 fout, "Number of used registers: %d\n\n", listLength(graph->registers));
793
794 fprintf(fout, "## Basic Blocks\n\n");
795
796 int counter = 1;
797 t_listNode *curNode = graph->blocks;
798 while (curNode != NULL) {
799 t_basicBlock *curBlock = (t_basicBlock *)curNode->data;
800 fprintf(fout, "Block %d:\n", counter);
801 cfgDumpBB(curBlock, fout, verbose);
802 fprintf(fout, "\n");
803
804 counter++;
805 curNode = curNode->next;
806 }
807 fflush(fout);
808}
void bbAddPred(t_basicBlock *block, t_basicBlock *pred)
Definition cfg.c:163
t_basicBlock * newBasicBlock(void)
Definition cfg.c:127
void deleteBasicBlock(t_basicBlock *block)
Definition cfg.c:141
t_basicBlock * cfgCreateBlock(t_cfg *graph)
Definition cfg.c:265
void bbAddSucc(t_basicBlock *block, t_basicBlock *succ)
Definition cfg.c:175
Control Flow Graph generation and related analyses.
Error logging utilities.
bool printInstruction(t_instruction *instr, FILE *fp, bool machineRegIDs)
char * registerIDToString(t_regID regID, bool machineRegIDs)
t_listNode * pred
List of predecessors to this basic block.
Definition cfg.h:65
t_regID tempRegID
Register identifier.
Definition cfg.h:34
t_listNode * registers
List of all temporary registers used in the program.
Definition cfg.h:78
t_listNode * mcRegWhitelist
Physical register whitelist. Used by the register allocator.
Definition cfg.h:36
t_listNode * in
Set of registers live at the entry of the node ('in' set).
Definition cfg.h:54
t_listNode * nodes
List of instructions in the block.
Definition cfg.h:67
t_cfg * parent
The containing basic block.
Definition cfg.h:64
t_basicBlock * parent
Pointer to the containing basic block.
Definition cfg.h:46
t_listNode * out
Set of registers live at the exit of the node ('out' set).
Definition cfg.h:56
t_listNode * succ
List of successors to this basic block.
Definition cfg.h:66
t_instruction * instr
Pointer to the instruction associated with this node.
Definition cfg.h:48
t_listNode * blocks
List of all the basic blocks, in program order.
Definition cfg.h:73
t_basicBlock * endingBlock
Definition cfg.h:76
t_cfgReg * defs[CFG_MAX_DEFS]
Set of registers defined by this node ('def' set). NULL slots are ignored.
Definition cfg.h:50
t_cfgReg * uses[CFG_MAX_USES]
Set of registers used by this node ('use' set). NULL slots are ignored.
Definition cfg.h:52
void cfgToProgram(t_program *program, t_cfg *graph)
Definition cfg.c:413
void cfgComputeLiveness(t_cfg *graph)
Definition cfg.c:639
void deleteCFG(t_cfg *graph)
Definition cfg.c:235
t_listNode * bbGetLiveOut(t_basicBlock *bblock)
Definition cfg.c:465
int cfgIterateNodes(t_cfg *graph, void *context, int(*callback)(t_bbNode *node, int nodeIndex, void *context))
Definition cfg.c:437
#define CFG_MAX_USES
Maximum number of temporary register uses for each node.
Definition cfg.h:27
t_bbNode * bbInsertInstruction(t_basicBlock *block, t_instruction *instr)
Definition cfg.c:184
#define CFG_MAX_DEFS
Maximum number of temporary register definitions for each node.
Definition cfg.h:25
t_bbNode * bbInsertInstructionBefore(t_basicBlock *block, t_instruction *instr, t_bbNode *ip)
Definition cfg.c:193
void cfgDump(t_cfg *graph, FILE *fout, bool verbose)
Definition cfg.c:775
t_listNode * bbGetLiveIn(t_basicBlock *bblock)
Definition cfg.c:477
t_cfg * programToCFG(t_program *program)
Definition cfg.c:370
t_bbNode * bbInsertInstructionAfter(t_basicBlock *block, t_instruction *instr, t_bbNode *ip)
Definition cfg.c:207
Definition cfg.h:44
Definition cfg.h:71
Definition cfg.h:32
void fatalError(const char *format,...)
Definition errors.c:32
struct t_listNode * next
Definition list.h:40
struct t_listNode * prev
Definition list.h:42
void * data
Pointer to the data associated to this node.
Definition list.h:44
t_listNode * listInsertBefore(t_listNode *list, t_listNode *listPos, void *data)
Definition list.c:61
t_listNode * listFindAndRemove(t_listNode *list, void *data)
Definition list.c:180
t_listNode * listInsertAfter(t_listNode *list, t_listNode *listPos, void *data)
Definition list.c:44
t_listNode * listClone(t_listNode *list)
Definition list.c:240
t_listNode * listInsert(t_listNode *list, void *data, int pos)
Definition list.c:86
t_listNode * listFind(t_listNode *list, void *data)
Definition list.c:142
int listLength(t_listNode *list)
Definition list.c:214
t_listNode * deleteList(t_listNode *list)
Definition list.c:189
t_listNode * listFindWithCallback(t_listNode *list, void *data, bool(*compareFunc)(void *a, void *b))
Definition list.c:124
t_listNode * listRemoveNode(t_listNode *list, t_listNode *element)
Definition list.c:148
t_listNode * listGetLastNode(t_listNode *list)
Definition list.c:51
A node belonging a list.
Definition list.h:39
t_label * addressParam
Definition program.h:77
t_listNode * instructions
List of instructions.
Definition program.h:100
t_listNode * mcRegWhitelist
Definition program.h:66
unsigned int labelID
Unique numeric identifier for the label.
Definition program.h:49
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
t_regID ID
The register identifier.
Definition program.h:63
t_label * label
Label associated with the instruction, or NULL.
Definition program.h:71
t_instrArg * rDest
Destination argument (or NULL if none).
Definition program.h:73
#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
int t_regID
Type for register identifiers.
Definition program.h:28
#define TARGET_REG_ZERO_IS_CONST
Definition target_info.h:34
bool isUnconditionalJump(t_instruction *instr)
Definition target_info.c:15
bool isJumpInstruction(t_instruction *instr)
Definition target_info.c:21
bool isExitInstruction(t_instruction *instr)
Definition target_info.c:9
Generation of the output assembly program.
Properties of the target machine.