コード例 #1
0
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");
		}
	}
}
コード例 #2
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");
	}
}
コード例 #3
0
ファイル: expr_if.c プロジェクト: 8l/ucc-c-compiler
static type *pointer_to_qualified(type *base, type *lhs, type *rhs)
{
	enum type_qualifier qlhs = lhs ? type_qual(type_next(lhs)) : qual_none;
	enum type_qualifier qrhs = rhs ? type_qual(type_next(rhs)) : qual_none;

	return type_ptr_to(type_qualify(base, qlhs | qrhs));
}
コード例 #4
0
ファイル: sanitize.c プロジェクト: 8l/ucc-c-compiler
static void sanitize_assert(const out_val *cond, out_ctx *octx, const char *desc)
{
    out_blk *land = out_blk_new(octx, "san_end");
    out_blk *blk_undef = out_blk_new(octx, "san_bad");

    out_ctrl_branch(octx,
                    cond,
                    land,
                    blk_undef);

    out_current_blk(octx, blk_undef);
    out_comment(octx, "sanitizer for %s", desc);
    if(cc1_sanitize_handler_fn) {
        type *voidty = type_nav_btype(cc1_type_nav, type_void);
        funcargs *args = funcargs_new();
        type *fnty_noptr = type_func_of(voidty, args, NULL);
        type *fnty_ptr = type_ptr_to(fnty_noptr);
        char *mangled = func_mangle(cc1_sanitize_handler_fn, fnty_noptr);

        const out_val *fn = out_new_lbl(octx, fnty_ptr, mangled, 0);

        out_val_release(octx, out_call(octx, fn, NULL, fnty_ptr));

        if(mangled != cc1_sanitize_handler_fn)
            free(mangled);
    }
    out_ctrl_end_undefined(octx);

    out_current_blk(octx, land);
}
コード例 #5
0
ファイル: stack.c プロジェクト: 8l/ucc-c-compiler
const out_val *out_aalloc(
		out_ctx *octx, unsigned sz, unsigned align, type *in_ty)
{
	type *ty = type_ptr_to(in_ty
		? in_ty : type_nav_btype(cc1_type_nav, type_nchar));

	align_sz(&sz, align);

	/* packing takes care of everything */
	pack_next(&octx->cur_stack_sz, NULL, sz, align);

	v_set_cur_stack_sz(octx, octx->cur_stack_sz);

	return v_new_bp3_below(octx, NULL, ty, octx->cur_stack_sz);
}
コード例 #6
0
ファイル: vla.c プロジェクト: bobrippling/ucc-c-compiler
static void vla_cache_size(
		type *const qual_t, out_ctx *octx,
		type *const arith_ty,
		const out_val *sz,
		const out_val *stack_ent)
{
	type *ptrsizety = type_ptr_to(arith_ty);
	dynmap **pvlamap, *vlamap;
	struct cc1_out_ctx *cc1_octx;

	/* keep the caller's retain */
	out_val_retain(octx, stack_ent);

	stack_ent = out_change_type(octx, stack_ent, ptrsizety);
	out_val_retain(octx, stack_ent); /* retain for the vlamap */
	out_store(octx, stack_ent, sz);

	cc1_octx = cc1_out_ctx_or_new(octx);

	vlamap = *(pvlamap = &cc1_octx->vlamap);
	if(!vlamap){
		/* type * => out_val const* */
		vlamap = *pvlamap = dynmap_new(type *, NULL, type_hash);
	}
コード例 #7
0
ファイル: op.c プロジェクト: 8l/ucc-c-compiler
static void apply_ptr_step(
		out_ctx *octx,
		const out_val **lhs, const out_val **rhs,
		const out_val **div_out)
{
	int l_ptr = !!type_is((*lhs)->t, type_ptr);
	int r_ptr = !!type_is((*rhs)->t, type_ptr);
	int ptr_step;

	if(!l_ptr && !r_ptr)
		return;

	ptr_step = calc_ptr_step((l_ptr ? *lhs : *rhs)->t);

	if(l_ptr ^ r_ptr){
		/* ptr +/- int, adjust the non-ptr by sizeof *ptr */
		const out_val **incdec = (l_ptr ? rhs : lhs);
		out_val *mut_incdec;

		*incdec = mut_incdec = v_dup_or_reuse(octx, *incdec, (*incdec)->t);

		switch(mut_incdec->type){
			case V_CONST_I:
				if(ptr_step == -1){
					*incdec = out_op(octx, op_multiply,
							*incdec,
							vla_size(
								type_next((l_ptr ? *lhs : *rhs)->t),
								octx));

					mut_incdec = NULL; /* safety */
				}else{
					mut_incdec->bits.val_i *= ptr_step;
				}
				break;

			case V_CONST_F:
				assert(0 && "float pointer inc?");

			case V_LBL:
			case V_FLAG:
			case V_REG_SPILT:
				assert(mut_incdec->retains == 1);
				*incdec = (out_val *)v_to_reg(octx, *incdec);

			case V_REG:
			{
				const out_val *n;
				if(ptr_step == -1){
					n = vla_size(
							type_next((l_ptr ? *lhs : *rhs)->t),
							octx);
				}else{
					n = out_new_l(
						octx,
						type_nav_btype(cc1_type_nav, type_intptr_t),
						ptr_step);
				}

				*incdec = (out_val *)out_op(octx, op_multiply, *incdec, n);
				break;
			}
		}

	}else if(l_ptr && r_ptr){
		/* difference - divide afterwards */
		if(ptr_step == -1){
			*div_out = vla_size(type_next((*lhs)->t), octx);
		}else{
			*div_out = out_new_l(octx,
					type_ptr_to(type_nav_btype(cc1_type_nav, type_void)),
					ptr_step);
		}
	}
}
コード例 #8
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));
}
コード例 #9
0
ファイル: impl.c プロジェクト: 8l/ucc-c-compiler
static void impl_overlay_mem_reg(
		out_ctx *octx,
		unsigned memsz, unsigned nregs,
		struct vreg regs[], int mem2reg,
		const out_val *ptr)
{
	const unsigned pws = platform_word_size();
	struct vreg *cur_reg = regs;
	unsigned reg_i = 0;

	if(memsz == 0){
		out_val_release(octx, ptr);
		return;
	}

	UCC_ASSERT(
			nregs * pws >= memsz,
			"not enough registers for memory overlay");

	out_comment(octx,
			"overlay, %s2%s(%u)",
			mem2reg ? "mem" : "reg",
			mem2reg ? "reg" : "mem",
			memsz);

	if(!mem2reg){
		/* reserve all registers so we don't accidentally wipe before the spill */
		for(reg_i = 0; reg_i < nregs; reg_i++)
			v_reserve_reg(octx, &regs[reg_i]);
	}

	for(;; cur_reg++, reg_i++){
		/* read/write whatever size is required */
		type *this_ty;
		unsigned this_sz;

		if(cur_reg->is_float){
			UCC_ASSERT(memsz >= 4, "float for memsz %u?", memsz);

			this_ty = type_nav_btype(
					cc1_type_nav,
					memsz > 4 ? type_double : type_float);

		}else{
			this_ty = type_nav_MAX_FOR(cc1_type_nav, memsz);
		}
		this_sz = type_size(this_ty, NULL);

		UCC_ASSERT(this_sz <= memsz, "reading/writing too much memory");

		ptr = out_change_type(octx, ptr, type_ptr_to(this_ty));

		out_val_retain(octx, ptr);

		if(mem2reg){
			const out_val *fetched;

			/* can use impl_deref, as we have a register already,
			 * and know that the memory is an lvalue and not a bitfield
			 *
			 * this means we can load straight into the desired register
			 */
			fetched = impl_deref(octx, ptr, cur_reg);

			UCC_ASSERT(reg_i < nregs, "reg oob");

			if(fetched->type != V_REG || !vreg_eq(&fetched->bits.regoff.reg, cur_reg)){
				/* move to register */
				v_freeup_reg(octx, cur_reg);
				fetched = v_to_reg_given(octx, fetched, cur_reg);
			}
			out_flush_volatile(octx, fetched);
			v_reserve_reg(octx, cur_reg); /* prevent changes */

		}else{
			const out_val *vreg = v_new_reg(octx, NULL, this_ty, cur_reg);

			out_store(octx, ptr, vreg);
		}

		memsz -= this_sz;

		/* early termination */
		if(memsz == 0)
			break;

		/* increment our memory pointer */
		ptr = out_change_type(
				octx,
				ptr,
				type_ptr_to(type_nav_btype(cc1_type_nav, type_uchar)));

		ptr = out_op(octx, op_plus,
				ptr,
				out_new_l(
					octx,
					type_nav_btype(cc1_type_nav, type_intptr_t),
					pws));
	}

	out_val_release(octx, ptr);

	/* done, unreserve all registers */
	for(reg_i = 0; reg_i < nregs; reg_i++)
		v_unreserve_reg(octx, &regs[reg_i]);
}
コード例 #10
0
ファイル: expr_if.c プロジェクト: guoguocat/ucc-c-compiler
void fold_expr_if(expr *e, symtable *stab)
{
	consty konst;
	type *tt_l, *tt_r;

	FOLD_EXPR(e->expr, stab);
	const_fold(e->expr, &konst);

	fold_check_expr(e->expr, FOLD_CHK_NO_ST_UN, "if-expr");

	if(e->lhs){
		FOLD_EXPR(e->lhs, stab);
		fold_check_expr(e->lhs,
				FOLD_CHK_NO_ST_UN | FOLD_CHK_ALLOW_VOID,
				"if-lhs");
	}

	FOLD_EXPR(e->rhs, stab);
	fold_check_expr(e->rhs,
			FOLD_CHK_NO_ST_UN | FOLD_CHK_ALLOW_VOID,
			"if-rhs");


	/*

	Arithmetic                             Arithmetic                           Arithmetic type after usual arithmetic conversions
	// Structure or union type                Compatible structure or union type   Structure or union type with all the qualifiers on both operands
	void                                   void                                 void
	Pointer to compatible type             Pointer to compatible type           Pointer to type with all the qualifiers specified for the type
	Pointer to type                        NULL pointer (the constant 0)        Pointer to type
	Pointer to object or incomplete type   Pointer to void                      Pointer to void with all the qualifiers specified for the type

	GCC and Clang seem to relax the last rule:
		a) resolve if either is any pointer, not just (void *)
	  b) resolve to a pointer to the incomplete-type
	*/

	tt_l = (e->lhs ? e->lhs : e->expr)->tree_type;
	tt_r = e->rhs->tree_type;

	if(type_is_integral(tt_l) && type_is_integral(tt_r)){
		expr **middle_op = e->lhs ? &e->lhs : &e->expr;

		expr_check_sign("?:", *middle_op, e->rhs, &e->where);

		e->tree_type = op_promote_types(
				op_unknown,
				middle_op, &e->rhs, &e->where, stab);

	}else if(type_is_void(tt_l) || type_is_void(tt_r)){
		e->tree_type = type_nav_btype(cc1_type_nav, type_void);

	}else if(type_cmp(tt_l, tt_r, 0) & TYPE_EQUAL_ANY){
		/* pointer to 'compatible' type */
		e->tree_type = type_qualify(tt_l,
				type_qual(tt_l) | type_qual(tt_r));

	}else{
		/* brace yourself. */
		int l_ptr_null = expr_is_null_ptr(
				e->lhs ? e->lhs : e->expr, NULL_STRICT_VOID_PTR);

		int r_ptr_null = expr_is_null_ptr(e->rhs, NULL_STRICT_VOID_PTR);

		int l_complete = !l_ptr_null && type_is_complete(tt_l);
		int r_complete = !r_ptr_null && type_is_complete(tt_r);

		if((l_complete && r_ptr_null) || (r_complete && l_ptr_null)){
			e->tree_type = l_ptr_null ? tt_r : tt_l;

		}else{
			int l_ptr = l_ptr_null || type_is(tt_l, type_ptr);
			int r_ptr = r_ptr_null || type_is(tt_r, type_ptr);

			if(l_ptr || r_ptr){
				fold_type_chk_warn(
						tt_l, tt_r, &e->where, "?: pointer type mismatch");

				/* qualified void * */
				e->tree_type = type_qualify(
						type_ptr_to(type_nav_btype(cc1_type_nav, type_void)),
						type_qual(tt_l) | type_qual(tt_r));

			}else{
				char buf[TYPE_STATIC_BUFSIZ];

				warn_at(&e->where, "conditional type mismatch (%s vs %s)",
						type_to_str(tt_l), type_to_str_r(buf, tt_r));

				e->tree_type = type_nav_btype(cc1_type_nav, type_void);
			}
		}
	}

	e->freestanding = (e->lhs ? e->lhs : e->expr)->freestanding || e->rhs->freestanding;
}