예제 #1
0
def extractStmts(exp):
	stmts = []
	
	if classGuard(exp, BinOp, Dictionary, List, UnaryOp):
		for child in exp:
			if classGuard(child, Statement, FunctionCall):
				stmts.append(child)
			
			else:
				stmts.append(extractStmts(child))
	
	return flatten(stmts)
예제 #2
0
def propagateValuesPrime(node, consts, gather = True):
	# Memorize or replace symbol values, as appropriate.
	if gather:
		if isinstance(node, Assign) and isinstance(node.var, Symbol) and classGuard(node.exp, Boolean, Integer, Name, Symbol):
			consts[node.var] = node.exp
		
		elif isinstance(node, Phi) and len(node.srcs) == 1 and consts.has_key(node.srcs[0]):
			consts[node.target] = consts[node.srcs[0]]
	
	elif isinstance(node, Symbol) and consts.has_key(node):
		return consts[node]
	
	# Values in Phi nodes should never be replaced.
	if isinstance(node, While):
		# This looks all weird because we have to change the order of the
		# While node's children to propigate values appropriately.
		
		children = node.getChildren()
		children = children[1:] + children[0:1]
		
		newChildren = [propagateValuesPrime(child, consts, gather) for child in children]
		
		newChildren = newChildren[-1:] + newChildren[0:-1]
		
		node.setChildren(newChildren)
	
	elif not isinstance(node, Phi):
		newChildren = [propagateValuesPrime(child, consts, gather) for child in node]
		node.setChildren(newChildren)
	
	return consts if isinstance(node, Module) else node
예제 #3
0
def precolor(node):
	if classGuard(node, Assign, Phi):
		sym = extractSymbol(node)
		
		if not sym.has_key('precolor'):
			sym['precolor'] = None
	
	elif isinstance(node, Div) and isinstance(node.left, Symbol):
		node.left['precolor'] = eax
	
	elif isinstance(node, Function):
		# This clause pre-colors function arguments with their position on
		# the stack relative to the %ebp register.  The first argument
		# starts 8 bytes above the base pointer.  Each successive argument is
		# 4 bytes above that.
		
		offset = 8
		
		for sym in node.argSymbols:
			sym['precolor'] = Mem(offset, 'up', True)
			
			#Advance to the next argument offset.
			offset += 4
	
	elif isinstance(node, Return):
		# Values are returned from functions in the %eax register.
		
		node['precolor'] = eax
	
	for child in node:
		precolor(child)
예제 #4
0
def reads(node):
    if classGuard(node, Assign, Phi):
        sym = extractSymbol(node)

        if not sym.has_key('reads'):
            sym['reads'] = 0

    elif isinstance(node, Function):
        for sym in node.argSymbols:
            sym['reads'] = 0

    elif isinstance(node, Symbol):
        # This is kind of ugly, but because of Python's scoping rules we can
        # read from a variable before it is 'in scope.'

        if node.has_key('reads'):
            node['reads'] += 1
        else:
            node['reads'] = 1

    elif isinstance(node, Subscript) and isinstance(node.symbol, Symbol):
        # This little hack is here to take care of cases where subscripts are
        # applied to literal values. After the flatten transformation this
        # branch will be taken whenever we see a subscript.

        node.symbol['reads'] += 1

    for child in node:
        reads(child)
예제 #5
0
def eliminateDeadStores(node, klass = 0):
	newChildren = []
	
	if isinstance(node, Class):
		klass += 1
	
	for child in node:
		newChildren.append(eliminateDeadStores(child, klass))
	
	node.setChildren(flatten(newChildren))
	
	if isinstance(node, Assign):
		sym = extractSymbol(node.var)
		
		if sym['reads'] == 0 and klass == 0:
			if classGuard(node.exp, Class, FunctionCall):
				return node
			
			else:
				return None
		
		else:
			return node
	
	elif isinstance(node, Phi) and node.target['reads'] == 0:
		return None
	
	else:
		return node
예제 #6
0
def eliminateDeadStores(node, klass=0):
    newChildren = []

    if isinstance(node, Class):
        klass += 1

    for child in node:
        newChildren.append(eliminateDeadStores(child, klass))

    node.setChildren(flatten(newChildren))

    if isinstance(node, Assign):
        sym = extractSymbol(node.var)

        if sym['reads'] == 0 and klass == 0:
            if classGuard(node.exp, Class, FunctionCall):
                return node

            else:
                return None

        else:
            return node

    elif isinstance(node, Phi) and node.target['reads'] == 0:
        return None

    else:
        return node
예제 #7
0
def precolor(node):
    if classGuard(node, Assign, Phi):
        sym = extractSymbol(node)

        if not sym.has_key('precolor'):
            sym['precolor'] = None

    elif isinstance(node, Div) and isinstance(node.left, Symbol):
        node.left['precolor'] = eax

    elif isinstance(node, Function):
        # This clause pre-colors function arguments with their position on
        # the stack relative to the %ebp register.  The first argument
        # starts 8 bytes above the base pointer.  Each successive argument is
        # 4 bytes above that.

        offset = 8

        for sym in node.argSymbols:
            sym['precolor'] = Mem(offset, 'up', True)

            #Advance to the next argument offset.
            offset += 4

    elif isinstance(node, Return):
        # Values are returned from functions in the %eax register.

        node['precolor'] = eax

    for child in node:
        precolor(child)
예제 #8
0
def flatten(node, st=None, inPlace=False):
    newChildren = []
    newInPlace = None
    preStmts = []

    # Setup flattening for this node's children.
    if util.classGuard(node, Assign, BasicBlock, Module):
        newInPlace = node.__class__

    elif isinstance(node, Function):
        st = node.st

    # Flatten our children.
    if isinstance(node, While):
        if not isinstance(node.cond, Symbol):
            condBody, node.cond = flatten(node.cond, st)
            node.condBody = BasicBlock(condBody)

        bodyPreStmts, node.body = flatten(node.body, st)
        preStmts.append(bodyPreStmts)

    elif isinstance(node, If):
        for child in node:
            childPreStmts, newChild = flatten(child, st, newInPlace)

            preStmts.append(childPreStmts)
            newChildren.append(newChild)

        # Set our new child nodes.
        newChildren = util.flatten(newChildren)
        node.setChildren(newChildren)

    else:
        for child in node:
            childPreStmts, newChild = flatten(child, st, newInPlace)

            if isinstance(node, BasicBlock):
                newChildren.append(childPreStmts)
                newChildren.append(newChild)

            else:
                preStmts.append(childPreStmts)
                newChildren.append(newChild)

        # Set our new child nodes.
        newChildren = util.flatten(newChildren)
        node.setChildren(newChildren)

    # Flatten the current node.
    if classGuard(node, BinOp, FunctionCall, IfExp, UnaryOp) and not inPlace:
        sym = st.getTemp()
        preStmts.append(Assign(sym, node))

        node = sym

    # Flatten our list of pre-statements.
    preStmts = util.flatten(preStmts)

    return node if isinstance(node, Module) else (preStmts, node)
예제 #9
0
def flatten(node, st = None, inPlace = False):
	newChildren	= []
	newInPlace	= None
	preStmts		= []
	
	# Setup flattening for this node's children.
	if util.classGuard(node, Assign, BasicBlock, Module):
		newInPlace = node.__class__
	
	elif isinstance(node, Function):
		st = node.st
	
	# Flatten our children.
	if isinstance(node, While):
		if not isinstance(node.cond, Symbol):
			condBody, node.cond = flatten(node.cond, st)
			node.condBody = BasicBlock(condBody)
		
		bodyPreStmts, node.body = flatten(node.body, st)
		preStmts.append(bodyPreStmts)
	
	elif isinstance(node, If):
		for child in node:
			childPreStmts, newChild = flatten(child, st, newInPlace)
			
			preStmts.append(childPreStmts)
			newChildren.append(newChild)
		
		# Set our new child nodes.
		newChildren = util.flatten(newChildren)
		node.setChildren(newChildren)
	
	else:
		for child in node:
			childPreStmts, newChild = flatten(child, st, newInPlace)
			
			if isinstance(node, BasicBlock):
				newChildren.append(childPreStmts)
				newChildren.append(newChild)
			
			else:
				preStmts.append(childPreStmts)
				newChildren.append(newChild)
		
		# Set our new child nodes.
		newChildren = util.flatten(newChildren)
		node.setChildren(newChildren)
	
	# Flatten the current node.
	if classGuard(node, BinOp, FunctionCall, IfExp, UnaryOp) and not inPlace:
		sym = st.getTemp()
		preStmts.append(Assign(sym, node))
		
		node = sym
	
	# Flatten our list of pre-statements.
	preStmts = util.flatten(preStmts)
	
	return node if isinstance(node, Module) else (preStmts, node)
예제 #10
0
def eliminateDeadCode(node):
	newChildren = []
	
	for child in node:
		newChild = eliminateDeadCode(child)
		
		if isinstance(node, BasicBlock):
			if classGuard(newChild, Class, Function, FunctionCall, SetAttr, Statement):
				newChildren.append(newChild)
			
			elif isinstance(newChild, BasicBlock):
				newChildren.append(newChild.children)
			
			elif isinstance(newChild, Return):
				newChildren.append(newChild)
				
				# All nodes after the Return node will be discarded due to
				# unreachability.
				break
			
			else:
				# Anything that reaches here is an expression outside of a
				# statement, and therefor has no effect on the program.
				# Therefor we remove any nested statements from the
				# expression then throw it away.
				newChildren.append(extractStmts(newChild))
		
		else:
			newChildren.append(newChild)
	
	node.setChildren(flatten(newChildren))
	
	if classGuard(node, If, IfExp) and isinstance(node.cond, Literal):
		# If statements or expressions with a literal conditional value can
		# be eliminated and replaced with the appropriate BasicBlock's
		# children.
			
		return node.then if node.cond.value else node.els
	
	else:
		return node
예제 #11
0
def liveness(node, alive=[]):
    if isinstance(node, Module):
        alive = []

    if not classGuard(node, Name, String, Symbol):
        node['pre-alive'] = set(alive)

    if isinstance(node, Function):
        for sym in node.argSymbols:
            #Functions might have arguments that are never read.
            if sym['reads'] > 0:
                sym['tmp'] = sym['reads']
                alive.append(sym)

    for child in node:
        liveness(child, alive)

    if classGuard(node, Assign, Phi):
        sym = extractSymbol(node)

        if not sym.has_key('tmp'):
            sym['tmp'] = sym['reads']
            alive.append(sym)

    elif isinstance(node, Symbol) or (isinstance(node, Subscript)
                                      and isinstance(node.symbol, Symbol)):
        sym = extractSymbol(node)

        if sym.has_key('tmp'):
            sym['tmp'] -= 1

            if sym['tmp'] == 0:
                alive.remove(sym)

        else:
            sym['tmp'] = sym['reads']
            alive.append(sym)

    if not classGuard(node, Name, String, Symbol):
        node['post-alive'] = set(alive)
예제 #12
0
def move(src, dest):
    if config.arch == 'x86':
        from assembler.x86.ib import TwoOp, OneOp

    elif config.arch == 'x86_64':
        from assembler.x86_64.ib import TwoOp, OneOp

    if isinstance(src, Immediate):
        dest.tagged = src.packed

    elif classGuard(src, Label, Mem, Register):
        dest.tagged = src.tagged

    return TwoOp('mov', src, dest)
예제 #13
0
def scope(node, outerScope = None):
	if isinstance(node, Function):
		outerScope = node.name
		
		# Main doesn't have any arguments, so all function arguments can be
		# marked 'local'
		for sym in node.argSymbols:
			sym['scope'] = 'local'
	
	elif classGuard(node, Assign, Phi):
		sym = extractSymbol(node)
		
		sym['scope'] = 'global' if outerScope.name == 'main' else 'local'
	
	for child in node:
		scope(child, outerScope)
예제 #14
0
def propagateValuesPrime(node, consts, gather=True):
    # Memorize or replace symbol values, as appropriate.
    if gather:
        if isinstance(node,
                      Assign) and isinstance(node.var, Symbol) and classGuard(
                          node.exp, Boolean, Integer, Name, Symbol):
            consts[node.var] = node.exp

        elif isinstance(node, Phi) and len(node.srcs) == 1 and consts.has_key(
                node.srcs[0]):
            consts[node.target] = consts[node.srcs[0]]

    elif isinstance(node, Symbol) and consts.has_key(node):
        return consts[node]

    # Values in Phi nodes should never be replaced.
    if isinstance(node, While):
        # This looks all weird because we have to change the order of the
        # While node's children to propigate values appropriately.

        children = node.getChildren()
        children = children[1:] + children[0:1]

        newChildren = [
            propagateValuesPrime(child, consts, gather) for child in children
        ]

        newChildren = newChildren[-1:] + newChildren[0:-1]

        node.setChildren(newChildren)

    elif not isinstance(node, Phi):
        newChildren = [
            propagateValuesPrime(child, consts, gather) for child in node
        ]
        node.setChildren(newChildren)

    return consts if isinstance(node, Module) else node
