From 83d005c9c6937236523ae15eaef792c8ef3dae06 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Mon, 28 Nov 2011 19:17:30 +0000 Subject: Fix shifting and document is better Left shift was interpreted as right and left shift did not work properly for negative values --- README | 5 ++++- pp2cc.py | 41 +++++++++++++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/README b/README index fe2a379..db9c929 100644 --- a/README +++ b/README @@ -54,7 +54,10 @@ function calls - supported, result is stored in register R0 (for int functions) A7.4 Unary Operators - supported: ++ -- + - ~ ! Unsupported: sizeof & * A7.5 Casts - unsupported A7.6-A7.7, A7.9-7.13 - supported: * / % + - < > <= >= == != & ^ | Left to right -A7.8 Shift - << >> is supported, if negative, no shift will be performed +A7.8 Shift - << >> is supported, if the second operand is negative, no shift +will be performed. The shift treats the first operand as an unsigned integer. +Example in bits assuming 4-bit words: 1000 (-8) >> 2 becomes 0010 (2), 0110 (6) +<< 1 becomes 1100 (-4) A7.14-A7.15 Logical AND && and OR || are supported. Result is indeed 0 or 1 A7.16 Conditional operator ? : - supported A7.17 Assignment - supported: = Unsupported: *= /= %= += -= <<= >>= &= ^= |= diff --git a/pp2cc.py b/pp2cc.py index 97e091d..a13be6f 100755 --- a/pp2cc.py +++ b/pp2cc.py @@ -531,10 +531,6 @@ class Parse(object): lines.append(self.asm.binary_op("LOAD", reg_first, 1, label=bin_true)) lines.append(self.asm.noop(bin_end, register=reg_first)) elif op in ("<<", ">>"): - op = { - "<<": "MULS", - ">>": "DIV" - }[op] if isinstance(node.right, c_ast.Constant): shift_bits = self.convertStrToInteger(operand) if shift_bits < 0: @@ -546,7 +542,25 @@ class Parse(object): # shifting only makes a difference if shifting a number # larger than 0 (e.g. 1 << 1) operand = pow(2, shift_bits) - lines.append(self.asm.binary_op(op, reg_first, operand)) + if op == "<<": + lines.append(self.asm.binary_op("MULS", reg_first, operand)) + 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)) + # shift it by one + lines.append(self.asm.binary_op("DIV", reg_first, 1)) + # make it positive if not already + mask = "%0" + (self.WORDSIZE - 1) * "1" + lines.append(self.asm.binary_op("AND", reg_first, mask, + label=lbl_make_positive)) + # decrease shift count and finish if nothing to shift + operand /= 2 + if operand > 1: + lines.append(self.asm.binary_op("DIV", reg_first, operand)) else: lbl_gen = self.uniqLbl("gen2_loop") lbl_gen_end = self.uniqLbl("gen2_done") @@ -557,7 +571,22 @@ class Parse(object): # 1 and jump to the end lines.append(self.asm.branch_op("BLE", lbl_gen_end)) - lines.append(self.asm.binary_op(op, reg_first, 2, label=lbl_gen)) + 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 + 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)) + # continue regular shifting + lines.append(self.asm.binary_op("DIV", reg_first, 2, label=lbl_gen)) lines.append(self.asm.binary_op("SUB", reg_second, 1)) # if we came from BLE, x <= 0. BGT only jumps if x > 0, so # we can safe another NOOP by adding the label here -- cgit v1.2.1