Commit f1de6761 authored by Michael Beck's avatar Michael Beck
Browse files

initial versions of new two complement code

[r15853]
parent afb61d4e
#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;
}
/** 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;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment