18#define MAX_INSTR_ARGS (CFG_MAX_DEFS + CFG_MAX_USES)
21#define RA_SPILL_REQUIRED ((t_regID)(-2))
23#define RA_REGISTER_INVALID ((t_regID)(-1))
112 if (interval == NULL)
120static int compareLiveIntStartPoints(
void *varA,
void *varB)
135static int compareLiveIntEndPoints(
void *varA,
void *varB)
149static bool compareLiveIntWithRegID(
void *a,
void *b)
161static t_listNode *updateIntervalsWithLiveVarAtLocation(
166 intervals, &(var->
tempRegID), compareLiveIntWithRegID);
168 if (!element_found) {
172 intervals =
listInsert(intervals, interval, -1);
177 assert(interval_found->startPoint <= counter);
178 assert(interval_found->endPoint <= counter);
179 interval_found->endPoint = counter;
187static t_listNode *updateIntervalsWithInstrAtLocation(
193 while (elem != NULL) {
195 result = updateIntervalsWithLiveVarAtLocation(result, curCFGReg, counter);
200 while (elem != NULL) {
202 result = updateIntervalsWithLiveVarAtLocation(result, curCFGReg, counter);
209 updateIntervalsWithLiveVarAtLocation(result, node->
defs[i], counter);
215static int getLiveIntervalsNodeCallback(
216 t_bbNode *node,
int nodeIndex,
void *context)
219 *list = updateIntervalsWithInstrAtLocation(*list, node, nodeIndex);
238 for (; b; b = b->
next) {
250 for (; b; b = b->
next) {
269 for (; i; i = i->
next) {
280 for (; j; j = j->
next) {
305static int handleCallerSaveRegistersNodeCallback(
306 t_bbNode *node,
int nodeIndex,
void *context)
315 if (node->
defs[i] != NULL)
320 if (node->
uses[i] != NULL)
329 if (ival->
startPoint <= nodeIndex && nodeIndex <= ival->endPoint) {
334 li_ival = li_ival->
next;
344 cfgIterateNodes(cfg, (
void *)ra, handleCallerSaveRegistersNodeCallback);
353 result->
label = label;
358static bool compareSpillLocWithRegId(
void *a,
void *b)
363 if (spillLoc == NULL)
368static void deleteSpillLocationList(
t_listNode *spills)
374 while (curNode != NULL) {
377 curNode = curNode->
next;
403 while (curCFGRegNode != NULL) {
405 if (maxTempRegID < curCFGReg->tempRegID)
407 curCFGRegNode = curCFGRegNode->
next;
415 for (
int counter = 0; counter < result->
tempRegNum; counter++)
427 initializeRegisterConstraints(result);
428 handleCallerSaveRegisters(result, result->
graph);
442 deleteLiveInterval(curInterval);
443 curNode = curNode->
next;
448 deleteSpillLocationList(RA->
spills);
455static bool compareFreeRegListNodes(
void *freeReg,
void *constraintReg)
466 if (*activeInterv == NULL)
471 while (curNode != NULL) {
479 if (curInterval->endPoint > interval->
startPoint)
486 if (curInterval->endPoint == interval->
startPoint) {
488 if (curIntReg >= 0) {
516 if (constraints == NULL)
534static void spillAtInterval(
540 if (*activeInterv == NULL) {
550 if (lastInterval->endPoint > interval->
endPoint) {
576 curNode = curNode->
next) {
581 expireOldIntervals(RA, &activeInterv, &freeRegs, curInterval);
583 t_regID reg = assignRegister(RA, &freeRegs, curInterval->mcRegConstraints);
587 spillAtInterval(RA, &activeInterv, curInterval);
592 RA->
bindings[curInterval->tempRegID] = reg;
615 sprintf(name,
".t%d", counter);
628 if (elementFound == NULL)
629 fatalError(
"bug: t%d missing from the spill label list", rSpilled);
647 if (elementFound == NULL)
648 fatalError(
"bug: t%d missing from the spill label list", rSpilled);
657 if ((curCFGNode->
instr)->label != NULL) {
658 loadInstr->
label = (curCFGNode->
instr)->label;
659 (curCFGNode->
instr)->label = NULL;
666static void materializeRegAllocInBBForInstructionNode(
t_regAllocator *RA,
682 argState[numArgs].
reg = instr->
rDest;
688 argState[numArgs].
reg = instr->
rSrc1;
694 argState[numArgs].
reg = instr->
rSrc2;
702 for (
int argIdx = 0; argIdx < numArgs; argIdx++) {
714 spillSlotInUse[slot] =
true;
715 if (argState[argIdx].isDestination)
723 for (
int argIdx = 0; argIdx < numArgs; argIdx++) {
727 if (argState[argIdx].spillSlot != -1)
734 bool alreadyFound =
false;
735 for (
int otherArg = 0; otherArg < argIdx && !alreadyFound; otherArg++) {
736 if (argState[argIdx].reg->ID == argState[otherArg].reg->ID) {
751 if (spillSlotInUse[slot] ==
false)
767 spillSlotInUse[slot] =
true;
774 if (!argState[argIdx].isDestination) {
775 genLoadSpillVariable(RA, argState[argIdx].reg->ID,
782 for (
int argIdx = 0; argIdx < numArgs; argIdx++) {
784 if (argState[argIdx].spillSlot == -1) {
804 while (curInnerNode != NULL) {
809 materializeRegAllocInBBForInstructionNode(RA, &state, curBlock, curCFGNode);
810 curInnerNode = curInnerNode->
next;
812 if (curCFGNode == NULL)
813 fatalError(
"bug: invalid CFG where a block has no nodes");
815 bool bbHasTermInstr = curBlock->
nodes &&
831 while (curBlockNode != NULL) {
833 materializeRegAllocInBB(RA, curBlock);
834 curBlockNode = curBlockNode->
next;
844 executeLinearScan(regalloc);
847 materializeSpillMemory(regalloc);
851 materializeRegAllocInCFG(regalloc);
869 fprintf(fout,
"%s: ", regStr);
879 spillLi = spillLi->
next;
883 fprintf(fout,
"spilled to label %s\n", labelName);
886 fprintf(fout,
"spilled to an undefined location\n");
889 fprintf(fout,
"unassigned\n");
892 fprintf(fout,
"assigned to %s\n", reg);
906 while (curNode != NULL) {
910 fprintf(fout,
"%s:\n", regStr);
913 fprintf(fout,
" live interval = [%3d, %3d]\n", interval->
startPoint,
915 fprintf(fout,
" constraints = {");
921 fprintf(fout,
"%s", reg);
928 fprintf(fout,
"}\n");
930 curNode = curNode->
next;
942 fprintf(fout,
"# Register Allocation dump\n\n");
944 fprintf(fout,
"## Statistics\n\n");
945 fprintf(fout,
"Number of available physical registers: %d\n",
NUM_GP_REGS);
946 fprintf(fout,
"Number of virtual registers used: %d\n\n", RA->
tempRegNum);
948 fprintf(fout,
"## Live intervals and constraints\n\n");
952 fprintf(fout,
"## Register assignment\n\n");
Control Flow Graph generation and related analyses.
Code generation functions.
char * registerIDToString(t_regID regID, bool machineRegIDs)
t_regID tempRegID
Register identifier.
t_listNode * registers
List of all temporary registers used in the program.
t_listNode * mcRegWhitelist
Physical register whitelist. Used by the register allocator.
t_listNode * in
Set of registers live at the entry of the node ('in' set).
t_listNode * nodes
List of instructions in the block.
t_listNode * out
Set of registers live at the exit of the node ('out' set).
t_instruction * instr
Pointer to the instruction associated with this node.
t_listNode * blocks
List of all the basic blocks, in program order.
t_cfgReg * defs[CFG_MAX_DEFS]
Set of registers defined by this node ('def' set). NULL slots are ignored.
t_cfgReg * uses[CFG_MAX_USES]
Set of registers used by this node ('use' set). NULL slots are ignored.
void cfgToProgram(t_program *program, t_cfg *graph)
void cfgComputeLiveness(t_cfg *graph)
void deleteCFG(t_cfg *graph)
int cfgIterateNodes(t_cfg *graph, void *context, int(*callback)(t_bbNode *node, int nodeIndex, void *context))
#define CFG_MAX_USES
Maximum number of temporary register uses for each node.
#define CFG_MAX_DEFS
Maximum number of temporary register definitions for each node.
t_bbNode * bbInsertInstructionBefore(t_basicBlock *block, t_instruction *instr, t_bbNode *ip)
t_cfg * programToCFG(t_program *program)
t_bbNode * bbInsertInstructionAfter(t_basicBlock *block, t_instruction *instr, t_bbNode *ip)
void fatalError(const char *format,...)
t_instruction * genSWGlobal(t_program *program, t_regID rs1, t_label *label, t_regID r_temp)
t_instruction * genLWGlobal(t_program *program, t_regID rd, t_label *label)
void * data
Pointer to the data associated to this node.
t_listNode * listFindAndRemove(t_listNode *list, void *data)
t_listNode * listClone(t_listNode *list)
t_listNode * listInsert(t_listNode *list, void *data, int pos)
#define LIST_DATA_TO_INT(data)
Convert a data item pointer created by INT_TO_LIST_DATA() to an integer.
#define INT_TO_LIST_DATA(data)
Convert an integer from a list data pointer.
t_listNode * listFind(t_listNode *list, void *data)
t_listNode * deleteList(t_listNode *list)
t_listNode * listFindWithCallback(t_listNode *list, void *data, bool(*compareFunc)(void *a, void *b))
t_listNode * listRemoveNode(t_listNode *list, t_listNode *element)
t_listNode * listInsertSorted(t_listNode *list, void *data, int(*compareFunc)(void *a, void *b))
t_listNode * listGetLastNode(t_listNode *list)
t_instrArg * rSrc1
First source argument (or NULL if none).
t_instrArg * rSrc2
Second source argument (or NULL if none).
t_regID ID
The register identifier.
t_instrArg * rDest
Destination argument (or NULL if none).
#define REG_INVALID
Constant used for invalid register identifiers.
#define REG_0
Constant identifying a register whose value is always zero.
t_symbol * createSymbol(t_program *program, char *ID, t_symbolType type, int arraySize)
char * getLabelName(t_label *label)
int t_regID
Type for register identifiers.
@ TYPE_INT
‘int’ scalar type.
t_regAllocator * newRegAllocator(t_program *program)
void regallocDump(t_regAllocator *RA, FILE *fout)
void deleteRegAllocator(t_regAllocator *RA)
void regallocRun(t_regAllocator *regalloc)
t_listNode * getListOfMachineRegisters(void)
#define TARGET_REG_ZERO_IS_CONST
t_regID getSpillMachineRegister(int i)
t_listNode * getListOfCallerSaveMachineRegisters(void)
#define NUM_GP_REGS
Number of general-purpose registers usable by the register allocator.
bool isJumpInstruction(t_instruction *instr)
bool isExitInstruction(t_instruction *instr)
bool isCallInstruction(t_instruction *instr)
t_listNode * getListOfGenPurposeMachineRegisters(void)
Program object definition and management.
int startPoint
Index of the first instruction that uses/defines this register.
bool isDestination
If the register is a destination register.
t_regID tempRegID
Identifier of the register.
t_listNode * mcRegConstraints
#define MAX_INSTR_ARGS
Maximum amount of arguments to an instruction.
t_program * program
The program where register allocation needs to be performed.
t_instrArg * reg
The instruction argument structure.
t_cfg * graph
The temporary control flow graph produced from the program.
t_regID assignedTempReg
Temporary register ID associated to this spill register.
void dumpLiveIntervals(t_listNode *intervals, FILE *fout)
t_spillRegState regs[NUM_SPILL_REGS]
#define RA_REGISTER_INVALID
Fictitious register ID marking currently unallocated temporaries.
int endPoint
Index of the last instruction that uses/defines this register.
t_listNode * liveIntervals
List of live intervals, ordered depending on their start index.
int tempRegNum
Number of temporary registers in the program.
t_listNode * spills
List of spill locations for temporary registers in the program.
#define RA_SPILL_REQUIRED
Fictitious register ID associated to registers to be spilled.
t_label * label
The label pointing to the spill area.
void dumpVariableBindings(t_regAllocator *RA, FILE *fout)
Structure describing a live interval of a register in a program.
Structure encapsulating the state of the register allocator.
Structure representing the current state of a spill-reserved register.
Spill register slots state.
Register allocation pass.
Generation of the output assembly program.
Properties of the target machine.