예제 #15
0
def selectInstructions(node, cf, dest=None):

    # Error out if we receive a complex node that should have been flattened
    # or translated out before instruction selection.
    if not node.isSimple():
        raise Exception(
            'Non-simple node passed to instruction selection pass.')

    if isinstance(node, ast.Assign):
        # The destination is a name, so we need to translate it.
        dest = selectInstructions(node.var, cf)

        if isinstance(node.exp, ast.Name):
            code = Block('')

            # The source is a name, so we need to translate it.
            src = selectInstructions(node.exp, cf)

            if isinstance(src, Mem) and isinstance(dest, Mem):

                tmpColor = getTempColor(cf, node)

                code.append(move(src, tmpColor))
                code.append(move(tmpColor, dest))

            elif src != dest:
                code.append(move(src, dest))

            return code
        elif isinstance(node.exp, ast.Integer):
            src = selectInstructions(node.exp, cf)
            src = pack(src, INT)

            return move(src, dest)
        else:
            # Here the right side of the assignment is a complex expression.
            # We will select instructions for it, giving the Symbol
            # representing the variable's location as the destination.
            return selectInstructions(node.exp, cf, dest)

    elif isinstance(node, ast.BasicBlock):
        code = Block()

        for child in node:
            code.append(selectInstructions(child, cf))

        return code

    elif isinstance(node, ast.BinOp):
        code = Block()

        # The left and right operands need to be translated, but the
        # destination is already a Symbol,
        origLeft = left = selectInstructions(node.left, cf)
        origRight = right = selectInstructions(node.right, cf)

        #########
        # Setup #
        #########

        # This code will make sure that both the right and left parameters are
        # in registers.

        # tmpColor0 will be a register, and hold the final result of our
        # computation.  The result may need to be moved if tmpColor0 is not
        # the destination.
        tmpColor0 = getTmpColor(cf, node) if isinstance(dest, Mem) else dest

        # The default tag for a result will be an int.  If it already is
        # tagged, as will be the case for logical instructions or Add, it
        # won't end up being tagged.
        tmpColor0.tag = INT

        # Get the left operand into a register.
        if isinstance(left, Mem):
            if right != dest:
                code.append(move(left, tmpColor0))
                left = tmpColor0

            else:
                tmpColor1 = getTmpColor(
                    cf, node) if tmpColor0 == dest else tmpColor0
                code.append(move(left, tmpColor1))
                left = tmpColor1

        elif isinstance(left, Immediate):
            if isinstance(node, ast.Div):
                # Move our dividend into rax and padd rdx.
                code.append(move(left, rax))
                code.append(move(Immediate(left.value >> 31), rdx))
                left = rax

            elif isinstance(node, ast.Sub):
                tmpColor1 = getTmpColor(
                    cf, node) if right == tmpColor0 else tmpColor0

                # Move the right operand to another register if it is in
                # tmpColor0.
                if right == tmpColor0:
                    code.append(move(right, tmpColor1))
                    right = tmpColor1

                # Move the left hand immediate into the destination register.
                code.append(move(left, tmpColor0))
                left = tmpColor0

            elif right != dest:
                # If the left hand value is an immediate and this is an add
                # or multiply operation the right hand value needs to be in
                # the destination register.
                code.append(move(right, tmpColor0))
                right = tmpColor0

        elif isinstance(left, Register):
            if isinstance(node, ast.Div) and left != rax:
                # Move our dividend into rax and padd rdx.
                code.append(move(left, rax))
                code.append(move(left, rdx))
                code.append(TwoOp('sar', Immediate(31), rdx))
                left = rax

            elif left != dest:
                code.append(move(left, tmpColor0))
                left = tmpColor0

        # Get the right operand into a register.
        if isinstance(right, Mem):
            if left != tmpColor0 and classGuard(
                    node, Add, Mul) and not isinstance(node, Logical):
                code.append(move(right, tmpColor0))
                left = right
                right = tmpColor0

            else:
                tmpColor1 = getTmpColor(cf, node, tmpColor0)

                code.append(move(right, tmpColor1))
                right = tmpColor1

        elif isinstance(right, Immediate) and isinstance(node, ast.Div) and \
        not ((right.value % 2) == 0 and (right.value / 2) < 63):

            # If the right hand side is an immediate it needs to be
            # placed into a register for divide operations.
            tmpColor1 = getTmpColor(cf,
                                    node) if left == tmpColor0 else tmpColor0

            code.append(move(right, tmpColor1))
            right = tmpColor1

        # Untag the left operand if it isn't an immediate.
        if isinstance(left, Color) and classGuard(node, ast.Div, ast.Mul,
                                                  ast.Sub):
            code.append(untag(left))

        # Untag the right operand if it isn't an immediate.
        if isinstance(right, Color) and classGuard(node, ast.Div, ast.Mul,
                                                   ast.Sub):
            code.append(untag(right))

        #############
        # End Setup #
        #############

        if isinstance(node, ast.Add):
            # The right value is never going to be an immediate due to our
            # constant folding transformation.
            if isinstance(left, Immediate):
                # This value hasn't been untagged yet.
                code.append(untag(tmpColor0))

                if left.value == 1:
                    code.append(OneOp('inc', tmpColor0))

                else:
                    code.append(TwoOp('add', left, tmpColor0))

            else:
                # Build the case where we need to call the add function.
                case0 = Block()
                case0.append(OneOp('push', right))
                case0.append(OneOp('push', left))
                case0.append(OneOp('call', ast.Name('add'), None))
                case0.append(TwoOp('sub', Immediate(8), rsp))
                case0.append(tag(rax, OBJ))

                if rax != dest:
                    case0.append(move(rax, tmpColor0))

                # Build the case where we are adding two integers.
                case1 = Block()

                # Untag values as necessary.
                case1.append(untag(left))
                case1.append(untag(right))

                # Decide which operand to add to which.
                if left == tmpColor0:
                    case1.append(TwoOp('add', right, tmpColor0))

                else:
                    case1.append(TwoOp('add', left, tmpColor0))

                # Tag the result of the integer addition.
                case1.append(tag(tmpColor0, INT))

                # Re-tag the operands.
                case1.append(tag(left, INT))
                case1.append(tag(right, INT))

                code.append(
                    buildITE(tmpColor0, case0, case1, TAG_MASK, 'je', True))

        elif isinstance(node, ast.Div):
            if isinstance(right, Immediate) and (
                    right.value % 2) == 0 and (right.value / 2) < 63:
                # We can shift to the right instead of dividing.
                dist = right.value / 2

                code.append(TwoOp('sar', Immediate(dist), tmpColor0))

            else:
                code.append(OneOp('idiv', right, None))

                if tmpColor0 != rax:
                    code.append(move(rax, tmpColor0))

        elif isinstance(node, ast.Mul):
            if isinstance(left, Immediate) and (
                    left.value % 2) == 0 and (left.value / 2) < 63:
                # We can shift to the left instead of multiplying.
                dist = left.value / 2

                code.append(TwoOp('sal', Immediate(dist), tmpColor0))

            elif right == dest or isinstance(left, Immediate):
                code.append(TwoOp('imul', left, tmpColor0))

            else:
                code.append(TwoOp('imul', right, tmpColor0))

        elif isinstance(node, ast.Sub):
            if isinstance(right, Immediate) and right == 1:
                code.append(OneOp('dec', tmpColor0))

            else:
                code.append(TwoOp('sub', right, tmpColor0))

        elif classGuard(node, ast.And, ast.Or):
            jmp = 'jl' if isinstance(node, ast.And) else 'jg'

            if left == dest:
                case0 = move(right, tmpColor0)
                case1 = None

            else:
                case0 = move(right, tmpColor0)
                case1 = move(left, tmpColor0)

            code.append(buildITE(left, case0, case1, FALS, jmp, True))

        elif classGuard(node, ast.Eq, ast.Ne):
            case0 = Block()

            if isinstance(node, ast.Eq):
                funName = ast.Name('equal')
                jmp = 'jz'

            else:
                funName = ast.Name('not_equal')
                jmp = 'jnz'

            # Build the case where we need to call the equal function.
            case0.append(OneOp('push', right))
            case0.append(OneOp('push', left))
            case0.append(OneOp('call', funName, None))
            case0.append(TwoOp('sub', Immediate(8), esp))
            case0.append(tag(rax, BOOL))
            case0.append(move(rax, tmpColor0))

            case2 = move(TRU, tmpColor0)
            case3 = move(FALS, tmpColor0)

            # Build the case where we are comparing two integers or
            # booleans.
            case1 = buildITE(right, case2, case3, left, jmp)

            code.append(buildITE(tmpColor0, case0, case1, TAG_MASK, 'je',
                                 True))

        elif isinstance(node, ast.Is):
            case0 = move(FALS, tmpColor0)
            case1 = move(TRU, tmpColor0)

            code.append(buildITE(right, case0, case1, left))

        ###########
        # Cleanup #
        ###########

        # Re-tag left, right, and result appropriately.
        code.append(tag(tmpColor0))

        if isinstance(origLeft, Register) and origLeft in toColors(
                node['post-alive']):
            code.append(tag(origLeft))

        if isinstance(origRight, Register) and origRight in toColors(
                node['post-alive']):
            code.append(tag(origRight))

        # Move the result.
        if tmpColor0 != dest:
            code.append(move(tmpColor0, dest))

        ###############
        # End Cleanup #
        ###############

        return code

    elif isinstance(node, ast.Boolean):
        if isinstance(node, ast.Tru):
            return TRU

        elif isinstance(node, ast.Fals):
            return FALS

    elif isinstance(node, ast.FunctionCall):
        code = Block()

        # Save any caller saved registers currently in use.
        saveColors = toColors(node['post-alive'])
        saveRegs(code, caller, saveColors)

        # Either move our arguments into their registers, or push them onto
        # the stack.
        addSize = 0
        index = 0
        for arg in node.args:
            src = selectInstructions(arg, cf)

            # Pack immediates if they haven't been packed yet.
            if isinstance(src, Immediate):
                src = pack(src, INT)

            reg = None
            if index < len(args):
                reg = args[index]

            if reg != src:
                code.append(move(src, reg))

            elif not reg:
                code.append(OneOp("push", src))
                addSize += 8

            index += 1

        # Clear rax's tagged and tag values.
        rax.clear()

        #Make the function call.
        code.append(OneOp("call", node.name, None))

        # Restore the stack.
        if addSize > 0:
            code.append(TwoOp("add", Immediate(addSize), rsp))

        # Tag the result if necessary.
        code.append(tag(rax, node.tag))

        # Move the result into the proper destination.
        if dest and dest != rax:
            code.append(move(rax, dest))

        # Restore any caller saved registers that are in use.
        restoreRegs(code, caller, saveColors)

        return code

    elif isinstance(node, ast.If):
        cond = selectInstructions(node.cond, cf)
        then = selectInstructions(node.then, cf)
        els = selectInstructions(node.els, cf)

        return buildITE(cond, then, els)

    elif isinstance(node, ast.Integer):
        return Immediate(node.value)

    elif isinstance(node, ast.Module):
        code = Block()
        code.header = "# x86_64\n"
        code.header += ".globl main\n"
        code.header += "main:\n"

        usedColors = toColors(node.collectSymbols())

        # Save any callee saved registers we used.
        saveRegs(code, callee, usedColors)

        # Expand the stack.
        if cf.offset > 0:
            code.append(TwoOp('sub', Immediate(cf.offset), Register('rsp')))

        # Append the module's code.
        code.append(selectInstructions(node.block, cf))

        endBlock = Block()

        # Restore any callee saved registers we used.
        restoreRegs(endBlock, callee, usedColors)

        # Put our exit value in %rax
        endBlock.append(TwoOp('mov', Immediate(0), rax))
        # Return
        endBlock.append(Instruction("ret"))

        code.append(endBlock)

        return code

    elif isinstance(node, ast.Symbol):
        if node.has_key('color'):
            return node['color']
        else:
            raise Exception("Uncolored symbol ({0}) encountered.".format(node))

    elif isinstance(node, ast.UnaryOp):
        code = Block()

        src = selectInstructions(node.operand, cf)

        #########
        # Setup #
        #########

        tmpColor = getTmpColor(cf, node) if isinstance(dest, Mem) else dest

        if src != tmpColor:
            code.append(move(src, tmpColor))

        # Untag the argument.
        code.append(untag(tmpColor))

        #############
        # End Setup #
        #############

        if isinstance(node, ast.Negate):
            code.append(OneOp('neg', tmpColor))

            # Tell the cleanup code to tag the result as an integer.
            tmpColor.tagged = False
            tmpColor.tag = INT

        elif isinstance(node, ast.Not):
            case0 = move(FALS, tmpColor)
            case1 = move(TRU, tmpColor)

            code.append(buildITE(src, case0, case1, FALS, 'jle'))

        ###########
        # Cleanup #
        ###########

        # Tag the result.
        code.append(tag(tmpColor))

        if tmpColor != dest:
            code.append(move(tmpColor, dest))

        ###############
        # End Cleanup #
        ###############

        return code
