MWCC/compiler_and_linker/unsorted/CInt64.c

892 lines
20 KiB
C

#include "compiler/CInt64.h"
const CInt64 cint64_negone = {0xFFFFFFFF, 0xFFFFFFFF};
const CInt64 cint64_zero = {0, 0};
const CInt64 cint64_one = {0, 1};
const CInt64 cint64_max = {0x7FFFFFFF, 0xFFFFFFFF};
const CInt64 cint64_min = {0x80000000, 0};
#define SHIFT_LEFT_ONE(a, b) do { a <<= 1; if (b & 0x80000000) { a |= 1; } b <<= 1; } while(0)
void CInt64_Init(void) {
}
CInt64 CInt64_Not(CInt64 input) {
CInt64 output;
Boolean c;
c = (input.hi == 0 && input.lo == 0);
CInt64_SetLong(&output, c);
return output;
}
CInt64 CInt64_Inv(CInt64 input) {
CInt64 output;
output.hi = ~input.hi;
output.lo = ~input.lo;
return output;
}
CInt64 CInt64_Add(CInt64 lhs, CInt64 rhs) {
if (lhs.lo & 0x80000000) {
if (rhs.lo & 0x80000000) {
lhs.lo += rhs.lo;
lhs.hi += 1;
} else {
lhs.lo += rhs.lo;
if (!(lhs.lo & 0x80000000))
lhs.hi += 1;
}
} else {
if (rhs.lo & 0x80000000) {
lhs.lo += rhs.lo;
if (!(lhs.lo & 0x80000000))
lhs.hi += 1;
} else {
lhs.lo += rhs.lo;
}
}
lhs.hi += rhs.hi;
return lhs;
}
CInt64 CInt64_Neg(CInt64 input) {
CInt64 result;
result = CInt64_Add(CInt64_Inv(input), cint64_one);
return result;
}
CInt64 CInt64_Sub(CInt64 lhs, CInt64 rhs) {
lhs = CInt64_Add(lhs, CInt64_Neg(rhs));
return lhs;
}
CInt64 CInt64_MulU(CInt64 lhs, CInt64 rhs) {
CInt64 result;
CInt64 work1;
UInt32 aaaa;
UInt32 bbbb;
UInt32 cccc;
UInt32 dddd;
UInt32 eeee;
aaaa = rhs.lo;
result.hi = result.lo = 0;
bbbb = lhs.lo;
cccc = rhs.hi;
for (dddd = aaaa; bbbb != 0; dddd <<= 1, bbbb >>= 1) {
if (bbbb & 1) {
work1.hi = cccc;
work1.lo = dddd;
result = CInt64_Add(result, work1);
}
cccc <<= 1;
if (dddd & 0x80000000)
cccc |= 1;
}
eeee = lhs.hi;
while (eeee != 0 && aaaa != 0) {
if (eeee & 1)
result.hi += aaaa;
aaaa <<= 1;
eeee >>= 1;
}
return result;
}
CInt64 CInt64_Mul(CInt64 lhs, CInt64 rhs) {
if (CInt64_IsNegative(&rhs)) {
if (CInt64_IsNegative(&lhs)) {
return CInt64_MulU(CInt64_Neg(lhs), CInt64_Neg(rhs));
}
return CInt64_Neg(CInt64_MulU(lhs, CInt64_Neg(rhs)));
}
if (CInt64_IsNegative(&lhs)) {
return CInt64_Neg(CInt64_MulU(CInt64_Neg(lhs), rhs));
}
return CInt64_MulU(lhs, rhs);
}
void CInt64_DivMod(const CInt64 *lhs, const CInt64 *rhs, CInt64 *pDiv, CInt64 *pMod) {
Boolean bad;
UInt32 workA;
UInt32 workB;
UInt32 leftA;
UInt32 leftB;
UInt32 rightA;
UInt32 rightB;
UInt32 outA;
UInt32 outB;
CInt64 work;
int counter;
bad = (rhs->hi == 0) && (rhs->lo == 0);
if (!bad) {
workA = 0;
workB = 0;
leftA = lhs->hi;
leftB = lhs->lo;
rightA = rhs->hi;
rightB = rhs->lo;
outA = 0;
outB = 0;
counter = 0;
do {
workA <<= 1;
if (workB & 0x80000000)
workA |= 1;
workB <<= 1;
if (leftA & 0x80000000)
workB |= 1;
leftA <<= 1;
if (leftB & 0x80000000)
leftA |= 1;
leftB <<= 1;
outA <<= 1;
if (outB & 0x80000000)
outA |= 1;
outB <<= 1;
if (workA <= rightA) {
if (workA != rightA)
continue;
if (workB < rightB)
continue;
}
outB |= 1;
work.hi = workA;
work.lo = workB;
work = CInt64_Sub(work, *rhs);
workA = work.hi;
workB = work.lo;
} while (++counter < 64);
if (pDiv) {
pDiv->hi = outA;
pDiv->lo = outB;
}
if (pMod) {
pMod->hi = workA;
pMod->lo = workB;
}
}
}
CInt64 CInt64_Div(CInt64 lhs, CInt64 rhs) {
CInt64 result;
if (CInt64_IsNegative(&rhs)) {
rhs = CInt64_Neg(rhs);
if (CInt64_IsNegative(&lhs)) {
lhs = CInt64_Neg(lhs);
CInt64_DivMod(&lhs, &rhs, &result, 0);
return result;
} else {
CInt64_DivMod(&lhs, &rhs, &result, 0);
return CInt64_Neg(result);
}
} else {
if (CInt64_IsNegative(&lhs)) {
lhs = CInt64_Neg(lhs);
CInt64_DivMod(&lhs, &rhs, &result, 0);
return CInt64_Neg(result);
} else {
CInt64_DivMod(&lhs, &rhs, &result, 0);
return result;
}
}
}
CInt64 CInt64_DivU(CInt64 lhs, CInt64 rhs) {
CInt64 result;
CInt64_DivMod(&lhs, &rhs, &result, 0);
return result;
}
CInt64 CInt64_Mod(CInt64 lhs, CInt64 rhs) {
CInt64 result;
if (CInt64_IsNegative(&lhs)) {
lhs = CInt64_Neg(lhs);
if (CInt64_IsNegative(&rhs))
rhs = CInt64_Neg(rhs);
CInt64_DivMod(&lhs, &rhs, 0, &result);
return CInt64_Neg(result);
} else {
if (CInt64_IsNegative(&rhs))
rhs = CInt64_Neg(rhs);
CInt64_DivMod(&lhs, &rhs, 0, &result);
return result;
}
}
CInt64 CInt64_ModU(CInt64 lhs, CInt64 rhs) {
CInt64 result;
CInt64_DivMod(&lhs, &rhs, 0, &result);
return result;
}
CInt64 CInt64_Shl(CInt64 lhs, CInt64 rhs) {
int counter;
UInt32 a;
UInt32 b;
if (rhs.hi == 0 && rhs.lo < 64) {
a = lhs.hi;
b = lhs.lo;
for (counter = rhs.lo; counter != 0; --counter) {
a <<= 1;
if (b & 0x80000000)
a |= 1;
b <<= 1;
}
lhs.hi = a;
lhs.lo = b;
} else {
lhs.hi = 0;
lhs.lo = 0;
}
return lhs;
}
CInt64 CInt64_Shr(CInt64 lhs, CInt64 rhs) {
int counter;
SInt32 a;
UInt32 b;
if (rhs.hi == 0 && rhs.lo < 64) {
a = lhs.hi;
b = lhs.lo;
for (counter = rhs.lo; counter != 0; --counter) {
b >>= 1;
if (a & 1)
b |= 0x80000000;
a >>= 1;
}
lhs.hi = a;
lhs.lo = b;
} else {
if (lhs.hi & 0x80000000) {
lhs.hi = 0xFFFFFFFF;
lhs.lo = 0xFFFFFFFF;
} else {
lhs.hi = 0;
lhs.lo = 0;
}
}
return lhs;
}
CInt64 CInt64_ShrU(CInt64 lhs, CInt64 rhs) {
int counter;
UInt32 a;
UInt32 b;
if (rhs.hi == 0 && rhs.lo < 64) {
a = lhs.hi;
b = lhs.lo;
for (counter = rhs.lo; counter != 0; --counter) {
b >>= 1;
if (a & 1)
b |= 0x80000000;
a >>= 1;
}
lhs.hi = a;
lhs.lo = b;
} else {
lhs.hi = 0;
lhs.lo = 0;
}
return lhs;
}
int CInt64_UnsignedCompare(const CInt64 *lhs, const CInt64 *rhs) {
if (lhs->hi == rhs->hi) {
if (lhs->lo < rhs->lo)
return -1;
else
return lhs->lo > rhs->lo;
} else {
return ((UInt32) lhs->hi < rhs->hi) ? -1 : 1;
}
}
int CInt64_SignedCompare(const CInt64 *lhs, const CInt64 *rhs) {
CInt64 lhs_;
CInt64 rhs_;
lhs_ = CInt64_Xor(*lhs, cint64_min);
rhs_ = CInt64_Xor(*rhs, cint64_min);
return CInt64_UnsignedCompare(&lhs_, &rhs_);
}
Boolean CInt64_Less(CInt64 lhs, CInt64 rhs) {
return CInt64_SignedCompare(&lhs, &rhs) < 0;
}
Boolean CInt64_LessU(CInt64 lhs, CInt64 rhs) {
return CInt64_UnsignedCompare(&lhs, &rhs) < 0;
}
Boolean CInt64_Greater(CInt64 lhs, CInt64 rhs) {
return CInt64_SignedCompare(&lhs, &rhs) > 0;
}
Boolean CInt64_GreaterU(CInt64 lhs, CInt64 rhs) {
return CInt64_UnsignedCompare(&lhs, &rhs) > 0;
}
Boolean CInt64_LessEqual(CInt64 lhs, CInt64 rhs) {
return CInt64_SignedCompare(&lhs, &rhs) <= 0;
}
Boolean CInt64_LessEqualU(CInt64 lhs, CInt64 rhs) {
return CInt64_UnsignedCompare(&lhs, &rhs) <= 0;
}
Boolean CInt64_GreaterEqual(CInt64 lhs, CInt64 rhs) {
return CInt64_SignedCompare(&lhs, &rhs) >= 0;
}
Boolean CInt64_GreaterEqualU(CInt64 lhs, CInt64 rhs) {
return CInt64_UnsignedCompare(&lhs, &rhs) >= 0;
}
Boolean CInt64_Equal(CInt64 lhs, CInt64 rhs) {
return lhs.hi == rhs.hi && lhs.lo == rhs.lo;
}
Boolean CInt64_NotEqual(CInt64 lhs, CInt64 rhs) {
return lhs.hi != rhs.hi || lhs.lo != rhs.lo;
}
Boolean CInt64_IsInRange(CInt64 value, short len) {
CInt64 bound;
if (value.hi & 0x80000000) {
switch (len) {
case 1:
bound.lo = 0xFFFFFF80;
bound.hi = 0xFFFFFFFF;
break;
case 2:
bound.lo = 0xFFFF8000;
bound.hi = 0xFFFFFFFF;
break;
case 4:
bound.lo = 0x80000000;
bound.hi = 0xFFFFFFFF;
break;
case 8:
return 1;
default:
return 0;
}
return CInt64_GreaterEqual(value, bound);
} else {
switch (len) {
case 1:
bound.lo = 0x7F;
bound.hi = 0;
break;
case 2:
bound.lo = 0x7FFF;
bound.hi = 0;
break;
case 4:
bound.lo = 0x7FFFFFFF;
bound.hi = 0;
break;
case 8:
return 1;
default:
return 0;
}
return CInt64_LessEqual(value, bound);
}
}
Boolean CInt64_IsInURange(CInt64 value, short len) {
switch (len) {
case 1:
return value.hi == 0 && (value.lo & 0xFFFFFF00) == 0;
case 2:
return value.hi == 0 && (value.lo & 0xFFFF0000) == 0;
case 4:
return value.hi == 0;
case 8:
return 1;
default:
return 0;
}
}
CInt64 CInt64_And(CInt64 lhs, CInt64 rhs) {
lhs.hi &= rhs.hi;
lhs.lo &= rhs.lo;
return lhs;
}
CInt64 CInt64_Xor(CInt64 lhs, CInt64 rhs) {
lhs.hi ^= rhs.hi;
lhs.lo ^= rhs.lo;
return lhs;
}
CInt64 CInt64_Or(CInt64 lhs, CInt64 rhs) {
lhs.hi |= rhs.hi;
lhs.lo |= rhs.lo;
return lhs;
}
void CInt64_ConvertInt32(CInt64 *i) {
i->hi = (i->lo & 0x80000000) ? 0xFFFFFFFF : 0;
}
void CInt64_ConvertUInt32(CInt64 *i) {
i->hi = 0;
}
void CInt64_ConvertInt16(CInt64 *i) {
i->lo = (SInt16) i->lo;
i->hi = (i->lo & 0x80000000) ? 0xFFFFFFFF : 0;
}
void CInt64_ConvertUInt16(CInt64 *i) {
i->lo = (UInt16) i->lo;
i->hi = 0;
}
void CInt64_ConvertInt8(CInt64 *i) {
i->lo = (SInt8) i->lo;
i->hi = (i->lo & 0x80000000) ? 0xFFFFFFFF : 0;
}
void CInt64_ConvertUInt8(CInt64 *i) {
i->lo = (UInt8) i->lo;
i->hi = 0;
}
void CInt64_ConvertUFromLongDouble(CInt64 *pResult, double value) {
union { float f; UInt32 l; } cvt;
UInt32 a, b;
float threshold;
int bits;
if (value <= 0.0) {
pResult->hi = 0;
pResult->lo = 0;
return;
}
cvt.l = 0x5F800000;
if (value >= cvt.f) {
pResult->hi = 0xFFFFFFFF;
pResult->lo = 0xFFFFFFFF;
return;
}
a = b = 0;
for (bits = 63; bits >= 0; bits--) {
a <<= 1;
if (b & 0x80000000)
a |= 1;
b <<= 1;
if ((short) bits == 0) {
threshold = 1.0f;
} else {
cvt.l = (((short) bits + 127) & 255) << 23;
threshold = cvt.f;
}
if (threshold <= value) {
b |= 1;
value -= threshold;
}
}
pResult->hi = a;
pResult->lo = b;
}
void CInt64_ConvertFromLongDouble(CInt64 *pResult, double value) {
if (value < 0.0) {
CInt64_ConvertUFromLongDouble(pResult, -value);
*pResult = CInt64_Neg(*pResult);
} else {
CInt64_ConvertUFromLongDouble(pResult, value);
}
}
double CInt64_ConvertUToLongDouble(const CInt64 *value) {
Boolean bad;
UInt32 work;
int counter;
double result;
bad = (value->hi == 0) && (value->lo == 0);
if (bad) {
return 0.0;
} else {
result = 0.0;
work = value->hi;
if (work != 0) {
for (counter = 0; counter < 32; counter++) {
result += result;
if (work & 0x80000000)
result += 1.0;
work <<= 1;
}
}
counter = 0;
work = value->lo;
for (; counter < 32; counter++) {
result += result;
if (work & 0x80000000)
result += 1.0;
work <<= 1;
}
return result;
}
}
double CInt64_ConvertToLongDouble(const CInt64 *value) {
CInt64 tmp;
if (value->hi & 0x80000000) {
tmp = CInt64_Neg(*value);
return -CInt64_ConvertUToLongDouble(&tmp);
} else {
return CInt64_ConvertUToLongDouble(value);
}
}
char *CInt64_ScanOctString(CInt64 *pResult, char *str, Boolean *pFail) {
int ch;
CInt64 tmp;
UInt32 a;
UInt32 b;
*pFail = 0;
pResult->hi = pResult->lo = 0;
while ((ch = *str) >= '0' && *str <= '7') {
a = pResult->hi;
b = pResult->lo;
if (a & 0xE0000000)
*pFail = 1;
SHIFT_LEFT_ONE(a, b);
SHIFT_LEFT_ONE(a, b);
SHIFT_LEFT_ONE(a, b);
pResult->hi = a;
pResult->lo = b;
CInt64_SetLong(&tmp, ch - '0');
*pResult = CInt64_Add(*pResult, tmp);
++str;
}
return str;
}
char *CInt64_ScanDecString(CInt64 *pResult, char *str, Boolean *pFail) {
int ch;
CInt64 tmp;
UInt32 a;
UInt32 b;
*pFail = 0;
pResult->hi = pResult->lo = 0;
while ((ch = *str) >= '0' && *str <= '9') {
a = pResult->hi;
b = pResult->lo;
if (a & 0xE0000000)
*pFail = 1;
SHIFT_LEFT_ONE(a, b);
tmp.hi = a;
tmp.lo = b;
SHIFT_LEFT_ONE(a, b);
SHIFT_LEFT_ONE(a, b);
pResult->hi = a;
pResult->lo = b;
if (CInt64_IsNegative(pResult)) {
*pResult = CInt64_Add(*pResult, tmp);
if (!CInt64_IsNegative(pResult))
*pFail = 1;
} else {
*pResult = CInt64_Add(*pResult, tmp);
}
CInt64_SetLong(&tmp, ch - '0');
if (CInt64_IsNegative(pResult)) {
*pResult = CInt64_Add(*pResult, tmp);
if (!CInt64_IsNegative(pResult))
*pFail = 1;
} else {
*pResult = CInt64_Add(*pResult, tmp);
}
++str;
}
return str;
}
char *CInt64_ScanHexString(CInt64 *pResult, char *str, Boolean *pFail) {
int digit;
CInt64 tmp;
UInt32 a;
UInt32 b;
*pFail = 0;
pResult->hi = pResult->lo = 0;
for (;;) {
digit = str[0];
if (digit >= '0' && digit <= '9')
digit = digit - '0';
else if (digit >= 'A' && digit <= 'F')
digit = digit - 'A' + 10;
else if (digit >= 'a' && digit <= 'f')
digit = digit - 'a' + 10;
else
break;
++str;
a = pResult->hi;
b = pResult->lo;
if (a & 0xF0000000)
*pFail = 1;
SHIFT_LEFT_ONE(a, b);
SHIFT_LEFT_ONE(a, b);
SHIFT_LEFT_ONE(a, b);
SHIFT_LEFT_ONE(a, b);
pResult->hi = a;
pResult->lo = b;
CInt64_SetLong(&tmp, (char) digit);
*pResult = CInt64_Add(*pResult, tmp);
}
return str;
}
char *CInt64_ScanBinString(CInt64 *pResult, char *str, Boolean *pFail) {
char digit;
UInt32 a;
UInt32 b;
*pFail = 0;
pResult->hi = pResult->lo = 0;
for (;;) {
if (*str == '0')
digit = 0;
else if (*str == '1')
digit = 1;
else
break;
++str;
a = pResult->hi;
b = pResult->lo;
if (a & 0x80000000)
*pFail = 1;
SHIFT_LEFT_ONE(a, b);
pResult->hi = a;
pResult->lo = b;
if (digit == 1)
*pResult = CInt64_Add(*pResult, cint64_one);
}
return str;
}
char *CInt64_ScanAsmNumber(CInt64 *pResult, char *str, Boolean *pFail) {
Boolean isMaybeBin;
Boolean isOct;
Boolean isMaybeDec;
Boolean isBin;
char *p;
isMaybeBin = 1;
isOct = *str == '0';
isMaybeDec = 1;
isBin = 0;
p = str;
for (;;) {
if (*p == 0)
break;
if (strchr("01", p[0])) {
if (isBin)
isMaybeBin = 0;
} else if (strchr("bB", p[0])) {
isBin = 1;
isMaybeDec = 0;
isOct = 0;
} else if (strchr("234567", p[0])) {
isMaybeBin = 0;
} else if (strchr("89", p[0])) {
isOct = 0;
isMaybeBin = 0;
} else if (strchr("acdefACEDF", p[0])) {
isMaybeDec = 0;
isMaybeBin = 0;
} else {
break;
}
++p;
}
if (isMaybeBin && isBin) {
return CInt64_ScanBinString(pResult, str, pFail) + 1;
} else if (p[0] == 'h' || p[0] == 'H') {
return CInt64_ScanHexString(pResult, str, pFail) + 1;
} else if (isOct) {
return CInt64_ScanOctString(pResult, str, pFail);
} else if (isMaybeDec) {
return CInt64_ScanDecString(pResult, str, pFail);
} else {
*pFail = 1;
return p;
}
}
int CInt64_PrintDec(char *output, CInt64 value) {
int length;
CInt64 rem;
CInt64 divisor;
char buf[40];
char *bufp;
length = 0;
if (CInt64_IsNegative(&value)) {
value = CInt64_Neg(value);
*output = '-';
output++;
length++;
}
if (!CInt64_IsZero(&value)) {
divisor.lo = 10;
divisor.hi = 0;
bufp = buf;
for (;;) {
rem = CInt64_ModU(value, divisor);
*(bufp++) = rem.lo + '0';
value = CInt64_DivU(value, divisor);
if (CInt64_IsZero(&value))
break;
}
while (--bufp >= buf) {
*(output++) = *bufp;
length++;
}
} else {
*(output++) = '0';
length++;
}
*output = 0;
return length;
}
int CInt64_PrintHex(char *output, CInt64 value) {
int length;
CInt64 rem;
CInt64 shift;
CInt64 mask;
char buf[32];
char *bufp;
length = 0;
if (!CInt64_IsZero(&value)) {
shift.lo = 4;
shift.hi = 0;
mask.lo = 0xF;
mask.hi = 0;
bufp = buf;
for (;;) {
rem = CInt64_And(value, mask);
if ((SInt32) rem.lo >= 10)
*(bufp++) = rem.lo + 'A';
else
*(bufp++) = rem.lo + '0';
value = CInt64_ShrU(value, shift);
if (CInt64_IsZero(&value))
break;
}
while (--bufp >= buf) {
*(output++) = *bufp;
length++;
}
} else {
*(output++) = '0';
length++;
}
*output = 0;
return length;
}
int CInt64_PrintBin(char *output, CInt64 value) {
int length;
CInt64 rem;
char buf[64];
char *bufp;
length = 0;
if (!CInt64_IsZero(&value)) {
bufp = buf;
for (;;) {
rem = CInt64_And(value, cint64_one);
if (CInt64_Equal(rem, cint64_one))
*(bufp++) = '1';
else
*(bufp++) = '0';
value = CInt64_ShrU(value, cint64_one);
if (CInt64_IsZero(&value))
break;
}
while (--bufp >= buf) {
*(output++) = *bufp;
length++;
}
} else {
*(output++) = '0';
length++;
}
*output = 0;
return length;
}