integral_t type_max(type *r, where *from) { unsigned sz = type_size(r, from); unsigned bits = sz * CHAR_BIT; int is_signed = type_is_signed(r); integral_t max = ~0ULL >> (INTEGRAL_BITS - bits); if(is_signed) max = max / 2 - 1; return max; }
type *decl_type_for_bitfield(decl *d) { assert(!type_is(d->ref, type_func)); if(d->bits.var.field_width){ const unsigned bits = const_fold_val_i(d->bits.var.field_width); const int is_signed = type_is_signed(d->ref); unsigned bytes = bits / CHAR_BIT; /* need to add on a byte for any leftovers */ if(bits % CHAR_BIT) bytes++; return type_nav_MAX_FOR(cc1_type_nav, bytes, is_signed); }else{ return d->ref; } }
static void try_shift_conv( out_ctx *octx, enum op_type *binop, const out_val **lhs, const out_val **rhs) { if(type_is_signed((*lhs)->t)) return; if(*binop == op_divide && (*rhs)->type == V_CONST_I){ integral_t k = (*rhs)->bits.val_i; if((k & (k - 1)) == 0){ /* power of two, can shift */ out_val *mut; *binop = op_shiftr; *rhs = mut = v_dup_or_reuse(octx, *rhs, (*rhs)->t); mut->bits.val_i = log2(k); } }else if(*binop == op_multiply){ const out_val **vconst = (*lhs)->type == V_CONST_I ? lhs : rhs; integral_t k = (*vconst)->bits.val_i; if((k & (k - 1)) == 0){ out_val *mut; *binop = op_shiftl; *vconst = mut = v_dup_or_reuse(octx, *vconst, (*vconst)->t); mut->bits.val_i = log2(k); if(vconst == lhs){ /* need to swap as shift expects the constant to be rhs */ const out_val *tmp = *lhs; *lhs = *rhs; *rhs = tmp; } } } }
void bitfield_trunc_check(decl *mem, expr *from) { consty k; if(expr_kind(from, cast)){ /* we'll warn about bitfield truncation, prevent warnings * about cast truncation */ from->expr_cast_implicit = 0; } const_fold(from, &k); if(k.type == CONST_NUM){ const sintegral_t kexp = k.bits.num.val.i; /* highest may be -1 - kexp is zero */ const int highest = integral_high_bit(k.bits.num.val.i, from->tree_type); const int is_signed = type_is_signed(mem->bits.var.field_width->tree_type); const_fold(mem->bits.var.field_width, &k); UCC_ASSERT(k.type == CONST_NUM, "bitfield size not val?"); UCC_ASSERT(K_INTEGRAL(k.bits.num), "fp bitfield size?"); if(highest > (sintegral_t)k.bits.num.val.i || (is_signed && highest == (sintegral_t)k.bits.num.val.i)) { sintegral_t kexp_to = kexp & ~(-1UL << k.bits.num.val.i); cc1_warn_at(&from->where, bitfield_trunc, "truncation in store to bitfield alters value: " "%" NUMERIC_FMT_D " -> %" NUMERIC_FMT_D, kexp, kexp_to); } } }
static integral_t convert_integral_to_integral_warn( const integral_t in, type *tin, type *tout, int do_warn, where *w) { /* * C99 * 6.3.1.3 Signed and unsigned integers * * When a value with integer type is converted to another integer type * other than _Bool, if the value can be represented by the new type, it * is unchanged. * * Otherwise, if the new type is unsigned, the value is converted by * repeatedly adding or subtracting one more than the maximum value that * can be represented in the new type until the value is in the range of * the new type. * * Otherwise, the new type is signed and the value cannot be represented * in it; either the result is implementation-defined or an * implementation-defined signal is raised. */ /* representable * if size(out) > size(in) * or if size(out) == size(in) * and conversion is not unsigned -> signed * or conversion is unsigned -> signed and in < signed-max */ const unsigned sz_out = type_size(tout, w); const int signed_in = type_is_signed(tin); const int signed_out = type_is_signed(tout); sintegral_t to_iv_sign_ext; integral_t to_iv = integral_truncate(in, sz_out, &to_iv_sign_ext); integral_t ret; if(!signed_out && signed_in){ const unsigned sz_in_bits = CHAR_BIT * type_size(tin, w); const unsigned sz_out_bits = CHAR_BIT * sz_out; /* e.g. "(unsigned)-1". Pick to_iv, i.e. the unsigned truncated repr * this assumes that signed ints on the host machine we're run on * are 2's complement, i.e. truncated a negative gives us all 1s, * which we truncate */ ret = to_iv; /* need to ensure sign extension */ if(ret & (1ULL << (sz_in_bits - 1)) && sz_in_bits != sz_out_bits) { ret |= -1ULL << sz_in_bits; /* need to unmask any top bits, e.g. int instead of long long */ if(sz_out_bits >= CHAR_BIT * sizeof(ret)){ /* shift would be a no-op (technically UB) */ }else{ ret &= -1ULL >> sz_out_bits; } } }else if(signed_in){