예제 #16
0
def selectInstructions(node, cf, dest = None):
	
	global shifts
	
	# Error out if we receive a complex node that should have been flattened
	# or translated out before instruction selection.
	if not node.isSimple():
		raise Exception('Non-simple node passed to instruction selection pass.')
	
	if isinstance(node, ast.Assign):
		# The destination is a name, so we need to translate it.
		dest = selectInstructions(node.var, cf)
		
		if isinstance(node.exp, ast.Symbol):
			code = Block('')
			
			# The source is a name, so we need to translate it.
			src = selectInstructions(node.exp, cf)
			
			if isinstance(src, Mem) and isinstance(dest, Mem):
				
				tmpColor = getTmpColor(cf, node)
				
				code.append(move(src, tmpColor))
				code.append(move(tmpColor, dest))
			
			elif src != dest:
				code.append(move(src, dest))
			
			return code
		elif classGuard(node.exp, ast.Boolean, ast.Integer):
			src = selectInstructions(node.exp, cf)
			
			if isinstance(node.exp, ast.Integer):
				src = pack(src, INT)
			
			return move(src, dest)
		
		else:
			# Here the right side of the assignment is a complex expression.
			# We will select instructions for it, giving the Symbol
			# representing the variable's location as the destination.
			return selectInstructions(node.exp, cf, dest)
	
	elif isinstance(node, ast.BasicBlock):
		code = Block()
		
		for child in node:
			code.append(selectInstructions(child, cf))
		
		return code
	
	elif isinstance(node, ast.BinOp):
		code = Block()
		
		# The left and right operands need to be translated, but the
		# destination is already a Symbol,
		origLeft = left = selectInstructions(node.left, cf)
		origRight = right = selectInstructions(node.right, cf)
		
		#########
		# Setup #
		#########
		
		# This code will make sure that both the right and left parameters are
		# in registers.
		
		# tmpColor0 will be a register, and hold the final result of our
		# computation.  The result may need to be moved if tmpColor0 is not
		# the destination.
		tmpColor0 = getTmpColor(cf, node) if isinstance(dest, Mem) else dest
		
		# The default tag for a result will be an int.  If it is already
		# tagged, as will be the case for logical instructions or Add, it won't
		# end up being tagged.
		tmpColor0.tag = INT
		
		# Get the left operand into a register.
		if classGuard(left, Mem, Label):
			if right != dest:
				code.append(move(left, tmpColor0))
				left = tmpColor0
			
			else:
				tmpColor1 = getTmpColor(cf, node) if tmpColor0 == dest else tmpColor0
				code.append(move(left, tmpColor1))
				left = tmpColor1
		
		elif isinstance(left, Immediate):
			if isinstance(node, ast.Div):
				# Move our dividend into %eax.
				code.append(move(left, eax))
				left = eax
			
			elif isinstance(node, ast.Sub):
				tmpColor1 = getTmpColor(cf, node) if right == tmpColor0 else tmpColor0
				
				# Move the right operand to another register if it is in
				# tmpColor0.
				if right == tmpColor0:
					code.append(move(right, tmpColor1))
					right = tmpColor1
				
				# Move the left hand immediate into the destination register.
				code.append(move(left, tmpColor0))
				left = tmpColor0
					
			elif right != dest:
				# If the left hand value is an immediate and this is an add
				# or multiply operation the right hand value needs to be in
				# the destination register.
				code.append(move(right, tmpColor0))
				right = tmpColor0
		
		elif isinstance(left, Register):
			if isinstance(node, ast.Div) and left != eax:
				# Move our dividend into eax.
				code.append(move(left, eax))
				left = eax
			
			elif left != dest and right != dest:
				code.append(move(left, tmpColor0))
				left = tmpColor0
		
		# Get the right operand into a register.
		if classGuard(right, Mem, Label):
			if left != tmpColor0 and classGuard(node, ast.Add, ast.Mul) and not isinstance(node, ast.Logical):
				code.append(move(right, tmpColor0))
				left = right
				right = tmpColor0
			
			else:
				tmpColor1 = getTmpColor(cf, node, tmpColor0)
				
				code.append(move(right, tmpColor1))
				right = tmpColor1
		
		elif isinstance(right, Immediate) and isinstance(node, ast.Div) and right.value not in shifts:
			
			# If the right hand side is an immediate it needs to be
			# placed into a register for divide operations.
			tmpColor1 = getTmpColor(cf, node) if left == tmpColor0 else tmpColor0
		
			code.append(move(right, tmpColor1))
			right = tmpColor1
		
		# Untag the left operand if it isn't an immediate.
		if isinstance(left, Color) and classGuard(node, ast.Div, ast.Mul, ast.Sub):
			code.append(untag(left))
		
		# Untag the right operand if it isn't an immediate.
		if isinstance(right, Color) and classGuard(node, ast.Div, ast.Mul, ast.Sub):
			code.append(untag(right))
		
		#############
		# End Setup #
		#############
		
		if isinstance(node, ast.Add):
			# The right value is never going to be an immediate due to our
			# constant folding transformation.
			if isinstance(left, Immediate):
				#This value hasn't been untagged yet.
				code.append(untag(tmpColor0))
				
				if left.value == 1:
					code.append(OneOp('inc', tmpColor0))
				
				elif left.value == -1:
					code.append(OneOp('dec', tmpColor0))
				
				else:
					code.append(TwoOp('add', left, tmpColor0))
			
			else:
				# Build the case where we need to call the add function.
				case0 = Block()
				
				case0.append(untag(left, OBJ))
				case0.append(untag(right, OBJ))
				
				case0.append(OneOp('push', right))
				case0.append(OneOp('push', left))
				
				case0.append(OneOp('call', ast.Name('add'), None))
				case0.append(TwoOp('add', Immediate(8), esp))
				
				case0.append(tag(eax, OBJ))
				case0.append(tag(left, OBJ))
				case0.append(tag(right, OBJ))
				
				if eax != dest:
					case0.append(move(eax, tmpColor0))
				
				# Build the case where we are adding two integers.
				case1 = Block()
				
				# Untag values as necessary.
				case1.append(untag(left))
				case1.append(untag(right))
				
				# Decide which operand to add to which.
				if left == tmpColor0:
					case1.append(TwoOp('add', right, tmpColor0))
				
				else:
					case1.append(TwoOp('add', left, tmpColor0))
				
				# Tag the result of the integer addition.
				case1.append(tag(tmpColor0, INT))
				
				# Re-tag the operands.
				case1.append(tag(left, INT))
				case1.append(tag(right, INT))
				
				code.append(buildITE(tmpColor0, case0, case1, TAG_MASK, 'je', True))
			
		elif isinstance(node, ast.Div):
			if isinstance(right, Immediate) and right.value in shifts:
				# We can shift to the right instead of dividing.
				dist = shifts[right.value]
				
				code.append(TwoOp('sar', Immediate(dist), eax))
			
			else:
				# Prepare out %edx.
				code.append(Instruction('cltd'))
				
				code.append(OneOp('idiv', right))
				
			if tmpColor0 != eax:
				code.append(move(eax, tmpColor0))
		
		elif isinstance(node, ast.Mul):
			if isinstance(left, Immediate) and left.value in shifts:
				# We can shift to the left instead of multiplying.
				dist = shifts[left.value]
				
				code.append(TwoOp('sal', Immediate(dist), tmpColor0))
			
			elif right == dest or isinstance(left, Immediate):
				code.append(TwoOp('imul', left, tmpColor0))
			
			else:
				code.append(TwoOp('imul', right, tmpColor0))
				code.append(tag(right, INT))
		
		elif isinstance(node, ast.Sub):
			if isinstance(right, Immediate) and right.value == 1:
				code.append(OneOp('dec', tmpColor0))
			
			else:
				code.append(TwoOp('sub', right, tmpColor0))
		
		elif classGuard(node, ast.And, ast.Or):
			jmp = 'jl' if isinstance(node, ast.And) else 'jg'
			
			if left == dest:
				case0 = move(right, tmpColor0)
				case1 = None
			
			else:
				case0 = move(right, tmpColor0)
				case1 = move(left, tmpColor0)
				
			code.append(buildITE(left, case0, case1, FALS, jmp, True))
		
		elif classGuard(node, ast.Eq, ast.Ne):
			case0 = Block()
			
			if isinstance(node, ast.Eq):
				funName = ast.Name('equal')
				jmp = 'jne'
			
			else:
				funName = ast.Name('not_equal')
				jmp = 'je'
			
			# Build the case where we need to call the equal function.
			if isinstance(left, Register):
				case0.append(untag(left, OBJ))
			
			if isinstance(right, Register):
				case0.append(untag(right, OBJ))
			
			case0.append(OneOp('push', right))
			case0.append(OneOp('push', left))
			
			case0.append(OneOp('call', funName, None))
			case0.append(TwoOp('add', Immediate(8), esp))
			
			case0.append(tag(eax, BOOL))
			
			if isinstance(left, Register) and left != eax:
				case0.append(tag(left))
			
			if isinstance(right, Register) and right != eax:
				case0.append(tag(right))
			
			if tmpColor0 != eax:
				case0.append(move(eax, tmpColor0))
			
			case2 = move(TRU, tmpColor0)
			case3 = move(FALS, tmpColor0)
			
			# Pack left and right immediates for comparison.
			if isinstance(left, Immediate):
				left = pack(right, INT)
			
			if isinstance(right, Immediate):
				right = pack(right, INT)
			
			# Build the case where we are comparing two integers or
			# booleans.
			case1 = buildITE(right, case2, case3, left, jmp)
			
			code.append(buildITE(tmpColor0, case0, case1, TAG_MASK, 'je', True))
		
		elif isinstance(node, ast.Is):
			case0 = move(FALS, tmpColor0)
			case1 = move(TRU, tmpColor0)
			
			code.append(buildITE(right, case0, case1, left))
		
		###########
		# Cleanup #
		###########
		
		# Re-tag left, right, and result appropriately.
		code.append(tag(tmpColor0))
		
		if isinstance(origLeft, Register) and origLeft in toColors(node['post-alive']):
			code.append(tag(origLeft))
		
		if isinstance(origRight, Register) and origRight in toColors(node['post-alive']):
			code.append(tag(origRight))
		
		# Move the result.
		if tmpColor0 != dest:
			code.append(move(tmpColor0, dest))
		
		###############
		# End Cleanup #
		###############
		
		return code
	
	elif isinstance(node, ast.Boolean):
		if isinstance(node, ast.Tru):
			return TRU
		
		elif isinstance(node, ast.Fals):
			return FALS
	
	elif isinstance(node, ast.Function):
		code = Block()
		
		# Mark that the arguments are taged.
		#~for color in toColors(node.argSymbols):
			#~color.tagged = True
		
		code.append(Directive("globl {0}".format(node.name), False))
		code.append(Directive('align 4', False))
		code.append(Label(node.name, ''))
		
		# Push the old base pointer onto the stack.
		code.append(OneOp('push', ebp))
		# Make the old stack pointer the new base pointer.
		code.append(move(esp, ebp))
		
		usedColors = toColors(node.collectSymbols())
		
		# Save any callee saved registers we used.
		saveRegs(code, callee, usedColors)
		
		# Expand the stack.
		foo = cf.offset - 4
		if foo > 0:
			code.append(TwoOp('sub', Immediate(foo), esp))
		
		# Append the module's code.
		code.append(selectInstructions(node.block, cf))
		
		endBlock = Block()
		# Restore the stack.
		if foo > 0:
			endBlock.append(TwoOp('add', Immediate(foo), esp))
		
		# Restore any callee saved registers we used.
		restoreRegs(endBlock, callee, usedColors)
		
		# Restore the %esp and %ebp registers.
		endBlock.append(Instruction('leave'))
		# Return
		endBlock.append(Instruction('ret'))

		code.append(endBlock)
		
		return code
	
	elif isinstance(node, ast.FunctionCall):
		code = Block()
		
		# Save any caller saved registers that are in use after this call.
		saveColors = toColors(node['post-alive'])
		saveRegs(code, caller, saveColors)
		
		addSize = 0
		args = list(node.args)
		args.reverse()
		for arg in args:
			src = selectInstructions(arg, cf)
			
			# Pack immediates if they haven't been packed yet.
			if isinstance(src, Immediate):
				src = pack(src, INT)
			
			elif isinstance(src, ast.Name) or (isinstance(src, Label) and src.reference):
				src = '$' + str(src)
			
			code.append(OneOp('push', src))
			addSize += 4
		
		# Clear eax's tagged and tag values.
		eax.clear()
		
		# Make the function call.
		if isinstance(node.name, ast.Name):
			# This is the direct call case.
			code.append(OneOp('call', node.name, None))
		
		else:
			# This is the case when we recieved the function pointer as an
			# argument.  This can either result in a direct or an indirect
			# call.
			src = selectInstructions(node.name, cf)
			
			if isinstance(src, Mem) or src == eax:
				tmpColor = getTmpColor(cf, node)
				code.append(move(src, tmpColor))
				src = tmpColor
			
			# This is the case where we need to unpack the closure.
			case0 = Block()
			
			case0.append(OneOp('push', src))
			case0.append(OneOp('call', ast.Name('get_free_vars'), None))
			
			case0.append(TwoOp('add', Immediate(4), esp))
			case0.append(OneOp('push', eax))
			case0.append(OneOp('push', src))
			
			case0.append(OneOp('call', ast.Name('get_fun_ptr'), None))
			case0.append(TwoOp('add', Immediate(4), esp))
			
			case0.append(OneOp('call', '*' + str(eax), None))
			
			# The case where it is a direct call (made indirectly).
			case1 = OneOp('call', '*' + str(src), None)
			
			code.append(buildITE(src, case0, case1, TAG_MASK, 'je', True))
		
		#~name = '*' + str(node.name['color']) if isinstance(node.name, Symbol) else node.name
		#~code.append(OneOp('call', name, None))
		
		# Restore the stack.
		if addSize > 0:
			code.append(TwoOp('add', Immediate(addSize), esp))
		
		# Tag the result if necessary.
		code.append(tag(eax, node.tag))
		
		# Move the result into the proper destination.
		if dest and dest != eax:
			code.append(move(eax, dest))
		
		# Restore any caller saved registers that are in use.
		restoreRegs(code, caller, saveColors)

		return code
	
	elif isinstance(node, ast.If):
		cond = selectInstructions(node.cond, cf)
		then = selectInstructions(node.then, cf)
		els  = selectInstructions(node.els,  cf)
		
		thenSyms = node.then.collectSymbols('r')
		elseSyms = node.els.collectSymbols('r')
		
		# Insert Phi moves.
		for phi in node.jn:
			for sym in phi.srcs:
				if sym['color'] != phi.target['color']:
					(then if sym in thenSyms else els).append(move(sym['color'], phi.target['color']))
		
		# Here we compare the conditional to False, and if it is less then or
		# equal to False (either False or 0) we will go to the else case.
		return buildITE(cond, then, els, FALS, 'jle')
	
	elif isinstance(node, ast.Integer):
		return Immediate(node.value)
	
	elif isinstance(node, ast.Module):
		code = Block("# x86\n")
		
		data = Block("# Data\n")
		funs = Block("\n# Functions\n")
		
		# Define our data section.
		for sym in node.collectSymbols():
			if sym['heapify'] and sym not in node.strings.values():
				data.append(Directive("globl {0}".format(sym['color']), False))
				data.append(Directive('data'))
				data.append(Directive('align 4'))
				data.append(Directive("size {0}, 4".format(sym['color'])))
				
				data.append(sym['color'])
				data.append(Directive('long 1'))
				data.append(Directive('section .data'))
		
		# Add any strings we may need to define.
		for string in node.strings:
			sym = node.strings[string]
			
			data.append(sym['color'])
			data.append(Directive("string \"{0}\"".format(string)))
			data.append(Directive('text'))
		
		# Define our functions.
		for fun in node.functions:
			funs.append(selectInstructions(fun, cf))
		
		# Concatenate our code.
		code.append(data)
		code.append(funs)
		
		return code
	
	elif isinstance(node, ast.Name):
		return node
	
	elif isinstance(node, ast.Return):
		code = Block()
		
		src = selectInstructions(node.value, cf)
		# Pack immediates if they haven't been packed yet.
		if isinstance(src, Immediate):
			src = pack(src, INT)
		
		elif isinstance(src, ast.Name):
			src = '$' + str(src)
		
		if src != eax:
			code.append(move(src, eax))
		
		return code
	
	elif isinstance(node, ast.String):
		return node['color']
	
	elif isinstance(node, ast.Symbol):
		if node.has_key('color'):
			return node['color']
		else:
			raise Exception("Uncolored symbol ({0}) encountered.".format(node))
	
	elif isinstance(node, ast.UnaryOp):
		code = Block()
		
		src = selectInstructions(node.operand, cf)
		
		#########
		# Setup #
		#########
		
		tmpColor = getTmpColor(cf, node) if isinstance(dest, Mem) else dest
		
		if src != tmpColor:
			code.append(move(src, tmpColor))
		
		# Untag the argument.
		code.append(untag(tmpColor))
		
		#############
		# End Setup #
		#############
		
		if isinstance(node, ast.Negate):
			code.append(OneOp('neg', tmpColor))
			
			# Tell the cleanup code to tag the result as an integer.
			tmpColor.tagged = False
			tmpColor.tag = INT
		
		elif isinstance(node, ast.Not):
			case0 = move(FALS, tmpColor)
			case1 = move(TRU, tmpColor)
			
			code.append(buildITE(src, case0, case1, FALS, 'jle'))
		
		###########
		# Cleanup #
		###########
		
		# Tag the result.
		code.append(tag(tmpColor))
		
		if tmpColor != dest:
			code.append(move(tmpColor, dest))
		
		###############
		# End Cleanup #
		###############
		
		return code
	
	elif isinstance(node, ast.While):
		code = Block()
		
		cond		= selectInstructions(node.cond, cf)
		condBody	= selectInstructions(node.condBody, cf)
		body		= selectInstructions(node.body, cf)
		
		# Insert Phi moves.
		for phi in node.jn.phis:
			for src in phi:
				if src['color'] != phi.target['color']:
					(code if src in node['pre-alive'] else body).append(move(src['color'], phi.target['color']))
		
		l0 = getLabel()
		l1 = getLabel()
		
		# Initial jump to the cond block.
		code.append(OneOp('jmp', l1, None))
		
		# The body label and the body.
		code.append(l0)
		code.append(body)
		
		# Cond label and cond body.
		code.append(l1)
		code.append(condBody)
		
		# Test to see if we should loop.
		code.append(TwoOp('cmp', FALS, cond))
		code.append(OneOp('jg', l0, None))
		
		return code
