Beispiel #1
0
const out_val *gen_expr_if(const expr *e, out_ctx *octx)
{
	out_blk *landing = out_blk_new(octx, "if_end"),
	        *blk_lhs = out_blk_new(octx, "if_lhs"),
	        *blk_rhs = out_blk_new(octx, "if_rhs");
	const out_val *cond = gen_expr(e->expr, octx);

	if(!e->lhs)
		out_val_retain(octx, cond);

	out_ctrl_branch(octx, cond, blk_lhs, blk_rhs);

	out_current_blk(octx, blk_lhs);
	{
		out_ctrl_transfer(octx, landing,
				e->lhs ? gen_expr(e->lhs, octx) : cond,
				&blk_lhs);
	}

	out_current_blk(octx, blk_rhs);
	{
		out_ctrl_transfer(octx, landing,
				gen_expr(e->rhs, octx),
				&blk_rhs);
	}

	out_current_blk(octx, landing);
	return out_ctrl_merge(octx, blk_lhs, blk_rhs);
}
const out_val *gen_expr_assign_compound(const expr *e, out_ctx *octx)
{
	/* int += float
	 * lea int, cast up to float, add, cast down to int, store
	 */
	const out_val *saved_post = NULL, *addr_lhs, *rhs, *lhs, *result;

	addr_lhs = gen_expr(e->lhs, octx);

	out_val_retain(octx, addr_lhs); /* 2 */

	if(e->assign_is_post){
		out_val_retain(octx, addr_lhs); /* 3 */
		saved_post = out_deref(octx, addr_lhs); /* addr_lhs=2, saved_post=1 */
	}

	/* delay the dereference until after generating rhs.
	 * this is fine, += etc aren't sequence points
	 */

	rhs = gen_expr(e->rhs, octx);

	/* here's the delayed dereference */
	lhs = out_deref(octx, addr_lhs); /* addr_lhs=1 */
	if(e->bits.compoundop.upcast_ty)
		lhs = out_cast(octx, lhs, e->bits.compoundop.upcast_ty, /*normalise_bool:*/1);

	result = out_op(octx, e->bits.compoundop.op, lhs, rhs);
	gen_op_trapv(e->tree_type, &result, octx, e->bits.compoundop.op);

	if(e->bits.compoundop.upcast_ty) /* need to cast back down to store */
		result = out_cast(octx, result, e->tree_type, /*normalise_bool:*/1);

	if(!saved_post)
		out_val_retain(octx, result);
	out_store(octx, addr_lhs, result);

	if(!saved_post)
		return result;
	return saved_post;
}
Beispiel #3
0
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);
	}
Beispiel #4
0
const out_val *gen_expr_assign(const expr *e, out_ctx *octx)
{
	const out_val *val, *store;

	UCC_ASSERT(!e->assign_is_post, "assign_is_post set for non-compound assign");

	assert(!type_is_s_or_u(e->tree_type));

	val = gen_expr(e->rhs, octx);
	store = gen_expr(e->lhs, octx);
	out_val_retain(octx, store);

	out_store(octx, store, val);

	/* re-read from the store,
	 * e.g. if the value has undergone bitfield truncation */
	return out_deref(octx, store);
}
Beispiel #5
0
static void sanitize_assert_order(
    const out_val *test, enum op_type op, long limit,
    type *op_type, out_ctx *octx, const char *desc)
{
    const out_val *vlimit = out_new_l(
                                octx,
                                op_type,
                                limit);

    const out_val *lengthened_test = out_change_type(
                                         octx,
                                         out_val_retain(octx, test),
                                         op_type);

    const out_val *cmp = out_op(octx, op, lengthened_test, vlimit);

    sanitize_assert(cmp, octx, desc);
}
Beispiel #6
0
static const out_val *vla_cached_size(type *const qual_t, out_ctx *octx)
{
	type *t = type_skip_all(qual_t);
	struct cc1_out_ctx **cc1_octx = cc1_out_ctx(octx);
	dynmap *vlamap;

	if(*cc1_octx && (vlamap = (*cc1_octx)->vlamap)){
		const out_val *stack_off = dynmap_get(type *, const out_val *, vlamap, t);

		if(stack_off){
			out_comment(octx, "vla saved size for %s", type_to_str(qual_t));

			out_val_retain(octx, stack_off);
			return out_deref(octx, stack_off);
		}
	}

	return NULL;
}
Beispiel #7
0
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]);
}