Exemple #1
0
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
   and 'long long' cases. */
void gen_cvt_itof(int t)
{
    gv(RC_ST0);
    if (t == VT_FLOAT)
        out_op(IL_OP_CONV_R4);
    else
        out_op(IL_OP_CONV_R8);
}
Exemple #2
0
/* convert from one floating point type to another */
void gen_cvt_ftof(int t)
{
    gv(RC_ST0);
    if (t == VT_FLOAT) {
        out_op(IL_OP_CONV_R4);
    } else {
        out_op(IL_OP_CONV_R8);
    }
}
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");
		}
	}
}
Exemple #4
0
/* XXX: handle long long case */
void gen_cvt_ftoi(int t)
{
    gv(RC_ST0);
    switch(t) {
    case VT_INT | VT_UNSIGNED:
        out_op(IL_OP_CONV_U4);
        break;
    case VT_LLONG:
        out_op(IL_OP_CONV_I8);
        break;
    case VT_LLONG | VT_UNSIGNED:
        out_op(IL_OP_CONV_U8);
        break;
    default:
        out_op(IL_OP_CONV_I4);
        break;
    }
}
Exemple #5
0
void v_stack_adj(out_ctx *octx, v_stackt amt, int sub)
{
	out_flush_volatile(
			octx,
			out_op(
				octx, sub ? op_minus : op_plus,
				v_new_sp(octx, NULL),
				out_new_l(
					octx,
					type_nav_btype(cc1_type_nav, type_intptr_t),
					amt)));
}
Exemple #6
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);
}
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;
}
Exemple #8
0
/* store register 'r' in lvalue 'v' */
void store(int r, SValue *sv)
{
    int v, fc, ft;

    v = sv->r & VT_VALMASK;
    fc = sv->c.i;
    ft = sv->t;
    if (v == VT_LOCAL) {
        if (fc >= ARG_BASE) {
            fc -= ARG_BASE;
            /* XXX: check IL arg store semantics */
            if (fc <= 0xff) {
                out_opb(IL_OP_STARG_S, fc);
            } else {
                out_opi(IL_OP_STARG, fc);
            }
        } else {
            if (fc >= 0 && fc <= 4) {
                out_op(IL_OP_STLOC_0 + fc);
            } else if (fc <= 0xff) {
                out_opb(IL_OP_STLOC_S, fc);
            } else {
                out_opi(IL_OP_STLOC, fc);
            }
        }
    } else if (v == VT_CONST) {
        /* XXX: handle globals */
        out_opi(IL_OP_STSFLD, 0);
    } else {
        if ((ft & VT_BTYPE) == VT_FLOAT)
            out_op(IL_OP_STIND_R4);
        else if ((ft & VT_BTYPE) == VT_DOUBLE)
            out_op(IL_OP_STIND_R8);
        else if ((ft & VT_BTYPE) == VT_LDOUBLE)
            out_op(IL_OP_STIND_R8);
        else if ((ft & VT_BTYPE) == VT_BYTE)
            out_op(IL_OP_STIND_I1);
        else if ((ft & VT_BTYPE) == VT_SHORT)
            out_op(IL_OP_STIND_I2);
        else
            out_op(IL_OP_STIND_I4);
    }
}
void gen_expr_assign_compound(expr *e)
{
	/* int += float
	 * lea int, cast up to float, add, cast down to int, store
	 */
	lea_expr(e->bits.compound_upcast ? expr_cast_child(e->lhs) : e->lhs);

	if(e->assign_is_post){
		out_dup();
		out_deref();
		out_flush_volatile();
		out_swap();
		out_comment("saved for compound op");
	}

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

	gen_expr(e->rhs);

	/* here's the delayed dereference */
	out_swap();
	out_deref();
	if(e->bits.compound_upcast)
		out_cast(e->lhs->tree_type, /*normalise_bool:*/1);
	out_swap();

	out_op(e->op);

	if(e->bits.compound_upcast) /* need to cast back down to store */
		out_cast(e->tree_type, /*normalise_bool:*/1);

	out_store();

	if(e->assign_is_post)
		out_pop();
}
Exemple #10
0
/**
 * 函数名:out_ic
 * 作者:ao
 * 功能:将中间代码打印至文件ir.txt
 */