예제 #17
0
def selectInstructions(node, cf, dest = None):
	
	# Error out if we receive a complex node that should have been flattened
	# or translated out before instruction selection.
	if not node.isSimple():
		raise Exception('Non-simple node passed to instruction selection pass.')
	
	if isinstance(node, ast.Assign):
		# The destination is a name, so we need to translate it.
		dest = selectInstructions(node.var, cf)
		
		if isinstance(node.exp, ast.Name):
			code = Block('')
			
			# The source is a name, so we need to translate it.
			src = selectInstructions(node.exp, cf)
			
			if isinstance(src, Mem) and isinstance(dest, Mem):
				
				tmpColor = getTempColor(cf, node)
				
				code.append(move(src, tmpColor))
				code.append(move(tmpColor, dest))
			
			elif src != dest:
				code.append(move(src, dest))
			
			return code
		elif isinstance(node.exp, ast.Integer):
			src = selectInstructions(node.exp, cf)
			src = pack(src, INT)
			
			return move(src, dest)
		else:
			# Here the right side of the assignment is a complex expression.
			# We will select instructions for it, giving the Symbol
			# representing the variable's location as the destination.
			return selectInstructions(node.exp, cf, dest)
	
	elif isinstance(node, ast.BasicBlock):
		code = Block()
		
		for child in node:
			code.append(selectInstructions(child, cf))
		
		return code
	
	elif isinstance(node, ast.BinOp):
		code = Block()
		
		# The left and right operands need to be translated, but the
		# destination is already a Symbol,
		origLeft = left = selectInstructions(node.left, cf)
		origRight = right = selectInstructions(node.right, cf)
		
		#########
		# Setup #
		#########
		
		# This code will make sure that both the right and left parameters are
		# in registers.
		
		# tmpColor0 will be a register, and hold the final result of our
		# computation.  The result may need to be moved if tmpColor0 is not
		# the destination.
		tmpColor0 = getTmpColor(cf, node) if isinstance(dest, Mem) else dest
		
		# The default tag for a result will be an int.  If it already is
		# tagged, as will be the case for logical instructions or Add, it
		# won't end up being tagged.
		tmpColor0.tag = INT
		
		# Get the left operand into a register.
		if isinstance(left, Mem):
			if right != dest:
				code.append(move(left, tmpColor0))
				left = tmpColor0
			
			else:
				tmpColor1 = getTmpColor(cf, node) if tmpColor0 == dest else tmpColor0
				code.append(move(left, tmpColor1))
				left = tmpColor1
		
		elif isinstance(left, Immediate):
			if isinstance(node, ast.Div):
				# Move our dividend into rax and padd rdx.
				code.append(move(left, rax))
				code.append(move(Immediate(left.value >> 31), rdx))
				left = rax
			
			elif isinstance(node, ast.Sub):
				tmpColor1 = getTmpColor(cf, node) if right == tmpColor0 else tmpColor0
				
				# Move the right operand to another register if it is in
				# tmpColor0.
				if right == tmpColor0:
					code.append(move(right, tmpColor1))
					right = tmpColor1
				
				# Move the left hand immediate into the destination register.
				code.append(move(left, tmpColor0))
				left = tmpColor0
					
			elif right != dest:
				# If the left hand value is an immediate and this is an add
				# or multiply operation the right hand value needs to be in
				# the destination register.
				code.append(move(right, tmpColor0))
				right = tmpColor0
		
		elif isinstance(left, Register):
			if isinstance(node, ast.Div) and left != rax:
				# Move our dividend into rax and padd rdx.
				code.append(move(left, rax))
				code.append(move(left, rdx))
				code.append(TwoOp('sar', Immediate(31), rdx))
				left = rax
			
			elif left != dest:
				code.append(move(left, tmpColor0))
				left = tmpColor0
		
		# Get the right operand into a register.
		if isinstance(right, Mem):
			if left != tmpColor0 and classGuard(node, Add, Mul) and not isinstance(node, Logical):
				code.append(move(right, tmpColor0))
				left = right
				right = tmpColor0
			
			else:
				tmpColor1 = getTmpColor(cf, node, tmpColor0)
				
				code.append(move(right, tmpColor1))
				right = tmpColor1
		
		elif isinstance(right, Immediate) and isinstance(node, ast.Div) and \
		not ((right.value % 2) == 0 and (right.value / 2) < 63):
			
			# If the right hand side is an immediate it needs to be
			# placed into a register for divide operations.
			tmpColor1 = getTmpColor(cf, node) if left == tmpColor0 else tmpColor0
		
			code.append(move(right, tmpColor1))
			right = tmpColor1
		
		# Untag the left operand if it isn't an immediate.
		if isinstance(left, Color) and classGuard(node, ast.Div, ast.Mul, ast.Sub):
			code.append(untag(left))
		
		# Untag the right operand if it isn't an immediate.
		if isinstance(right, Color) and classGuard(node, ast.Div, ast.Mul, ast.Sub):
			code.append(untag(right))
		
		#############
		# End Setup #
		#############
		
		if isinstance(node, ast.Add):
			# The right value is never going to be an immediate due to our
			# constant folding transformation.
			if isinstance(left, Immediate):
				# This value hasn't been untagged yet.
				code.append(untag(tmpColor0))
				
				if left.value == 1:
					code.append(OneOp('inc', tmpColor0))
				
				else:
					code.append(TwoOp('add', left, tmpColor0))
			
			else:
				# Build the case where we need to call the add function.
				case0 = Block()
				case0.append(OneOp('push', right))
				case0.append(OneOp('push', left))
				case0.append(OneOp('call', ast.Name('add'), None))
				case0.append(TwoOp('sub', Immediate(8), rsp))
				case0.append(tag(rax, OBJ))
				
				if rax != dest:
					case0.append(move(rax, tmpColor0))
				
				# Build the case where we are adding two integers.
				case1 = Block()
				
				# Untag values as necessary.
				case1.append(untag(left))
				case1.append(untag(right))
				
				# Decide which operand to add to which.
				if left == tmpColor0:
					case1.append(TwoOp('add', right, tmpColor0))
				
				else:
					case1.append(TwoOp('add', left, tmpColor0))
				
				# Tag the result of the integer addition.
				case1.append(tag(tmpColor0, INT))
				
				# Re-tag the operands.
				case1.append(tag(left, INT))
				case1.append(tag(right, INT))
				
				code.append(buildITE(tmpColor0, case0, case1, TAG_MASK, 'je', True))
		
		elif isinstance(node, ast.Div):
			if isinstance(right, Immediate) and (right.value % 2) == 0 and (right.value / 2) < 63:
				# We can shift to the right instead of dividing.
				dist = right.value / 2
				
				code.append(TwoOp('sar', Immediate(dist), tmpColor0))
			
			else:
				code.append(OneOp('idiv', right, None))
				
				if tmpColor0 != rax:
					code.append(move(rax, tmpColor0))
		
		elif isinstance(node, ast.Mul):
			if isinstance(left, Immediate) and (left.value % 2) == 0 and (left.value / 2) < 63:
				# We can shift to the left instead of multiplying.
				dist = left.value / 2
				
				code.append(TwoOp('sal', Immediate(dist), tmpColor0))
			
			elif right == dest or isinstance(left, Immediate):
				code.append(TwoOp('imul', left, tmpColor0))
			
			else:
				code.append(TwoOp('imul', right, tmpColor0))
		
		elif isinstance(node, ast.Sub):
			if isinstance(right, Immediate) and right == 1:
				code.append(OneOp('dec', tmpColor0))
			
			else:
				code.append(TwoOp('sub', right, tmpColor0))
		
		elif classGuard(node, ast.And, ast.Or):
			jmp = 'jl' if isinstance(node, ast.And) else 'jg'
			
			if left == dest:
				case0 = move(right, tmpColor0)
				case1 = None
			
			else:
				case0 = move(right, tmpColor0)
				case1 = move(left, tmpColor0)
				
			code.append(buildITE(left, case0, case1, FALS, jmp, True))
		
		elif classGuard(node, ast.Eq, ast.Ne):
			case0 = Block()
			
			if isinstance(node, ast.Eq):
				funName = ast.Name('equal')
				jmp = 'jz'
			
			else:
				funName = ast.Name('not_equal')
				jmp = 'jnz'
			
			# Build the case where we need to call the equal function.
			case0.append(OneOp('push', right))
			case0.append(OneOp('push', left))
			case0.append(OneOp('call', funName, None))
			case0.append(TwoOp('sub', Immediate(8), esp))
			case0.append(tag(rax, BOOL))
			case0.append(move(rax, tmpColor0))
			
			case2 = move(TRU, tmpColor0)
			case3 = move(FALS, tmpColor0)
			
			# Build the case where we are comparing two integers or
			# booleans.
			case1 = buildITE(right, case2, case3, left, jmp)
			
			code.append(buildITE(tmpColor0, case0, case1, TAG_MASK, 'je', True))
		
		elif isinstance(node, ast.Is):
			case0 = move(FALS, tmpColor0)
			case1 = move(TRU, tmpColor0)
			
			code.append(buildITE(right, case0, case1, left))
		
		###########
		# Cleanup #
		###########
		
		# Re-tag left, right, and result appropriately.
		code.append(tag(tmpColor0))
		
		if isinstance(origLeft, Register) and origLeft in toColors(node['post-alive']):
			code.append(tag(origLeft))
		
		if isinstance(origRight, Register) and origRight in toColors(node['post-alive']):
			code.append(tag(origRight))
		
		# Move the result.
		if tmpColor0 != dest:
			code.append(move(tmpColor0, dest))
		
		###############
		# End Cleanup #
		###############
		
		return code
	
	elif isinstance(node, ast.Boolean):
		if isinstance(node, ast.Tru):
			return TRU
		
		elif isinstance(node, ast.Fals):
			return FALS
	
	elif isinstance(node, ast.FunctionCall):
		code = Block()
		
		# Save any caller saved registers currently in use.
		saveColors = toColors(node['post-alive'])
		saveRegs(code, caller, saveColors)
		
		# Either move our arguments into their registers, or push them onto
		# the stack.
		addSize = 0
		index = 0
		for arg in node.args:
			src = selectInstructions(arg, cf)
			
			# Pack immediates if they haven't been packed yet.
			if isinstance(src, Immediate):
				src = pack(src, INT)
			
			reg = None
			if index < len(args):
				reg = args[index]
			
			if reg != src:
				code.append(move(src, reg))
			
			elif not reg:
				code.append(OneOp("push", src))
				addSize += 8
			
			index += 1
		
		# Clear rax's tagged and tag values.
		rax.clear()
		
		#Make the function call.
		code.append(OneOp("call", node.name, None))
		
		# Restore the stack.
		if addSize > 0:
			code.append(TwoOp("add", Immediate(addSize), rsp))
		
		# Tag the result if necessary.
		code.append(tag(rax, node.tag))
		
		# Move the result into the proper destination.
		if dest and dest != rax:
			code.append(move(rax, dest))
		
		# Restore any caller saved registers that are in use.
		restoreRegs(code, caller, saveColors)
		
		return code
	
	elif isinstance(node, ast.If):
		cond = selectInstructions(node.cond, cf)
		then = selectInstructions(node.then, cf)
		els  = selectInstructions(node.els,  cf)
		
		return buildITE(cond, then, els)
	
	elif isinstance(node, ast.Integer):
		return Immediate(node.value)
	
	elif isinstance(node, ast.Module):
		code = Block()
		code.header  = "# x86_64\n"
		code.header += ".globl main\n"
		code.header += "main:\n"
		
		usedColors = toColors(node.collectSymbols())
		
		# Save any callee saved registers we used.
		saveRegs(code, callee, usedColors)
		
		# Expand the stack.
		if cf.offset > 0:
			code.append(TwoOp('sub', Immediate(cf.offset), Register('rsp')))
		
		# Append the module's code.
		code.append(selectInstructions(node.block, cf))
		
		endBlock = Block()
		
		# Restore any callee saved registers we used.
		restoreRegs(endBlock, callee, usedColors)
		
		# Put our exit value in %rax
		endBlock.append(TwoOp('mov', Immediate(0), rax))
		# Return
		endBlock.append(Instruction("ret"))

		code.append(endBlock)
		
		return code
	
	elif isinstance(node, ast.Symbol):
		if node.has_key('color'):
			return node['color']
		else:
			raise Exception("Uncolored symbol ({0}) encountered.".format(node))
	
	elif isinstance(node, ast.UnaryOp):
		code = Block()
		
		src = selectInstructions(node.operand, cf)
		
		#########
		# Setup #
		#########
		
		tmpColor = getTmpColor(cf, node) if isinstance(dest, Mem) else dest
		
		if src != tmpColor:
			code.append(move(src, tmpColor))
		
		# Untag the argument.
		code.append(untag(tmpColor))
		
		#############
		# End Setup #
		#############
		
		if isinstance(node, ast.Negate):
			code.append(OneOp('neg', tmpColor))
			
			# Tell the cleanup code to tag the result as an integer.
			tmpColor.tagged = False
			tmpColor.tag = INT
		
		elif isinstance(node, ast.Not):
			case0 = move(FALS, tmpColor)
			case1 = move(TRU, tmpColor)
			
			code.append(buildITE(src, case0, case1, FALS, 'jle'))
		
		###########
		# Cleanup #
		###########
		
		# Tag the result.
		code.append(tag(tmpColor))
		
		if tmpColor != dest:
			code.append(move(tmpColor, dest))
		
		###############
		# End Cleanup #
		###############
		
		return code
