initial versions of new two complement code
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Tue, 18 Sep 2007 06:38:16 +0000 (06:38 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Tue, 18 Sep 2007 06:38:16 +0000 (06:38 +0000)
[r15853]

ir/tv/tc_calc.c [new file with mode: 0644]
ir/tv/tc_calc.h [new file with mode: 0644]

diff --git a/ir/tv/tc_calc.c b/ir/tv/tc_calc.c
new file mode 100644 (file)
index 0000000..a4b20be
--- /dev/null
@@ -0,0 +1,249 @@
+#include "irnode.h"
+#include "tc_calc.h"
+
+/* shift bits with sign extension */
+#define SHRS(v, c)     ((v) < 0 ? ~((~(v)) >> (c)) : (v) >> (c))
+
+#define SIGN(v) ((v)->part[0] & TC_VALUE_PART_SIGN_BIT)
+
+/* the carry and overflow bits */
+int tc_Carry, tc_Overflow;
+
+/**
+ * Produce a tc_value from a long value
+ */
+void tc_from_long(tc_value *tcv, long value) {
+       int i;
+
+       for (i = NUM_VALUE_PARTS - 1; i >= 0; --i) {
+               long part = value & TC_VALUE_PART_MASK;
+               tcv->part[i] = (tc_value_part)part;
+               value = SHRS(value, TC_VALUE_PART_SIZE);
+       }
+}
+
+/**
+ * Bit complement an tc_value: res = ~a.
+ */
+void tc_not(const tc_value *a, tc_value *res) {
+       int     i;
+
+       for (i = NUM_VALUE_PARTS - 1; i >= 0; --i)
+               res->part[i] = ~a->part[i] & TC_VALUE_PART_MAX_UINT;
+}
+
+/**
+ * Logical AND of two tc_values: res = a & b.
+ */
+void tc_and(const tc_value *a, const tc_value *b, tc_value *res) {
+       int     i;
+
+       for (i = NUM_VALUE_PARTS - 1; i >= 0; --i)
+               res->part[i] = a->part[i] & b->part[i];
+}
+
+/**
+ * Logical OR of two tc_values: res = a | b.
+ */
+void tc_or(const tc_value *a, const tc_value *b, tc_value *res) {
+       int     i;
+
+       for (i = NUM_VALUE_PARTS - 1; i >= 0; --i)
+               res->part[i] = a->part[i] | b->part[i];
+}
+
+/**
+ * Logical exclusive OR of two tc_values: res = a ^ b.
+ */
+void tc_eor(const tc_value *a, const tc_value *b, tc_value *res) {
+       int     i;
+
+       for (i = NUM_VALUE_PARTS - 1; i >= 0; --i)
+               res->part[i] = a->part[i] ^ b->part[i];
+}
+
+
+/**
+ * Compare two tc_value's.
+ */
+pn_Cmp tc_cmp(const tc_value *a, const tc_value *b) {
+       int i;
+
+       for (i = 0; i < NUM_VALUE_PARTS; ++i) {
+               if (a->part[i] > b->part[i])
+                       return pn_Cmp_Gt;
+               if (a->part[i] < b->part[i])
+                       return pn_Cmp_Lt;
+       }
+       return pn_Cmp_Eq;
+}
+
+/**
+ * Add two tc_values: res = a + b. Sets carry and overflow.
+ */
+void tc_add(const tc_value *a, const tc_value *b, tc_value *res) {
+       int     i, carry = 0, sign_a;
+
+       tc_Carry = tc_Overflow = 0;
+
+       for (i = NUM_VALUE_PARTS - 1; i >= 0; --i) {
+               tc_temp t = (tc_temp)a->part[i] + (tc_temp)b->part[i] + carry;
+               if (t > TC_VALUE_PART_MAX_UINT) {
+                       t -= TC_VALUE_PART_MAX_UINT;
+                       carry = 1;
+               } else
+                       carry = 0;
+               res->part[i] = (tc_value_part)t;
+       }
+       /* Check for overflow. */
+       tc_Carry = carry;
+
+       /* A signed overflow occurred if the two operands have the same sign and
+       the result has a different sign. */
+       sign_a = SIGN(a);
+    tc_Overflow = (sign_a == SIGN(b)) && (sign_a != SIGN(res));
+}
+
+/**
+ * Subtract two tc_values: res = a - b. Sets carry and overflow.
+ */
+void tc_sub(const tc_value *a, const tc_value *b, tc_value *res) {
+       int         i, sign_a;
+       tc_temp borrow = 0;
+
+       tc_Carry = tc_Overflow = 0;
+       for (i = NUM_VALUE_PARTS - 1; i >= 0; --i) {
+               tc_temp t;
+               t = (tc_temp)a->part[i] - (tc_temp)b->part[i] - borrow;
+               if (t < 0) {
+                       t += TC_VALUE_PART_MAX_UINT + 1;
+                       borrow = 1;
+               } else
+                       borrow = 0;
+               res->part[i] = (tc_value_part)t;
+       }
+       /* Check for underflow or overflow. */
+       tc_Carry = borrow;
+       /* A signed overflow occurred if the two operands have the same sign and
+       the result has a different sign. */
+       sign_a = SIGN(a);
+    tc_Overflow = (sign_a == SIGN(b)) && (sign_a != SIGN(res));
+}
+
+/**
+ * Negate an tc_value: res = -a. Sets carry and overflow.
+ */
+void tc_neg(const tc_value *a, tc_value *res) {
+       tc_from_long(res, 0);
+       tc_sub(res, a, res);
+}
+
+#define NUM_WORK_PARTS (NUM_VALUE_PARTS * 2)
+
+/**
+ * Multiply two unsigned tc_values producing a double precision result : w = a * b.
+ */
+static void _tc_umul(const tc_value *a, const tc_value *b, unsigned tc_value_part *w) {
+       unsigned tc_value_part *u = &a->part;
+       unsigned tc_value_part *v = &b->part;
+
+       int i, j;
+
+       for (i = 0; i < NUM_WORK_PARTS; ++i)
+               w[i] = 0;
+
+       for (j = NUM_VALUE_PARTS - 1; j >= 0; --j) {
+               unsigned tc_temp k = 0;
+               for (i = NUM_VALUE_PARTS - 1; i >= 0; --i) {
+                       tc_temp t = u[i] * v[j] + k;
+                       w[i + j] = t & TC_VALUE_PART_MASK;
+                       k = t >> 16;
+               }
+               w[j + NUM_VALUE_PARTS] = k & TC_VALUE_PART_MASK;
+       }
+}
+
+/**
+ * Multiply two unsigned tc_values: res = a * b.
+ */
+static void tc_umul(const tc_value *a, const tc_value *b, tc_value *res) {
+       unsigned tc_value_part w[NUM_WORK_PARTS];
+       int i, ov = 0;
+
+       _tc_umul(a, b, w);
+
+       /* copy the lower result bits */
+       for (i = 0; i < NUM_VALUE_PARTS; ++i)
+               res->part[i] = (tc_value_part)w[i];
+
+       /* check for overflow */
+       for (; i < NUM_WORK_PARTS; ++i) {
+               if (w[i] != 0) {
+                       ov = 0;
+                       break;
+               }
+       }
+       tc_Overflow = tc_Carry = ov;
+}
+
+/**
+ * Multiply two unsigned tc_values: res = a * b.
+ */
+static void tc_umul(const tc_value *a, const tc_value *b, tc_value *res) {
+       unsigned tc_value_part w[NUM_WORK_PARTS];
+       int i, ov = 0;
+
+       _tc_umul(a, b, w);
+
+       /* copy the lower result bits */
+       for (i = 0; i < NUM_VALUE_PARTS; ++i)
+               res->part[i] = (tc_value_part)w[i];
+
+       /* check for overflow */
+       for (; i < NUM_WORK_PARTS; ++i) {
+               if (w[i] != 0) {
+                       ov = 0;
+                       break;
+               }
+       }
+       tc_Overflow = tc_Carry = ov;
+}
+/**
+ * Multiply two signed tc_values: res = a * b.
+ */
+static void tc_smul(const tc_value *a, const tc_value *b, tc_value *res) {
+       unsigned tc_value_part w[NUM_WORK_PARTS];
+       int i, ov = 0, neg_res = 0;
+       const tc_value *u = a, *v = b;
+       tc_value na, nb;
+
+       if (SIGN(a)) {
+               tc_neg(a, na);
+               u = na;
+               neg_res = ~neg_res;
+       }
+       if (SIGN(b)) {
+               tc_neg(b, nb);
+               v = nb;
+               neg_res = ~neg_res;
+       }
+
+       _tc_umul(u, v, w);
+
+       /* copy the lower result bits */
+       for (i = 0; i < NUM_VALUE_PARTS; ++i)
+               res->part[i] = (tc_value_part)w[i];
+
+       /* check for overflow */
+       for (; i < NUM_WORK_PARTS; ++i) {
+               if (w[i] != 0) {
+                       ov = 0;
+                       break;
+               }
+       }
+
+       if (neg_res)
+               tc_neg(res, res);
+
+       tc_Overflow = tc_Carry = ov;
+}
diff --git a/ir/tv/tc_calc.h b/ir/tv/tc_calc.h
new file mode 100644 (file)
index 0000000..1a750a7
--- /dev/null
@@ -0,0 +1,33 @@
+
+/** Should be at least 16 bit. */
+typedef unsigned short tc_value_part;
+
+/** Should be at least 32 bit */
+typedef long tc_temp;
+
+/**
+ * We need 64 + 2 bit for floating point support
+ */
+#define TC_VALUE_SIZE          80
+#define TC_VALUE_PART_SIZE     16
+#define TC_VALUE_PART_MASK     0xFFFF
+#define TC_VALUE_PART_MAX_UINT 0xFFFF
+#define TC_VALUE_PART_SIGN_BIT 0x8000
+
+#define NUM_VALUE_PARTS     (TC_VALUE_SIZE / TC_VALUE_PART_SIZE)
+
+/**
+ * A two complement value. Note that the parts are store in BIG-Endian.
+ * this makes most loops counting towards zero and allows simple access
+ * to the sign bit.
+ */
+typedef struct tc_value {
+       tc_value_part part[NUM_VALUE_PARTS];
+} tc_value;
+
+
+/**
+ * Every operation produces two bits. Carry and Overflow.
+ * Carry means unsigned overflow, Overflow means signed overflow.
+ */
+extern int tc_Carry, tc_Overflow;