📄 iexpr.c
字号:
//this needs en_cfp and en_fp_ref, en_csp, en_sp_ref
/*
Copyright 1994-2003 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
This program is derived from the cc68k complier by
Matthew Brandt (mattb@walkingdog.net)
You may contact the author of this derivative at:
mailto::camille@bluegrass.net
or by snail mail at:
David Lindauer
850 Washburn Ave Apt 99
Louisville, KY 40222
*/
/*
* iexpr.c
*
* routies to take an enode list and generate icode
*/
#include <stdio.h>
#include <stdlib.h>
#include "utype.h"
#include "lists.h"
#include "expr.h"
#include "c.h"
#include "iexpr.h"
#include "iopt.h"
#include "diag.h"
/*
* this module contains all of the code generation routines
* for evaluating expressions and conditions.
*/
extern int global_flag;
extern int retlab;
extern SYM *currentfunc;
extern long nextlabel;
extern long bittab[32];
extern IMODE rret;
extern int stdintsize, stdretblocksize;
extern SYM *declclass;
IMODE *structret_imode;
int chksize(int lsize, int rsize)
/*
* compare two sizes, ignoring sign during comparison
*/
{
int l, r;
l = lsize;
r = rsize;
if (l < 0)
l = - l;
if (r < 0)
r = - r;
return (l > r);
}
//-------------------------------------------------------------------------
SYM *varsp(ENODE *node)
{
if (!node)
return 0;
switch (node->nodetype)
{
case en_nalabcon:
case en_nacon:
case en_napccon:
case en_absacon:
case en_autocon:
case en_autoreg:
case en_tempref:
return node->v.sp;
}
return 0;
}
//-------------------------------------------------------------------------
IMODE *make_imaddress(ENODE *node, int size)
{
SYM *sp = node->v.sp;
IMODE *ap2;
if (sp && sp->imaddress)
return sp->imaddress;
if (sp && sp->storage_class != sc_auto && sp->storage_class != sc_autoreg)
global_flag++;
ap2 = xalloc(sizeof(IMODE));
ap2->offset = copy_enode(node); /* use as constant node */
ap2->mode = i_immed;
ap2->size = size;
if (sp && sp->storage_class != sc_auto && sp->storage_class != sc_autoreg)
global_flag--;
if (sp)
sp->imaddress = ap2;
return ap2;
}
//-------------------------------------------------------------------------
IMODE *make_bf(ENODE *node, IMODE *ap, int size)
/*
* construct a bit field reference for 68020 bit field instructions
*/
{
if (node->startbit == - 1)
DIAG("Illegal bit field");
ap->startbit = node->startbit;
ap->bits = node->bits;
ap->size = size;
return ap;
}
//-------------------------------------------------------------------------
IMODE *make_immed(long i)
/*
* make a node to reference an immediate value i.
*/
{
IMODE *ap = xalloc(sizeof(IMODE));
ap->mode = i_immed;
ap->offset = makenode(en_icon, (char*)i, 0);
ap->size = ISZ_NONE;
return ap;
}
//-------------------------------------------------------------------------
IMODE *make_fimmed(long double f)
/*
* make a node to reference an immediate value i.
*/
{
IMODE *ap = xalloc(sizeof(IMODE));
ap->mode = i_immed;
ap->offset = makenode(en_lrcon, 0, 0);
ap->offset->v.f = f;
ap->size = ISZ_NONE;
return ap;
}
//-------------------------------------------------------------------------
IMODE *make_parmadj(long i)
/*
* make a direct immediate, e.g. for parmadj
*/
{
ENODE *node = makenode(en_icon, (char*)i, 0);
IMODE *ap = xalloc(sizeof(IMODE));
ap->mode = i_immed;
ap->offset = node;
return ap;
}
//-------------------------------------------------------------------------
IMODE *make_offset(ENODE *node)
/*
* make a direct reference to a node.
*/
{
IMODE *ap;
SYM *sp = varsp(node);
if (sp && sp->imvalue)
return sp->imvalue;
if (sp && sp->storage_class != sc_auto && sp->storage_class != sc_autoreg)
global_flag++;
ap = xalloc(sizeof(IMODE));
ap->offset = copy_enode(node);
if (sp && sp->storage_class != sc_auto && sp->storage_class != sc_autoreg)
global_flag--;
ap->mode = i_direct;
ap->size = natural_size(node);
if (sp)
sp->imvalue = ap;
return ap;
}
//-------------------------------------------------------------------------
IMODE *genasn(ENODE *node, int size)
/*
* Find the targe of an assigment. if node is 0 we need a temp reg,
* otherwise we calculate the assignment target
*/
{
if (!node)
return tempreg(size, 0);
return gen_expr(node, 0, size);
}
//-------------------------------------------------------------------------
IMODE *indnode(IMODE *ap1, int size)
/*
* copy the address mode and change it to an indirect type
*
*/
{
IMODE *ap;
SYM *sp;
int hassp = FALSE;
if (ap1->mode == i_ind)
{
IMODE *ap2 = tempreg(ISZ_ADDR, 0),*ap3;
ap2->bits = ap1->bits;
ap2->startbit = ap1->startbit;
gen_icode(i_assn, ap2, ap1, 0);
ap3 = xalloc(sizeof(IMODE));
*ap3 = *ap2;
ap3->mode = i_ind;
ap3->size = size;
return ap3;
}
sp = varsp(ap1->offset);
if (sp && sp->imind)
{
ap = sp->imind;
ap->offset = ap1->offset;
}
else
{
if (sp)
{
if (sp && sp->storage_class != sc_auto && sp->storage_class !=
sc_autoreg)
global_flag++;
ap = xalloc(sizeof(IMODE));
*ap = *ap1;
ap->offset = copy_enode(ap->offset);
if (sp && sp->storage_class != sc_auto && sp->storage_class !=
sc_autoreg)
global_flag--;
}
else
{
ap = xalloc(sizeof(IMODE));
*ap = *ap1;
}
ap1->size = ISZ_ADDR;
ap->mode = i_ind;
if (sp)
sp->imind = ap;
}
return ap;
}
//-------------------------------------------------------------------------
IMODE *gen_deref(ENODE *node, int flags, int size)
/*
* return the addressing mode of a dereferenced node.
*/
{
IMODE *ap1, *ap2, *ap3, *ap4;
int siz1, psize;
SYM *sp;
int nt = node->v.p[0]->nodetype;
psize = size;
if (psize < 0)
psize = - psize;
/* get size */
switch (node->nodetype) /* get load size */
{
case en_substack:
case en_structret:
siz1 = ISZ_ADDR;
break;
case en_bool_ref:
siz1 = ISZ_BOOL;
break;
case en_ub_ref:
siz1 = ISZ_UCHAR;
break;
case en_b_ref:
siz1 = - ISZ_UCHAR;
break;
case en_uw_ref:
siz1 = ISZ_USHORT;
break;
case en_w_ref:
siz1 = - ISZ_USHORT;
break;
case en_i_ref:
siz1 = - ISZ_UINT;
break;
case en_a_ref:
siz1 = ISZ_ADDR;
break;
case en_l_ref:
siz1 = - ISZ_ULONG;
break;
case en_ptr_ref:
siz1 = ISZ_ADDR;
break;
case en_add:
case en_addstruc:
siz1 = ISZ_ADDR;
break;
case en_ui_ref:
siz1 = ISZ_UINT;
break;
case en_ua_ref:
siz1 = ISZ_ADDR;
break;
case en_ul_ref:
siz1 = ISZ_ULONG;
break;
case en_ll_ref:
siz1 = - ISZ_ULONGLONG;
break;
case en_ull_ref:
siz1 = ISZ_ULONGLONG;
break;
case en_floatref:
siz1 = ISZ_FLOAT;
break;
case en_doubleref:
siz1 = ISZ_DOUBLE;
break;
case en_longdoubleref:
siz1 = ISZ_LDOUBLE;
break;
case en_fimaginaryref:
siz1 = ISZ_IFLOAT;
break;
case en_rimaginaryref:
siz1 = ISZ_IDOUBLE;
break;
case en_lrimaginaryref:
siz1 = ISZ_ILDOUBLE;
break;
case en_fcomplexref:
siz1 = ISZ_CFLOAT;
break;
case en_rcomplexref:
siz1 = ISZ_CDOUBLE;
break;
case en_lrcomplexref:
siz1 = ISZ_CLDOUBLE;
break;
default:
siz1 = ISZ_UINT;
}
/* deref for add nodes */
if (node->v.p[0]->nodetype == en_add || node->v.p[0]->nodetype == en_addstruc)
{
ap1 = gen_expr(node->v.p[0], 0, size);
ap1 = indnode(ap1, siz1);
ap1->offset->cflags = node->v.p[0]->cflags;
return ap1;
}
/* deref for auto variables */
else if (node->v.p[0]->nodetype == en_imode)
{
ap1 = node->v.p[0]->v.p[1];
return ap1;
}
/* deref for cpu registers */
else if (node->v.p[0]->nodetype == en_regref)
{
ap1 = gen_expr(node->v.p[0], 0, ISZ_REG);
ap1->offset->cflags = node->v.p[0]->cflags;
return ap1;
}
/* other deref */
switch (nt)
{
case en_labcon:
ap1 = xalloc(sizeof(IMODE));
ap1->mode = i_direct;
ap1->offset = node->v.p[0];
ap1->size = siz1;
break;
case en_nalabcon:
case en_nacon:
case en_napccon:
case en_autocon:
case en_autoreg:
case en_absacon:
sp = node->v.p[0]->v.sp;
if (sp->imvalue)
return sp->imvalue;
if (sp && sp->storage_class != sc_auto && sp->storage_class !=
sc_autoreg)
global_flag++;
ap1 = xalloc(sizeof(IMODE));
sp->imvalue = ap1;
ap1->mode = i_direct;
ap1->offset = copy_enode(node->v.p[0]);
ap1->size = siz1;
if (sp)
if (sp->storage_class != sc_auto && sp->storage_class != sc_autoreg)
global_flag--;
break;
default:
ap1 = gen_expr( node->v.p[0], 0, siz1); /* generate address */
ap1 = indnode(ap1, siz1);
break;
}
ap1->offset->cflags = node->v.p[0]->cflags;
return ap1;
}
//-------------------------------------------------------------------------
IMODE *gen_unary(ENODE *node, int flags, int size, int op)
/*
* generate code to evaluate a unary minus or complement.
*/
{
IMODE *ap, *ap1;
ap = gen_expr(node->v.p[0], F_VOL, size);
gen_icode(op, ap1 = genasn(0, size), ap, 0);
return ap1;
}
//-------------------------------------------------------------------------
IMODE *gen_binary(ENODE *node, int flags, int size, int op)
/*
* generate code to evaluate a binary node and return
* the addressing mode of the result.
*/
{
IMODE *ap, *ap1, *ap2;
ap1 = gen_expr(node->v.p[0], F_VOL, size);
ap2 = gen_expr(node->v.p[1], 0, size);
if (ap1->size >= ISZ_CFLOAT || ap2->size >= ISZ_CFLOAT)
size = max(ap1->size,ap2->size);
else
if (ap1->size >= ISZ_IFLOAT && ap2->size < ISZ_IFLOAT)
if (ap2->size < ISZ_FLOAT)
size = ap1->size;
else
size = max(ap1->size - ISZ_IFLOAT, ap2->size - ISZ_FLOAT) + ISZ_CFLOAT;
else
if (ap2->size >= ISZ_IFLOAT && ap1->size < ISZ_IFLOAT)
if (ap1->size < ISZ_FLOAT)
size = ap2->size;
else
size = max(ap2->size - ISZ_IFLOAT, ap1->size - ISZ_FLOAT) + ISZ_CFLOAT;
gen_icode(op, ap = genasn(0, size), ap1, ap2);
return ap;
}
//-------------------------------------------------------------------------
IMODE *gen_pdiv( ENODE *node, int flags, int size)
/*
* generate code for an array/structure size compensation
*/
{
IMODE *ap, *ap1, *ap2;
ap1 = gen_expr( node->v.p[0], F_VOL, ISZ_UINT);
ap2 = gen_expr( node->v.p[1], 0, ISZ_USHORT);
gen_icode(i_udiv, ap = genasn(0, size), ap2, ap1);
return ap;
}
//-------------------------------------------------------------------------
IMODE *gen_pmul( ENODE *node, int flags, int size)
/*
* generate code for an array/structure size compensation
*/
{
IMODE *ap, *ap1, *ap2;
ap1 = gen_expr( node->v.p[0], F_VOL, ISZ_UINT);
ap2 = gen_expr( node->v.p[1], 0, ISZ_UINT);
gen_icode(i_umul, ap = genasn(0, size), ap2, ap1);
return ap;
}
//-------------------------------------------------------------------------
IMODE *gen_hook( ENODE *node, int flags, int size)
/*
* generate code to evaluate a condition operator node (?:)
*/
{
IMODE *ap1, *ap2;
int false_label, end_label;
false_label = nextlabel++;
end_label = nextlabel++;
flags = flags | F_VOL;
falsejp(node->v.p[0], false_label);
node = node->v.p[1];
ap1 = tempreg(natural_size(node), 0);
ap2 = gen_expr( node->v.p[0], flags, size);
gen_icode(i_assn, ap1, ap2, 0);
ap1->offset->v.sp->iglobal = TRUE;
gen_igoto(end_label);
gen_label(false_label);
ap2 = gen_expr( node->v.p[1], flags, size);
gen_icode(i_assn, ap1, ap2, 0);
ap1->offset->v.sp->iglobal = TRUE;
gen_label(end_label);
return ap1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -