From 9e797458dd8d144544564674a8767c077ed4bd39 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Wed, 30 Nov 2011 23:18:10 +0000 Subject: Support for all assignment except shifting, fix rightshift bug --- pp2cc.py | 56 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 17 deletions(-) (limited to 'pp2cc.py') diff --git a/pp2cc.py b/pp2cc.py index 6e6e614..6217f41 100755 --- a/pp2cc.py +++ b/pp2cc.py @@ -441,7 +441,7 @@ class Parse(object): # word size in bits self.WORDSIZE = 18 # preload operators and their instructions - self.binary_ops = { + self.math_ops = { "+": "ADD", "-": "SUB", "*": "MULS", @@ -459,6 +459,7 @@ class Parse(object): "==": "BEQ", "!=": "BNE" } + self.binary_ops = self.math_ops self.binary_ops.update(self.comparison_ops) # local and global variable names to be defined in @DATA @@ -718,21 +719,27 @@ class Parse(object): else: # because DIV works with signed numbers, right shift is # a bit harder because the sign bit does not vanish - lbl_make_positive = self.uniqLbl("shiftPositive") - lines.append(self.asm.binary_op("CMP", reg_first, 0)) - # if it's positive, skip handling for negative values - lines.append(self.asm.branch_op("BPL", lbl_make_positive)) - # -1 / 2 = 0, so make sure that the last bit is zero + # Assume 4-bit numbers in the next example. + # binary | decimal + # 1111 | -1 + # 0111 | 7 + # The rightmost bit is insignificant in a right shift + # but causes issues with division by two for -1 because + # it gets rounded to 0. After removal of the rightmost + # bit and division by two, all bits are shifted left, + # but the result is still negative. Since we're doing a + # zero-padded shift (unsigned), clear the leftmost bit + # For positive numbers, this has no side effects lines.append(self.asm.binary_op("AND", reg_first, "%10")) - # shift it by one - lines.append(self.asm.binary_op("DIV", reg_first, 1)) - # make it positive if not already + # shift it by one to the right + lines.append(self.asm.binary_op("DIV", reg_first, 2)) + # clear the leftmost bit by masking it with 011..11 mask = "%0" + (self.WORDSIZE - 1) * "1" - lines.append(self.asm.binary_op("AND", reg_first, mask, - label=lbl_make_positive)) + lines.append(self.asm.binary_op("AND", reg_first, mask)) # decrease shift count and finish if nothing to shift operand /= 2 if operand > 1: + # process the remaining shift lines.append(self.asm.binary_op("DIV", reg_first, operand)) else: lbl_gen = self.uniqLbl("gen2_loop") @@ -747,14 +754,12 @@ class Parse(object): if op == "<<": lines.append(self.asm.binary_op("MULS", reg_first, 2, label=lbl_gen)) else: - # now first check if the first number is negative... - lines.append(self.asm.binary_op("CMP", reg_first, 0)) - lines.append(self.asm.branch_op("BPL", lbl_gen)) - # shift it by one - lines.append(self.asm.binary_op("DIV", reg_first, 1)) - # make negative values positive + # see above big block of comments for explanation + lines.append(self.asm.binary_op("AND", reg_first, "%10")) + lines.append(self.asm.binary_op("DIV", reg_first, 2)) mask = "%0" + (self.WORDSIZE - 1) * "1" lines.append(self.asm.binary_op("AND", reg_first, mask)) + # decrease shift count and finish if shift count is zero lines.append(self.asm.binary_op("SUB", reg_second, 1)) lines.append(self.asm.branch_op("BEQ", lbl_gen_end)) @@ -1162,6 +1167,23 @@ class Parse(object): if node.op == "=": lines.append(self.asm.binary_op("STOR", result_reg, "[" + lvalue_reg + "]")) + elif (len(node.op) == 2 and node.op[1] == "=" and + node.op[0] in self.math_ops): + binop = self.math_ops[node.op[0]] + # abuse lvalue_reg to save a register by storing the value of the + # lvalue. This should allow for doing x / y first before assigning + # (writing) to y + lines.append(self.asm.push(lvalue_reg)) + # get the value of lvalue, e.g. the value of x + lines.append(self.asm.binary_op("LOAD", lvalue_reg, "["+lvalue_reg+"]")) + # perform the operation on the value + lines.append(self.asm.binary_op(binop, lvalue_reg, result_reg)) + # since lvalue_reg is now the integer result, use result_reg as the + # register for holding the address of y + lines.append(self.asm.pull(result_reg)) + # finally store the result from lvalue_reg into result_reg + lines.append(self.asm.binary_op("STOR", lvalue_reg, + "[" + result_reg + "]")) else: raise RuntimeError("Unsupported assignment operator: " + node.op) return lines -- cgit v1.2.1