예제 #18
0
def selectInstructions(node, cf, dest=None):

    global shifts

    # Error out if we receive a complex node that should have been flattened
    # or translated out before instruction selection.
    if not node.isSimple():
        raise Exception(
            'Non-simple node passed to instruction selection pass.')

    if isinstance(node, ast.Assign):
        # The destination is a name, so we need to translate it.
        dest = selectInstructions(node.var, cf)

        if isinstance(node.exp, ast.Symbol):
            code = Block('')

            # The source is a name, so we need to translate it.
            src = selectInstructions(node.exp, cf)

            if isinstance(src, Mem) and isinstance(dest, Mem):

                tmpColor = getTmpColor(cf, node)

                code.append(move(src, tmpColor))
                code.append(move(tmpColor, dest))

            elif src != dest:
                code.append(move(src, dest))

            return code
        elif classGuard(node.exp, ast.Boolean, ast.Integer):
            src = selectInstructions(node.exp, cf)

            if isinstance(node.exp, ast.Integer):
                src = pack(src, INT)

            return move(src, dest)

        else:
            # Here the right side of the assignment is a complex expression.
            # We will select instructions for it, giving the Symbol
            # representing the variable's location as the destination.
            return selectInstructions(node.exp, cf, dest)

    elif isinstance(node, ast.BasicBlock):
        code = Block()

        for child in node:
            code.append(selectInstructions(child, cf))

        return code

    elif isinstance(node, ast.BinOp):
        code = Block()

        # The left and right operands need to be translated, but the
        # destination is already a Symbol,
        origLeft = left = selectInstructions(node.left, cf)
        origRight = right = selectInstructions(node.right, cf)

        #########
        # Setup #
        #########

        # This code will make sure that both the right and left parameters are
        # in registers.

        # tmpColor0 will be a register, and hold the final result of our
        # computation.  The result may need to be moved if tmpColor0 is not
        # the destination.
        tmpColor0 = getTmpColor(cf, node) if isinstance(dest, Mem) else dest

        # The default tag for a result will be an int.  If it is already
        # tagged, as will be the case for logical instructions or Add, it won't
        # end up being tagged.
        tmpColor0.tag = INT

        # Get the left operand into a register.
        if classGuard(left, Mem, Label):
            if right != dest:
                code.append(move(left, tmpColor0))
                left = tmpColor0

            else:
                tmpColor1 = getTmpColor(
                    cf, node) if tmpColor0 == dest else tmpColor0
                code.append(move(left, tmpColor1))
                left = tmpColor1

        elif isinstance(left, Immediate):
            if isinstance(node, ast.Div):
                # Move our dividend into %eax.
                code.append(move(left, eax))
                left = eax

            elif isinstance(node, ast.Sub):
                tmpColor1 = getTmpColor(
                    cf, node) if right == tmpColor0 else tmpColor0

                # Move the right operand to another register if it is in
                # tmpColor0.
                if right == tmpColor0:
                    code.append(move(right, tmpColor1))
                    right = tmpColor1

                # Move the left hand immediate into the destination register.
                code.append(move(left, tmpColor0))
                left = tmpColor0

            elif right != dest:
                # If the left hand value is an immediate and this is an add
                # or multiply operation the right hand value needs to be in
                # the destination register.
                code.append(move(right, tmpColor0))
                right = tmpColor0

        elif isinstance(left, Register):
            if isinstance(node, ast.Div) and left != eax:
                # Move our dividend into eax.
                code.append(move(left, eax))
                left = eax

            elif left != dest and right != dest:
                code.append(move(left, tmpColor0))
                left = tmpColor0

        # Get the right operand into a register.
        if classGuard(right, Mem, Label):
            if left != tmpColor0 and classGuard(
                    node, ast.Add,
                    ast.Mul) and not isinstance(node, ast.Logical):
                code.append(move(right, tmpColor0))
                left = right
                right = tmpColor0

            else:
                tmpColor1 = getTmpColor(cf, node, tmpColor0)

                code.append(move(right, tmpColor1))
                right = tmpColor1

        elif isinstance(right, Immediate) and isinstance(
                node, ast.Div) and right.value not in shifts:

            # If the right hand side is an immediate it needs to be
            # placed into a register for divide operations.
            tmpColor1 = getTmpColor(cf,
                                    node) if left == tmpColor0 else tmpColor0

            code.append(move(right, tmpColor1))
            right = tmpColor1

        # Untag the left operand if it isn't an immediate.
        if isinstance(left, Color) and classGuard(node, ast.Div, ast.Mul,
                                                  ast.Sub):
            code.append(untag(left))

        # Untag the right operand if it isn't an immediate.
        if isinstance(right, Color) and classGuard(node, ast.Div, ast.Mul,
                                                   ast.Sub):
            code.append(untag(right))

        #############
        # End Setup #
        #############

        if isinstance(node, ast.Add):
            # The right value is never going to be an immediate due to our
            # constant folding transformation.
            if isinstance(left, Immediate):
                #This value hasn't been untagged yet.
                code.append(untag(tmpColor0))

                if left.value == 1:
                    code.append(OneOp('inc', tmpColor0))

                elif left.value == -1:
                    code.append(OneOp('dec', tmpColor0))

                else:
                    code.append(TwoOp('add', left, tmpColor0))

            else:
                # Build the case where we need to call the add function.
                case0 = Block()

                case0.append(untag(left, OBJ))
                case0.append(untag(right, OBJ))

                case0.append(OneOp('push', right))
                case0.append(OneOp('push', left))

                case0.append(OneOp('call', ast.Name('add'), None))
                case0.append(TwoOp('add', Immediate(8), esp))

                case0.append(tag(eax, OBJ))
                case0.append(tag(left, OBJ))
                case0.append(tag(right, OBJ))

                if eax != dest:
                    case0.append(move(eax, tmpColor0))

                # Build the case where we are adding two integers.
                case1 = Block()

                # Untag values as necessary.
                case1.append(untag(left))
                case1.append(untag(right))

                # Decide which operand to add to which.
                if left == tmpColor0:
                    case1.append(TwoOp('add', right, tmpColor0))

                else:
                    case1.append(TwoOp('add', left, tmpColor0))

                # Tag the result of the integer addition.
                case1.append(tag(tmpColor0, INT))

                # Re-tag the operands.
                case1.append(tag(left, INT))
                case1.append(tag(right, INT))

                code.append(
                    buildITE(tmpColor0, case0, case1, TAG_MASK, 'je', True))

        elif isinstance(node, ast.Div):
            if isinstance(right, Immediate) and right.value in shifts:
                # We can shift to the right instead of dividing.
                dist = shifts[right.value]

                code.append(TwoOp('sar', Immediate(dist), eax))

            else:
                # Prepare out %edx.
                code.append(Instruction('cltd'))

                code.append(OneOp('idiv', right))

            if tmpColor0 != eax:
                code.append(move(eax, tmpColor0))

        elif isinstance(node, ast.Mul):
            if isinstance(left, Immediate) and left.value in shifts:
                # We can shift to the left instead of multiplying.
                dist = shifts[left.value]

                code.append(TwoOp('sal', Immediate(dist), tmpColor0))

            elif right == dest or isinstance(left, Immediate):
                code.append(TwoOp('imul', left, tmpColor0))

            else:
                code.append(TwoOp('imul', right, tmpColor0))
                code.append(tag(right, INT))

        elif isinstance(node, ast.Sub):
            if isinstance(right, Immediate) and right.value == 1:
                code.append(OneOp('dec', tmpColor0))

            else:
                code.append(TwoOp('sub', right, tmpColor0))

        elif classGuard(node, ast.And, ast.Or):
            jmp = 'jl' if isinstance(node, ast.And) else 'jg'

            if left == dest:
                case0 = move(right, tmpColor0)
                case1 = None

            else:
                case0 = move(right, tmpColor0)
                case1 = move(left, tmpColor0)

            code.append(buildITE(left, case0, case1, FALS, jmp, True))

        elif classGuard(node, ast.Eq, ast.Ne):
            case0 = Block()

            if isinstance(node, ast.Eq):
                funName = ast.Name('equal')
                jmp = 'jne'

            else:
                funName = ast.Name('not_equal')
                jmp = 'je'

            # Build the case where we need to call the equal function.
            if isinstance(left, Register):
                case0.append(untag(left, OBJ))

            if isinstance(right, Register):
                case0.append(untag(right, OBJ))

            case0.append(OneOp('push', right))
            case0.append(OneOp('push', left))

            case0.append(OneOp('call', funName, None))
            case0.append(TwoOp('add', Immediate(8), esp))

            case0.append(tag(eax, BOOL))

            if isinstance(left, Register) and left != eax:
                case0.append(tag(left))

            if isinstance(right, Register) and right != eax:
                case0.append(tag(right))

            if tmpColor0 != eax:
                case0.append(move(eax, tmpColor0))

            case2 = move(TRU, tmpColor0)
            case3 = move(FALS, tmpColor0)

            # Pack left and right immediates for comparison.
            if isinstance(left, Immediate):
                left = pack(right, INT)

            if isinstance(right, Immediate):
                right = pack(right, INT)

            # Build the case where we are comparing two integers or
            # booleans.
            case1 = buildITE(right, case2, case3, left, jmp)

            code.append(buildITE(tmpColor0, case0, case1, TAG_MASK, 'je',
                                 True))

        elif isinstance(node, ast.Is):
            case0 = move(FALS, tmpColor0)
            case1 = move(TRU, tmpColor0)

            code.append(buildITE(right, case0, case1, left))

        ###########
        # Cleanup #
        ###########

        # Re-tag left, right, and result appropriately.
        code.append(tag(tmpColor0))

        if isinstance(origLeft, Register) and origLeft in toColors(
                node['post-alive']):
            code.append(tag(origLeft))

        if isinstance(origRight, Register) and origRight in toColors(
                node['post-alive']):
            code.append(tag(origRight))

        # Move the result.
        if tmpColor0 != dest:
            code.append(move(tmpColor0, dest))

        ###############
        # End Cleanup #
        ###############

        return code

    elif isinstance(node, ast.Boolean):
        if isinstance(node, ast.Tru):
            return TRU

        elif isinstance(node, ast.Fals):
            return FALS

    elif isinstance(node, ast.Function):
        code = Block()

        # Mark that the arguments are taged.
        #~for color in toColors(node.argSymbols):
        #~color.tagged = True

        code.append(Directive("globl {0}".format(node.name), False))
        code.append(Directive('align 4', False))
        code.append(Label(node.name, ''))

        # Push the old base pointer onto the stack.
        code.append(OneOp('push', ebp))
        # Make the old stack pointer the new base pointer.
        code.append(move(esp, ebp))

        usedColors = toColors(node.collectSymbols())

        # Save any callee saved registers we used.
        saveRegs(code, callee, usedColors)

        # Expand the stack.
        foo = cf.offset - 4
        if foo > 0:
            code.append(TwoOp('sub', Immediate(foo), esp))

        # Append the module's code.
        code.append(selectInstructions(node.block, cf))

        endBlock = Block()
        # Restore the stack.
        if foo > 0:
            endBlock.append(TwoOp('add', Immediate(foo), esp))

        # Restore any callee saved registers we used.
        restoreRegs(endBlock, callee, usedColors)

        # Restore the %esp and %ebp registers.
        endBlock.append(Instruction('leave'))
        # Return
        endBlock.append(Instruction('ret'))

        code.append(endBlock)

        return code

    elif isinstance(node, ast.FunctionCall):
        code = Block()

        # Save any caller saved registers that are in use after this call.
        saveColors = toColors(node['post-alive'])
        saveRegs(code, caller, saveColors)

        addSize = 0
        args = list(node.args)
        args.reverse()
        for arg in args:
            src = selectInstructions(arg, cf)

            # Pack immediates if they haven't been packed yet.
            if isinstance(src, Immediate):
                src = pack(src, INT)

            elif isinstance(src, ast.Name) or (isinstance(src, Label)
                                               and src.reference):
                src = '$' + str(src)

            code.append(OneOp('push', src))
            addSize += 4

        # Clear eax's tagged and tag values.
        eax.clear()

        # Make the function call.
        if isinstance(node.name, ast.Name):
            # This is the direct call case.
            code.append(OneOp('call', node.name, None))

        else:
            # This is the case when we recieved the function pointer as an
            # argument.  This can either result in a direct or an indirect
            # call.
            src = selectInstructions(node.name, cf)

            if isinstance(src, Mem) or src == eax:
                tmpColor = getTmpColor(cf, node)
                code.append(move(src, tmpColor))
                src = tmpColor

            # This is the case where we need to unpack the closure.
            case0 = Block()

            case0.append(OneOp('push', src))
            case0.append(OneOp('call', ast.Name('get_free_vars'), None))

            case0.append(TwoOp('add', Immediate(4), esp))
            case0.append(OneOp('push', eax))
            case0.append(OneOp('push', src))

            case0.append(OneOp('call', ast.Name('get_fun_ptr'), None))
            case0.append(TwoOp('add', Immediate(4), esp))

            case0.append(OneOp('call', '*' + str(eax), None))

            # The case where it is a direct call (made indirectly).
            case1 = OneOp('call', '*' + str(src), None)

            code.append(buildITE(src, case0, case1, TAG_MASK, 'je', True))

        #~name = '*' + str(node.name['color']) if isinstance(node.name, Symbol) else node.name
        #~code.append(OneOp('call', name, None))

        # Restore the stack.
        if addSize > 0:
            code.append(TwoOp('add', Immediate(addSize), esp))

        # Tag the result if necessary.
        code.append(tag(eax, node.tag))

        # Move the result into the proper destination.
        if dest and dest != eax:
            code.append(move(eax, dest))

        # Restore any caller saved registers that are in use.
        restoreRegs(code, caller, saveColors)

        return code

    elif isinstance(node, ast.If):
        cond = selectInstructions(node.cond, cf)
        then = selectInstructions(node.then, cf)
        els = selectInstructions(node.els, cf)

        thenSyms = node.then.collectSymbols('r')
        elseSyms = node.els.collectSymbols('r')

        # Insert Phi moves.
        for phi in node.jn:
            for sym in phi.srcs:
                if sym['color'] != phi.target['color']:
                    (then if sym in thenSyms else els).append(
                        move(sym['color'], phi.target['color']))

        # Here we compare the conditional to False, and if it is less then or
        # equal to False (either False or 0) we will go to the else case.
        return buildITE(cond, then, els, FALS, 'jle')

    elif isinstance(node, ast.Integer):
        return Immediate(node.value)

    elif isinstance(node, ast.Module):
        code = Block("# x86\n")

        data = Block("# Data\n")
        funs = Block("\n# Functions\n")

        # Define our data section.
        for sym in node.collectSymbols():
            if sym['heapify'] and sym not in node.strings.values():
                data.append(Directive("globl {0}".format(sym['color']), False))
                data.append(Directive('data'))
                data.append(Directive('align 4'))
                data.append(Directive("size {0}, 4".format(sym['color'])))

                data.append(sym['color'])
                data.append(Directive('long 1'))
                data.append(Directive('section .data'))

        # Add any strings we may need to define.
        for string in node.strings:
            sym = node.strings[string]

            data.append(sym['color'])
            data.append(Directive("string \"{0}\"".format(string)))
            data.append(Directive('text'))

        # Define our functions.
        for fun in node.functions:
            funs.append(selectInstructions(fun, cf))

        # Concatenate our code.
        code.append(data)
        code.append(funs)

        return code

    elif isinstance(node, ast.Name):
        return node

    elif isinstance(node, ast.Return):
        code = Block()

        src = selectInstructions(node.value, cf)
        # Pack immediates if they haven't been packed yet.
        if isinstance(src, Immediate):
            src = pack(src, INT)

        elif isinstance(src, ast.Name):
            src = '$' + str(src)

        if src != eax:
            code.append(move(src, eax))

        return code

    elif isinstance(node, ast.String):
        return node['color']

    elif isinstance(node, ast.Symbol):
        if node.has_key('color'):
            return node['color']
        else:
            raise Exception("Uncolored symbol ({0}) encountered.".format(node))

    elif isinstance(node, ast.UnaryOp):
        code = Block()

        src = selectInstructions(node.operand, cf)

        #########
        # Setup #
        #########

        tmpColor = getTmpColor(cf, node) if isinstance(dest, Mem) else dest

        if src != tmpColor:
            code.append(move(src, tmpColor))

        # Untag the argument.
        code.append(untag(tmpColor))

        #############
        # End Setup #
        #############

        if isinstance(node, ast.Negate):
            code.append(OneOp('neg', tmpColor))

            # Tell the cleanup code to tag the result as an integer.
            tmpColor.tagged = False
            tmpColor.tag = INT

        elif isinstance(node, ast.Not):
            case0 = move(FALS, tmpColor)
            case1 = move(TRU, tmpColor)

            code.append(buildITE(src, case0, case1, FALS, 'jle'))

        ###########
        # Cleanup #
        ###########

        # Tag the result.
        code.append(tag(tmpColor))

        if tmpColor != dest:
            code.append(move(tmpColor, dest))

        ###############
        # End Cleanup #
        ###############

        return code

    elif isinstance(node, ast.While):
        code = Block()

        cond = selectInstructions(node.cond, cf)
        condBody = selectInstructions(node.condBody, cf)
        body = selectInstructions(node.body, cf)

        # Insert Phi moves.
        for phi in node.jn.phis:
            for src in phi:
                if src['color'] != phi.target['color']:
                    (code if src in node['pre-alive'] else body).append(
                        move(src['color'], phi.target['color']))

        l0 = getLabel()
        l1 = getLabel()

        # Initial jump to the cond block.
        code.append(OneOp('jmp', l1, None))

        # The body label and the body.
        code.append(l0)
        code.append(body)

        # Cond label and cond body.
        code.append(l1)
        code.append(condBody)

        # Test to see if we should loop.
        code.append(TwoOp('cmp', FALS, cond))
        code.append(OneOp('jg', l0, None))

        return code
예제 #19
0
 def append(self, inst):
     if (isinstance(inst, Block) and len(inst.insts) > 0) or classGuard(
             inst, Directive, Instruction, Label):
         self.insts.append(inst)