示例#1
0
class TinyGenerator():

    def __init__(self, IRcode, globalVariables=None, stringInit=0, functName=""):
        self.IRcode = IRcode
        self.tinyCode = ""
        self.declCode = ""
        self.regNum = 0
        self.tempNum = 0
        self.regDict = {}
        self.declDict = {}
        # self.regVals = {}
        self.stringDict = {}
        # self.writeVals = {}
        self.parameters = 0
        self.functCFG = None
        self.lineNum = 0
        self.totalLineNum = 0
        self.numTempParams = 0
        self.tempsSpilledDict = {} # Saves mapping of temp to stack in case of spilling
        self.stringInit = stringInit # If this code generation is just for the string initialization
        self.globalVariables = globalVariables
        self.stackOffset = 2
        self.localVarOffset = 4
        self.numLocalParams = 0
        self.registersToPush = ["r0", "r1", "r2", "r3"]
        self.functName = functName

        # Add 4 registers
        self.Registers = []
        self.Registers.append(RegisterStatus(0))
        self.Registers.append(RegisterStatus(1))
        self.Registers.append(RegisterStatus(2))
        self.Registers.append(RegisterStatus(3))

        if not stringInit:
            self.functCFG = CFG(IRcode, functName=self.functName)
            self.functCFG.populateNodeInfo()
            self.functCFG.removeLinesWithNoPredecessors()
            self.functCFG.runLivenessAnalysis(globalVariables)
            self.functCFG.setLeaders()
            self.functCFG.printGraphWithNodeLists() if DEBUG else None

            # self.functCFG.printGraph()
            self.IRcode = self.functCFG.getCode()

    def generate(self):
        oldLocalVarOffset = self.localVarOffset
        self.generateCode()
        self.updateLocalVarOffset()

        while oldLocalVarOffset != self.localVarOffset:
            oldLocalVarOffset = self.localVarOffset
            print("; RESTARTING EVERYTHING cause varOffset is {0}\n\n\n\n\n".format(self.localVarOffset)) if DEBUG else None

            # Restore defaults for everything
            self.tinyCode = ""
            self.declCode = ""
            self.regNum = 0
            self.tempNum = 0
            self.regDict = {}
            self.declDict = {}
            self.stringDict = {}
            self.parameters = 0
            self.lineNum = 0
            self.totalLineNum = 0
            self.numTempParams = 0
            self.tempsSpilledDict = {} # Saves mapping of temp to stack in case of spilling
            self.stackOffset = 2
            self.numLocalParams = 0

            self.generateCode()
            self.updateLocalVarOffset()

        return self.tinyCode

    def generateCode(self):
        stmtList = self.IRcode.split("\n")
        switcher = {
                "INCI": self.inci,
                "DECI": self.deci,
                "ADDI": self.addi,
                "ADDF": self.addf,
                "SUBI": self.subi,
                "SUBF": self.subf,
                "MULTI": self.multi,
                "MULTF": self.multf,
                "DIVI": self.divi,
                "DIVF": self.divf,
                "STOREI": self.storei,
                "STOREF": self.storei,
                "STORES": self.stores,
                "GTI": self.comp,
                "GEI": self.comp,
                "LTI": self.comp,
                "LEI": self.comp,
                "NEI": self.comp,
                "EQI": self.comp,
                "GTF": self.comp,
                "GEF": self.comp,
                "LTF": self.comp,
                "LEF": self.comp,
                "NEF": self.comp,
                "EQF": self.comp,
                "JUMP": self.jump,
                "LABEL": self.label,
                "READI": self.readi,
                "READF": self.readf,
                "WRITEI": self.writei,
                "WRITEF": self.writef,
                "WRITES": self.writes,
                "JSR":self.jsr,
                "PUSH":self.push,
                "POP":self.pop,
                "RET":self.ret,
                "LINK":self.link
            }
        #set up a main caller
        code = []
        self.totalLineNum = len(stmtList)
        
        # code.append("push")
        # code.append("push r0")
        # code.append("push r1")
        # code.append("push r2")
        # code.append("push r3")

        # code.append("jsr main")

        # code.append("sys halt")

        # self.tinyCode += "\n".join(code) + "\n"

        for line in stmtList:
            if not self.stringInit:
                if self.lineNum in self.functCFG.leaders:
                    self.resetRegisters(keepValid=1)
            # Get the function from switcher dictionary
            func = switcher.get(line.split(" ")[0], self.errorFunct)
            # Execute the function
            print(";", line) if DEBUG else None
            func(line)
            if not self.stringInit:
                if self.lineNum in self.functCFG.leaders:
                    self.invalidateAllRegisters()
            self.lineNum += 1
            self.printRegs() if DEBUG else None
        # print(self.regVals)

        # if len(self.declDict) != 0:
        #     self.tinyCode = "var " + "\nvar ".join(self.declDict.keys()) + "\n" + self.tinyCode + "\nend"
        # else:
        #     self.tinyCode = self.tinyCode + "\nend"
        
        self.tinyCode = re.sub(r'link.*\n', "link {0}\n".format(str(self.numLocalParams + self.localVarOffset + self.numTempParams)), self.tinyCode)
        self.removeUnnecessaryMoves()
        return self.tinyCode

    def updateLocalVarOffset(self):
        registersUsed = []
        for register in self.Registers:
            print("; Register used at least Once for {0}: {1}".format(register.regNum, str(register.usedAtLeastOnce))) if DEBUG else None
            if register.usedAtLeastOnce:
                registersUsed.append("r{0}".format(register.regNum))
        self.localVarOffset = len(registersUsed)
        self.registersToPush = registersUsed


    # def countRegsUsed(self):
    #     tinyCodeArray = self.tinyCode.split("\n")
    #     regsUsed = []
    #     for tinyLine in tinyCodeArray:
    #         tinyLineSplit = tinyLine.split()
    #         if tinyLineSplit

    def resetRegisters(self, keepValid=0):
        print("; resetting reg allocation") if DEBUG else None
        registersFreed = []
        for regNum in range(4):
            if self.Registers[regNum].valid:
                self.freeRegister("r{0}".format(regNum), keepTemporaries=1)
                registersFreed.append("r{0}".format(regNum))
                if keepValid:
                    self.Registers[regNum].valid = 1
        return registersFreed

    def invalidateAllRegisters(self):
        for regNum in range(4):
            self.Registers[regNum].valid = 0

    def saveGlobalVariablesBack(self):
        print("; storing globalVariables back") if DEBUG else None
        for regNum in range(4):
            if self.Registers[regNum].valid and self.Registers[regNum].variable in self.globalVariables:
                self.freeRegister("r{0}".format(regNum))


    def removeUnnecessaryMoves(self):
        tinyCodeArray = self.tinyCode.strip().rstrip('\n').split('\n')
        linesToRemove = []
        for tinyLine in tinyCodeArray:
            tinyLine = tinyLine.strip()
            if tinyLine == "":
                continue
            tinyLineSplit = tinyLine.split()
            if tinyLineSplit[0] != "move":
                continue
            if tinyLineSplit[1] == tinyLineSplit[2]:
                linesToRemove.append(tinyLine)

        for lineToRemove in linesToRemove:
            tinyCodeArray.remove(lineToRemove)

        self.tinyCode = "\n".join(tinyCodeArray) + "\n"
        return


    def printRegs(self):
        strToPrint = ""
        for register in self.Registers:
            strToPrint += " r{0} -> ".format(register.regNum)    
            if register.valid:
                strToPrint += register.variable
            else:
                strToPrint += "null"
        print(";", strToPrint)

        return


    def convertIRVarToTinyVar(self, IRVar):
        tinyVar = ""
        if not IRVar.startswith("$"):
            tinyVar = IRVar
            self.declDict[tinyVar] = ""
        elif IRVar.startswith("$L"):
            tinyVar = "$" + str(int(IRVar.replace("L", "-")[1:]) - self.localVarOffset)
        elif IRVar.startswith("$P"):
            tinyVar = "$" + str(-int(IRVar[2:]) + self.stackOffset + self.parameters)
        elif IRVar.startswith("$R"):
            tinyVar = "$" + str(self.stackOffset + self.parameters)

        return tinyVar

    def ensureRegister(self, variable, doneWithLine=0):
        print("; ensuring {0}".format(variable)) if DEBUG else None
        for register in self.Registers:
            if register.variable == variable and register.valid:
                return "r{0}".format(register.regNum)

        register = self.registerAllocate(variable, doneWithLine)
        tinyVar = self.convertIRVarToTinyVar(variable)
        if variable in self.tempsSpilledDict.keys():
            tinyVar = self.tempsSpilledDict[variable]
            del self.tempsSpilledDict[variable]
        print(";move {0} {1}\n".format(tinyVar, register)) if DEBUG else None
        self.tinyCode += "move {0} {1}\n".format(tinyVar, register)
        return register

    def checkVariableLive(self, variable):
        return variable in self.functCFG.CFGNodeList[self.lineNum].outList


    def spillRegister(self, register, keepTemporaries=0):
        regNum = int(register[1])
        tinyVar = self.convertIRVarToTinyVar(self.Registers[regNum].variable)

        if self.Registers[regNum].variable.startswith("$T") and keepTemporaries:
            return

        if self.Registers[regNum].variable.startswith("$T"):  
            tempStackVar = self.numLocalParams + self.localVarOffset + 1
            while True:
                if "$-{0}".format(tempStackVar) in self.tempsSpilledDict.values():
                    tempStackVar += 1
                    continue

                if (tempStackVar - self.numLocalParams - self.localVarOffset) > self.numTempParams:
                    self.numTempParams = (tempStackVar - self.numLocalParams - self.localVarOffset)

                tinyVar = "$-{0}".format(tempStackVar)
                self.tempsSpilledDict[self.Registers[regNum].variable] = tinyVar
                print("; spilling temp ",self.Registers[regNum].variable) if DEBUG else None
                break

        print("; spilling {0} to {1}".format(register, tinyVar)) if DEBUG else None
        print("; move {0} {1}\n".format(register, tinyVar)) if DEBUG else None
        self.tinyCode += "move {0} {1}\n".format(register, tinyVar)
        return


    def freeRegister(self, register, keepTemporaries=0):
        regNum = int(register[1])
        print("; freeing {0} with {1}, valid: {2}, dirty: {3}".format(register, self.Registers[regNum].variable, self.Registers[regNum].valid, self.Registers[regNum].dirty)) if DEBUG else None
        if self.Registers[regNum].valid and self.Registers[regNum].dirty and self.checkVariableLive(self.Registers[regNum].variable):
            self.spillRegister(register, keepTemporaries=keepTemporaries)
        if self.Registers[regNum].variable.startswith("$T") and keepTemporaries:  
            return
        self.Registers[regNum].valid = 0
        self.Registers[regNum].dirty = 0
        return
    

    def chooseRegToFree(self, doneWithLine=0):
        regsToUse = [0,1,2,3]
        regsToRemove = []
        if not doneWithLine:
            for regNum in regsToUse:
                if self.Registers[regNum].valid and self.Registers[regNum].variable in self.functCFG.CFGNodeList[self.lineNum].genList:
                    regsToRemove.append(regNum)
            for regNum in regsToRemove:
                regsToUse.remove(regNum)

            if len(regsToUse) == 1:
                return regsToUse[0]

        tempRegsToRemove = []
        for regNum in regsToUse:
            if self.Registers[regNum].dirty:
                tempRegsToRemove.append(regNum)

        for regNum in tempRegsToRemove:
            regsToUse.remove(regNum)

        if len(regsToUse) == 1:
            return regsToUse[0]

        if len(regsToUse) == 0:
            regsToUse = [0,1,2,3]
            for regNum in regsToRemove:
                regsToUse.remove(regNum)


        lineToCheck = self.lineNum + 1
        while True:
            print(";", regsToUse) if DEBUG else None
            if lineToCheck == (self.totalLineNum - 1):
                return regsToUse[0]
            if lineToCheck in self.functCFG.leaders:
                return regsToUse[0]

            regsToRemove = []
            for regNum in regsToUse:
                if self.Registers[regNum].variable in self.functCFG.CFGNodeList[lineToCheck].genList:
                    regsToRemove.append(regNum)

            for regNum in regsToRemove:
                regsToUse.remove(regNum)
                if len(regsToUse) == 1:
                    return regsToUse[0]
            lineToCheck += 1

    def chooseAndFreeRegister(self, doneWithLine=0):
        regNum = self.chooseRegToFree(doneWithLine)
        self.freeRegister("r{0}".format(regNum))
        return regNum

    def registerAllocate(self, varName, doneWithLine=0, registersToUse=[]):
        print("; starting allocation of {0}".format(varName)) if DEBUG else None
        regNum = 0
        if len(registersToUse) != 0:
            regNum = int(registersToUse[0][1])
        else:
            for register in self.Registers:
                if not register.valid: 
                    register.valid = 1
                    register.dirty = 0
                    register.variable = varName
                    print("; allocating {0} to r{1}".format(varName, register.regNum)) if DEBUG else None
                    register.usedAtLeastOnce = True
                    return "r{0}".format(register.regNum)
                    # foundReg = 1
                    # regToUse = register.regNum

            regNum = self.chooseAndFreeRegister(doneWithLine)

        self.Registers[regNum].valid = 1
        self.Registers[regNum].dirty = 0
        self.Registers[regNum].variable = varName
        self.Registers[regNum].usedAtLeastOnce = True
        print("; allocating {0} to r{1}".format(varName, regNum)) if DEBUG else None
        return "r{0}".format(regNum)

    def freeRegistersIfDead(self, variablesToTryFree, keepVariablesLive=[]):
        registersFreed = []
        for regNum in range(4):
            if self.Registers[regNum].valid and self.Registers[regNum].variable in variablesToTryFree and self.Registers[regNum].variable not in keepVariablesLive:
                if (not self.checkVariableLive(self.Registers[regNum].variable)) or (self.Registers[regNum].variable in self.functCFG.CFGNodeList[self.lineNum].killList):
                    print("; freeing cause dead r{0} with {1} -> {2}".format(regNum, self.Registers[regNum].variable, self.functCFG.CFGNodeList[self.lineNum].outList)) if DEBUG else None
                    self.Registers[regNum].valid = 0
                    self.Registers[regNum].dirty = 0
                    registersFreed.append("r{0}".format(regNum))

        return registersFreed


    def temporaryAllocate(self):
            tempName = "&{}".format(self.tempNum)
            self.functCFG.CFGNodeList[self.lineNum].genList.append(tempName)
            self.tempNum += 1
            return self.registerAllocate(tempName)

    def incDecOperandSetup(self, op1):
        opmrl_op1 = ""
        opmrl_op2 = ""
        reg_op2   = ""
        isReg1    = False
        op1Allocated = False

        reg_op2 = self.ensureRegister(op1, 0)
        self.markRegisterDirty(reg_op2)

        return reg_op2

    def inci(self, IRLine):
        lineSplit = IRLine.split(" ")
        op1 = lineSplit[1]
        code = []

        reg_op2 = self.incDecOperandSetup(op1)
        code.append("inci {0}".format(reg_op2))

        self.tinyCode += "\n".join(code) + "\n"

        regsToTryFree = []
        regsToTryFree.append(op1)

        self.freeRegistersIfDead(regsToTryFree)
        return

    def deci(self, IRLine):
        lineSplit = IRLine.split(" ")
        op1 = lineSplit[1]
        code = []

        reg_op2 = self.incDecOperandSetup(op1)
        code.append("deci {0}".format(reg_op2))

        self.tinyCode += "\n".join(code) + "\n"

        regsToTryFree = []
        regsToTryFree.append(op1)

        self.freeRegistersIfDead(regsToTryFree)
        return

    def mathOperandSetup(self, op1, op2, result, orderMatters):
        opmrl_op1 = ""
        opmrl_op2 = ""
        reg_op2   = ""
        op1Allocated = False
        isReg1 = False
        isReg2 = False

        if op1.replace(".", "").replace("-", "").isdigit():
            opmrl_op1 = op1
        else:
            opmrl_op1 = self.ensureRegister(op1, 0)
            isReg1 = True

        if op2.replace(".", "").replace("-", "").isdigit():
            opmrl_op2 = op2
        else:
            opmrl_op2 = self.ensureRegister(op2, 0)
            isReg2 = True

        regsToTryFree = []
        if isReg1:
            regsToTryFree.append(op1)
        if isReg2:
            regsToTryFree.append(op2)
        print(";", op1, "-->", opmrl_op1) if DEBUG else None
        print(";", op2, "-->", opmrl_op2) if DEBUG else None

        registersFreed = self.freeRegistersIfDead(regsToTryFree, keepVariablesLive=[op2])
        reg_op2 = self.registerAllocate(result, doneWithLine=0, registersToUse=registersFreed)
        self.markRegisterDirty(reg_op2)
        self.freeRegistersIfDead(regsToTryFree)
        print(";", result, "-->", reg_op2) if DEBUG else None

        print("; opmrl_op1 = {0}, opmrl_op2 = {1}, reg_op2 = {2}".format(opmrl_op1, opmrl_op2, reg_op2)) if DEBUG else None
        print(("; move {0} {1}\n".format(opmrl_op1, reg_op2))) if DEBUG else None
        self.tinyCode += ("move {0} {1}\n".format(opmrl_op1, reg_op2))
        return opmrl_op2, reg_op2

    def addi(self, IRLine):
        lineSplit = IRLine.split(" ")
        op1 = lineSplit[1]
        op2 = lineSplit[2]
        result = lineSplit[3]
        code = []

        opmrl_op1, reg_op2 = self.mathOperandSetup(op1, op2, result, False)
        code.append("addi {0} {1}".format(opmrl_op1, reg_op2))

        self.tinyCode += "\n".join(code) + "\n"
        return

    def addf(self, IRLine):
        lineSplit = IRLine.split(" ")
        op1 = lineSplit[1]
        op2 = lineSplit[2]
        result = lineSplit[3]
        code = []

        opmrl_op1, reg_op2 = self.mathOperandSetup(op1, op2, result, False) 
        code.append("addr {0} {1}".format(opmrl_op1, reg_op2))

        self.tinyCode += "\n".join(code) + "\n"
        return

    def subi(self, IRLine):
        lineSplit = IRLine.split(" ")
        op1 = lineSplit[1]
        op2 = lineSplit[2]
        result = lineSplit[3]
        code = []

        opmrl_op1, reg_op2 = self.mathOperandSetup(op1, op2, result, True) 
        code.append("subi {0} {1}".format(opmrl_op1, reg_op2))
        
        self.tinyCode += "\n".join(code) + "\n"
        return

    def subf(self, IRLine):
        lineSplit = IRLine.split(" ")
        op1 = lineSplit[1]
        op2 = lineSplit[2]
        result = lineSplit[3]
        code = []

        opmrl_op1, reg_op2 = self.mathOperandSetup(op1, op2, result, True) 
        code.append("subr {0} {1}".format(opmrl_op1, reg_op2))
        
        self.tinyCode += "\n".join(code) + "\n"
        return

    def multi(self, IRLine):
        lineSplit = IRLine.split(" ")
        op1 = lineSplit[1]
        op2 = lineSplit[2]
        result = lineSplit[3]
        code = []

        opmrl_op1, reg_op2 = self.mathOperandSetup(op1, op2, result, False) 
        code.append("muli {0} {1}".format(opmrl_op1, reg_op2))
        
        self.tinyCode += "\n".join(code) + "\n"
        return

    def multf(self, IRLine):
        lineSplit = IRLine.split(" ")
        op1 = lineSplit[1]
        op2 = lineSplit[2]
        result = lineSplit[3]
        code = []

        opmrl_op1, reg_op2 = self.mathOperandSetup(op1, op2, result, False) 
        code.append("mulr {0} {1}".format(opmrl_op1, reg_op2))
        
        self.tinyCode += "\n".join(code) + "\n"
        return

    def divi(self, IRLine):
        lineSplit = IRLine.split(" ")
        op1 = lineSplit[1]
        op2 = lineSplit[2]
        result = lineSplit[3]
        code = []

        opmrl_op1, reg_op2 = self.mathOperandSetup(op1, op2, result, True) 
        code.append("divi {0} {1}".format(opmrl_op1, reg_op2))
        
        self.tinyCode += "\n".join(code) + "\n"
        return

    def divf(self, IRLine):
        lineSplit = IRLine.split(" ")
        op1 = lineSplit[1]
        op2 = lineSplit[2]
        result = lineSplit[3]
        code = []

        opmrl_op1, reg_op2 = self.mathOperandSetup(op1, op2, result, True) 
        code.append("divr {0} {1}".format(opmrl_op1, reg_op2))
        
        self.tinyCode += "\n".join(code) + "\n"
        return

    def storei(self, IRLine):
        lineSplit = IRLine.split(" ")
        op1 = lineSplit[1]
        result = lineSplit[2]
        code  = []
        opmrl_op1 = ""
        opmr_op2  = ""
        isMem1 = False
        isMem2 = False
        isReg1 = False

        if op1.replace(".", "").replace("-", "").isdigit():
            opmrl_op1 = op1
        else:
            opmrl_op1 = self.ensureRegister(op1, 0)
            isReg1 = True

        regsToTryFree = []
        if isReg1:
            regsToTryFree.append(op1)

        registersFreed = self.freeRegistersIfDead(regsToTryFree)
        if result.startswith("$R"):
            isMem2 = True
            opmr_op2 = "$" + str(self.stackOffset + self.parameters)
        else:
            opmr_op2 = self.registerAllocate(result, 1, registersToUse=registersFreed)
            self.markRegisterDirty(opmr_op2)

        print("; move {0} {1}".format(opmrl_op1, opmr_op2)) if DEBUG else None
        code.append("move {0} {1}".format(opmrl_op1, opmr_op2)) 
        self.tinyCode += "\n".join(code) + "\n"
        return

    def stores(self, IRLine):
        lineSplit = IRLine.split(" ")
        result = " ".join(lineSplit[1:-1])
        op1 = lineSplit[-1]
        code  = []

        if op1.startswith("$L"):
            self.tinyCode += "str {0} {1}\n".format(op1, result)
        else:
            self.tinyCode = "str {0} {1}\n".format(op1, result) + self.tinyCode

        return

    def compOperand(self, op1, op2, dataType):
        code = []
        opmrl_op1 = ""
        opmrl_op2 = ""
        reg_op2   = ""
        op1Allocated = False
        flipped = False
        isReg1 = False
        isReg2 = False

        if (not op1.replace(".", "").replace("-", "").isdigit()) and (op2.replace(".", "").replace("-", "").isdigit()):
            flipped = True
            op2, op1 = op1, op2

        if op1.replace(".", "").replace("-", "").isdigit():
            opmrl_op1 = op1
        else:
            opmrl_op1 = self.ensureRegister(op1, 0)
            isReg1 = True

        if op2.replace(".", "").replace("-", "").isdigit():
            opmr_op2 = self.temporaryAllocate()
        else:
            opmrl_op2 = self.ensureRegister(op2, 0)
            isReg2 = True

        regsToTryFree = []
        if isReg1:
            regsToTryFree.append(op1)
        if isReg2:
            regsToTryFree.append(op2)

        self.freeRegistersIfDead(regsToTryFree)

        if dataType:
            code.append("cmpi {0} {1}".format(opmrl_op1, opmrl_op2))
        else:
            code.append("cmpr {0} {1}".format(opmrl_op1, opmrl_op2))
    

        self.tinyCode += "\n".join(code) + "\n"
        return flipped

    def comp(self, IRLine):
        lineSplit = IRLine.split(" ")
        op  = lineSplit[0]
        op1 = lineSplit[1]
        op2 = lineSplit[2]
        label = lineSplit[3]
        CompOP = None
        code = []

        if op in ["LTI", "LTF"]:
            CompOP = COMPOP.LT
        elif op in ["GTI","GTF"]:
            CompOP = COMPOP.GT
        elif op in ["EQI","EQF"]:
            CompOP = COMPOP.EQ
        elif op in ["NEI","NEF"]:
            CompOP = COMPOP.NE
        elif op in ["LEI","LEF"]:
            CompOP = COMPOP.LE
        elif op in ["GEI","GEF"]:
            CompOP = COMPOP.GE

        flipped = self.compOperand(op1, op2, op.endswith("I"))
        if flipped:
            CompOP = COMPOP.inverseTinyOP(CompOP)

        if CompOP == COMPOP.LT:
            code.append("jlt {0}".format(label))
        elif CompOP == COMPOP.GT:
            code.append("jgt {0}".format(label))
        elif CompOP == COMPOP.EQ:
            code.append("jeq {0}".format(label))
        elif CompOP == COMPOP.NE:
            code.append("jne {0}".format(label))
        elif CompOP == COMPOP.LE:
            code.append("jle {0}".format(label))
        elif CompOP == COMPOP.GE:
            code.append("jge {0}".format(label))

        self.tinyCode += "\n".join(code) + "\n"
        return

    def jump(self, IRLine):
        lineSplit = IRLine.split(" ")
        label = lineSplit[1]
        code = []

        code.append("jmp {0}".format(label))    
        self.tinyCode += "\n".join(code) + "\n"

        return

    def label(self, IRLine):
        lineSplit = IRLine.split(" ")
        label = lineSplit[1]
        code = []

        code.append("label {0}".format(label))   
        self.tinyCode += "\n".join(code) + "\n"

        return

    def readWriteOperandSetup(self, op2, code):
        opmr_op2 = ""
        if op2.replace(".", "").replace("-", "").isdigit():
            regVar = self.temporaryAllocate()
            code.append("move {0} r{1}".format(op2, self.regDict[regVar])) 
            opmr_op2 = "r" + str(self.regDict[regVar])   
        elif not op2.startswith("$"):
            opmr_op2 = op2
            self.declDict[opmr_op2] = ""
        elif op2.startswith("$L"):
            opmr_op2 = op2.replace("L", "-")
        elif op2.startswith("$P"):
            opmr_op2 = "$" + str(-int(op2[2:]) + self.stackOffset + self.parameters)
        elif op2.startswith("$R"):
            opmr_op2 = "$" + str(self.stackOffset + self.parameters)
        else:
            self.registerAllocate(op2)
            opmr_op2 = "r{0}".format(self.regDict[op2])

        return opmr_op2

    def markRegisterDirty(self, op):
        self.Registers[int(op[1])].dirty = 1
        return


    def readOperandSetup(self, op2, code):
        reg_op2 = self.registerAllocate(op2, 1)
        self.markRegisterDirty(reg_op2)
        return reg_op2

    def writeOperandSetup(self, op2, code):
        opmr_op2 = ""
        if op2.replace(".", "").replace("-", "").isdigit():
            opmr_op2 = self.temporaryAllocate()
            code.append("move {0} {1}".format(op2, opmr_op2)) 
        else:
            opmr_op2 = self.ensureRegister(op2, 0)

        self.freeRegistersIfDead([op2])
        return opmr_op2


    def readi(self, IRLine):
        lineSplit = IRLine.split(" ")
        result = lineSplit[1]
        code = []

        opmr_op2 = self.readOperandSetup(result, code)
        code.append("sys readi {0}".format(opmr_op2)) 
        
        self.tinyCode += "\n".join(code) + "\n"
        pass

    def readf(self, IRLine):
        lineSplit = IRLine.split(" ")
        result = lineSplit[1]
        code = []

        opmr_op2 = self.readOperandSetup(result, code)
        code.append("sys readr {0}".format(opmr_op2)) 
        
        self.tinyCode += "\n".join(code) + "\n"
        pass

    def writei(self, IRLine):
        lineSplit = IRLine.split(" ")
        result = lineSplit[1]
        code = []

        opmr_op2 = self.writeOperandSetup(result, code)
        code.append("sys writei {0}".format(opmr_op2)) 
        
        self.tinyCode += "\n".join(code) + "\n"
        pass

    def writef(self, IRLine):
        lineSplit = IRLine.split(" ")
        result = lineSplit[1]
        code = []

        opmr_op2 = self.writeOperandSetup(result, code)
        code.append("sys writer {0}".format(opmr_op2)) 
        
        self.tinyCode += "\n".join(code) + "\n"
        pass

    def writes(self, IRLine):
        lineSplit = IRLine.split(" ")
        result = lineSplit[1]
        code = []

        code.append("sys writes {0}".format(result)) 
        
        self.tinyCode += "\n".join(code) + "\n"
        pass

    def jsr(self, IRLine):
        lineSplit = IRLine.split(" ")
        label = lineSplit[1]
        code = []
        self.saveGlobalVariablesBack()

        # code.append("push r0")
        # code.append("push r1")
        # code.append("push r2")
        # code.append("push r3")

        code.append("jsr {0}".format(label))

        # code.append("pop r3")
        # code.append("pop r2")
        # code.append("pop r1")
        # code.append("pop r0")

        self.tinyCode += "\n".join(code) + "\n"
        return

    def push(self, IRLine):
        lineSplit = IRLine.rstrip().split(" ")
        code = []
        value = ""
        isReg1 = False
        if len(lineSplit) == 2:
            op1 = lineSplit[1]
            if op1.replace(".", "").replace("-", "").isdigit():
                value = op1
            else:
                value = self.ensureRegister(op1)
                isReg1 = True

            if isReg1:
                self.freeRegistersIfDead([op1])
            code.append("push {0}".format(value))
        else:
            code.append("push")

        self.tinyCode += "\n".join(code) + "\n"
        return


    def pop(self, IRLine):
        lineSplit = IRLine.rstrip().split(" ")
        code = []
        if len(lineSplit) == 2:
            op1 = lineSplit[1]
            value = self.registerAllocate(op1)
            code.append("pop {0}".format(value))
            self.markRegisterDirty(value)
        else:
            code.append("pop")

        self.tinyCode += "\n".join(code) + "\n"
        return

    def ret(self, IRLine):
        code = []
        self.saveGlobalVariablesBack()
        if self.functName != "main":
            for registerToPush in reversed(self.registersToPush):
                code.append("pop {0}".format(registerToPush))
        code.append("unlnk")
        code.append("ret")
        self.tinyCode += "\n".join(code) + "\n"

    def link(self, IRLine):
        lineSplit = IRLine.split(" ")
        parameters = lineSplit[2]
        localparam = lineSplit[1]
        code = []
        self.parameters = int(parameters)
        self.numLocalParams = int(localparam)
        code.append("link {0}".format(str(self.numLocalParams + self.localVarOffset)))


        if self.functName != "main":
            for registerToPush in self.registersToPush:
                code.append("push {0}".format(registerToPush))
        self.tinyCode += "\n".join(code) + "\n"

    def errorFunct(self, IRLine):
        pass