def __init__(self, ir): # Create a flow graph flowGraph = FlowGraph(ir.tac) blockNodes = flowGraph._blockNodes countNodes = len(blockNodes) # Create the Register and Address Descriptor for all available register and variables. # The Address Descriptor table, contains information about all the non local variables's value location self._addrDis = AddrDis() # The Register Descriptor table, contains information about allocation of all the registers self._regDis = RegDis() # self._tr = Translator() self._st = ir.symbolTable self._regAlloc = RegAlloc(self._st, self._regDis, self._addrDis) # a set of empty registers self._freeRs = AvalRegs self._codeBlocks = [] self._globalVars = {} self._newBlockIns = [] # Holds register which stores constant for a instruction. # There registers must be free after execution of that instruction self._toFreeRs = [] # For each node in blockNode of flow graph as node: for node in blockNodes: blockIns = node._block if blockIns == "entry" or blockIns == "exit": # entry and exit nodes, continue continue # Generate the Next-Use-Live for `blockIns`. nextUseLiveST, nonTempVars = NextUseLive(blockIns, ir.symbolTable) # check if the key exists in address discriptor self._addrDis.add(nonTempVars) # add the nonTemp variables into global data region for var in nonTempVars: self._globalVars[var] = "" #- For each Instruction `Ins` in `blockIns`: i = 0 self._newBlockIns = [] jumpIns = [] countBlock = len(blockIns) while i < countBlock: tac = blockIns[i] self._toFreeRs = [] # get the next use info about the current line nextUse = nextUseLiveST[i + 1] # Get the type of `Ins` # if `Ins` isOfType "Operations" (dest = src1 op src2): if tac.type == InstrType.assgn: # handle to operation type and return generated instructions self.handleOps(tac, nextUse) # else if `Ins` isOfType "Copy Statement"(dest = src): elif tac.type == InstrType.copy: self.handleCopy(tac, nextUse) # else if `Ins` isOfType "cond_jump" elif tac.type == InstrType.cjump: jumpIns += self.handleCondJump(tac, nextUse) # else if `Ins` is of type "uncond_jump" elif tac.type == InstrType.ujump: jumpIns.append("j " + str(tac.target)) # else if `Ins` is of type "func_call" elif tac.type == InstrType.call or tac.type == InstrType.libFn: jumpIns += self.handleFnsCalls(tac, nextUse) # else if `Ins` is of type "func_label" elif tac.type == InstrType.label: self._newBlockIns.append("addi $sp, $sp, -4") self._newBlockIns.append("sw $ra, 0($sp)") # the return type elif tac.type == InstrType.ret: jumpIns += self.handleReturns(tac, nextUse) # Handle the parametes, Handle the parameters right here as # we need other parameters here too elif tac.type == InstrType.params: # get all the parameters # do a loop and get all the parameters allocatedRs = {} j = 0 while tac.type == InstrType.params: param = tac.src attrs = self._st.getAttrs(param) if attrs["type"] == "const_int": self._newBlockIns.append("li $a" + str(j) + ", " + str(attrs["val"])) else: rParam = self._regAlloc.getReg( param, tac, nextUse, allocatedRs) allocatedRs[param] = rParam self._regAlloc.removeFromFree(rParam) # If src=Ins.srcOperand is not in 'Register': # get it from memory and store in the register self.lwInR(param, rParam) self._newBlockIns.append("move $a" + str(j) + ", " + str(rParam)) # # Change the Addr_Des[dest] so that it holds only location `R_dest`. # self._addrDis.setR(param, rParam) if i < countBlock - 1: i += 1 nextUse = nextUseLiveST[i + 1] tac = blockIns[i] else: break j += 1 continue else: print "code:142:: Unhandled instruction at " + tac.lineNumber self._newBlockIns.append("tac") # For register to be free, Free them self._regAlloc.addToFree(self._toFreeRs) i += 1 # we done with the block, now time to restore the lost values self.restoreAtEnd(nonTempVars) self._newBlockIns += jumpIns ##### End of for loop for this block self._codeBlocks.append(self._newBlockIns) self._regAlloc.addToFree(self._toFreeRs)
def __init__(self, ir, stm): # Create a flow graph flowGraph = FlowGraph(ir.tac) blockNodes = flowGraph._blockNodes countNodes = len(blockNodes) # To hold the constant string with there key name self._strs = {} self._st = stm self._fns = flowGraph._fns self._codeBlocks = [] self._globalVars = {} self._newBlockIns = [] # Holds register which stores constant for a instruction. # There registers must be free after execution of that instruction self._toFreeRs = [] # For each node in blockNode of flow graph as node: nodeNumber = -1 for node in blockNodes: # Create the Register and Address Descriptor for all available register and variables. # The Address Descriptor table, contains information about all the non local variables's value location self._addrDis = AddrDis() # The Register Descriptor table, contains information about allocation of all the registers self._regDis = RegDis() # self._tr = Translator() self._regAlloc = RegAlloc(self._st, self._regDis, self._addrDis) self._newBlockIns = [] blockIns = node._block if blockIns == "entry" or blockIns == "exit": # entry and exit nodes, continue continue # Some dead code elimination if a node don't have link to it's parents if (len(node._parentNodes) == 0): # remove me from my children's parent as they also won't be accessible by me # for child in node._nextNodes: # child._parentNodes.remove(node) self._codeBlocks.append(self._newBlockIns) nodeNumber += 1 continue # Generate the Next-Use-Live for `blockIns`. nextUseLiveST, nonTempVars = NextUseLive(blockIns) # print nonTempVars # check if the key exists in address discriptor self._addrDis.add(nonTempVars) # add the nonTemp variables into global data region # for var in nonTempVars: # self._globalVars[var] = "" #- For each Instruction `Ins` in `blockIns`: i = 0 jumpIns = [] paramIns = [] countBlock = len(blockIns) nodeNumber += 1 if nodeNumber in self._fns.keys(): self._newBlockIns.append("addi $sp, -8") self._newBlockIns.append("sw $ra, 0($sp)") self._newBlockIns.append("sw $fp, 4($sp)") self._newBlockIns.append("move $fp, $sp") self._newBlockIns.append( "addi $sp, -" + str(self._st.ftable[self._fns[nodeNumber]]["st"].width)) while i < countBlock: tac = blockIns[i] self._toFreeRs = [] # get the next use info about the current line nextUse = nextUseLiveST[i + 1] # Get the type of `Ins` # if `Ins` isOfType "Operations" (dest = src1 op src2): if tac.type == InstrType.assgn: # handle to operation type and return generated instructions self.handleOps(tac, nextUse) # else if `Ins` isOfType "Copy Statement"(dest = src): elif tac.type == InstrType.copy: self.handleCopy(tac, nextUse) # else if `Ins` isOfType "cond_jump" elif tac.type == InstrType.cjump: jumpIns += self.handleCondJump(tac, nextUse) # else if `Ins` is of type "uncond_jump" elif tac.type == InstrType.ujump: jumpIns.append("j " + str(tac.target)) # else if `Ins` is of type "func_call" elif tac.type == InstrType.call or tac.type == InstrType.libFn: paramIns.reverse() jumpIns += paramIns jumpIns += self.handleFnsCalls(tac, nextUse) # else if `Ins` is of type "func_label" elif tac.type == InstrType.label: self._newBlockIns.append("addi $sp, $sp, -4") self._newBlockIns.append("sw $ra, 0($sp)") # the return type elif tac.type == InstrType.ret: jumpIns += self.handleReturns(tac, nextUse) # Handle the parametes, Handle the parameters right here as # we need other parameters here too elif tac.type == InstrType.params: # handle the parameters # push them onto the stack paramIns += self.handleParams(tac, nextUse) else: print "code:142:: Unhandled instruction at " + tac.lineNumber self._newBlockIns.append("tac") # For register to be free, Free them self._regAlloc.addToFree(self._toFreeRs) i += 1 # we done with the block, now time to restore the lost values self.restoreAtEnd(nonTempVars) self._newBlockIns += jumpIns ##### End of for loop for this block self._codeBlocks.append(self._newBlockIns) self._regAlloc.addToFree(self._toFreeRs)