summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <lekensteyn@gmail.com>2011-11-28 19:17:30 +0000
committerPeter Wu <lekensteyn@gmail.com>2011-11-28 19:17:30 +0000
commit83d005c9c6937236523ae15eaef792c8ef3dae06 (patch)
tree6b158ced67556fe1947032cf720800184adb386a
parent0086c2a0a421df52be49817293fcdab0221e010f (diff)
downloadpp2cc-83d005c9c6937236523ae15eaef792c8ef3dae06.tar.gz
Fix shifting and document is better
Left shift was interpreted as right and left shift did not work properly for negative values
-rw-r--r--README5
-rwxr-xr-xpp2cc.py41
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