int out_ic() {
    ics_now = intercodes;
    while(ics_now != NULL) {
        switch(ics_now->code->kind) {
            case 0: printf("FUNCTION %s\n",ics_now->code->u.func_d.name);break;
            case 1: {
                printf("PARAM ");
                out_op(ics_now->code->u.param.param);
                printf("\n");
                break;
            }
            case 2: {
                out_op(ics_now->code->u.func_c.reop);
                printf(" := CALL %s\n",ics_now->code->u.func_c.name);
            }
            case 3: {
                printf("DEC ");
                out_op(ics_now->code->u.dec.var);
                printf(" %d\n",ics_now->code->u.dec.size);
                break;
            }
            case 4: {
                printf("ARG ");
                out_op(ics_now->code->u.arg.arg);
                printf("\n");
                break;
            }
            case 5: {
                out_op(ics_now->code->u.assign.left);
                printf(" := ");
                out_op(ics_now->code->u.assign.right);
                printf("\n");
                break;
            }
            case 6: {
                out_op(ics_now->code->u.relop.result);
                printf(" := ");
                out_op(ics_now->code->u.relop.left);
                printf(" %s ",ics_now->code->u.relop.r_kind);
                out_op(ics_now->code->u.relop.right);
                printf("\n");
                break;
            } 
            case 7: {
                out_op(ics_now->code->u.binop.result);
                printf(" := ");
                out_op(ics_now->code->u.binop.op1);
                printf(" %s ",ics_now->code->u.binop.o_kind);
                out_op(ics_now->code->u.binop.op2);
                printf("\n");
                break;
            }
            case 8: {
                out_op(ics_now->code->u.notop.result);
                printf(" := !");
                out_op(ics_now->code->u.notop.op);
                printf("\n");
                break;
            }
            case 9: {
                printf("RETURN ");
                out_op(ics_now->code->u.retop.result);
                printf("\n");
                break;
            }
            case 10: {
                printf("IF ");
                out_op(ics_now->code->u.ifop.relop);
                printf(" GOTO ");
                out_op(ics_now->code->u.ifop.label);
                printf("\n");
                break;
            }
            case 11: {
                printf("LABEL ");
                out_op(ics_now->code->u.label.label);
                printf(" :\n");
                break;
            }
            case 12: {
                printf("GOTO ");
                out_op(ics_now->code->u.gtop.gtop);
                printf("\n");
                break;
            }
        }
        ics_now = ics_now->next;
    }
    return 1;
}
Exemple #11
0
const out_val *out_op(
		out_ctx *octx, enum op_type binop,
		const out_val *lhs, const out_val *rhs)
{
	const out_val *div = NULL;
	const out_val *vconst = NULL, *vregp_or_lbl = NULL;
	const out_val *result;
	const out_val *decay_except[] = { lhs, rhs, NULL };

	v_decay_flags_except(octx, decay_except); /* an op instruction may change cpu flags */

	fill_if_type(lhs, &vconst, &vregp_or_lbl);
	fill_if_type(rhs, &vconst, &vregp_or_lbl);

	/* check for adding or subtracting to stack */
	if(vconst && vregp_or_lbl){
		result = try_mem_offset(octx, binop, vconst, vregp_or_lbl, rhs);
		if(result)
			return result;
	}

	if(vconst && const_is_noop(binop, vconst, vconst == lhs))
		return consume_one(octx, vconst == lhs ? rhs : lhs, lhs, rhs);

	/* constant folding */
	if(vconst && (fopt_mode & FOPT_CONST_FOLD)){
		const out_val *oconst = (vconst == lhs ? rhs : lhs);

		if(oconst->type == V_CONST_I){
			int step_l = calc_ptr_step(lhs->t);
			int step_r = calc_ptr_step(rhs->t);
			out_val *consted;

			/* currently we bail if something like (short *)0 + 2
			 * is attempted */
			if(step_l == 1 && step_r == 1){
				consted = try_const_fold(octx, binop, lhs, rhs);
				if(consted)
					return consted;
			}
		}
	}

	switch(binop){
		case op_plus:
		case op_minus:
			apply_ptr_step(octx, &lhs, &rhs, &div);
			break;
		case op_multiply:
		case op_divide:
			if(vconst && (fopt_mode & FOPT_TRAPV) == 0)
				try_shift_conv(octx, &binop, &lhs, &rhs);
			break;
		default:
			break;
	}

	result = impl_op(octx, binop, lhs, rhs);

	if(div)
		result = out_op(octx, op_divide, result, div);

	return result;
}
Exemple #12
0
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);
		}
	}
}
Exemple #13
0
/* generate an integer binary operation */
void gen_opi(int op)
{
    gv2(RC_ST1, RC_ST0);
    switch(op) {
    case '+':
        out_op(IL_OP_ADD);
        goto std_op;
    case '-':
        out_op(IL_OP_SUB);
        goto std_op;
    case '&':
        out_op(IL_OP_AND);
        goto std_op;
    case '^':
        out_op(IL_OP_XOR);
        goto std_op;
    case '|':
        out_op(IL_OP_OR);
        goto std_op;
    case '*':
        out_op(IL_OP_MUL);
        goto std_op;
    case TOK_SHL:
        out_op(IL_OP_SHL);
        goto std_op;
    case TOK_SHR:
        out_op(IL_OP_SHR_UN);
        goto std_op;
    case TOK_SAR:
        out_op(IL_OP_SHR);
        goto std_op;
    case '/':
    case TOK_PDIV:
        out_op(IL_OP_DIV);
        goto std_op;
    case TOK_UDIV:
        out_op(IL_OP_DIV_UN);
        goto std_op;
    case '%':
        out_op(IL_OP_REM);
        goto std_op;
    case TOK_UMOD:
        out_op(IL_OP_REM_UN);
    std_op:
        vtop--;
        vtop[0].r = REG_ST0;
        break;
    case TOK_EQ:
    case TOK_NE:
    case TOK_LT:
    case TOK_LE:
    case TOK_GT:
    case TOK_GE:
    case TOK_ULT:
    case TOK_ULE:
    case TOK_UGT:
    case TOK_UGE:
        vtop--;
        vtop[0].r = VT_CMP;
        vtop[0].c.i = op;
        break;
    }
}
Exemple #14
0
/* generate function epilog */
void gfunc_epilog(void)
{
    out_op(IL_OP_RET);
    fprintf(il_outfile, "}\n\n");
}
Exemple #15
0
/* load 'r' from value 'sv' */
void load(int r, SValue *sv)
{
    int v, fc, ft;

    v = sv->r & VT_VALMASK;
    fc = sv->c.i;
    ft = sv->t;

    if (sv->r & VT_LVAL) {
        if (v == VT_LOCAL) {
            if (fc >= ARG_BASE) {
                fc -= ARG_BASE;
                if (fc >= 0 && fc <= 4) {
                    out_op(IL_OP_LDARG_0 + fc);
                } else if (fc <= 0xff) {
                    out_opb(IL_OP_LDARG_S, fc);
                } else {
                    out_opi(IL_OP_LDARG, fc);
                }
            } else {
                if (fc >= 0 && fc <= 4) {
                    out_op(IL_OP_LDLOC_0 + fc);
                } else if (fc <= 0xff) {
                    out_opb(IL_OP_LDLOC_S, fc);
                } else {
                    out_opi(IL_OP_LDLOC, fc);
                }
            }
        } else if (v == VT_CONST) {
                /* XXX: handle globals */
                out_opi(IL_OP_LDSFLD, 0);
        } else {
            if ((ft & VT_BTYPE) == VT_FLOAT) {
                out_op(IL_OP_LDIND_R4);
            } else if ((ft & VT_BTYPE) == VT_DOUBLE) {
                out_op(IL_OP_LDIND_R8);
            } else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
                out_op(IL_OP_LDIND_R8);
            } else if ((ft & VT_TYPE) == VT_BYTE)
                out_op(IL_OP_LDIND_I1);
            else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED))
                out_op(IL_OP_LDIND_U1);
            else if ((ft & VT_TYPE) == VT_SHORT)
                out_op(IL_OP_LDIND_I2);
            else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED))
                out_op(IL_OP_LDIND_U2);
            else
                out_op(IL_OP_LDIND_I4);
        } 
    } else {
        if (v == VT_CONST) {
            /* XXX: handle globals */
            if (fc >= -1 && fc <= 8) {
                out_op(IL_OP_LDC_I4_M1 + fc + 1); 
            } else {
                out_opi(IL_OP_LDC_I4, fc);
            }
        } else if (v == VT_LOCAL) {
            if (fc >= ARG_BASE) {
                fc -= ARG_BASE;
                if (fc <= 0xff) {
                    out_opb(IL_OP_LDARGA_S, fc);
                } else {
                    out_opi(IL_OP_LDARGA, fc);
                }
            } else {
                if (fc <= 0xff) {
                    out_opb(IL_OP_LDLOCA_S, fc);
                } else {
                    out_opi(IL_OP_LDLOCA, fc);
                }
            }
        } else {
            /* XXX: do it */
        }
    }
}
Exemple #16
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]);
}