From: Michael Beck Date: Tue, 18 Sep 2007 06:38:16 +0000 (+0000) Subject: initial versions of new two complement code X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=f1de6761de7948ab64ee3bdcea6fb4223fb57738;p=libfirm initial versions of new two complement code [r15853] --- diff --git a/ir/tv/tc_calc.c b/ir/tv/tc_calc.c new file mode 100644 index 000000000..a4b20be2a --- /dev/null +++ b/ir/tv/tc_calc.c @@ -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 index 000000000..1a750a729 --- /dev/null +++ b/ir/tv/tc_calc.h @@ -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;