void gen_expr_funcall(expr *e, symtable *stab) { const char *const fname = e->expr->spel; expr **iter; int nargs = 0; if(fopt_mode & FOPT_ENABLE_ASM && fname && !strcmp(fname, ASM_INLINE_FNAME)){ const char *str; expr *arg1; int i; if(!e->funcargs || e->funcargs[1] || !expr_kind(e->funcargs[0], addr)) die_at(&e->where, "invalid __asm__ arguments"); arg1 = e->funcargs[0]; str = arg1->array_store->data.str; for(i = 0; i < arg1->array_store->len - 1; i++){ char ch = str[i]; if(!isprint(ch) && !isspace(ch)) invalid: die_at(&arg1->where, "invalid __asm__ string (character %d)", ch); } if(str[i]) goto invalid; asm_temp(0, "; start manual __asm__"); fprintf(cc_out[SECTION_TEXT], "%s\n", arg1->array_store->data.str); asm_temp(0, "; end manual __asm__"); }else{ /* continue with normal funcall */ if(e->funcargs){ /* need to push on in reverse order */ for(iter = e->funcargs; *iter; iter++); for(iter--; iter >= e->funcargs; iter--){ gen_expr(*iter, stab); nargs++; } } if(e->sym && !e->sym->decl->decl_ptr && e->sym->decl->spel){ /* simple */ asm_temp(1, "call %s", e->sym->decl->spel); }else{ gen_expr(e->expr, stab); asm_temp(1, "pop rax ; function address"); asm_temp(1, "call rax ; duh"); } if(nargs) asm_temp(1, "add rsp, %d ; %d arg%s", nargs * platform_word_size(), nargs, nargs == 1 ? "" : "s"); asm_temp(1, "push rax ; ret"); } }
unsigned decl_size(decl *d) { if(type_is_void(d->ref)) die_at(&d->where, "%s is void", d->spel); if(!type_is(d->ref, type_func) && d->bits.var.field_width) die_at(&d->where, "can't take size of a bitfield"); return type_size(d->ref, &d->where); }
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_expr_addr(expr *e, symtable *stab) { if(e->bits.lbl.spel){ decl *in_func = symtab_func(stab); if(!in_func) die_at(&e->where, "address-of-label outside a function"); if(e->bits.lbl.static_ctx) in_func->bits.func.contains_static_label_addr = 1; (e->bits.lbl.label = symtab_label_find_or_new( stab, e->bits.lbl.spel, &e->where)) ->uses++; /* address of label - void * */ e->tree_type = type_ptr_to(type_nav_btype(cc1_type_nav, type_void)); }else{ /* if it's an identifier, act as a read */ fold_inc_writes_if_sym(e->lhs, stab); fold_expr_nodecay(e->lhs, stab); e->tree_type = type_ptr_to(e->lhs->tree_type); /* can address: lvalues, arrays and functions */ if(!expr_is_addressable(e->lhs)){ warn_at_print_error(&e->where, "can't take the address of %s (%s)", expr_str_friendly(e->lhs), type_to_str(e->lhs->tree_type)); fold_had_error = 1; return; } if(expr_kind(e->lhs, identifier)){ sym *sym = e->lhs->bits.ident.bits.ident.sym; if(sym){ decl *d = sym->decl; if((d->store & STORE_MASK_STORE) == store_register) die_at(&e->lhs->where, "can't take the address of register"); } } fold_check_expr(e->lhs, FOLD_CHK_ALLOW_VOID | FOLD_CHK_NO_BITFIELD, "address-of"); } }
static attribute *parse_attr_section(symtable *symtab, const char *ident) { /* __attribute__((section ("sectionname"))) */ attribute *da; char *func; size_t len, i; (void)symtab; (void)ident; EAT(token_open_paren); if(curtok != token_string) die_at(NULL, "string expected for section"); token_get_current_str(&func, &len, NULL, NULL); EAT(token_string); for(i = 0; i < len; i++) if(!isprint(func[i])) { if(i < len - 1 || func[i] != '\0') cc1_warn_at(NULL, attr_section_badchar, "character 0x%x detected in section", func[i]); break; } da = attribute_new(attr_section); da->bits.section = func; EAT(token_close_paren); return da; }
static attribute *parse_attr_cleanup(symtable *scope, const char *ident) { char *sp; where ident_loc; attribute *attr = NULL; struct symtab_entry ent; (void)ident; EAT(token_open_paren); if(curtok != token_identifier) die_at(NULL, "identifier expected for cleanup function"); where_cc1_current(&ident_loc); sp = token_current_spel(); EAT(token_identifier); if(symtab_search(scope, sp, NULL, &ent) && ent.type == SYMTAB_ENT_DECL) { attr = attribute_new(attr_cleanup); attr->bits.cleanup = ent.bits.decl; } else { warn_at_print_error(&ident_loc, "function '%s' not found", sp); fold_had_error = 1; } EAT(token_close_paren); return attr; }
void token_get_current_str( char **ps, size_t *pl, int *pwide, where *w) { extern char *currentstring; extern size_t currentstringlen; extern int currentstringwide; *ps = currentstring; if(pwide) *pwide = currentstringwide; else if(currentstringwide) die_at(NULL, "wide string not wanted"); if(w){ extern where currentstringwhere; memcpy_safe(w, ¤tstringwhere); } if(pl){ *pl = currentstringlen; }else{ char *p = memchr(currentstring, '\0', currentstringlen); if(p && p < currentstring + currentstringlen - 1) cc1_warn_at(NULL, str_contain_nul, "nul-character terminates string early (%s)", p + 1); } currentstring = NULL; currentstringlen = 0; }
void flow_fold(stmt_flow *flow, symtable **pstab) { if(flow){ decl **i; *pstab = flow->for_init_symtab; fold_shadow_dup_check_block_decls(*pstab); /* sanity check on _flow_ vars only */ for(i = symtab_decls(*pstab); i && *i; i++){ decl *const d = *i; switch((enum decl_storage)(d->store & STORE_MASK_STORE)){ case store_auto: case store_default: case store_register: break; default: die_at(&d->where, "%s variable in statement-initialisation", decl_store_to_str(d->store)); } /* block decls/for-init decls must be complete */ fold_check_decl_complete(d); if(d->bits.var.init.expr) FOLD_EXPR(d->bits.var.init.expr, *pstab); } } }
static void sentinel_check(where *w, expr *e, expr **args, const int variadic, const int nstdargs, symtable *stab) { #define ATTR_WARN_RET(w, ...) \ do{ cc1_warn_at(w, attr_sentinel, __VA_ARGS__); return; }while(0) attribute *attr = func_or_builtin_attr_present(e, attr_sentinel); int i, nvs; expr *sentinel; if(!attr) return; if(!variadic) return; /* warning emitted elsewhere, on the decl */ if(attr->bits.sentinel){ consty k; FOLD_EXPR(attr->bits.sentinel, stab); const_fold(attr->bits.sentinel, &k); if(k.type != CONST_NUM || !K_INTEGRAL(k.bits.num)) die_at(&attr->where, "sentinel attribute not reducible to integer constant"); i = k.bits.num.val.i; }else{ i = 0; } nvs = dynarray_count(args) - nstdargs; if(nvs == 0) ATTR_WARN_RET(w, "not enough variadic arguments for a sentinel"); UCC_ASSERT(nvs >= 0, "too few args"); if(i >= nvs) ATTR_WARN_RET(w, "sentinel index is not a variadic argument"); sentinel = args[(nstdargs + nvs - 1) - i]; /* must be of a pointer type, printf("%p\n", 0) is undefined */ if(!expr_is_null_ptr(sentinel, NULL_STRICT_ANY_PTR)) ATTR_WARN_RET(&sentinel->where, "sentinel argument expected (got %s)", type_to_str(sentinel->tree_type)); #undef ATTR_WARN_RET }
void fold_stmt_goto(stmt *s) { if(!symtab_func(s->symtab)) die_at(&s->where, "goto outside of a function"); if(s->expr){ FOLD_EXPR(s->expr, s->symtab); }else{ (s->bits.lbl.label = symtab_label_find_or_new( s->symtab, s->bits.lbl.spel, &s->where)) ->uses++; dynarray_add(&s->bits.lbl.label->jumpers, s); } }
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); }
void fold_expr_funcall(expr *e, symtable *stab) { decl *df; funcargs *args_exp; if(expr_kind(e->expr, identifier) && e->expr->spel){ char *const sp = e->expr->spel; e->sym = symtab_search(stab, sp); if(!e->sym){ df = decl_new_where(&e->where); df->type->primitive = type_int; df->type->spec |= spec_extern; cc1_warn_at(&e->where, 0, WARN_IMPLICIT_FUNC, "implicit declaration of function \"%s\"", sp); df->spel = sp; df->funcargs = funcargs_new(); if(e->funcargs) /* set up the funcargs as if it's "x()" - i.e. any args */ function_empty_args(df->funcargs); e->sym = symtab_add(symtab_root(stab), df, sym_global, SYMTAB_WITH_SYM, SYMTAB_PREPEND); }else{ df = e->sym->decl; } fold_expr(e->expr, stab); }else{ fold_expr(e->expr, stab); /* * convert int (*)() to remove the deref */ if(decl_is_func_ptr(e->expr->tree_type)){ /* XXX: memleak */ e->expr = e->expr->lhs; fprintf(stderr, "FUNCPTR\n"); }else{ fprintf(stderr, "decl %s\n", decl_to_str(e->expr->tree_type)); } df = e->expr->tree_type; if(!decl_is_callable(df)){ die_at(&e->expr->where, "expression %s (%s) not callable", e->expr->f_str(), decl_to_str(df)); } } e->tree_type = decl_copy(df); /* * int (*x)(); * (*x)(); * evaluates to tree_type = int; */ decl_func_deref(e->tree_type); if(e->funcargs){ expr **iter; for(iter = e->funcargs; *iter; iter++) fold_expr(*iter, stab); } /* func count comparison, only if the func has arg-decls, or the func is f(void) */ args_exp = decl_funcargs(e->tree_type); UCC_ASSERT(args_exp, "no funcargs for decl %s", df->spel); if(args_exp->arglist || args_exp->args_void){ expr **iter_arg; decl **iter_decl; int count_decl, count_arg; count_decl = count_arg = 0; for(iter_arg = e->funcargs; iter_arg && *iter_arg; iter_arg++, count_arg++); for(iter_decl = args_exp->arglist; iter_decl && *iter_decl; iter_decl++, count_decl++); if(count_decl != count_arg && (args_exp->variadic ? count_arg < count_decl : 1)){ die_at(&e->where, "too %s arguments to function %s (got %d, need %d)", count_arg > count_decl ? "many" : "few", df->spel, count_arg, count_decl); } if(e->funcargs){ funcargs *argument_decls = funcargs_new(); for(iter_arg = e->funcargs; *iter_arg; iter_arg++) dynarray_add((void ***)&argument_decls->arglist, (*iter_arg)->tree_type); fold_funcargs_equal(args_exp, argument_decls, 1, &e->where, "argument", df->spel); funcargs_free(argument_decls, 0); } } }
void fold_expr_struct(expr *e, symtable *stab) { /* * lhs = any ptr-to-struct expr * rhs = struct member ident */ const int ptr_expect = !e->expr_is_st_dot; struct_union_enum_st *sue; char *spel; fold_expr_no_decay(e->lhs, stab); /* don't fold the rhs - just a member name */ if(e->rhs){ UCC_ASSERT(expr_kind(e->rhs, identifier), "struct/union member not identifier (%s)", e->rhs->f_str()); UCC_ASSERT(!e->bits.struct_mem.d, "already have a struct-member"); spel = e->rhs->bits.ident.spel; }else{ UCC_ASSERT(e->bits.struct_mem.d, "no member specified already?"); spel = NULL; } /* we access a struct, of the right ptr depth */ { type *r = e->lhs->tree_type; if(ptr_expect){ type *rtest = type_is(r, type_ptr); if(!rtest && !(rtest = type_is(r, type_array))) goto err; r = rtest->ref; /* safe - rtest is an array */ } if(!(sue = type_is_s_or_u(r))){ err: die_at(&e->lhs->where, "'%s' (%s-expr) is not a %sstruct or union (member %s)", type_to_str(e->lhs->tree_type), e->lhs->f_str(), ptr_expect ? "pointer to " : "", spel); } } if(!sue_complete(sue)){ char wbuf[WHERE_BUF_SIZ]; die_at(&e->lhs->where, "%s incomplete type (%s)\n" "%s: note: forward declared here", ptr_expect ? "dereferencing pointer to" : "accessing member of", type_to_str(e->lhs->tree_type), where_str_r(wbuf, &sue->where)); } if(spel){ /* found the struct, find the member */ decl *d_mem = struct_union_member_find(sue, spel, &e->bits.struct_mem.extra_off, NULL); if(!d_mem) die_at(&e->where, "%s %s has no member named \"%s\"", sue_str(sue), sue->spel, spel); e->rhs->tree_type = (e->bits.struct_mem.d = d_mem)->ref; }/* else already have the member */ /* * if it's a.b, convert to (&a)->b for asm gen * e = { lhs = "a", rhs = "b", type = dot } * e = { * type = ptr, * lhs = { cast<void *>, expr = { expr = "a", type = addr } }, * rhs = "b", * } */ if(!ptr_expect){ expr *cast, *addr; addr = expr_new_addr(e->lhs); cast = expr_new_cast(addr, type_ptr_to(type_nav_btype(cc1_type_nav, type_void)), 1); e->lhs = cast; e->expr_is_st_dot = 0; FOLD_EXPR(e->lhs, stab); } /* pull qualifiers from the struct to the member */ e->tree_type = type_qualify( e->bits.struct_mem.d->ref, type_qual(e->lhs->tree_type)); }