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)
class CodeGen(): """Code Generator""" 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) # self._flowGraph = flowGraph # Handler for operation type instructions def handleOps(self, tac, nextUse): operands = tac.operands dest = tac.dest srcs = tac.srcs # Get Registers for all operands (using GetReg(Ins) method). Say R_dest, R_src1, R_src2. allocatedRs = {} ## selection of registers for sources: srcInt = False bothInt = False for src in srcs: # if source is an integer, don't assign a real register. Make a fake register with the same value # but if both the srcs are integers, then we must store one of them in register if srcInt: bothInt = True attrs = self._st.getAttrs(src) srcInt = attrs["type"] == "const_int" if not srcInt: rSrc = self._regAlloc.getReg(src, tac, nextUse, allocatedRs) self.storeSpilled(rSrc) allocatedRs[src] = rSrc self._regAlloc.removeFromFree(rSrc) # remove from free list # if `src` not in 'Register' (according to Reg_Des for R_src): # get it from memory and store it in a register self.lwInR(src, rSrc) else: intVal = attrs["val"] # check if the source is already alloted. This will be case # when both operands are same if src in allocatedRs.keys(): continue if tac.operator == "+" and (not bothInt): allocatedRs[src] = str(intVal) else: rSrc = self._regAlloc.getReg(src, tac, nextUse, allocatedRs) allocatedRs[src] = rSrc self.storeSpilled(rSrc) # if op is addition and src is int, then we know, we added a fake register. so no need # to for a load or change in addr and register discriptor tables. else # load that contant self.genLiInstr(rSrc, src) # set the register to be free after execution of this instruction self._toFreeRs.append(rSrc) ## selection of registers for destination: # issues are the same as for srcs, just a minor differences # select a register that only holds value for x, if there is one. found = False reg = self._regDis.onlyVarReg(dest) if reg != None: allocatedRs[dest] = reg self._regAlloc.removeFromFree( reg) # remove the register from free list found = True if not found: # for all srcs: for src in srcs: attrs = self._st.getAttrs(src) if attrs["type"] == "const_int": continue # if src has not next-use and not live and R_src holds only src, after being loaded, then R_src can be use as R_dest. "OK". if nextUse[src][0] == 0 and nextUse[src][1] == -1: # get all the locations that src is present in for location in self._addrDis.fetchR(src): if self._regDis.isIn(location): # a register location # Now check if R_src holds only src. if so, return it if self._regDis.isOnlyVar(location, src): allocatedRs[dest] = location self._regAlloc.removeFromFree( location ) # remove the location (register) from free list found = True break # check if found, else loop for other sources if found: break # if still not found, get from regs if not found: rDest = self._regAlloc.getReg(dest, tac, nextUse, allocatedRs) self.storeSpilled(rDest) allocatedRs[dest] = rDest self._regAlloc.removeFromFree( rDest) # remove from free registers # create instruction for addi if operator is "+" and srcs are int # Issue The Instruction `op R_dest, R_src1, R_src2` if srcInt and tac.operator == "+": consts = None regs = [] for src in operands: try: c = int(allocatedRs[src]) except Exception, e: # raise e regs.append(str(allocatedRs[src])) else: consts = c # consts will be none when both of them are same intergers if consts != None: self._newBlockIns.append("addi " + ', '.join(regs) + ', ' + str(consts)) else: self._newBlockIns.append("addi " + ', '.join(regs)) else:
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)
class CodeGen(): """Code Generator""" 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) # self._flowGraph = flowGraph # Handler for operation type instructions def handleOps(self, tac, nextUse): operands = tac.operands dest = tac.dest srcs = tac.srcs # Get Registers for all operands (using GetReg(Ins) method). Say R_dest, R_src1, R_src2. allocatedRs = {} ## selection of registers for sources: srcInt = False bothInt = False for src in srcs: # if source is an integer, don't assign a real register. Make a fake register with the same value # but if both the srcs are integers, then we must store one of them in register if srcInt: bothInt = True srcInt = True if "const_" in src["type"] else False if not srcInt: rSrc = self._regAlloc.getReg(src, tac, nextUse, allocatedRs) self.storeSpilled(rSrc) allocatedRs[src["place"]] = rSrc self._regAlloc.removeFromFree(rSrc) # remove from free list # if `src` not in 'Register' (according to Reg_Des for R_src): # get it from memory and store it in a register self.lwInR(src, rSrc) else: # get the int value intVal = src["place"] # check if the source is already alloted. This will be case # when both operands are same if src in allocatedRs.keys(): continue if tac.operator == "+" and (not bothInt): allocatedRs[src["place"]] = str(intVal) else: rSrc = self._regAlloc.getReg(src, tac, nextUse, allocatedRs) allocatedRs[src["place"]] = rSrc self.storeSpilled(rSrc) # if op is addition and src is int, then we know, we added a fake register. so no need # to for a load or change in addr and register discriptor tables. else # load that contant self.genLiInstr(rSrc, src) # set the register to be free after execution of this instruction self._toFreeRs.append(rSrc) ## selection of registers for destination: # issues are the same as for srcs, just a minor differences # select a register that only holds value for x, if there is one. found = False reg = self._regDis.onlyVarReg(dest) if reg != None: rDest = reg self._regAlloc.removeFromFree(reg) # remove the register from free list found = True if not found: # for all srcs: for src in srcs: if "const_" in src["type"]: continue # if src has not next-use and not live and R_src holds only src, after being loaded, then R_src can be use as R_dest. "OK". if nextUse[src["place"]][0] == 0 and nextUse[src["place"]][1] == -1: # get all the locations that src is present in for location in self._addrDis.fetchR(src): if self._regDis.isIn(location): # a register location # Now check if R_src holds only src. if so, return it if self._regDis.isOnlyVar(location, src): rDest = location self._regAlloc.removeFromFree(location) # remove the location (register) from free list found = True break # check if found, else loop for other sources if found: break # if still not found, get from regs if not found: rDest = self._regAlloc.spill(tac, nextUse, allocatedRs) self.storeSpilled(rDest) self._regAlloc.removeFromFree(rDest) # remove from free registers # create instruction for addi if operator is "+" and srcs are int # Issue The Instruction `op R_dest, R_src1, R_src2` if srcInt and tac.operator == "+": consts = None regs = [] for src in srcs: try: c = int(allocatedRs[src["place"]]) except Exception, e: # raise e regs.append(str(allocatedRs[src["place"]])) else: consts = c # consts will be none when both of them are same intergers if consts != None: self._newBlockIns.append("addi "+ str(rDest) +", " +', '.join(regs) + ', '+str(consts)) else: self._newBlockIns.append("addi "+ str(rDest) +", "+ ', '.join(regs)) else:
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)