static void bitfield_val_set( struct bitfield_val *bfv, expr *kval, expr *field_w) { bfv->val = kval ? const_fold_val_i(kval) : 0; bfv->offset = 0; bfv->width = const_fold_val_i(field_w); }
static int decl_cmp_ctor_dtor_pri( const void *a, const void *b, enum attribute_type attr_ty) { decl *da = *(decl **)a, *db = *(decl **)b; attribute *attr_a = attribute_present(da, attr_ty); attribute *attr_b = attribute_present(db, attr_ty); assert(attr_a && attr_b); { struct expr *exp_a = attr_a->bits.priority; struct expr *exp_b = attr_b->bits.priority; integral_t ia, ib; switch(!!exp_a + !!exp_b){ case 0: return 0; case 1: return exp_a ? -1 : 1; case 2: break; default: assert(0); } ia = const_fold_val_i(exp_a); ib = const_fold_val_i(exp_b); return ia - ib; } }
void style_stmt_case_range(stmt *s) { stylef("\ncase %ld ... %ld: ", (long)const_fold_val_i(s->expr), (long)const_fold_val_i(s->expr2)); gen_stmt(s->lhs); }
static void gen_expr_struct_lea(expr *e) { ASSERT_NOT_DOT(); gen_expr(e->lhs); /* cast for void* arithmetic */ out_change_type(type_ptr_to(type_nav_btype(cc1_type_nav, type_void))); out_push_l(type_nav_btype(cc1_type_nav, type_intptr_t), struct_offset(e)); /* integral offset */ out_op(op_plus); if(fopt_mode & FOPT_VERBOSE_ASM) out_comment("struct member %s", e->bits.struct_mem.d->spel); { decl *d = e->bits.struct_mem.d; out_change_type(type_ptr_to(d->ref)); /* set if we're a bitfield - out_deref() and out_store() * i.e. read + write then handle this */ if(d->bits.var.field_width){ unsigned w = const_fold_val_i(d->bits.var.field_width); out_set_bitfield(d->bits.var.struct_offset_bitfield, w); out_comment("struct bitfield lea"); } } }
unsigned type_size(type *r, const where *from) { switch(r->type){ case type_auto: ICE("__auto_type"); case type_btype: return btype_size(r->bits.type, from); case type_tdef: { decl *d = r->bits.tdef.decl; type *sub; if(d) return type_size(d->ref, from); sub = r->bits.tdef.type_of->tree_type; UCC_ASSERT(sub, "type_size for unfolded typedef"); return type_size(sub, from); } case type_attr: case type_cast: case type_where: return type_size(r->ref, from); case type_ptr: case type_block: return platform_word_size(); case type_func: /* function size is one, sizeof(main) is valid */ return 1; case type_array: { integral_t sz; if(type_is_void(r->ref)) die_at(from, "array of void"); if(!r->bits.array.size) die_at(from, "array has an incomplete size"); sz = const_fold_val_i(r->bits.array.size); return sz * type_size(r->ref, from); } } ucc_unreach(0); }
void fold_stmt_case_range(stmt *s) { integral_t lv, rv; FOLD_EXPR(s->expr, s->symtab); FOLD_EXPR(s->expr2, s->symtab); fold_check_expr(s->expr, FOLD_CHK_INTEGRAL | FOLD_CHK_CONST_I, "case-range"); lv = const_fold_val_i(s->expr); fold_check_expr(s->expr2, FOLD_CHK_INTEGRAL | FOLD_CHK_CONST_I, "case-range"); rv = const_fold_val_i(s->expr2); if(lv >= rv) die_at(&s->where, "case range equal or inverse"); s->bits.case_lbl = out_label_case(CASE_RANGE, lv); fold_stmt_and_add_to_curswitch(s, &s->bits.case_lbl); }
static void print_enum(struct_union_enum_st *et) { sue_member **mi; idt_printf("enum %s:\n", et->spel); gen_str_indent++; for(mi = et->members; *mi; mi++){ enum_member *m = (*mi)->enum_member; idt_printf("member %s = %" NUMERIC_FMT_D "\n", m->spel, const_fold_val_i(m->val)); } gen_str_indent--; }
void gen_expr_str_struct(expr *e) { decl *mem = e->bits.struct_mem.d; idt_printf("struct/union member %s offset %d\n", mem->spel, struct_offset(e)); if(mem->bits.var.field_width) idt_printf("bitfield offset %u, width %u\n", mem->bits.var.struct_offset_bitfield, (unsigned)const_fold_val_i(mem->bits.var.field_width)); gen_str_indent++; print_expr(e->lhs); gen_str_indent--; }
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 print_struct(struct_union_enum_st *sue) { sue_member **iter; if(!sue_complete(sue)){ idt_printf("incomplete %s %s\n", sue_str(sue), sue->spel); return; } idt_printf("%s %s (size %d):\n", sue_str(sue), sue->spel, sue_size(sue, &sue->where)); gen_str_indent++; for(iter = sue->members; iter && *iter; iter++){ decl *d = (*iter)->struct_member; idt_printf("decl %s:\n", d->spel ? d->spel : "<anon>"); gen_str_indent++; print_decl(d, PDECL_INDENT | PDECL_NEWLINE | PDECL_ATTR); if(!type_is(d->ref, type_func)){ #define SHOW_FIELD(nam) idt_printf("." #nam " = %u\n", d->bits.var.nam) SHOW_FIELD(struct_offset); if(d->bits.var.field_width){ integral_t v = const_fold_val_i(d->bits.var.field_width); gen_str_indent++; idt_printf(".field_width = %" NUMERIC_FMT_D "\n", v); SHOW_FIELD(struct_offset_bitfield); gen_str_indent--; } } gen_str_indent--; } gen_str_indent--; }
static enum type_cmp type_cmp_r( type *const orig_a, type *const orig_b, enum type_cmp_opts opts) { enum type_cmp ret; type *a, *b; int subchk = 1; if(!orig_a || !orig_b) return orig_a == orig_b ? TYPE_EQUAL : TYPE_NOT_EQUAL; a = type_skip_all(orig_a); b = type_skip_all(orig_b); /* array/func decay takes care of any array->ptr checks */ if(a->type != b->type){ /* allow _Bool <- pointer */ if(type_is_primitive(a, type__Bool) && type_is_ptr(b)) return TYPE_CONVERTIBLE_IMPLICIT; /* allow int <-> ptr (or block) */ if((type_is_ptr_or_block(a) && type_is_integral(b)) || (type_is_ptr_or_block(b) && type_is_integral(a))) { return TYPE_CONVERTIBLE_EXPLICIT; } /* allow void <- anything */ if(type_is_void(a)) return TYPE_CONVERTIBLE_IMPLICIT; /* allow block <-> fnptr */ if((type_is_fptr(a) && type_is(b, type_block)) || (type_is_fptr(b) && type_is(a, type_block))) { return TYPE_CONVERTIBLE_EXPLICIT; } return TYPE_NOT_EQUAL; } switch(a->type){ case type_auto: ICE("__auto_type"); case type_btype: subchk = 0; ret = btype_cmp(a->bits.type, b->bits.type); break; case type_array: if(a->bits.array.is_vla || b->bits.array.is_vla){ /* fine, pretend they're equal even if different expressions */ ret = TYPE_EQUAL_TYPEDEF; }else{ const int a_has_sz = !!a->bits.array.size; const int b_has_sz = !!b->bits.array.size; if(a_has_sz && b_has_sz){ integral_t av = const_fold_val_i(a->bits.array.size); integral_t bv = const_fold_val_i(b->bits.array.size); if(av != bv) return TYPE_NOT_EQUAL; }else if(a_has_sz != b_has_sz){ if((opts & TYPE_CMP_ALLOW_TENATIVE_ARRAY) == 0) return TYPE_NOT_EQUAL; } } /* next */ break; case type_block: case type_ptr: break; case type_cast: case type_tdef: case type_attr: case type_where: ICE("should've been skipped"); case type_func: switch(funcargs_cmp(a->bits.func.args, b->bits.func.args)){ case FUNCARGS_EXACT_EQUAL: case FUNCARGS_IMPLICIT_CONV: break; default: /* "void (int)" and "void (int, int)" aren't equal, * but a cast can soon fix it */ return TYPE_CONVERTIBLE_EXPLICIT; } break; } if(subchk) ret = type_cmp_r(a->ref, b->ref, opts); if(ret == TYPE_NOT_EQUAL && a->type == type_func) { /* "int (int)" and "void (int)" aren't equal - but castable */ ret = TYPE_CONVERTIBLE_EXPLICIT; } if(ret == TYPE_NOT_EQUAL && a->type == type_ptr && fopt_mode & FOPT_PLAN9_EXTENSIONS) { /* allow b to be an anonymous member of a, if pointers */ struct_union_enum_st *a_sue = type_is_s_or_u(a), *b_sue = type_is_s_or_u(b); if(a_sue && b_sue /* already know they aren't equal */){ /* b_sue has an a_sue, * the implicit cast adjusts to return said a_sue */ if(struct_union_member_find_sue(b_sue, a_sue)) return TYPE_CONVERTIBLE_IMPLICIT; } } /* allow ptr <-> ptr */ if(ret == TYPE_NOT_EQUAL && type_is_ptr(a) && type_is_ptr(b)) ret = TYPE_CONVERTIBLE_EXPLICIT; /* char * and int * are explicitly conv., * even though char and int are implicit */ if(ret == TYPE_CONVERTIBLE_IMPLICIT && a->type == type_ptr) ret = TYPE_CONVERTIBLE_EXPLICIT; if(a->type == type_ptr || a->type == type_block){ switch(ret){ #define MAP(a, b) case a: ret = b; break MAP(TYPE_QUAL_ADD, TYPE_QUAL_POINTED_ADD); MAP(TYPE_QUAL_SUB, TYPE_QUAL_POINTED_SUB); MAP(TYPE_QUAL_POINTED_ADD, TYPE_QUAL_NESTED_CHANGE); MAP(TYPE_QUAL_POINTED_SUB, TYPE_QUAL_NESTED_CHANGE); #undef MAP default: break; } } if(ret & TYPE_EQUAL_ANY){ enum type_qualifier a_qual = type_qual(orig_a); enum type_qualifier b_qual = type_qual(orig_b); if(a_qual && b_qual){ switch(type_qual_cmp(a_qual, b_qual)){ case -1: /* a has more */ ret = TYPE_QUAL_ADD; break; case 1: /* b has more */ ret = TYPE_QUAL_SUB; break; } }else if(a_qual){ ret = TYPE_QUAL_ADD; }else if(b_qual){ ret = TYPE_QUAL_SUB; } /* else neither are casts */ } if(ret == TYPE_EQUAL){ int at = orig_a->type == type_tdef; int bt = orig_b->type == type_tdef; if(at != bt){ /* one is a typedef */ ret = TYPE_EQUAL_TYPEDEF; }else if(at){ /* both typedefs */ if(orig_a->bits.tdef.decl != orig_b->bits.tdef.decl){ ret = TYPE_EQUAL_TYPEDEF; } } /* else no typedefs */ } return ret; }
static void type_add_str( type *r, const char *spel, int *need_spc, char **bufp, int *sz, type *stop_at) { int need_paren; type *array_qual = NULL, *next_ty; if(!r){ /* reached the bottom/end - spel */ if(spel){ ADD_SPC(); BUF_ADD("%s", spel); *need_spc = 0; } return; } if(stop_at && r->tmp == stop_at){ type_add_str(r->tmp, spel, need_spc, bufp, sz, stop_at); return; } type_add_str_pre(r, &need_paren, need_spc, bufp, sz); next_ty = r->tmp; if(r->type == type_array && r->tmp && r->tmp->type == type_cast){ array_qual = r->tmp; next_ty = array_qual->tmp; } type_add_str(next_ty, spel, need_spc, bufp, sz, stop_at); switch(r->type){ case type_auto: ICE("__auto_type"); case type_tdef: /* tdef "aka: %s" handled elsewhere */ case type_attr: /* attribute not handled here */ case type_btype: case type_cast: case type_where: /**/ case type_block: break; case type_func: type_add_funcargs(r->bits.func.args, need_spc, bufp, sz); break; case type_ptr: #ifdef SHOW_DECAYED_ARRAYS if(!r->bits.ptr.size) #endif break; /* fall */ case type_array: { const char *sz_space = ""; BUF_ADD("["); if(r->bits.array.is_vla == 0 && r->bits.array.is_static){ BUF_ADD("static"); sz_space = " "; } if(array_qual){ BUF_ADD("%s%s", sz_space, type_qual_to_str(array_qual->bits.cast.qual, 0)); sz_space = " "; } switch(r->bits.array.is_vla){ case 0: if(r->bits.array.size){ BUF_ADD( "%s%" NUMERIC_FMT_D, sz_space, const_fold_val_i(r->bits.array.size)); } break; case VLA: BUF_ADD("vla"); break; case VLA_STAR: BUF_ADD("*"); break; } BUF_ADD("]"); break; } } if(need_paren) BUF_ADD(")"); #undef IS_PTR }