1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096 |
- /*
- * Integer number functions.
- *
- * Copyright (C) 2001-2007 Peter Johnson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
- #include "util.h"
- #include <ctype.h>
- #include <limits.h>
- #include "coretype.h"
- #include "bitvect.h"
- #include "file.h"
- #include "errwarn.h"
- #include "intnum.h"
- /* "Native" "word" size for intnum calculations. */
- #define BITVECT_NATIVE_SIZE 256
- struct yasm_intnum {
- union val {
- long l; /* integer value (for integers <32 bits) */
- wordptr bv; /* bit vector (for integers >=32 bits) */
- } val;
- enum { INTNUM_L, INTNUM_BV } type;
- };
- /* static bitvect used for conversions */
- static /*@only@*/ wordptr conv_bv;
- /* static bitvects used for computation */
- static /*@only@*/ wordptr result, spare, op1static, op2static;
- static /*@only@*/ BitVector_from_Dec_static_data *from_dec_data;
- void
- yasm_intnum_initialize(void)
- {
- conv_bv = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE);
- result = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE);
- spare = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE);
- op1static = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE);
- op2static = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE);
- from_dec_data = BitVector_from_Dec_static_Boot(BITVECT_NATIVE_SIZE);
- }
- void
- yasm_intnum_cleanup(void)
- {
- BitVector_from_Dec_static_Shutdown(from_dec_data);
- BitVector_Destroy(op2static);
- BitVector_Destroy(op1static);
- BitVector_Destroy(spare);
- BitVector_Destroy(result);
- BitVector_Destroy(conv_bv);
- }
- /* Compress a bitvector into intnum storage.
- * If saved as a bitvector, clones the passed bitvector.
- * Can modify the passed bitvector.
- */
- static void
- intnum_frombv(/*@out@*/ yasm_intnum *intn, wordptr bv)
- {
- if (Set_Max(bv) < 31) {
- intn->type = INTNUM_L;
- intn->val.l = (long)BitVector_Chunk_Read(bv, 31, 0);
- } else if (BitVector_msb_(bv)) {
- /* Negative, negate and see if we'll fit into a long. */
- unsigned long ul;
- BitVector_Negate(bv, bv);
- if (Set_Max(bv) >= 32 ||
- ((ul = BitVector_Chunk_Read(bv, 32, 0)) & 0x80000000)) {
- /* too negative */
- BitVector_Negate(bv, bv);
- intn->type = INTNUM_BV;
- intn->val.bv = BitVector_Clone(bv);
- } else {
- intn->type = INTNUM_L;
- intn->val.l = -((long)ul);
- }
- } else {
- intn->type = INTNUM_BV;
- intn->val.bv = BitVector_Clone(bv);
- }
- }
- /* If intnum is a BV, returns its bitvector directly.
- * If not, converts into passed bv and returns that instead.
- */
- static wordptr
- intnum_tobv(/*@returned@*/ wordptr bv, const yasm_intnum *intn)
- {
- if (intn->type == INTNUM_BV)
- return intn->val.bv;
- BitVector_Empty(bv);
- if (intn->val.l >= 0)
- BitVector_Chunk_Store(bv, 32, 0, (unsigned long)intn->val.l);
- else {
- BitVector_Chunk_Store(bv, 32, 0, (unsigned long)-intn->val.l);
- BitVector_Negate(bv, bv);
- }
- return bv;
- }
- yasm_intnum *
- yasm_intnum_create_dec(char *str)
- {
- yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
- switch (BitVector_from_Dec_static(from_dec_data, conv_bv,
- (unsigned char *)str)) {
- case ErrCode_Pars:
- yasm_error_set(YASM_ERROR_VALUE, N_("invalid decimal literal"));
- break;
- case ErrCode_Ovfl:
- yasm_error_set(YASM_ERROR_OVERFLOW,
- N_("Numeric constant too large for internal format"));
- break;
- default:
- break;
- }
- intnum_frombv(intn, conv_bv);
- return intn;
- }
- yasm_intnum *
- yasm_intnum_create_bin(char *str)
- {
- yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
- switch (BitVector_from_Bin(conv_bv, (unsigned char *)str)) {
- case ErrCode_Pars:
- yasm_error_set(YASM_ERROR_VALUE, N_("invalid binary literal"));
- break;
- case ErrCode_Ovfl:
- yasm_error_set(YASM_ERROR_OVERFLOW,
- N_("Numeric constant too large for internal format"));
- break;
- default:
- break;
- }
- intnum_frombv(intn, conv_bv);
- return intn;
- }
- yasm_intnum *
- yasm_intnum_create_oct(char *str)
- {
- yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
- switch (BitVector_from_Oct(conv_bv, (unsigned char *)str)) {
- case ErrCode_Pars:
- yasm_error_set(YASM_ERROR_VALUE, N_("invalid octal literal"));
- break;
- case ErrCode_Ovfl:
- yasm_error_set(YASM_ERROR_OVERFLOW,
- N_("Numeric constant too large for internal format"));
- break;
- default:
- break;
- }
- intnum_frombv(intn, conv_bv);
- return intn;
- }
- yasm_intnum *
- yasm_intnum_create_hex(char *str)
- {
- yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
- switch (BitVector_from_Hex(conv_bv, (unsigned char *)str)) {
- case ErrCode_Pars:
- yasm_error_set(YASM_ERROR_VALUE, N_("invalid hex literal"));
- break;
- case ErrCode_Ovfl:
- yasm_error_set(YASM_ERROR_OVERFLOW,
- N_("Numeric constant too large for internal format"));
- break;
- default:
- break;
- }
- intnum_frombv(intn, conv_bv);
- return intn;
- }
- /*@-usedef -compdef -uniondef@*/
- yasm_intnum *
- yasm_intnum_create_charconst_nasm(const char *str)
- {
- yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
- size_t len = strlen(str);
- if(len*8 > BITVECT_NATIVE_SIZE)
- yasm_error_set(YASM_ERROR_OVERFLOW,
- N_("Character constant too large for internal format"));
- /* be conservative in choosing bitvect in case MSB is set */
- if (len > 3) {
- BitVector_Empty(conv_bv);
- intn->type = INTNUM_BV;
- } else {
- intn->val.l = 0;
- intn->type = INTNUM_L;
- }
- switch (len) {
- case 3:
- intn->val.l |= ((unsigned long)str[2]) & 0xff;
- intn->val.l <<= 8;
- /*@fallthrough@*/
- case 2:
- intn->val.l |= ((unsigned long)str[1]) & 0xff;
- intn->val.l <<= 8;
- /*@fallthrough@*/
- case 1:
- intn->val.l |= ((unsigned long)str[0]) & 0xff;
- case 0:
- break;
- default:
- /* >=32 bit conversion */
- while (len) {
- BitVector_Move_Left(conv_bv, 8);
- BitVector_Chunk_Store(conv_bv, 8, 0,
- ((unsigned long)str[--len]) & 0xff);
- }
- intn->val.bv = BitVector_Clone(conv_bv);
- }
- return intn;
- }
- yasm_intnum *
- yasm_intnum_create_charconst_tasm(const char *str)
- {
- yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
- size_t len = strlen(str);
- size_t i;
- if(len*8 > BITVECT_NATIVE_SIZE)
- yasm_error_set(YASM_ERROR_OVERFLOW,
- N_("Character constant too large for internal format"));
- /* be conservative in choosing bitvect in case MSB is set */
- if (len > 3) {
- BitVector_Empty(conv_bv);
- intn->type = INTNUM_BV;
- } else {
- intn->val.l = 0;
- intn->type = INTNUM_L;
- }
- /* tasm uses big endian notation */
- i = 0;
- switch (len) {
- case 3:
- intn->val.l |= ((unsigned long)str[i++]) & 0xff;
- intn->val.l <<= 8;
- /*@fallthrough@*/
- case 2:
- intn->val.l |= ((unsigned long)str[i++]) & 0xff;
- intn->val.l <<= 8;
- /*@fallthrough@*/
- case 1:
- intn->val.l |= ((unsigned long)str[i++]) & 0xff;
- case 0:
- break;
- default:
- /* >=32 bit conversion */
- while (i < len) {
- BitVector_Chunk_Store(conv_bv, 8, (len-i-1)*8,
- ((unsigned long)str[i]) & 0xff);
- i++;
- }
- intn->val.bv = BitVector_Clone(conv_bv);
- }
- return intn;
- }
- /*@=usedef =compdef =uniondef@*/
- yasm_intnum *
- yasm_intnum_create_uint(unsigned long i)
- {
- yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
- if (i > LONG_MAX) {
- /* Too big, store as bitvector */
- intn->val.bv = BitVector_Create(BITVECT_NATIVE_SIZE, TRUE);
- intn->type = INTNUM_BV;
- BitVector_Chunk_Store(intn->val.bv, 32, 0, i);
- } else {
- intn->val.l = (long)i;
- intn->type = INTNUM_L;
- }
- return intn;
- }
- yasm_intnum *
- yasm_intnum_create_int(long i)
- {
- yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
- intn->val.l = i;
- intn->type = INTNUM_L;
- return intn;
- }
- yasm_intnum *
- yasm_intnum_create_leb128(const unsigned char *ptr, int sign,
- unsigned long *size)
- {
- yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
- const unsigned char *ptr_orig = ptr;
- unsigned long i = 0;
- BitVector_Empty(conv_bv);
- for (;;) {
- BitVector_Chunk_Store(conv_bv, 7, i, *ptr);
- i += 7;
- if ((*ptr & 0x80) != 0x80)
- break;
- ptr++;
- }
- *size = (unsigned long)(ptr-ptr_orig)+1;
- if(i > BITVECT_NATIVE_SIZE)
- yasm_error_set(YASM_ERROR_OVERFLOW,
- N_("Numeric constant too large for internal format"));
- else if (sign && (*ptr & 0x40) == 0x40)
- BitVector_Interval_Fill(conv_bv, i, BITVECT_NATIVE_SIZE-1);
- intnum_frombv(intn, conv_bv);
- return intn;
- }
- yasm_intnum *
- yasm_intnum_create_sized(unsigned char *ptr, int sign, size_t srcsize,
- int bigendian)
- {
- yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
- unsigned long i = 0;
- if (srcsize*8 > BITVECT_NATIVE_SIZE)
- yasm_error_set(YASM_ERROR_OVERFLOW,
- N_("Numeric constant too large for internal format"));
- /* Read the buffer into a bitvect */
- BitVector_Empty(conv_bv);
- if (bigendian) {
- /* TODO */
- yasm_internal_error(N_("big endian not implemented"));
- } else {
- for (i = 0; i < srcsize; i++)
- BitVector_Chunk_Store(conv_bv, 8, i*8, ptr[i]);
- }
- /* Sign extend if needed */
- if (srcsize*8 < BITVECT_NATIVE_SIZE && sign && (ptr[i-1] & 0x80) == 0x80)
- BitVector_Interval_Fill(conv_bv, i*8, BITVECT_NATIVE_SIZE-1);
- intnum_frombv(intn, conv_bv);
- return intn;
- }
- yasm_intnum *
- yasm_intnum_copy(const yasm_intnum *intn)
- {
- yasm_intnum *n = yasm_xmalloc(sizeof(yasm_intnum));
- switch (intn->type) {
- case INTNUM_L:
- n->val.l = intn->val.l;
- break;
- case INTNUM_BV:
- n->val.bv = BitVector_Clone(intn->val.bv);
- break;
- }
- n->type = intn->type;
- return n;
- }
- void
- yasm_intnum_destroy(yasm_intnum *intn)
- {
- if (intn->type == INTNUM_BV)
- BitVector_Destroy(intn->val.bv);
- yasm_xfree(intn);
- }
- /*@-nullderef -nullpass -branchstate@*/
- int
- yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand)
- {
- boolean carry = 0;
- wordptr op1, op2 = NULL;
- N_int count;
- /* Always do computations with in full bit vector.
- * Bit vector results must be calculated through intermediate storage.
- */
- op1 = intnum_tobv(op1static, acc);
- if (operand)
- op2 = intnum_tobv(op2static, operand);
- if (!operand && op != YASM_EXPR_NEG && op != YASM_EXPR_NOT &&
- op != YASM_EXPR_LNOT) {
- yasm_error_set(YASM_ERROR_ARITHMETIC,
- N_("operation needs an operand"));
- BitVector_Empty(result);
- return 1;
- }
- /* A operation does a bitvector computation if result is allocated. */
- switch (op) {
- case YASM_EXPR_ADD:
- BitVector_add(result, op1, op2, &carry);
- break;
- case YASM_EXPR_SUB:
- BitVector_sub(result, op1, op2, &carry);
- break;
- case YASM_EXPR_MUL:
- BitVector_Multiply(result, op1, op2);
- break;
- case YASM_EXPR_DIV:
- /* TODO: make sure op1 and op2 are unsigned */
- if (BitVector_is_empty(op2)) {
- yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero"));
- BitVector_Empty(result);
- return 1;
- } else
- BitVector_Divide(result, op1, op2, spare);
- break;
- case YASM_EXPR_SIGNDIV:
- if (BitVector_is_empty(op2)) {
- yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero"));
- BitVector_Empty(result);
- return 1;
- } else
- BitVector_Divide(result, op1, op2, spare);
- break;
- case YASM_EXPR_MOD:
- /* TODO: make sure op1 and op2 are unsigned */
- if (BitVector_is_empty(op2)) {
- yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero"));
- BitVector_Empty(result);
- return 1;
- } else
- BitVector_Divide(spare, op1, op2, result);
- break;
- case YASM_EXPR_SIGNMOD:
- if (BitVector_is_empty(op2)) {
- yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero"));
- BitVector_Empty(result);
- return 1;
- } else
- BitVector_Divide(spare, op1, op2, result);
- break;
- case YASM_EXPR_NEG:
- BitVector_Negate(result, op1);
- break;
- case YASM_EXPR_NOT:
- Set_Complement(result, op1);
- break;
- case YASM_EXPR_OR:
- Set_Union(result, op1, op2);
- break;
- case YASM_EXPR_AND:
- Set_Intersection(result, op1, op2);
- break;
- case YASM_EXPR_XOR:
- Set_ExclusiveOr(result, op1, op2);
- break;
- case YASM_EXPR_XNOR:
- Set_ExclusiveOr(result, op1, op2);
- Set_Complement(result, result);
- break;
- case YASM_EXPR_NOR:
- Set_Union(result, op1, op2);
- Set_Complement(result, result);
- break;
- case YASM_EXPR_SHL:
- if (operand->type == INTNUM_L && operand->val.l >= 0) {
- BitVector_Copy(result, op1);
- BitVector_Move_Left(result, (N_int)operand->val.l);
- } else /* don't even bother, just zero result */
- BitVector_Empty(result);
- break;
- case YASM_EXPR_SHR:
- if (operand->type == INTNUM_L && operand->val.l >= 0) {
- BitVector_Copy(result, op1);
- carry = BitVector_msb_(op1);
- count = (N_int)operand->val.l;
- while (count-- > 0)
- BitVector_shift_right(result, carry);
- } else /* don't even bother, just zero result */
- BitVector_Empty(result);
- break;
- case YASM_EXPR_LOR:
- BitVector_Empty(result);
- BitVector_LSB(result, !BitVector_is_empty(op1) ||
- !BitVector_is_empty(op2));
- break;
- case YASM_EXPR_LAND:
- BitVector_Empty(result);
- BitVector_LSB(result, !BitVector_is_empty(op1) &&
- !BitVector_is_empty(op2));
- break;
- case YASM_EXPR_LNOT:
- BitVector_Empty(result);
- BitVector_LSB(result, BitVector_is_empty(op1));
- break;
- case YASM_EXPR_LXOR:
- BitVector_Empty(result);
- BitVector_LSB(result, !BitVector_is_empty(op1) ^
- !BitVector_is_empty(op2));
- break;
- case YASM_EXPR_LXNOR:
- BitVector_Empty(result);
- BitVector_LSB(result, !(!BitVector_is_empty(op1) ^
- !BitVector_is_empty(op2)));
- break;
- case YASM_EXPR_LNOR:
- BitVector_Empty(result);
- BitVector_LSB(result, !(!BitVector_is_empty(op1) ||
- !BitVector_is_empty(op2)));
- break;
- case YASM_EXPR_EQ:
- BitVector_Empty(result);
- BitVector_LSB(result, BitVector_equal(op1, op2));
- break;
- case YASM_EXPR_LT:
- BitVector_Empty(result);
- BitVector_LSB(result, BitVector_Compare(op1, op2) < 0);
- break;
- case YASM_EXPR_GT:
- BitVector_Empty(result);
- BitVector_LSB(result, BitVector_Compare(op1, op2) > 0);
- break;
- case YASM_EXPR_LE:
- BitVector_Empty(result);
- BitVector_LSB(result, BitVector_Compare(op1, op2) <= 0);
- break;
- case YASM_EXPR_GE:
- BitVector_Empty(result);
- BitVector_LSB(result, BitVector_Compare(op1, op2) >= 0);
- break;
- case YASM_EXPR_NE:
- BitVector_Empty(result);
- BitVector_LSB(result, !BitVector_equal(op1, op2));
- break;
- case YASM_EXPR_SEG:
- yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"),
- "SEG");
- break;
- case YASM_EXPR_WRT:
- yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"),
- "WRT");
- break;
- case YASM_EXPR_SEGOFF:
- yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"),
- ":");
- break;
- case YASM_EXPR_IDENT:
- if (result)
- BitVector_Copy(result, op1);
- break;
- default:
- yasm_error_set(YASM_ERROR_ARITHMETIC,
- N_("invalid operation in intnum calculation"));
- BitVector_Empty(result);
- return 1;
- }
- /* Try to fit the result into 32 bits if possible */
- if (acc->type == INTNUM_BV)
- BitVector_Destroy(acc->val.bv);
- intnum_frombv(acc, result);
- return 0;
- }
- /*@=nullderef =nullpass =branchstate@*/
- int
- yasm_intnum_compare(const yasm_intnum *intn1, const yasm_intnum *intn2)
- {
- wordptr op1, op2;
- if (intn1->type == INTNUM_L && intn2->type == INTNUM_L) {
- if (intn1->val.l < intn2->val.l)
- return -1;
- if (intn1->val.l > intn2->val.l)
- return 1;
- return 0;
- }
- op1 = intnum_tobv(op1static, intn1);
- op2 = intnum_tobv(op2static, intn2);
- return BitVector_Compare(op1, op2);
- }
- void
- yasm_intnum_zero(yasm_intnum *intn)
- {
- yasm_intnum_set_int(intn, 0);
- }
- void
- yasm_intnum_set(yasm_intnum *intn, const yasm_intnum *val)
- {
- if (intn->type == val->type) {
- switch (val->type) {
- case INTNUM_L:
- intn->val.l = val->val.l;
- break;
- case INTNUM_BV:
- BitVector_Copy(intn->val.bv, val->val.bv);
- break;
- }
- } else {
- switch (val->type) {
- case INTNUM_L:
- BitVector_Destroy(intn->val.bv);
- intn->val.l = val->val.l;
- break;
- case INTNUM_BV:
- intn->val.bv = BitVector_Clone(val->val.bv);
- break;
- }
- intn->type = val->type;
- }
- }
- void
- yasm_intnum_set_uint(yasm_intnum *intn, unsigned long val)
- {
- if (val > LONG_MAX) {
- if (intn->type != INTNUM_BV) {
- intn->val.bv = BitVector_Create(BITVECT_NATIVE_SIZE, TRUE);
- intn->type = INTNUM_BV;
- }
- BitVector_Chunk_Store(intn->val.bv, 32, 0, val);
- } else {
- if (intn->type == INTNUM_BV) {
- BitVector_Destroy(intn->val.bv);
- intn->type = INTNUM_L;
- }
- intn->val.l = (long)val;
- }
- }
- void
- yasm_intnum_set_int(yasm_intnum *intn, long val)
- {
- if (intn->type == INTNUM_BV)
- BitVector_Destroy(intn->val.bv);
- intn->type = INTNUM_L;
- intn->val.l = val;
- }
- int
- yasm_intnum_is_zero(const yasm_intnum *intn)
- {
- return (intn->type == INTNUM_L && intn->val.l == 0);
- }
- int
- yasm_intnum_is_pos1(const yasm_intnum *intn)
- {
- return (intn->type == INTNUM_L && intn->val.l == 1);
- }
- int
- yasm_intnum_is_neg1(const yasm_intnum *intn)
- {
- return (intn->type == INTNUM_L && intn->val.l == -1);
- }
- int
- yasm_intnum_sign(const yasm_intnum *intn)
- {
- if (intn->type == INTNUM_L) {
- if (intn->val.l == 0)
- return 0;
- else if (intn->val.l < 0)
- return -1;
- else
- return 1;
- } else
- return BitVector_Sign(intn->val.bv);
- }
- unsigned long
- yasm_intnum_get_uint(const yasm_intnum *intn)
- {
- switch (intn->type) {
- case INTNUM_L:
- if (intn->val.l < 0)
- return 0;
- return (unsigned long)intn->val.l;
- case INTNUM_BV:
- if (BitVector_msb_(intn->val.bv))
- return 0;
- if (Set_Max(intn->val.bv) > 32)
- return ULONG_MAX;
- return BitVector_Chunk_Read(intn->val.bv, 32, 0);
- default:
- yasm_internal_error(N_("unknown intnum type"));
- /*@notreached@*/
- return 0;
- }
- }
- long
- yasm_intnum_get_int(const yasm_intnum *intn)
- {
- switch (intn->type) {
- case INTNUM_L:
- return intn->val.l;
- case INTNUM_BV:
- if (BitVector_msb_(intn->val.bv)) {
- /* it's negative: negate the bitvector to get a positive
- * number, then negate the positive number.
- */
- unsigned long ul;
- BitVector_Negate(conv_bv, intn->val.bv);
- if (Set_Max(conv_bv) >= 32) {
- /* too negative */
- return LONG_MIN;
- }
- ul = BitVector_Chunk_Read(conv_bv, 32, 0);
- /* check for too negative */
- return (ul & 0x80000000) ? LONG_MIN : -((long)ul);
- }
- /* it's positive, and since it's a BV, it must be >0x7FFFFFFF */
- return LONG_MAX;
- default:
- yasm_internal_error(N_("unknown intnum type"));
- /*@notreached@*/
- return 0;
- }
- }
- void
- yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr,
- size_t destsize, size_t valsize, int shift,
- int bigendian, int warn)
- {
- wordptr op1 = op1static, op2;
- unsigned char *buf;
- unsigned int len;
- size_t rshift = shift < 0 ? (size_t)(-shift) : 0;
- int carry_in;
- /* Currently don't support destinations larger than our native size */
- if (destsize*8 > BITVECT_NATIVE_SIZE)
- yasm_internal_error(N_("destination too large"));
- /* General size warnings */
- if (warn<0 && !yasm_intnum_check_size(intn, valsize, rshift, 1))
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("value does not fit in signed %d bit field"),
- valsize);
- if (warn>0 && !yasm_intnum_check_size(intn, valsize, rshift, 2))
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("value does not fit in %d bit field"), valsize);
- /* Read the original data into a bitvect */
- if (bigendian) {
- /* TODO */
- yasm_internal_error(N_("big endian not implemented"));
- } else
- BitVector_Block_Store(op1, ptr, (N_int)destsize);
- /* If not already a bitvect, convert value to be written to a bitvect */
- op2 = intnum_tobv(op2static, intn);
- /* Check low bits if right shifting and warnings enabled */
- if (warn && rshift > 0) {
- BitVector_Copy(conv_bv, op2);
- BitVector_Move_Left(conv_bv, (N_int)(BITVECT_NATIVE_SIZE-rshift));
- if (!BitVector_is_empty(conv_bv))
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("misaligned value, truncating to boundary"));
- }
- /* Shift right if needed */
- if (rshift > 0) {
- carry_in = BitVector_msb_(op2);
- while (rshift-- > 0)
- BitVector_shift_right(op2, carry_in);
- shift = 0;
- }
- /* Write the new value into the destination bitvect */
- BitVector_Interval_Copy(op1, op2, (unsigned int)shift, 0, (N_int)valsize);
- /* Write out the new data */
- buf = BitVector_Block_Read(op1, &len);
- if (bigendian) {
- /* TODO */
- yasm_internal_error(N_("big endian not implemented"));
- } else
- memcpy(ptr, buf, destsize);
- yasm_xfree(buf);
- }
- /* Return 1 if okay size, 0 if not */
- int
- yasm_intnum_check_size(const yasm_intnum *intn, size_t size, size_t rshift,
- int rangetype)
- {
- wordptr val;
- /* If not already a bitvect, convert value to a bitvect */
- if (intn->type == INTNUM_BV) {
- if (rshift > 0) {
- val = conv_bv;
- BitVector_Copy(val, intn->val.bv);
- } else
- val = intn->val.bv;
- } else
- val = intnum_tobv(conv_bv, intn);
- if (size >= BITVECT_NATIVE_SIZE)
- return 1;
- if (rshift > 0) {
- int carry_in = BitVector_msb_(val);
- while (rshift-- > 0)
- BitVector_shift_right(val, carry_in);
- }
- if (rangetype > 0) {
- if (BitVector_msb_(val)) {
- /* it's negative */
- int retval;
- BitVector_Negate(conv_bv, val);
- BitVector_dec(conv_bv, conv_bv);
- retval = Set_Max(conv_bv) < (long)size-1;
- return retval;
- }
-
- if (rangetype == 1)
- size--;
- }
- return (Set_Max(val) < (long)size);
- }
- int
- yasm_intnum_in_range(const yasm_intnum *intn, long low, long high)
- {
- wordptr val = intnum_tobv(result, intn);
- wordptr lval = op1static;
- wordptr hval = op2static;
- /* Convert high and low to bitvects */
- BitVector_Empty(lval);
- if (low >= 0)
- BitVector_Chunk_Store(lval, 32, 0, (unsigned long)low);
- else {
- BitVector_Chunk_Store(lval, 32, 0, (unsigned long)(-low));
- BitVector_Negate(lval, lval);
- }
- BitVector_Empty(hval);
- if (high >= 0)
- BitVector_Chunk_Store(hval, 32, 0, (unsigned long)high);
- else {
- BitVector_Chunk_Store(hval, 32, 0, (unsigned long)(-high));
- BitVector_Negate(hval, hval);
- }
- /* Compare! */
- return (BitVector_Compare(val, lval) >= 0
- && BitVector_Compare(val, hval) <= 0);
- }
- static unsigned long
- get_leb128(wordptr val, unsigned char *ptr, int sign)
- {
- unsigned long i, size;
- unsigned char *ptr_orig = ptr;
- if (sign) {
- /* Signed mode */
- if (BitVector_msb_(val)) {
- /* Negative */
- BitVector_Negate(conv_bv, val);
- size = Set_Max(conv_bv)+2;
- } else {
- /* Positive */
- size = Set_Max(val)+2;
- }
- } else {
- /* Unsigned mode */
- size = Set_Max(val)+1;
- }
- /* Positive/Unsigned write */
- for (i=0; i<size; i += 7) {
- *ptr = (unsigned char)BitVector_Chunk_Read(val, 7, i);
- *ptr |= 0x80;
- ptr++;
- }
- *(ptr-1) &= 0x7F; /* Clear MSB of last byte */
- return (unsigned long)(ptr-ptr_orig);
- }
- static unsigned long
- size_leb128(wordptr val, int sign)
- {
- if (sign) {
- /* Signed mode */
- if (BitVector_msb_(val)) {
- /* Negative */
- BitVector_Negate(conv_bv, val);
- return (Set_Max(conv_bv)+8)/7;
- } else {
- /* Positive */
- return (Set_Max(val)+8)/7;
- }
- } else {
- /* Unsigned mode */
- return (Set_Max(val)+7)/7;
- }
- }
- unsigned long
- yasm_intnum_get_leb128(const yasm_intnum *intn, unsigned char *ptr, int sign)
- {
- wordptr val;
- /* Shortcut 0 */
- if (intn->type == INTNUM_L && intn->val.l == 0) {
- *ptr = 0;
- return 1;
- }
- /* If not already a bitvect, convert value to be written to a bitvect */
- val = intnum_tobv(op1static, intn);
- return get_leb128(val, ptr, sign);
- }
- unsigned long
- yasm_intnum_size_leb128(const yasm_intnum *intn, int sign)
- {
- wordptr val;
- /* Shortcut 0 */
- if (intn->type == INTNUM_L && intn->val.l == 0) {
- return 1;
- }
- /* If not already a bitvect, convert value to a bitvect */
- val = intnum_tobv(op1static, intn);
- return size_leb128(val, sign);
- }
- unsigned long
- yasm_get_sleb128(long v, unsigned char *ptr)
- {
- wordptr val = op1static;
- /* Shortcut 0 */
- if (v == 0) {
- *ptr = 0;
- return 1;
- }
- BitVector_Empty(val);
- if (v >= 0)
- BitVector_Chunk_Store(val, 32, 0, (unsigned long)v);
- else {
- BitVector_Chunk_Store(val, 32, 0, (unsigned long)(-v));
- BitVector_Negate(val, val);
- }
- return get_leb128(val, ptr, 1);
- }
- unsigned long
- yasm_size_sleb128(long v)
- {
- wordptr val = op1static;
- if (v == 0)
- return 1;
- BitVector_Empty(val);
- if (v >= 0)
- BitVector_Chunk_Store(val, 32, 0, (unsigned long)v);
- else {
- BitVector_Chunk_Store(val, 32, 0, (unsigned long)(-v));
- BitVector_Negate(val, val);
- }
- return size_leb128(val, 1);
- }
- unsigned long
- yasm_get_uleb128(unsigned long v, unsigned char *ptr)
- {
- wordptr val = op1static;
- /* Shortcut 0 */
- if (v == 0) {
- *ptr = 0;
- return 1;
- }
- BitVector_Empty(val);
- BitVector_Chunk_Store(val, 32, 0, v);
- return get_leb128(val, ptr, 0);
- }
- unsigned long
- yasm_size_uleb128(unsigned long v)
- {
- wordptr val = op1static;
- if (v == 0)
- return 1;
- BitVector_Empty(val);
- BitVector_Chunk_Store(val, 32, 0, v);
- return size_leb128(val, 0);
- }
- char *
- yasm_intnum_get_str(const yasm_intnum *intn)
- {
- unsigned char *s;
- switch (intn->type) {
- case INTNUM_L:
- s = yasm_xmalloc(16);
- sprintf((char *)s, "%ld", intn->val.l);
- return (char *)s;
- break;
- case INTNUM_BV:
- return (char *)BitVector_to_Dec(intn->val.bv);
- break;
- }
- /*@notreached@*/
- return NULL;
- }
- void
- yasm_intnum_print(const yasm_intnum *intn, FILE *f)
- {
- unsigned char *s;
- switch (intn->type) {
- case INTNUM_L:
- fprintf(f, "0x%lx", intn->val.l);
- break;
- case INTNUM_BV:
- s = BitVector_to_Hex(intn->val.bv);
- fprintf(f, "0x%s", (char *)s);
- yasm_xfree(s);
- break;
- }
- }
|