⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gen386.c

📁 一款拥有一定历史的C语言编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
	default:	    g_code (op_xor, IL4, &edx_reg, &edx_reg);	    break;	}	g_code (op, IL4, ap3, NIL_ADDRESS);	if (mod) {	    g_code (op_mov, IL4, &edx_reg, ap1);	} else {	    g_code (op_mov, IL4, &eax_reg, ap1);	}	break;    case op_asr:    case op_shr:    case op_shl:	/* evaluate the RHS */	ap3 = g_expr (ep->v.p[1], F_ALL);	validate (ap1);	if (ap3->mode != am_immed) {	    g_code (op_mov, ilen, ap3, &ecx_reg);	    g_code (op, ilen, &ecx_reg, ap1);	    freeop (ap3);	    break;	}	/*FALLTHRU */    default:	/* evaluate the RHS */	ap3 = g_expr (ep->v.p[1], F_ALL);	validate (ap1);	g_code (op, ilen, ap3, ap1);	freeop (ap3);    }    mask = (UVAL) bitmask ((BITSIZE) width);    g_code (op_and, ilen, mk_immed ((IVAL) mask), ap1);    /* rotate result back into position, and store */    g_rotate (ap1, ilen, -offset, tp_void, 0);    validate (ap2);    g_code (op_and, ilen, mk_immed ((IVAL) ~(mask << offset)), ap2);    g_code (op_or, ilen, ap1, ap2);    freeop (ap1);    freeop (ap2);    /* return a result */    ap2 = data_register ();    g_code (op_mov, ilen, ap1, ap2);    ap1 = ap2;    if ((FLAGS) (flags & F_NOVALUE) == F_NONE) {	/* result value needed */	g_rotate (ap1, ilen, offset, tp_void, 0);	if (mod) {	    /* post increment/decrement restore original value */	    switch (op) {	    case op_add:		g_code (op_sub, ilen, mk_immed (1L), ap1);		g_code (op_and, ilen, mk_immed ((IVAL) mask), ap1);		break;	    case op_sub:		g_code (op_add, ilen, mk_immed (1L), ap1);		g_code (op_and, ilen, mk_immed ((IVAL) mask), ap1);		break;	    default:		break;	    }	}    }    return mk_legal (ap1, flags, ep->etp);}/* * assign structures: ap1=dest, ap2=source */static void structassign P3 (ADDRESS *, ap1, ADDRESS *, ap2, SIZE, size){    ADDRESS *ap3;    if (!uses_structassign) {	FATAL ((__FILE__, "structassign", "USES"));    }    if (size == 4L) {	if (ap1->mode == am_dreg) {	    ap1 = mk_indirect (ap1->preg, NIL_EXPR);	} else {	    g_code (op_mov, IL4, ap1, &edi_reg);	    ap1 = mk_indirect (EDI, NIL_EXPR);	}	if (ap2->mode == am_dreg) {	    ap2 = mk_indirect (ap2->preg, NIL_EXPR);	} else {	    g_code (op_mov, IL4, ap2, &esi_reg);	    ap2 = mk_indirect (ESI, NIL_EXPR);	}	ap3 = data_register ();	g_code (op_mov, IL4, ap2, ap3);	g_code (op_mov, IL4, ap3, ap1);	freeop (ap3);    } else {	switch (ap2->mode) {	case am_mreg:	    g_code (op_mov, IL4, mk_high (ap1), mk_high (ap2));	    g_code (op_mov, IL4, mk_low (ap1), mk_low (ap2));	    break;	default:	    g_code (op_lea, IL4, ap1, &edi_reg);	    g_code (op_lea, IL4, ap2, &esi_reg);	    if ((size % 4L) == 0L) {		ap3 = mk_immed ((SIZE) ((USIZE) size >> 2));		ap3 = mk_legal (ap3, (FLAGS) (F_DREG | F_ECX), tp_long);		g_code (op_rep, IL0, NIL_ADDRESS, NIL_ADDRESS);		g_code (op_smov, IL4, NIL_ADDRESS, NIL_ADDRESS);	    } else if ((size % 2L) == 0L) {		ap3 = mk_immed ((SIZE) ((USIZE) size >> 1));		ap3 = mk_legal (ap3, (FLAGS) (F_DREG | F_ECX), tp_short);		g_code (op_rep, IL0, NIL_ADDRESS, NIL_ADDRESS);		g_code (op_smov, IL2, NIL_ADDRESS, NIL_ADDRESS);	    } else {		ap3 = mk_immed (size);		ap3 = mk_legal (ap3, (FLAGS) (F_DREG | F_ECX), tp_char);		g_code (op_rep, IL0, NIL_ADDRESS, NIL_ADDRESS);		g_code (op_smov, IL1, NIL_ADDRESS, NIL_ADDRESS);	    }	    freeop (ap3);	    break;	}    }}/* * generate code for an assignment node. */static ADDRESS *g_assign P2 (const EXPR *, ep, FLAGS, flags){    ADDRESS *ap1, *ap2, *ap3;    TYP    *tp = ep->etp;    SIZE    size = tp->size;    UVAL    mask;    switch (tp->type) {    case bt_longdouble:    case bt_double:    case bt_float:#ifdef FLOAT_IEEE	if (fpu_option) {	    ap1 = g_expr (ep->v.p[0], F_MEM);	    ap2 = g_expr (ep->v.p[1], F_FREG);	    validate (ap1);	    g_fcode ((flags & F_NOVALUE ? op_fstp : op_fst), (ILEN) size, ap1,		     NIL_ADDRESS);	    freeop (ap2);	    freeop (ap1);	    ap1 = flags & F_NOVALUE ? NIL_ADDRESS : float_register ();	    return mk_legal (ap1, flags, ep->etp);	}	/* FALLTHRU */#endif /* FLOAT_IEEE */    case bt_struct:    case bt_union:      array:	ap2 = g_expr (ep->v.p[1], F_ALL);	ap1 = g_expr (ep->v.p[0], F_ALL);	validate (ap2);	structassign (ap1, ap2, size);	freeop (ap1);	return mk_legal (ap2, flags, tp_pointer);    case bt_pointer32:	if (is_array_type (tp) || is_array_assignment (tp)) {	    goto array;	}	/*FALLTHRU */    default:	switch (ep->v.p[0]->nodetype) {	case en_fieldref:	    /*	     * Field assignment	     */	    /* get the value */	    mask = bitmask (ep->v.p[0]->v.bit.width);	    ap1 = g_expr (ep->v.p[1], (FLAGS) (F_DREG | F_IMMED | F_VOL));	    if (ap1->mode == am_immed) {		ap1->u.offset->v.i &= (IVAL) mask;		ap3 = mk_immed ((IVAL)				((USIZE) ap1->u.offset->v.i << (int) ep->v.p				 [0]->v.bit.offset));	    } else {		if (flags & F_NOVALUE) {		    ap3 = ap1;		    g_code (op_and, (ILEN) size, mk_immed ((IVAL) mask), ap3);		} else {		    if (is_signed_type (tp)) {			SIZE    i =			    tp_int->size * 8L -			    (SIZE) ep->v.p[0]->v.bit.width -			    (SIZE) ep->v.p[0]->v.bit.offset;			g_code (op_asl, (ILEN) size, mk_immed (i), ap1);			g_code (op_asr, (ILEN) size, mk_immed (i), ap1);			ap3 = data_register ();			g_code (op_mov, IL4, ap1, ap3);			g_code (op_and, (ILEN) size, mk_immed ((IVAL) mask),				ap3);		    } else {			g_code (op_and, (ILEN) size, mk_immed ((IVAL) mask),				ap1);			ap3 = data_register ();			g_code (op_mov, IL4, ap1, ap3);		    }		}		g_rotate (ap3, (ILEN) size, -(int) ep->v.p[0]->v.bit.offset,			  tp_void, 0);	    }	    mask <<= (int) ep->v.p[0]->v.bit.offset;	    ap2 = g_deref (ep->v.p[0]->v.p[0], ep->v.p[0]->etp);	    validate (ap3);	    g_code (op_and, (ILEN) size, mk_immed ((IVAL) ~mask), ap2);	    g_code (op_or, (ILEN) size, ap3, ap2);	    freeop (ap2);	    if (!(flags & F_NOVALUE)) {		freeop (ap3);		validate (ap1);	    }	    break;	    /*	     * (uns.) char, (uns.) short, (uns.) long, float	     *	     * we want to pass the right hand side as the expression value.	     * This can''t be done if the left side is a register variable on	     * which the right hand side addressing mode depends. But if the	     * left side IS a register variable, it is desirable to pass the	     * left side, so no problem.	     */	case en_register:	    /* pass the left side as expr. value */	    ap1 = g_expr (ep->v.p[0], F_ALL);	    ap2 = g_expr (ep->v.p[1], F_ALL);	    validate (ap1);	    g_code (op_mov, (ILEN) size, ap2, ap1);	    freeop (ap2);	    break;	default:	    /* pass the right side as expr. value */	    /* normally, this is more efficient */	    ap1 = g_expr (ep->v.p[1], F_ALL);	    ap2 = g_expr (ep->v.p[0], F_ALL);	    validate (ap1);	    switch (ap1->mode) {	    default:		if (ap2->mode != am_dreg) {		    ap3 = data_register ();		    g_code (op_mov, (ILEN) size, ap1, ap3);		    g_code (op_mov, (ILEN) size, ap3, ap2);		    freeop (ap3);		    freeop (ap2);		    freeop (ap1);		    if (flags & F_NOVALUE) {			ap1 = NIL_ADDRESS;		    } else {			ap1 = data_register ();			g_code (op_mov, (ILEN) size, ap3, ap1);		    }		    break;		}		/*FALLTHRU */	    case am_dreg:	    case am_immed:		g_code (op_mov, (ILEN) size, ap1, ap2);		freeop (ap2);		break;	    case am_mreg:		g_code (op_mov, (ILEN) size, mk_high (ap1), mk_high (ap2));		g_code (op_mov, (ILEN) size, mk_low (ap1), mk_low (ap2));		freeop (ap2);		break;	    }	    break;	}	return mk_legal (ap1, flags, ep->etp);    }}/* * push the operand expression onto the stack. return the number of bytes * pushed */static SIZE push_param P1 (const EXPR *, ep){    ADDRESS *ap;#ifdef FLOAT_IEEE    ADDRESS *ap1;#endif /* FLOAT_IEEE */    SIZE    size = ep->etp->size;    switch (size) {    case 1L:    case 2L:    case 3L:	ap = g_expr (ep, F_DREG);	g_code (op_push, IL4, ap, NIL_ADDRESS);	break;    case 4L:	ap = g_expr (ep, F_ALL);	switch (ap->mode) {#ifdef FLOAT_IEEE	case am_freg:	    g_code (op_sub, IL4, mk_immed (size), &esp_reg);	    ap1 = mk_indirect (ESP, NIL_EXPR);	    g_fcode (op_fstp, (ILEN) size, ap1, NIL_ADDRESS);	    break;#endif /* FLOAT_IEEE */	default:	    g_code (op_push, IL4, ap, NIL_ADDRESS);	    break;	}	break;    case 8L:	ap = g_expr (ep, F_ALL);	switch (ap->mode) {#ifdef FLOAT_IEEE	case am_freg:	    g_code (op_sub, IL4, mk_immed (size), &esp_reg);	    ap1 = mk_indirect (ESP, NIL_EXPR);	    g_fcode (op_fstp, (ILEN) size, ap1, NIL_ADDRESS);	    break;#endif /* FLOAT_IEEE */	default:	    g_code (op_push, IL4, mk_high (ap), NIL_ADDRESS);	    g_code (op_push, IL4, mk_low (ap), NIL_ADDRESS);	    break;	}	break;    default:	ap = g_expr (ep, F_ALL);	g_code (op_sub, IL4, mk_immed (size), &esp_reg);	structassign (&esp_reg, ap, size);	break;    }    freeop (ap);    return size;}/* * push a list of parameters onto the stack and return the number of * bytes that the parameters occupy. */static SIZE g_parms P1 (const EXPR *, ep){    SIZE    size;    is_parameter++;    for (size = 0L; ep != NIL_EXPR; ep = ep->v.p[1]) {	size += push_param (ep->v.p[0]);    }    is_parameter--;    return size;}static ADDRESS *func_result P3 (FLAGS, flags, SIZE, bytes, TYP *, tp){    ADDRESS *ap;    stack_offset += bytes;    if (is_parameter) {	g_stack (bytes);    }    if (flags & F_NOVALUE) {#if 0	if (ap->mode == am_freg) {	    g_fcode (op_fstp, IL10, mk_reg (ST0), NIL_ADDRESS);	}#endif	return NIL_ADDRESS;    }    switch (tp->type) {#ifdef FLOAT_IEEE    case bt_float:	if (fpu_option && fpu_return_option) {	    ap = float_register ();	} else {	    ap = data_register ();	}	return ap;    case bt_double:    case bt_longdouble:	if (fpu_option && fpu_return_option) {	    ap = float_register ();	} else {	    ap = mdata_register ();	}	return ap;#endif /* FLOAT_IEEE */    default:	if (flags & F_DREG) {	    ap = data_register ();	    if (ap->preg != reg_usage->result->reg[0]) {		g_code (op_mov, IL4, &eax_reg, ap);	    }	    return ap;	}    }    FATAL ((__FILE__, "func_result", "flags = 0x%x", flags));    return NIL_ADDRESS;}/* * generate a function call node and return the address mode of the result. */static ADDRESS *g_fcall P2 (const EXPR *, ep, FLAGS, flags){    ADDRESS *ap, *ap1;    SIZE    size;    EXPR   *ep0 = ep->v.p[0];    if (!is_parameter && ep->nodetype != en_call) {	switch (stackopt_option) {	case OPT_SAFE:	    /*	     *       no stack optimisation	     */	    g_stack (stack_offset);	    break;	case OPT_MINIMUM:	    /*	     *       "Minimum" stack optimisation.  Perform a stack optimisation	     *       unless:	     *       1.  The alloca() routine is called	     *       2.  The function call is via a variable	     *       3.  The function starts with an underscore character	     */	    if ((ep0->nodetype != en_nacon) ||		(ep0->v.str[0] == (CHAR) '_') || (ep0->v.str == alloca_name)) {		g_stack (stack_offset);	    }	    break;	case OPT_AVERAGE:	    /*	     *       "Forced" stack optimisation.   This will not suppress	     *       the optimisation on encountering calls to functions	     *       whose names begin with underscore.	     */	    if ((ep0->nodetype != en_nacon) || (ep0->v.str == alloca_name)) {		g_stack (stack_offset);	    }	    break;	case OPT_MAXIMUM:	    /*	     *       "Maximum" stack optimisation.   This will not suppress	     *       the optimisation on encountering calls to functions	     *       whose names begin with underscore or via a function	     *       variable.	     */	    if ((ep0->nodetype == en_nacon) && (ep0->v.str == alloca_name)) {		g_stack (stack_offset);	    }	    break;	default:	    CANNOT_REACH_HERE ();	    break;	}    }    /* push any used registers */    temp_inv ();    size = g_parms (ep->v.p[1]);	/* generate parameters */    /*     * for functions returning a structure or a union, push a pointer to the     * return value as additional argument The scratch space will be     * allocated in the stack frame of the calling function.     */    if (is_structure_type (ep->etp)) {	ap = mk_scratch (ep->etp->size);	ap1 = data_register ();	g_code (op_lea, IL4, ap, ap1);	g_code (op_push, IL4, ap1, NIL_ADDRESS);	freeop (ap1);	freeop (ap);	size += tp_pointer->size;    }    if (ep->nodetype == en_call) {	size = 0L;    }    /* call the function */    switch (ep0->nodetype) {    case en_nacon:    case en_labcon:	ap = mk_direct (ep0);	break;    default:	ap = g_expr (ep0, F_AREG);	ap = copy_addr (ap, am_ind);	ap->u.offset = NIL_EXPR;	freeop (ap);	break;    }    g_code (op_call, IL0, ap, NIL_ADDRESS);    ap = func_result (flags, size, ep->etp);    return mk_legal (ap, flags, ep->etp);}/* * generates code for a en_cast node */static ADDRESS *g_cast P4 (ADDRESS *, ap, TYP *, tp1, TYP *, tp2, FLAGS,			   flags){#ifdef FLOAT_IEEE    ADDRESS *ap1;#endif /* FLOAT_IEEE */    if (flags & F_NOVALUE) {#ifdef FLOAT_IEEE	if (ap->mode == am_freg) {	    g_fcode (op_fstp, IL10, mk_reg (ST0), NIL_ADDRESS);	}#endif /* FLOAT_IEEE */	freeop (ap);	return NIL_ADDRESS;    }    /* casts to a narrower integer type are no-ops since the 386 is low-endian */    /* to avoid code duplication, float/double is shared */    switch (tp2->type) {	/* type to cast to */#ifdef FLOAT_IEEE    case bt_float:    case bt_double:    case bt_longdouble:	switch (tp1->type) {	case bt_float:	case bt_double:	case bt_longdouble:	    ap = mk_legal (ap, F_FREG, tp1);	    return mk_legal (ap, flags, tp2);	case bt_uchar:	case bt_schar:	case bt_char:	case bt_charu:	case bt_short:	case bt_ushort:	case bt_int16:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -