MWCC/compiler_and_linker/unsorted/CInline.c

4207 lines
134 KiB
C

#include "compiler/CInline.h"
#include "compiler/CABI.h"
#include "compiler/CClass.h"
#include "compiler/CError.h"
#include "compiler/CException.h"
#include "compiler/CExpr.h"
#include "compiler/CFunc.h"
#include "compiler/CInit.h"
#include "compiler/CInt64.h"
#include "compiler/CMachine.h"
#include "compiler/CMangler.h"
#include "compiler/COptimizer.h"
#include "compiler/CParser.h"
#include "compiler/CPrepTokenizer.h"
#include "compiler/CTemplateNew.h"
#include "compiler/CodeGen.h"
#include "compiler/CompilerTools.h"
#include "compiler/Exceptions.h"
#include "compiler/InlineAsm.h"
#include "compiler/ObjGenMachO.h"
#include "compiler/Switch.h"
#include "compiler/enode.h"
#include "compiler/objects.h"
#include "compiler/scopes.h"
#include "compiler/templates.h"
#ifdef __MWERKS__
#pragma options align=mac68k
#endif
typedef struct IDTrans {
struct IDTrans *next;
SInt32 from;
SInt32 to;
} IDTrans;
typedef struct LabelTrans {
struct LabelTrans *next;
CLabel **labelptr;
short id;
} LabelTrans;
typedef struct UIDTemp {
struct UIDTemp *next;
Object *object;
SInt32 uid;
} UIDTemp;
typedef struct CI_Export {
struct CI_Export *next;
Object *object;
CI_FuncData *funcdata;
Boolean xC;
} CI_Export;
typedef struct AObject {
Object *object;
ENode *expr1;
ENode *expr2;
} AObject;
typedef struct CI_StmtLink {
struct CI_StmtLink *next;
Statement *stmt;
CI_Statement *ciStmt;
} CI_StmtLink;
#ifdef __MWERKS__
#pragma options align=reset
#endif
static CInlineCopyMode enode_copymode;
static Boolean enode_globalcopy;
static IDTrans *enode_idtrans;
static Object **local_dobjects;
static AObject *local_aobjects;
static CI_Var *loc_args;
static CI_Var *loc_vars;
static Boolean inline_expanded;
static Boolean any_inline_expanded;
static short cinline_level;
static LabelTrans *cinline_label_trans;
static Statement *cinline_first_stmt;
static ENode *cinline_stmtlevelexpr[16];
static short cinline_stmtlevelexprs;
static Boolean cinline_unconditionalpart;
static Boolean cinline_serialize_stmt;
static CI_Export *cinline_exportlist; // type?
static CI_Action *cinline_actionlist;
CI_Action *cinline_tactionlist;
static ObjectList *cinline_freflist;
static Boolean cinline_gendeps;
static Statement *cinline_serial_stmt;
static Statement *cinline_cur_serial_stmt;
static UIDTemp *cinline_uid_temps;
static Boolean cinline_has_sideeffect;
static SInt32 inline_max_size;
static Boolean recursive_inline;
static Object *expanding_function;
static Boolean cinline_funccallfound;
// forward decls
static ENode *CInline_FoldConst(ENode *expr);
static ENode *CInline_CopyNodes(ENode *node);
static SInt32 CInline_EstimateSizeOfFunc(CI_FuncData *funcdata, SInt32 size, SInt32 level);
static ENode *CInline_SerializeExpr(ENode *expr);
static void CInline_AddFRefList_InlineFunc(CI_FuncData *data);
void CInline_Init(void) {
cinline_exportlist = NULL;
cinline_actionlist = NULL;
cinline_tactionlist = NULL;
cinline_gendeps = 0;
}
static ENode *CInline_MakeNotNot(ENode *expr) {
expr = CInline_FoldConst(expr);
if (!ENODE_IS(expr, EINTCONST)) {
expr = makemonadicnode(expr, ELOGNOT);
expr->rtype = CParser_GetBoolType();
expr = makemonadicnode(expr, ELOGNOT);
} else {
expr->data.intval = CInt64_Not(CInt64_Not(expr->data.intval));
}
return expr;
}
static ENode *CInline_FoldConst(ENode *expr) {
ENode *inner;
ENode *right;
ENode *left;
ENodeList *list;
switch (expr->type) {
case EINTCONST:
case EFLOATCONST:
case ESTRINGCONST:
case EOBJREF:
case EPRECOMP:
case ETEMP:
case ELABEL:
case EOBJLIST:
case EINSTRUCTION:
case EVECTOR128CONST:
return expr;
case EMONMIN:
case EBINNOT:
case ELOGNOT:
expr->data.monadic = CInline_FoldConst(expr->data.monadic);
inner = expr->data.monadic;
switch (inner->type) {
case EINTCONST:
if (!ENODE_IS(expr, ELOGNOT)) {
inner->data.intval = CMach_CalcIntMonadic(
expr->rtype, CParser_GetOperator(expr->type), inner->data.intval);
} else {
inner->data.intval = CInt64_Not(inner->data.intval);
}
inner->rtype = expr->rtype;
return inner;
case EFLOATCONST:
if (ENODE_IS(expr, ELOGNOT)) {
inner->type = EINTCONST;
CInt64_SetLong(&inner->data.intval, CMach_FloatIsZero(inner->data.floatval));
} else {
inner->data.floatval = CMach_CalcFloatMonadic(
expr->rtype, CParser_GetOperator(expr->type), inner->data.floatval);
}
inner->rtype = expr->rtype;
return inner;
}
return expr;
case ETYPCON:
expr->data.monadic = CInline_FoldConst(expr->data.monadic);
switch (expr->data.monadic->type) {
case EINTCONST:
switch (expr->rtype->type) {
case TYPEFLOAT:
expr->type = EFLOATCONST;
expr->data.floatval = CMach_CalcFloatConvertFromInt(
expr->data.monadic->rtype, expr->data.monadic->data.intval);
return expr;
case TYPEINT:
expr->type = EINTCONST;
expr->data.intval = CExpr_IntConstConvert(
expr->rtype, expr->data.monadic->rtype, expr->data.monadic->data.intval);
break;
}
break;
case EFLOATCONST:
switch (expr->rtype->type) {
case TYPEFLOAT:
expr->type = EFLOATCONST;
expr->data.floatval = CMach_CalcFloatConvert(
expr->rtype, expr->data.monadic->data.floatval);
return expr;
case TYPEINT:
expr->type = EINTCONST;
expr->data.intval = CMach_CalcIntConvertFromFloat(
expr->rtype, expr->data.monadic->data.floatval);
return expr;
}
break;
}
return expr;
case EPOSTINC:
case EPOSTDEC:
expr->data.monadic = CInline_FoldConst(expr->data.monadic);
switch (expr->data.monadic->type) {
case EINTCONST:
case EFLOATCONST:
expr->data.monadic->rtype = expr->rtype;
return expr->data.monadic;
}
return expr;
case EPREINC:
case EPREDEC:
case EINDIRECT:
case EFORCELOAD:
case EBITFIELD:
expr->data.monadic = CInline_FoldConst(expr->data.monadic);
return expr;
case EMUL:
case EDIV:
case EMODULO:
case EADD:
case ESUB:
case ESHL:
case ESHR:
case EAND:
case EXOR:
case EOR:
expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
if ((left = expr->data.diadic.left)->type == (right = expr->data.diadic.right)->type) {
switch (left->type) {
case EINTCONST:
left->data.intval = CMach_CalcIntDiadic(
expr->rtype,
expr->data.diadic.left->data.intval,
CParser_GetOperator(expr->type),
right->data.intval);
left->rtype = expr->rtype;
return left;
case EFLOATCONST:
left->data.floatval = CMach_CalcFloatDiadic(
expr->rtype,
expr->data.diadic.left->data.floatval,
CParser_GetOperator(expr->type),
right->data.floatval);
left->rtype = expr->rtype;
return left;
}
}
return expr;
case ELESS:
case EGREATER:
case ELESSEQU:
case EGREATEREQU:
case EEQU:
case ENOTEQU:
expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
if ((left = expr->data.diadic.left)->type == (right = expr->data.diadic.right)->type) {
switch (left->type) {
case EINTCONST:
left->data.intval = CMach_CalcIntDiadic(
left->rtype,
expr->data.diadic.left->data.intval,
CParser_GetOperator(expr->type),
right->data.intval);
left->rtype = expr->rtype;
return left;
case EFLOATCONST:
CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(
left->rtype,
expr->data.diadic.left->data.floatval,
CParser_GetOperator(expr->type),
right->data.floatval
));
left->type = EINTCONST;
left->rtype = expr->rtype;
return left;
}
}
return expr;
case ELAND:
expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
if (iszero(expr->data.diadic.left))
return expr->data.diadic.left;
if (isnotzero(expr->data.diadic.left))
return CInline_MakeNotNot(expr->data.diadic.right);
expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
if (isnotzero(expr->data.diadic.right))
return CInline_MakeNotNot(expr->data.diadic.left);
return expr;
case ELOR:
expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
if (iszero(expr->data.diadic.left))
return CInline_MakeNotNot(expr->data.diadic.right);
if (isnotzero(expr->data.diadic.left))
return CInline_MakeNotNot(expr->data.diadic.left);
expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
if (iszero(expr->data.diadic.right))
return CInline_MakeNotNot(expr->data.diadic.left);
return expr;
case EASS:
case EMULASS:
case EDIVASS:
case EMODASS:
case EADDASS:
case ESUBASS:
case ESHLASS:
case ESHRASS:
case EANDASS:
case EXORASS:
case EORASS:
case ECOMMA:
case EROTL:
case EROTR:
expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
return expr;
case ECOND:
expr->data.cond.cond = CInline_FoldConst(expr->data.cond.cond);
if (isnotzero(expr->data.cond.cond))
return CInline_FoldConst(expr->data.cond.expr1);
if (iszero(expr->data.cond.cond))
return CInline_FoldConst(expr->data.cond.expr2);
expr->data.cond.expr1 = CInline_FoldConst(expr->data.cond.expr1);
expr->data.cond.expr2 = CInline_FoldConst(expr->data.cond.expr2);
return expr;
case EMFPOINTER:
expr->data.mfpointer.accessnode = CInline_FoldConst(expr->data.mfpointer.accessnode);
expr->data.mfpointer.mfpointer = CInline_FoldConst(expr->data.mfpointer.mfpointer);
return expr;
case EFUNCCALL:
case EFUNCCALLP:
expr->data.funccall.funcref = CInline_FoldConst(expr->data.funccall.funcref);
for (list = expr->data.funccall.args; list; list = list->next)
list->node = CInline_FoldConst(list->node);
return expr;
case ENULLCHECK:
expr->data.nullcheck.nullcheckexpr = CInline_FoldConst(expr->data.nullcheck.nullcheckexpr);
expr->data.nullcheck.condexpr = CInline_FoldConst(expr->data.nullcheck.condexpr);
return expr;
case EMEMBER:
if (expr->data.emember->expr)
expr->data.emember->expr = CInline_FoldConst(expr->data.emember->expr);
return expr;
default:
CError_FATAL(421);
return expr;
}
}
// unknown name
inline SInt32 CInline_GetLocalID2(Object *object) {
ObjectList *list;
SInt32 counter;
for (list = locals, counter = 0; list; list = list->next) {
if (list->object->datatype == DLOCAL) {
if (list->object == object)
return counter;
counter++;
}
}
return -1;
}
SInt32 CInline_GetLocalID(Object *object) {
ObjectList *list;
SInt32 counter;
if (object) {
for (list = arguments, counter = 0; list; list = list->next, counter++) {
if (list->object == object) {
loc_args[counter].xD = 1;
loc_args[counter].xE = 0;
return counter - 0x7FFFFFFF;
}
}
counter = CInline_GetLocalID2(object);
CError_ASSERT(465, counter >= 0);
loc_vars[counter].xD = 1;
return counter + 1;
}
return 0;
}
static Boolean CInline_IsTrivialExpression(ENode *expr) {
while (1) {
switch (expr->type) {
case EINTCONST:
case EFLOATCONST:
case EOBJREF:
case EARGOBJ:
case ELOCOBJ:
case EOBJLIST:
case EVECTOR128CONST:
return 0;
case ESTRINGCONST:
return copts.dont_reuse_strings;
case EMEMBER:
if (expr->data.emember->expr)
return CInline_IsTrivialExpression(expr->data.emember->expr);
return 0;
case EINDIRECT:
if (ENODE_IS(expr->data.monadic, EOBJREF)) {
if (expr->data.monadic->data.objref->datatype == DLOCAL &&
!(expr->data.monadic->data.objref->flags & OBJECT_FLAGS_2))
return 0;
if (is_const_object(expr->data.monadic->data.objref))
return 0;
return 1;
}
return 1;
case EPOSTINC:
case EPOSTDEC:
case EPREINC:
case EPREDEC:
case EFORCELOAD:
case EASS:
case EMULASS:
case EDIVASS:
case EMODASS:
case EADDASS:
case ESUBASS:
case ESHLASS:
case ESHRASS:
case EANDASS:
case EXORASS:
case EORASS:
case EFUNCCALL:
case EFUNCCALLP:
case EMFPOINTER:
case ENULLCHECK:
case EPRECOMP:
case ETEMP:
case ELABEL:
case EINSTRUCTION:
return 1;
case EMONMIN:
case EBINNOT:
case ELOGNOT:
case ETYPCON:
case EBITFIELD:
expr = expr->data.monadic;
continue;
case EMUL:
case EDIV:
case EMODULO:
case EADD:
case ESUB:
case ESHL:
case ESHR:
case ELESS:
case EGREATER:
case ELESSEQU:
case EGREATEREQU:
case EEQU:
case ENOTEQU:
case EAND:
case EXOR:
case EOR:
case ELAND:
case ELOR:
case ECOMMA:
case EROTL:
case EROTR:
if (CInline_IsTrivialExpression(expr->data.diadic.left))
return 1;
expr = expr->data.diadic.right;
continue;
case ECOND:
if (CInline_IsTrivialExpression(expr->data.cond.cond))
return 1;
if (CInline_IsTrivialExpression(expr->data.cond.expr1))
return 1;
expr = expr->data.cond.expr2;
continue;
default:
CError_FATAL(582);
}
}
}
Boolean CInline_ExpressionHasSideEffect(ENode *expr) {
while (1) {
switch (expr->type) {
case EINTCONST:
case EFLOATCONST:
case ESTRINGCONST:
case EOBJREF:
case EPRECOMP:
case ETEMP:
case EARGOBJ:
case ELOCOBJ:
case ELABEL:
case EOBJLIST:
case EVECTOR128CONST:
return 0;
case EPOSTINC:
case EPOSTDEC:
case EPREINC:
case EPREDEC:
case EASS:
case EMULASS:
case EDIVASS:
case EMODASS:
case EADDASS:
case ESUBASS:
case ESHLASS:
case ESHRASS:
case EANDASS:
case EXORASS:
case EORASS:
case EFUNCCALL:
case EFUNCCALLP:
case EINSTRUCTION:
return 1;
case EINDIRECT:
case EMONMIN:
case EBINNOT:
case ELOGNOT:
case EFORCELOAD:
case ETYPCON:
case EBITFIELD:
expr = expr->data.monadic;
continue;
case EMUL:
case EDIV:
case EMODULO:
case EADD:
case ESUB:
case ESHL:
case ESHR:
case ELESS:
case EGREATER:
case ELESSEQU:
case EGREATEREQU:
case EEQU:
case ENOTEQU:
case EAND:
case EXOR:
case EOR:
case ELAND:
case ELOR:
case ECOMMA:
case EROTL:
case EROTR:
if (CInline_ExpressionHasSideEffect(expr->data.diadic.left))
return 1;
expr = expr->data.diadic.right;
continue;
case EMEMBER:
if (expr->data.emember->expr)
return CInline_ExpressionHasSideEffect(expr->data.emember->expr);
return 0;
case EMFPOINTER:
if (CInline_ExpressionHasSideEffect(expr->data.mfpointer.accessnode))
return 1;
expr = expr->data.mfpointer.mfpointer;
continue;
case ENULLCHECK:
if (CInline_ExpressionHasSideEffect(expr->data.nullcheck.nullcheckexpr))
return 1;
expr = expr->data.nullcheck.condexpr;
continue;
case ECOND:
if (CInline_ExpressionHasSideEffect(expr->data.cond.cond))
return 1;
if (CInline_ExpressionHasSideEffect(expr->data.cond.expr1))
return 1;
expr = expr->data.cond.expr2;
continue;
default:
CError_FATAL(689);
}
}
}
static ENode *CInline_CopyExpressionSave(ENode *expr) {
CInlineCopyMode save_copymode;
Boolean save_globalcopy;
IDTrans *save_idtrans;
save_globalcopy = enode_globalcopy;
enode_globalcopy = 1;
save_copymode = enode_copymode;
enode_copymode = CopyMode4;
save_idtrans = enode_idtrans;
enode_idtrans = NULL;
expr = CInline_CopyNodes(expr);
enode_globalcopy = save_globalcopy;
enode_copymode = save_copymode;
enode_idtrans = save_idtrans;
return expr;
}
static SInt32 CInline_TranslateID(SInt32 id) {
IDTrans *trans;
for (trans = enode_idtrans; trans; trans = trans->next) {
if (trans->from == id)
return trans->to;
}
trans = lalloc(sizeof(IDTrans));
trans->next = enode_idtrans;
enode_idtrans = trans;
trans->from = id;
trans->to = CParser_GetUniqueID();
return trans->to;
}
static short CInline_GetLabelStatementNumber(HashNameNode *name) {
Statement *stmt;
short i;
for (stmt = cinline_first_stmt, i = 0; stmt; stmt = stmt->next, i++) {
if (stmt->type == ST_LABEL && stmt->label->uniquename == name)
return i;
}
CError_FATAL(742);
return 0;
}
static ENodeList *CInline_CopyNodeList(ENodeList *list) {
ENodeList *copy;
ENodeList *first;
ENodeList *last;
first = NULL;
while (list) {
if (enode_globalcopy)
copy = galloc(sizeof(ENodeList));
else
copy = lalloc(sizeof(ENodeList));
copy->node = CInline_CopyNodes(list->node);
copy->next = NULL;
if (first) {
last->next = copy;
last = copy;
} else {
first = last = copy;
}
list = list->next;
}
return first;
}
static EMemberInfo *CInline_CopyEMemberInfo(EMemberInfo *mi) {
EMemberInfo *copy;
if (enode_globalcopy)
copy = galloc(sizeof(EMemberInfo));
else
copy = lalloc(sizeof(EMemberInfo));
*copy = *mi;
if (copy->path)
copy->path = CClass_GetPathCopy(copy->path, enode_globalcopy);
if (copy->expr)
copy->expr = CInline_CopyNodes(copy->expr);
return copy;
}
static ENode *CInline_CopyNodes(ENode *node) {
ENode *copy;
if (enode_globalcopy)
copy = galloc(sizeof(ENode));
else
copy = lalloc(sizeof(ENode));
while (1) {
*copy = *node;
switch (copy->type) {
case ETEMPLDEP:
switch (copy->data.templdep.subtype) {
case TDE_PARAM:
case TDE_SIZEOF:
case TDE_ALIGNOF:
case TDE_QUALNAME:
case TDE_OBJ:
break;
case TDE_CAST:
copy->data.templdep.u.cast.args = CInline_CopyNodeList(copy->data.templdep.u.cast.args);
break;
case TDE_SOURCEREF:
copy->data.templdep.u.sourceref.expr = CInline_CopyNodes(copy->data.templdep.u.sourceref.expr);
break;
case TDE_ADDRESS_OF:
copy->data.templdep.u.monadic = CInline_CopyNodes(copy->data.templdep.u.monadic);
break;
default:
CError_FATAL(840);
}
break;
case ETEMP:
if (enode_copymode == CopyMode3 && copy->data.temp.uniqueid)
copy->data.temp.uniqueid = CInline_TranslateID(copy->data.temp.uniqueid);
break;
case ELABEL:
switch (enode_copymode) {
case CopyMode2:
copy->data.precompid = CInline_GetLabelStatementNumber(copy->data.label->uniquename);
return copy;
case CopyMode3:
case CopyMode4: {
LabelTrans *trans = lalloc(sizeof(LabelTrans));
trans->next = cinline_label_trans;
cinline_label_trans = trans;
trans->id = copy->data.precompid;
trans->labelptr = &copy->data.label;
return copy;
}
}
break;
case EINTCONST:
case EFLOATCONST:
case ESTRINGCONST:
case EOBJLIST:
case EINSTRUCTION:
case EVECTOR128CONST:
break;
case EPOSTINC:
case EPOSTDEC:
case EPREINC:
case EPREDEC:
case EMONMIN:
case EBINNOT:
case ELOGNOT:
case EFORCELOAD:
case ETYPCON:
case EBITFIELD:
copy->data.monadic = CInline_CopyNodes(copy->data.monadic);
break;
ENODE_CASE_DIADIC_ALL:
copy->data.diadic.left = CInline_CopyNodes(copy->data.diadic.left);
copy->data.diadic.right = CInline_CopyNodes(copy->data.diadic.right);
break;
case ECOND:
copy->data.cond.cond = CInline_CopyNodes(copy->data.cond.cond);
copy->data.cond.expr1 = CInline_CopyNodes(copy->data.cond.expr1);
copy->data.cond.expr2 = CInline_CopyNodes(copy->data.cond.expr2);
break;
case EMFPOINTER:
copy->data.mfpointer.accessnode = CInline_CopyNodes(copy->data.mfpointer.accessnode);
copy->data.mfpointer.mfpointer = CInline_CopyNodes(copy->data.mfpointer.mfpointer);
break;
case EFUNCCALL:
case EFUNCCALLP:
copy->data.funccall.funcref = CInline_CopyNodes(copy->data.funccall.funcref);
copy->data.funccall.args = CInline_CopyNodeList(copy->data.funccall.args);
break;
case ENULLCHECK:
copy->data.nullcheck.precompid = CInline_TranslateID(copy->data.nullcheck.precompid);
copy->data.nullcheck.nullcheckexpr = CInline_CopyNodes(copy->data.nullcheck.nullcheckexpr);
copy->data.nullcheck.condexpr = CInline_CopyNodes(copy->data.nullcheck.condexpr);
break;
case EPRECOMP:
copy->data.precompid = CInline_TranslateID(copy->data.precompid);
break;
case EINDIRECT:
if (
enode_copymode == CopyMode4 &&
ENODE_IS(copy->data.monadic, EARGOBJ) &&
local_aobjects[copy->data.monadic->data.longval].object == NULL
)
{
CError_ASSERT(910, local_aobjects[copy->data.monadic->data.longval].expr1);
copy = CInline_CopyExpressionSave(local_aobjects[copy->data.monadic->data.longval].expr1);
if (copy->rtype != node->rtype) {
if (IS_TYPE_INT(copy->rtype) && IS_TYPE_INT(node->rtype))
copy = makemonadicnode(copy, ETYPCON);
copy->rtype = node->rtype;
}
return copy;
}
copy->data.monadic = CInline_CopyNodes(copy->data.monadic);
break;
case EOBJREF:
if (enode_copymode == CopyMode2) {
ObjectList *list;
int i;
if (node->data.objref->datatype == DALIAS) {
CExpr_AliasTransform(node);
continue;
}
if (node->data.objref->datatype == DDATA)
return copy;
for (list = arguments, i = 0; list; list = list->next, i++) {
if (list->object == copy->data.objref) {
copy->type = EARGOBJ;
copy->data.longval = i;
return copy;
}
}
i = CInline_GetLocalID2(copy->data.objref);
if (i >= 0) {
copy->type = ELOCOBJ;
copy->data.longval = i;
return copy;
}
if (node->data.objref->datatype == DLOCAL)
CError_FATAL(949);
}
break;
case EARGOBJ:
switch (enode_copymode) {
case CopyMode4:
CError_ASSERT(957, local_aobjects[copy->data.longval].object);
copy->type = EOBJREF;
copy->data.objref = local_aobjects[copy->data.longval].object;
return copy;
case CopyMode3: {
ObjectList *list;
int i;
for (list = arguments, i = 0; list; list = list->next, i++) {
if (i == copy->data.longval) {
copy->type = EOBJREF;
copy->data.objref = list->object;
CError_ASSERT(966, copy->data.objref);
return copy;
}
}
}
default:
CError_FATAL(971);
}
case ELOCOBJ:
switch (enode_copymode) {
case CopyMode4:
copy->type = EOBJREF;
copy->data.objref = local_dobjects[copy->data.longval];
return copy;
case CopyMode3: {
ObjectList *list;
int i;
for (list = locals, i = 0; list; list = list->next, i++) {
if (i == copy->data.longval) {
copy->type = EOBJREF;
copy->data.objref = list->object;
CError_ASSERT(986, copy->data.objref);
return copy;
}
}
}
default:
CError_FATAL(991);
}
break;
case ENEWEXCEPTION:
case ENEWEXCEPTIONARRAY:
copy->data.newexception.initexpr = CInline_CopyNodes(copy->data.newexception.initexpr);
copy->data.newexception.tryexpr = CInline_CopyNodes(copy->data.newexception.tryexpr);
break;
case EINITTRYCATCH:
copy->data.itc.initexpr = CInline_CopyNodes(copy->data.itc.initexpr);
copy->data.itc.tryexpr = CInline_CopyNodes(copy->data.itc.tryexpr);
copy->data.itc.catchexpr = CInline_CopyNodes(copy->data.itc.catchexpr);
copy->data.itc.result = CInline_CopyNodes(copy->data.itc.result);
break;
case EMEMBER:
copy->data.emember = CInline_CopyEMemberInfo(copy->data.emember);
break;
default:
CError_FATAL(1015);
}
return copy;
}
}
static void CInline_CheckUsage(ENode *expr, Boolean flag) {
ENodeList *list;
ENode *inner;
while (1) {
switch (expr->type) {
case EARGOBJ:
loc_args[expr->data.longval].xD = 1;
loc_args[expr->data.longval].xE = 0;
return;
case ELOCOBJ:
loc_vars[expr->data.longval].xD = 1;
return;
case EINDIRECT:
if (ENODE_IS((inner = expr->data.monadic), EARGOBJ)) {
loc_args[inner->data.longval].xD = 1;
if (flag)
loc_args[inner->data.longval].xE = 0;
return;
}
expr = expr->data.monadic;
flag = 0;
continue;
case EMONMIN:
case EBINNOT:
case ELOGNOT:
case EFORCELOAD:
case ETYPCON:
case EBITFIELD:
expr = expr->data.monadic;
flag = 0;
continue;
case EPOSTINC:
case EPOSTDEC:
case EPREINC:
case EPREDEC:
expr = expr->data.monadic;
flag = 1;
continue;
case EASS:
case EMULASS:
case EDIVASS:
case EMODASS:
case EADDASS:
case ESUBASS:
case ESHLASS:
case ESHRASS:
case EANDASS:
case EXORASS:
case EORASS:
CInline_CheckUsage(expr->data.diadic.left, 1);
expr = expr->data.diadic.right;
flag = 0;
continue;
case EMUL:
case EDIV:
case EMODULO:
case EADD:
case ESUB:
case ESHL:
case ESHR:
case ELESS:
case EGREATER:
case ELESSEQU:
case EGREATEREQU:
case EEQU:
case ENOTEQU:
case EAND:
case EXOR:
case EOR:
case ELAND:
case ELOR:
case ECOMMA:
case EROTL:
case EROTR:
CInline_CheckUsage(expr->data.diadic.left, 0);
expr = expr->data.diadic.right;
flag = 0;
continue;
case EINTCONST:
case EFLOATCONST:
case ESTRINGCONST:
case EOBJREF:
case EPRECOMP:
case ETEMP:
case ELABEL:
case EOBJLIST:
case EVECTOR128CONST:
return;
case EMEMBER:
if (expr->data.emember->expr)
CInline_CheckUsage(expr->data.emember->expr, 0);
return;
case EFUNCCALL:
case EFUNCCALLP:
CInline_CheckUsage(expr->data.funccall.funcref, 0);
for (list = expr->data.funccall.args; list; list = list->next)
CInline_CheckUsage(list->node, 0);
return;
case ENULLCHECK:
CInline_CheckUsage(expr->data.nullcheck.nullcheckexpr, 0);
expr = expr->data.nullcheck.condexpr;
flag = 0;
continue;
case EMFPOINTER:
CInline_CheckUsage(expr->data.mfpointer.accessnode, 0);
expr = expr->data.mfpointer.mfpointer;
flag = 0;
continue;
case ECOND:
CInline_CheckUsage(expr->data.cond.cond, 0);
CInline_CheckUsage(expr->data.cond.expr1, 0);
expr = expr->data.cond.expr2;
flag = 0;
continue;
case EINSTRUCTION:
return;
default:
CError_FATAL(1146);
}
}
}
ENode *CInline_CopyExpression(ENode *expr, CInlineCopyMode mode) {
enode_copymode = mode;
switch (mode) {
case CopyMode0:
case CopyMode4:
enode_idtrans = NULL;
enode_globalcopy = 0;
expr = CInline_CopyNodes(expr);
break;
case CopyMode3:
enode_globalcopy = 0;
expr = CInline_CopyNodes(expr);
break;
case CopyMode1:
enode_idtrans = NULL;
enode_globalcopy = 1;
expr = CInline_CopyNodes(expr);
break;
case CopyMode2:
enode_idtrans = NULL;
enode_globalcopy = 1;
expr = CInline_CopyNodes(expr);
CInline_CheckUsage(expr, 0);
break;
}
return expr;
}
static UInt8 CInline_GetObjectSFlags(Object *object) {
UInt8 flags;
switch (object->sclass) {
case 0:
flags = CI_SFLAGS_NoClass;
break;
case TK_REGISTER:
flags = CI_SFLAGS_Register;
break;
case TK_AUTO:
flags = CI_SFLAGS_Auto;
break;
default:
CError_FATAL(1204);
}
if (object->flags & OBJECT_FLAGS_2)
flags |= CI_SFLAGS_HasObjectFlag2;
return flags;
}
static void CInline_SetObjectSFlags(Object *object, UInt8 sflags) {
if (sflags & CI_SFLAGS_HasObjectFlag2) {
object->flags |= OBJECT_FLAGS_2;
sflags &= ~CI_SFLAGS_HasObjectFlag2;
}
switch (sflags) {
case CI_SFLAGS_NoClass:
object->sclass = 0;
break;
case CI_SFLAGS_Register:
object->sclass = TK_REGISTER;
break;
case CI_SFLAGS_Auto:
object->sclass = TK_AUTO;
break;
default:
CError_FATAL(1229);
}
}
static Object *CInline_NewLocalObject(Type *type, short qual, UInt8 sflags, int unk) {
Object *object = CParser_NewLocalDataObject(NULL, 1);
object->name = CParser_GetUniqueName();
object->type = type;
object->qual = qual;
CInline_SetObjectSFlags(object, sflags);
CFunc_SetupLocalVarInfo(object);
return object;
}
static ENode *CInline_FuncArgConvert(ENode *expr) {
ENode *copy;
switch (expr->type) {
case EOBJREF:
copy = lalloc(sizeof(ENode));
*copy = *expr;
return copy;
case ETEMP:
CError_FATAL(1272);
}
return NULL;
}
static ENode *CInline_RefArgTransform(ENode *expr, Boolean flag) {
ENodeList *arg;
while (ENODE_IS(expr, ECOMMA))
expr = expr->data.diadic.right;
switch (expr->type) {
case EOBJREF:
case ETEMP:
if (flag)
return CInline_FuncArgConvert(expr);
break;
case EFUNCCALL:
if (IS_TYPE_POINTER_ONLY(expr->rtype) && IS_TYPE_CLASS(TPTR_TARGET(expr->rtype))) {
if (
ENODE_IS(expr->data.funccall.funcref, EOBJREF) &&
CClass_IsConstructor(expr->data.funccall.funcref->data.objref) &&
expr->data.funccall.args
)
return CInline_FuncArgConvert(expr->data.funccall.args->node);
if (
TPTR_TARGET(expr->rtype) == expr->data.funccall.functype->functype &&
CMach_GetFunctionResultClass(expr->data.funccall.functype) == 1 &&
(arg = expr->data.funccall.args)
)
{
switch (CABI_GetStructResultArgumentIndex(expr->data.funccall.functype)) {
case 0:
break;
case 1:
if ((arg = arg->next))
break;
CError_FATAL(1313);
default:
CError_FATAL(1314);
}
return CInline_FuncArgConvert(arg->node);
}
}
break;
}
return NULL;
}
static ENode *CInline_SetupArgsExpression(Object *object, CI_FuncData *data, ENodeList *list) {
ENode *commaNodes;
CI_Var *var;
ENodeList *scan;
ENode *expr;
SInt32 i;
Boolean is_oldstyle;
is_oldstyle = 0;
if (TYPE_FUNC(object->type)->args == &oldstyle)
is_oldstyle = 1;
local_dobjects = lalloc(sizeof(Object *) * data->numlocals);
local_aobjects = lalloc(sizeof(AObject) * data->numarguments);
for (i = 0, var = data->locals; i < data->numlocals; i++, var++) {
if (var->xD) {
object = CInline_NewLocalObject(var->type, var->qual, var->sflags, 0);
local_dobjects[i] = object;
if (!var->xE)
object->flags |= OBJECT_FLAGS_2;
} else {
local_dobjects[i] = NULL;
}
}
for (i = 0, var = data->arguments, scan = list; i < data->numarguments; i++, var++) {
local_aobjects[i].expr2 = NULL;
if (!var->xD) {
local_aobjects[i].object = NULL;
local_aobjects[i].expr1 = NULL;
} else if (
scan &&
var->xE &&
!CInline_IsTrivialExpression(scan->node) &&
(!is_oldstyle || scan->node->rtype->size == var->type->size)
)
{
local_aobjects[i].object = NULL;
local_aobjects[i].expr1 = scan->node;
} else if (
scan &&
var->xE &&
IS_TYPE_REFERENCE(var->type) &&
(expr = CInline_RefArgTransform(scan->node, 1))
)
{
local_aobjects[i].object = NULL;
local_aobjects[i].expr1 = expr;
local_aobjects[i].expr2 = scan->node;
} else {
local_aobjects[i].object = CInline_NewLocalObject(var->type, var->qual, var->sflags, 0);
local_aobjects[i].expr1 = NULL;
}
if (scan)
scan = scan->next;
}
commaNodes = NULL;
for (i = 0, scan = list; scan; scan = scan->next, i++) {
if (i >= data->numarguments) {
if (!commaNodes)
commaNodes = scan->node;
else
commaNodes = makecommaexpression(scan->node, commaNodes);
} else if (!local_aobjects[i].object || local_aobjects[i].expr2) {
if (local_aobjects[i].expr2) {
if (!commaNodes)
commaNodes = local_aobjects[i].expr2;
else
commaNodes = makecommaexpression(local_aobjects[i].expr2, commaNodes);
} else if (!local_aobjects[i].expr1 && CInline_IsTrivialExpression(scan->node)) {
commaNodes = !commaNodes ? scan->node : makecommaexpression(scan->node, commaNodes);
CError_ASSERT(1470, !ENODE_IS(scan->node, EPRECOMP));
}
} else {
if (is_oldstyle && scan->node->rtype->size != local_aobjects[i].object->type->size) {
scan->node = makemonadicnode(scan->node, ETYPCON);
scan->node->rtype = local_aobjects[i].object->type;
}
expr = makediadicnode(create_objectnode2(local_aobjects[i].object), scan->node, EASS);
if (!commaNodes)
commaNodes = expr;
else
commaNodes = makecommaexpression(expr, commaNodes);
}
}
return commaNodes;
}
static void CInline_ReturnCheckCB(ENode *expr) {
cinline_has_sideeffect = 1;
}
static ENode *CInline_ReturnCheck(ENode *expr) {
ENode *copy;
if (ENODE_IS(expr, EFORCELOAD))
return expr;
cinline_has_sideeffect = 0;
CExpr_SearchExprTree(expr, CInline_ReturnCheckCB, 3, EINDIRECT, EFUNCCALL, EFUNCCALLP);
if (!cinline_has_sideeffect)
return expr;
copy = lalloc(sizeof(ENode));
*copy = *expr;
copy->type = EFORCELOAD;
copy->data.monadic = expr;
return copy;
}
static ENode *CInline_ReturnMemResult(Object *object) {
int index = CABI_GetStructResultArgumentIndex(TYPE_FUNC(object->type));
if (local_aobjects[index].object == NULL)
return CInline_CopyExpressionSave(local_aobjects[index].expr1);
else
return create_objectnode(local_aobjects[index].object);
}
static ENode *CInline_InlineFunctionExpression(ENode *expr) {
Object *object;
CI_FuncData *funcdata;
short i;
Boolean flag26;
ENode *argsExpr;
object = expr->data.funccall.funcref->data.objref;
if (object->datatype == DALIAS)
object = object->u.alias.object;
funcdata = object->u.func.u.ifuncdata;
if (!funcdata)
return expr;
if (funcdata->can_inline < CI_CanInline6) {
if (funcdata->can_inline == CI_CanInline3) {
if (cinline_unconditionalpart && cinline_stmtlevelexprs < 16)
cinline_stmtlevelexpr[cinline_stmtlevelexprs++] = expr;
cinline_serialize_stmt = 1;
}
return expr;
}
flag26 = CMach_GetFunctionResultClass(TYPE_FUNC(object->type)) == 1;
argsExpr = CInline_SetupArgsExpression(object, funcdata, expr->data.funccall.args);
for (i = 0; i < funcdata->numstatements; i++) {
switch (funcdata->statements[i].type) {
case ST_RETURN:
if (funcdata->statements[i].u.expr) {
ENode *copy = CInline_CopyExpression(funcdata->statements[i].u.expr, CopyMode4);
if (flag26) {
if (argsExpr)
argsExpr = makecommaexpression(argsExpr, copy);
else
argsExpr = copy;
argsExpr = makecommaexpression(argsExpr, CInline_ReturnMemResult(object));
} else {
if (argsExpr)
argsExpr = makecommaexpression(argsExpr, CInline_ReturnCheck(copy));
else
argsExpr = CInline_ReturnCheck(copy);
}
}
break;
case ST_EXPRESSION:
if (argsExpr)
argsExpr = makecommaexpression(argsExpr, CInline_CopyExpression(funcdata->statements[i].u.expr, CopyMode4));
else
argsExpr = CInline_CopyExpression(funcdata->statements[i].u.expr, CopyMode4);
break;
default:
CError_FATAL(1632);
}
}
if (!argsExpr)
argsExpr = nullnode();
if (!IS_TYPE_VOID(expr->rtype))
argsExpr->rtype = expr->rtype;
inline_expanded = 1;
return CInline_FoldConst(argsExpr);
}
static Boolean CInline_CanExpand(ENode *expr) {
TypeFunc *tfunc;
Object *object;
object = expr->data.objref;
tfunc = TYPE_FUNC(object->type);
if (
IS_TYPE_FUNC(tfunc) &&
((object->qual & Q_INLINE) || (tfunc->flags & FUNC_FLAGS_800)) &&
(object->datatype == DFUNC || (object->datatype == DVFUNC && (expr->flags & ENODE_FLAG_80)))
)
return 1;
return 0;
}
static SInt32 CInline_EstimateSizeOfExpr(ENode *expr, SInt32 size, SInt32 level) {
ENodeList *list;
switch (expr->type) {
ENODE_CASE_MONADIC:
size = CInline_EstimateSizeOfExpr(expr->data.monadic, size, level) + 1;
break;
ENODE_CASE_DIADIC_ALL:
size = CInline_EstimateSizeOfExpr(expr->data.diadic.left, size, level);
if (size <= inline_max_size)
size = CInline_EstimateSizeOfExpr(expr->data.diadic.right, size, level) + 1;
break;
case EFUNCCALL:
case EFUNCCALLP:
if (
ENODE_IS(expr->data.funccall.funcref, EOBJREF) &&
expr->data.funccall.funcref->data.objref->u.func.u.ifuncdata &&
CInline_CanExpand(expr->data.funccall.funcref)
)
{
recursive_inline |= expr->data.funccall.funcref->data.objref == expanding_function;
if (level == 0) {
if (!recursive_inline)
size = inline_max_size + 1;
} else {
size = CInline_EstimateSizeOfFunc(expr->data.funccall.funcref->data.objref->u.func.u.ifuncdata, size, level - 1);
}
} else {
size++;
}
for (list = expr->data.funccall.args; list; list = list->next) {
if (size > inline_max_size)
break;
size = CInline_EstimateSizeOfExpr(list->node, size, level);
}
break;
case ECOND:
size = CInline_EstimateSizeOfExpr(expr->data.cond.cond, size, level);
if (size <= inline_max_size)
size = CInline_EstimateSizeOfExpr(expr->data.cond.expr1, size, level) + 1;
if (size <= inline_max_size)
size = CInline_EstimateSizeOfExpr(expr->data.cond.expr2, size, level) + 1;
break;
case ENULLCHECK:
size = CInline_EstimateSizeOfExpr(expr->data.nullcheck.nullcheckexpr, size, level);
if (size <= inline_max_size)
size = CInline_EstimateSizeOfExpr(expr->data.nullcheck.condexpr, size, level) + 1;
break;
case EMFPOINTER:
size = CInline_EstimateSizeOfExpr(expr->data.mfpointer.accessnode, size, level);
if (size <= inline_max_size)
size = CInline_EstimateSizeOfExpr(expr->data.mfpointer.mfpointer, size, level) + 1;
break;
case EMEMBER:
if (expr->data.emember->expr)
size = CInline_EstimateSizeOfExpr(expr->data.emember->expr, size, level) + 1;
break;
default:
size++;
}
return size;
}
static SInt32 CInline_EstimateSizeOfFunc(CI_FuncData *funcdata, SInt32 size, SInt32 level) {
CI_Statement *stmt;
SInt32 i;
size += funcdata->numstatements;
if (size > inline_max_size)
return size;
for (i = 0, stmt = funcdata->statements; i < funcdata->numstatements; i++, stmt++) {
switch (stmt->type) {
case ST_NOP:
case ST_LABEL:
case ST_GOTO:
case ST_ASM:
break;
case ST_EXPRESSION:
case ST_IFGOTO:
case ST_IFNGOTO:
case ST_BEGINCATCH:
case ST_ENDCATCH:
case ST_ENDCATCHDTOR:
case ST_GOTOEXPR:
size = CInline_EstimateSizeOfExpr(stmt->u.expr, size, level);
break;
case ST_SWITCH:
size = CInline_EstimateSizeOfExpr(stmt->u.switchdata->expr, size, level);
break;
case ST_RETURN:
if (stmt->u.expr)
size = CInline_EstimateSizeOfExpr(stmt->u.expr, size, level);
break;
default:
CError_FATAL(1840);
}
if (size > inline_max_size)
break;
}
return size;
}
static SInt32 EstimateExpandedSizeOfExpr(ENode *expr, SInt32 level) {
ENodeList *list;
SInt32 size;
size = 0;
switch (expr->type) {
ENODE_CASE_MONADIC:
size = EstimateExpandedSizeOfExpr(expr->data.monadic, level) + 1;
break;
ENODE_CASE_DIADIC_ALL:
size = EstimateExpandedSizeOfExpr(expr->data.diadic.left, level) + 1;
size += EstimateExpandedSizeOfExpr(expr->data.diadic.right, level);
break;
case EFUNCCALL:
case EFUNCCALLP:
if (
ENODE_IS(expr->data.funccall.funcref, EOBJREF) &&
expr->data.funccall.funcref->data.objref->u.func.u.ifuncdata &&
CInline_CanExpand(expr->data.funccall.funcref)
)
{
if (level) {
SInt32 est = CInline_EstimateSizeOfFunc(expr->data.funccall.funcref->data.objref->u.func.u.ifuncdata, size, level - 1);
if (est > inline_max_size)
size++;
else
size += est;
} else {
size++;
}
} else {
size++;
}
for (list = expr->data.funccall.args; list; list = list->next)
size += EstimateExpandedSizeOfExpr(list->node, level);
break;
case ECOND:
size = EstimateExpandedSizeOfExpr(expr->data.cond.cond, level) + 1;
size += EstimateExpandedSizeOfExpr(expr->data.cond.expr1, level);
size += EstimateExpandedSizeOfExpr(expr->data.cond.expr2, level);
break;
case ENULLCHECK:
size = EstimateExpandedSizeOfExpr(expr->data.nullcheck.nullcheckexpr, level) + 1;
size += EstimateExpandedSizeOfExpr(expr->data.nullcheck.condexpr, level);
break;
case EMFPOINTER:
size = EstimateExpandedSizeOfExpr(expr->data.mfpointer.accessnode, level) + 1;
size += EstimateExpandedSizeOfExpr(expr->data.mfpointer.mfpointer, level);
break;
case EMEMBER:
if (expr->data.emember->expr)
size = EstimateExpandedSizeOfExpr(expr->data.emember->expr, level);
break;
default:
size++;
}
return size;
}
static SInt32 EstimateExpandedSizeOfFunction(Statement *stmt) {
SInt32 size;
SInt32 level;
level = copts.inlinelevel;
if (!level)
level = 8;
size = 0;
while (stmt) {
switch (stmt->type) {
case ST_NOP:
break;
case ST_EXPRESSION:
case ST_SWITCH:
case ST_IFGOTO:
case ST_IFNGOTO:
case ST_BEGINCATCH:
case ST_ENDCATCH:
case ST_ENDCATCHDTOR:
case ST_GOTOEXPR:
size++;
size += EstimateExpandedSizeOfExpr(stmt->expr, level);
break;
case ST_RETURN:
size++;
if (stmt->expr)
size = EstimateExpandedSizeOfExpr(stmt->expr, level);
break;
case ST_LABEL:
case ST_GOTO:
case ST_ASM:
size++;
break;
default:
CError_FATAL(2015);
}
stmt = stmt->next;
}
return size;
}
static Boolean CInline_InlineFunctionCheck(ENode *expr) {
Object *object;
SInt32 level;
CI_FuncData *funcdata;
object = expr->data.objref;
if (object->datatype == DALIAS)
object = object->u.alias.object;
if (
IS_TYPE_FUNC(object->type) &&
((object->qual & Q_INLINE) || (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_800)) &&
(object->datatype == DFUNC || (object->datatype == DVFUNC && (expr->flags & ENODE_FLAG_80)))
)
{
if (copts.always_inline)
return 1;
if (copts.inline_bottom_up) {
if (!object->u.func.u.ifuncdata)
return 0;
level = (copts.inlinelevel == 0) ? (7 - cinline_level) : (copts.inlinelevel - cinline_level - 1);
if ((object->qual & Q_INLINE) && level == 0)
return 1;
if (CInline_EstimateSizeOfFunc(object->u.func.u.ifuncdata, 0, level) > inline_max_size)
return 0;
} else if (cinline_level > 0 && copts.inlinelevel == 0) {
funcdata = object->u.func.u.ifuncdata;
if (!funcdata)
return 0;
if (funcdata->numstatements > 10)
return 0;
if (cinline_level > 1 && funcdata->numstatements > 7)
return 0;
if (cinline_level > 2 && funcdata->numstatements > 3)
return 0;
}
return 1;
} else {
return 0;
}
return 0;
}
static ENode *CInline_ExpandExpression(ENode *expr) {
ENodeList *list;
Boolean save;
switch (expr->type) {
case EPOSTINC:
case EPOSTDEC:
case EPREINC:
case EPREDEC:
case EINDIRECT:
case EMONMIN:
case EBINNOT:
case ELOGNOT:
case ETYPCON:
case EBITFIELD:
expr->data.monadic = CInline_ExpandExpression(expr->data.monadic);
break;
case EFORCELOAD:
expr->data.monadic = CInline_ExpandExpression(expr->data.monadic);
if (ENODE_IS(expr->data.monadic, EFORCELOAD))
expr->data.monadic = expr->data.monadic->data.monadic;
break;
case EMUL:
case EDIV:
case EMODULO:
case EADD:
case ESUB:
case ESHL:
case ESHR:
case ELESS:
case EGREATER:
case ELESSEQU:
case EGREATEREQU:
case EEQU:
case ENOTEQU:
case EAND:
case EXOR:
case EOR:
case EASS:
case EMULASS:
case EDIVASS:
case EMODASS:
case EADDASS:
case ESUBASS:
case ESHLASS:
case ESHRASS:
case EANDASS:
case EXORASS:
case EORASS:
case EPMODULO:
case EROTL:
case EROTR:
expr->data.diadic.left = CInline_ExpandExpression(expr->data.diadic.left);
expr->data.diadic.right = CInline_ExpandExpression(expr->data.diadic.right);
break;
case ELAND:
case ELOR:
case ECOMMA:
expr->data.diadic.left = CInline_ExpandExpression(expr->data.diadic.left);
save = cinline_unconditionalpart;
cinline_unconditionalpart = 0;
expr->data.diadic.right = CInline_ExpandExpression(expr->data.diadic.right);
cinline_unconditionalpart = save;
break;
case EFUNCCALL:
case EFUNCCALLP:
expr->data.funccall.funcref = CInline_ExpandExpression(expr->data.funccall.funcref);
for (list = expr->data.funccall.args; list; list = list->next)
list->node = CInline_ExpandExpression(list->node);
if (ENODE_IS(expr->data.funccall.funcref, EOBJREF) && CInline_InlineFunctionCheck(expr->data.funccall.funcref))
expr = CInline_InlineFunctionExpression(expr);
break;
case ENULLCHECK:
expr->data.nullcheck.nullcheckexpr = CInline_ExpandExpression(expr->data.nullcheck.nullcheckexpr);
save = cinline_unconditionalpart;
cinline_unconditionalpart = 0;
expr->data.nullcheck.condexpr = CInline_ExpandExpression(expr->data.nullcheck.condexpr);
cinline_unconditionalpart = save;
break;
case EMFPOINTER:
expr->data.mfpointer.accessnode = CInline_ExpandExpression(expr->data.mfpointer.accessnode);
expr->data.mfpointer.mfpointer = CInline_ExpandExpression(expr->data.mfpointer.mfpointer);
break;
case ECOND:
expr->data.cond.cond = CInline_ExpandExpression(expr->data.cond.cond);
save = cinline_unconditionalpart;
cinline_unconditionalpart = 0;
expr->data.cond.expr1 = CInline_ExpandExpression(expr->data.cond.expr1);
expr->data.cond.expr2 = CInline_ExpandExpression(expr->data.cond.expr2);
cinline_unconditionalpart = save;
break;
case EMEMBER:
if (expr->data.emember->expr)
expr = CInline_ExpandExpression(expr->data.emember->expr);
else
expr = nullnode();
break;
case EINTCONST:
case EFLOATCONST:
case ESTRINGCONST:
case EOBJREF:
case EPRECOMP:
case ELABEL:
case EOBJLIST:
case EINSTRUCTION:
case EVECTOR128CONST:
break;
default:
CError_FATAL(2235);
}
return expr;
}
static Statement *CInline_NewStatement(StatementType sttype) {
Statement *stmt = lalloc(sizeof(Statement));
memclrw(stmt, sizeof(Statement));
stmt->type = sttype;
if (cinline_serial_stmt)
cinline_cur_serial_stmt->next = stmt;
else
cinline_serial_stmt = stmt;
cinline_cur_serial_stmt = stmt;
return stmt;
}
static ENode *CInline_LoadToTemp(ENode *expr, Object **objectptr) {
Object *object;
object = *objectptr;
if (!object) {
switch (expr->rtype->type) {
case TYPEVOID:
return expr;
case TYPEINT:
case TYPEFLOAT:
case TYPEENUM:
case TYPESTRUCT:
case TYPECLASS:
case TYPEMEMBERPOINTER:
case TYPEPOINTER:
object = create_temp_object(expr->rtype);
*objectptr = object;
break;
default:
CError_FATAL(2288);
}
}
return makediadicnode(create_objectnode(object), expr, EASS);
}
static ENode *CInline_SerializeEFORCELOAD(ENode *expr) {
Statement *stmt;
Object *temp = NULL;
while (ENODE_IS(expr->data.monadic, EFORCELOAD)) {
expr->data.monadic = expr->data.monadic->data.monadic;
}
expr->data.monadic = CInline_SerializeExpr(expr->data.monadic);
stmt = CInline_NewStatement(ST_EXPRESSION);
stmt->expr = CInline_LoadToTemp(expr->data.monadic, &temp);
return create_objectnode(temp);
}
static ENode *CInline_SerializeECOMMA(ENode *expr) {
Statement *stmt;
expr->data.diadic.left = CInline_SerializeExpr(expr->data.diadic.left);
stmt = CInline_NewStatement(ST_EXPRESSION);
stmt->expr = expr->data.diadic.left;
return CInline_SerializeExpr(expr->data.diadic.right);
}
static ENode *CInline_SerializeELOR(ENode *expr) {
ENode *n;
Statement *stmt;
CLabel *label;
Object *temp = NULL;
label = newlabel();
n = makemonadicnode(CInline_SerializeExpr(expr->data.diadic.left), ELOGNOT);
n->rtype = expr->rtype;
n = makemonadicnode(n, ELOGNOT);
n = CInline_LoadToTemp(n, &temp);
stmt = CInline_NewStatement(ST_IFGOTO);
stmt->expr = n;
stmt->label = label;
n = makemonadicnode(CInline_SerializeExpr(expr->data.diadic.right), ELOGNOT);
n->rtype = expr->rtype;
n = makemonadicnode(n, ELOGNOT);
n = CInline_LoadToTemp(n, &temp);
stmt = CInline_NewStatement(ST_EXPRESSION);
stmt->expr = n;
stmt = CInline_NewStatement(ST_LABEL);
stmt->label = label;
label->stmt = stmt;
return create_objectnode(temp);
}
static ENode *CInline_SerializeELAND(ENode *expr) {
ENode *n;
Statement *stmt;
CLabel *label;
Object *temp = NULL;
label = newlabel();
n = makemonadicnode(CInline_SerializeExpr(expr->data.diadic.left), ELOGNOT);
n->rtype = expr->rtype;
n = makemonadicnode(n, ELOGNOT);
n = CInline_LoadToTemp(n, &temp);
stmt = CInline_NewStatement(ST_IFNGOTO);
stmt->expr = n;
stmt->label = label;
n = makemonadicnode(CInline_SerializeExpr(expr->data.diadic.right), ELOGNOT);
n->rtype = expr->rtype;
n = makemonadicnode(n, ELOGNOT);
n = CInline_LoadToTemp(n, &temp);
stmt = CInline_NewStatement(ST_EXPRESSION);
stmt->expr = n;
stmt = CInline_NewStatement(ST_LABEL);
stmt->label = label;
label->stmt = stmt;
return create_objectnode(temp);
}
static ENode *CInline_SerializeEPRECOMP(ENode *expr) {
UIDTemp *uidtemp;
uidtemp = cinline_uid_temps;
while (1) {
if (!uidtemp)
CError_FATAL(2449);
if (uidtemp->uid == expr->data.precompid)
return create_objectnode(uidtemp->object);
uidtemp = uidtemp->next;
}
}
static ENode *CInline_SerializeENULLCHECK(ENode *expr) {
Statement *stmt;
CLabel *label;
ENode *n;
Object *temp = NULL;
UIDTemp uidtemp;
label = newlabel();
n = CInline_SerializeExpr(expr->data.nullcheck.nullcheckexpr);
stmt = CInline_NewStatement(ST_IFNGOTO);
stmt->expr = CInline_LoadToTemp(n, &temp);
stmt->label = label;
uidtemp.next = cinline_uid_temps;
uidtemp.object = temp;
uidtemp.uid = expr->data.nullcheck.precompid;
cinline_uid_temps = &uidtemp;
n = CInline_SerializeExpr(expr->data.nullcheck.condexpr);
stmt = CInline_NewStatement(ST_EXPRESSION);
stmt->expr = CInline_LoadToTemp(n, &temp);
cinline_uid_temps = uidtemp.next;
stmt = CInline_NewStatement(ST_LABEL);
stmt->label = label;
label->stmt = stmt;
return create_objectnode(temp);
}
static ENode *CInline_SerializeECOND(ENode *expr) {
Statement *stmt;
CLabel *label1;
CLabel *label2;
ENode *n;
Object *temp = NULL;
label1 = newlabel();
label2 = newlabel();
n = CInline_SerializeExpr(expr->data.cond.cond);
stmt = CInline_NewStatement(ST_IFNGOTO);
stmt->expr = n;
stmt->label = label1;
n = CInline_SerializeExpr(expr->data.cond.expr1);
n = CInline_LoadToTemp(n, &temp);
stmt = CInline_NewStatement(ST_EXPRESSION);
stmt->expr = n;
stmt = CInline_NewStatement(ST_GOTO);
stmt->label = label2;
stmt = CInline_NewStatement(ST_LABEL);
stmt->label = label1;
label1->stmt = stmt;
n = CInline_SerializeExpr(expr->data.cond.expr2);
n = CInline_LoadToTemp(n, &temp);
stmt = CInline_NewStatement(ST_EXPRESSION);
stmt->expr = n;
stmt = CInline_NewStatement(ST_LABEL);
stmt->label = label2;
label2->stmt = stmt;
if (!temp) {
n = nullnode();
n->rtype = &stvoid;
return n;
}
return create_objectnode(temp);
}
static ENode *CInline_SerializeExpr(ENode *expr) {
ENodeList *list;
switch (expr->type) {
case EFORCELOAD:
return CInline_SerializeEFORCELOAD(expr);
case ECOMMA:
return CInline_SerializeECOMMA(expr);
case ELAND:
return CInline_SerializeELAND(expr);
case ELOR:
return CInline_SerializeELOR(expr);
case EPRECOMP:
return CInline_SerializeEPRECOMP(expr);
case ENULLCHECK:
return CInline_SerializeENULLCHECK(expr);
case ECOND:
return CInline_SerializeECOND(expr);
case EINITTRYCATCH:
expr->data.itc.initexpr = CInline_SerializeExpr(expr->data.itc.initexpr);
expr->data.itc.tryexpr = CInline_SerializeExpr(expr->data.itc.tryexpr);
expr->data.itc.catchexpr = CInline_SerializeExpr(expr->data.itc.catchexpr);
expr->data.itc.result = CInline_SerializeExpr(expr->data.itc.result);
return expr;
case EPOSTINC:
case EPOSTDEC:
case EPREINC:
case EPREDEC:
case EINDIRECT:
case EMONMIN:
case EBINNOT:
case ELOGNOT:
case ETYPCON:
case EBITFIELD:
expr->data.monadic = CInline_SerializeExpr(expr->data.monadic);
return expr;
case EMUL:
case EDIV:
case EMODULO:
case EADD:
case ESUB:
case ESHL:
case ESHR:
case ELESS:
case EGREATER:
case ELESSEQU:
case EGREATEREQU:
case EEQU:
case ENOTEQU:
case EAND:
case EXOR:
case EOR:
case EASS:
case EMULASS:
case EDIVASS:
case EMODASS:
case EADDASS:
case ESUBASS:
case ESHLASS:
case ESHRASS:
case EANDASS:
case EXORASS:
case EORASS:
case EPMODULO:
case EROTL:
case EROTR:
expr->data.diadic.left = CInline_SerializeExpr(expr->data.diadic.left);
expr->data.diadic.right = CInline_SerializeExpr(expr->data.diadic.right);
return expr;
case EINTCONST:
case EFLOATCONST:
case ESTRINGCONST:
case EOBJREF:
case ELABEL:
case EOBJLIST:
case EINSTRUCTION:
case EVECTOR128CONST:
return expr;
case EFUNCCALL:
case EFUNCCALLP:
expr->data.funccall.funcref = CInline_SerializeExpr(expr->data.funccall.funcref);
for (list = expr->data.funccall.args; list; list = list->next)
list->node = CInline_SerializeExpr(list->node);
return expr;
case EMFPOINTER:
// bug???
expr->data.mfpointer.accessnode = CInline_SerializeExpr(expr->data.mfpointer.accessnode);
expr->data.mfpointer.accessnode = CInline_SerializeExpr(expr->data.mfpointer.mfpointer);
return expr;
case EMEMBER:
if (expr->data.emember->expr)
return CInline_SerializeExpr(expr->data.emember->expr);
return expr;
default:
CError_FATAL(2684);
return expr;
}
}
void CInline_SerializeStatement(Statement *stmt) {
Statement *scan;
Statement *copy;
cinline_serial_stmt = NULL;
cinline_uid_temps = NULL;
stmt->expr = CInline_SerializeExpr(stmt->expr);
if (cinline_serial_stmt) {
for (scan = cinline_serial_stmt; scan; scan = scan->next) {
scan->value = stmt->value;
scan->dobjstack = stmt->dobjstack;
scan->sourceoffset = stmt->sourceoffset;
scan->sourcefilepath = stmt->sourcefilepath;
}
copy = CInline_NewStatement(ST_EXPRESSION);
*copy = *stmt;
*stmt = *cinline_serial_stmt;
}
}
static void CInline_UnpackSwitch(Statement *stmt, CI_Statement *packstmt, CLabel **labels) {
SwitchInfo *info;
SwitchCase *swcase;
short i;
info = lalloc(sizeof(SwitchInfo));
stmt->label = (CLabel *) info;
CError_ASSERT(2730, info->defaultlabel = labels[packstmt->u.switchdata->defaultlabelID]);
info->x8 = packstmt->u.switchdata->unkSwitch8;
for (i = 0; i < packstmt->u.switchdata->numcases; i++) {
if (i == 0) {
swcase = lalloc(sizeof(SwitchCase));
info->cases = swcase;
} else {
swcase->next = lalloc(sizeof(SwitchCase));
swcase = swcase->next;
}
swcase->next = NULL;
swcase->min = packstmt->u.switchdata->cases[i].min;
swcase->max = packstmt->u.switchdata->cases[i].max;
CError_ASSERT(2740, swcase->label = labels[packstmt->u.switchdata->cases[i].labelID]);
}
}
Object *CInline_GetLocalObj(SInt32 id, Boolean flag) {
ObjectList *list;
if (id) {
if (id & 0x80000000) {
id = (id & 0x7FFFFFFF) - 1;
if (flag) {
CError_ASSERT(2761, local_aobjects[id].object);
return local_aobjects[id].object;
}
for (list = arguments; list; list = list->next, id--) {
if (id == 0)
return list->object;
}
CError_FATAL(2765);
} else {
id--;
if (flag) {
CError_ASSERT(2772, local_dobjects[id]);
return local_dobjects[id];
}
for (list = locals; list; list = list->next, id--) {
if (id == 0)
return list->object;
}
CError_FATAL(2776);
}
}
return NULL;
}
static ExceptionAction *CInline_UnpackActions(CI_Statement *packstmt, Boolean flag) {
ExceptionAction *packexc;
ExceptionAction *last;
ExceptionAction *exc;
packexc = packstmt->dobjstack;
last = NULL;
while (packexc) {
exc = galloc(sizeof(ExceptionAction));
exc->prev = last;
last = exc;
exc->type = packexc->type;
switch (packexc->type) {
case EAT_DESTROYLOCAL:
exc->data.destroy_local.local = CInline_GetLocalObj((SInt32) packexc->data.destroy_local.local, flag);
exc->data.destroy_local.dtor = packexc->data.destroy_local.dtor;
break;
case EAT_DESTROYLOCALCOND:
exc->data.destroy_local_cond.local = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_cond.local, flag);
exc->data.destroy_local_cond.dtor = packexc->data.destroy_local_cond.dtor;
exc->data.destroy_local_cond.cond = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_cond.cond, flag);
break;
case EAT_DESTROYLOCALOFFSET:
exc->data.destroy_local_offset.local = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_offset.local, flag);
exc->data.destroy_local_offset.dtor = packexc->data.destroy_local_offset.dtor;
exc->data.destroy_local_offset.offset = packexc->data.destroy_local_offset.offset;
break;
case EAT_DESTROYLOCALPOINTER:
exc->data.destroy_local_pointer.pointer = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_pointer.pointer, flag);
exc->data.destroy_local_pointer.dtor = packexc->data.destroy_local_pointer.dtor;
break;
case EAT_DESTROYLOCALARRAY:
exc->data.destroy_local_array.localarray = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_array.localarray, flag);
exc->data.destroy_local_array.dtor = packexc->data.destroy_local_array.dtor;
exc->data.destroy_local_array.elements = packexc->data.destroy_local_array.elements;
exc->data.destroy_local_array.element_size = packexc->data.destroy_local_array.element_size;
break;
case EAT_DESTROYPARTIALARRAY:
exc->data.destroy_partial_array.arraypointer = CInline_GetLocalObj((SInt32) packexc->data.destroy_partial_array.arraypointer, flag);
exc->data.destroy_partial_array.arraycounter = CInline_GetLocalObj((SInt32) packexc->data.destroy_partial_array.arraycounter, flag);
exc->data.destroy_partial_array.dtor = CInline_GetLocalObj((SInt32) packexc->data.destroy_partial_array.dtor, flag);
exc->data.destroy_partial_array.element_size = CInline_GetLocalObj((SInt32) packexc->data.destroy_partial_array.element_size, flag);
break;
case EAT_DESTROYMEMBER:
case EAT_DESTROYBASE:
exc->data.destroy_member.objectptr = CInline_GetLocalObj((SInt32) packexc->data.destroy_member.objectptr, flag);
exc->data.destroy_member.dtor = packexc->data.destroy_member.dtor;
exc->data.destroy_member.offset = packexc->data.destroy_member.offset;
break;
case EAT_DESTROYMEMBERCOND:
exc->data.destroy_member_cond.objectptr = CInline_GetLocalObj((SInt32) packexc->data.destroy_member_cond.objectptr, flag);
exc->data.destroy_member_cond.cond = CInline_GetLocalObj((SInt32) packexc->data.destroy_member_cond.cond, flag);
exc->data.destroy_member_cond.dtor = packexc->data.destroy_member_cond.dtor;
exc->data.destroy_member_cond.offset = packexc->data.destroy_member_cond.offset;
break;
case EAT_DESTROYMEMBERARRAY:
exc->data.destroy_member_array.objectptr = CInline_GetLocalObj((SInt32) packexc->data.destroy_member_array.objectptr, flag);
exc->data.destroy_member_array.dtor = packexc->data.destroy_member_array.dtor;
exc->data.destroy_member_array.offset = packexc->data.destroy_member_array.offset;
exc->data.destroy_member_array.elements = packexc->data.destroy_member_array.elements;
exc->data.destroy_member_array.element_size = packexc->data.destroy_member_array.element_size;
break;
case EAT_DELETEPOINTER:
case EAT_DELETELOCALPOINTER:
exc->data.delete_pointer.pointerobject = CInline_GetLocalObj((SInt32) packexc->data.delete_pointer.pointerobject, flag);
exc->data.delete_pointer.deletefunc = packexc->data.delete_pointer.deletefunc;
break;
case EAT_DELETEPOINTERCOND:
exc->data.delete_pointer_cond.pointerobject = CInline_GetLocalObj((SInt32) packexc->data.delete_pointer_cond.pointerobject, flag);
exc->data.delete_pointer_cond.deletefunc = packexc->data.delete_pointer_cond.deletefunc;
exc->data.delete_pointer_cond.cond = CInline_GetLocalObj((SInt32) packexc->data.delete_pointer_cond.cond, flag);
break;
case EAT_CATCHBLOCK: {
LabelTrans *trans;
exc->data.catch_block.catch_object = CInline_GetLocalObj((SInt32) packexc->data.catch_block.catch_object, flag);
exc->data.catch_block.catch_info_object = CInline_GetLocalObj((SInt32) packexc->data.catch_block.catch_info_object, flag);
trans = lalloc(sizeof(LabelTrans));
trans->next = cinline_label_trans;
cinline_label_trans = trans;
trans->id = (SInt32) packexc->data.catch_block.catch_label;
trans->labelptr = &exc->data.catch_block.catch_label;
exc->data.catch_block.catch_typeid = packexc->data.catch_block.catch_typeid;
exc->data.catch_block.catch_type = packexc->data.catch_block.catch_type;
exc->data.catch_block.catch_qual = packexc->data.catch_block.catch_qual;
break;
}
case EAT_ACTIVECATCHBLOCK:
exc->data.active_catch_block.catch_info_object = CInline_GetLocalObj((SInt32) packexc->data.active_catch_block.catch_info_object, flag);
break;
case EAT_SPECIFICATION: {
LabelTrans *trans;
exc->data.specification.unexp_ids = packexc->data.specification.unexp_ids;
exc->data.specification.unexp_id = packexc->data.specification.unexp_id;
trans = lalloc(sizeof(LabelTrans));
trans->next = cinline_label_trans;
cinline_label_trans = trans;
trans->id = (SInt32) packexc->data.specification.unexp_label;
trans->labelptr = &exc->data.specification.unexp_label;
exc->data.specification.unexp_info_object = CInline_GetLocalObj((SInt32) packexc->data.specification.unexp_info_object, flag);
break;
}
case EAT_TERMINATE:
break;
default:
CError_FATAL(2904);
}
packexc = packexc->prev;
}
return last;
}
static Statement *CInline_ExpandStatements(Object *funcobj, Statement *stmt, CI_FuncData *funcdata, ENode *funccall, CLabel *label, Object *resultobj, Boolean flag) {
CLabel **labels;
CI_Statement *packstmt;
short i;
CI_StmtLink *stmtLinks;
CI_StmtLink *link;
ENode *setupArgs;
Boolean is_result_class_1;
Statement origStmt;
origStmt = *stmt;
is_result_class_1 = CMach_GetFunctionResultClass(TYPE_FUNC(funcobj->type)) == 1;
if ((setupArgs = CInline_SetupArgsExpression(funcobj, funcdata, funccall->data.funccall.args))) {
stmt->type = ST_EXPRESSION;
stmt->expr = CInline_FoldConst(setupArgs);
} else {
stmt->type = ST_NOP;
}
stmtLinks = NULL;
cinline_label_trans = NULL;
labels = lalloc(sizeof(CLabel *) * funcdata->numstatements);
memclrw(labels, sizeof(CLabel *) * funcdata->numstatements);
for (i = 0, packstmt = funcdata->statements; i < funcdata->numstatements; i++, packstmt++) {
stmt->next = lalloc(sizeof(Statement));
stmt = stmt->next;
*stmt = origStmt;
stmt->type = packstmt->type;
stmt->flags = packstmt->flags;
stmt->value += packstmt->value;
if (packstmt->dobjstack) {
ExceptionAction *unpacked = CInline_UnpackActions(packstmt, 1);
if (stmt->dobjstack) {
ExceptionAction *scan = unpacked;
while (scan->prev)
scan = scan->prev;
scan->prev = stmt->dobjstack;
}
stmt->dobjstack = unpacked;
}
switch (stmt->type) {
case ST_NOP:
break;
case ST_EXPRESSION:
case ST_BEGINCATCH:
case ST_ENDCATCH:
case ST_ENDCATCHDTOR:
case ST_GOTOEXPR:
stmt->expr = CInline_FoldConst(CInline_CopyExpression(packstmt->u.expr, CopyMode4));
break;
case ST_RETURN:
if (packstmt->u.expr) {
stmt->expr = CInline_FoldConst(CInline_CopyExpression(packstmt->u.expr, CopyMode4));
if (is_result_class_1)
stmt->expr = makecommaexpression(stmt->expr, CInline_ReturnMemResult(funcobj));
if (resultobj) {
stmt->type = ST_EXPRESSION;
stmt->expr = makediadicnode(create_objectnode2(resultobj), stmt->expr, EASS);
} else {
stmt->type = origStmt.type;
if (stmt->type == ST_EXPRESSION && !CInline_ExpressionHasSideEffect(stmt->expr))
stmt->type = ST_NOP;
}
if (label) {
stmt->next = lalloc(sizeof(Statement));
stmt = stmt->next;
*stmt = origStmt;
stmt->type = ST_GOTO;
stmt->label = label;
}
} else {
if (label) {
stmt->type = ST_GOTO;
stmt->label = label;
} else {
stmt->type = ST_NOP;
}
}
break;
case ST_LABEL:
labels[i] = stmt->label = newlabel();
stmt->label->stmt = stmt;
break;
case ST_IFGOTO:
case ST_IFNGOTO:
stmt->expr = CInline_FoldConst(CInline_CopyExpression(packstmt->u.ifgoto.expr, CopyMode4));
case ST_GOTO:
link = lalloc(sizeof(CI_StmtLink));
link->next = stmtLinks;
stmtLinks = link;
link->stmt = stmt;
link->ciStmt = packstmt;
break;
case ST_SWITCH:
stmt->expr = CInline_FoldConst(CInline_CopyExpression(packstmt->u.switchdata->expr, CopyMode4));
case ST_ASM:
link = lalloc(sizeof(CI_StmtLink));
link->next = stmtLinks;
stmtLinks = link;
link->stmt = stmt;
link->ciStmt = packstmt;
break;
default:
CError_FATAL(3040);
}
}
if (label) {
stmt->next = lalloc(sizeof(Statement));
stmt = stmt->next;
*stmt = origStmt;
stmt->type = ST_LABEL;
stmt->label = label;
label->stmt = stmt;
if (flag) {
stmt->next = lalloc(sizeof(Statement));
stmt = stmt->next;
*stmt = origStmt;
}
}
while (stmtLinks) {
Statement *linkstmt = stmtLinks->stmt;
packstmt = stmtLinks->ciStmt;
switch (linkstmt->type) {
case ST_GOTO:
CError_ASSERT(3060, linkstmt->label = labels[packstmt->u.statementnum]);
break;
case ST_IFGOTO:
case ST_IFNGOTO:
CError_ASSERT(3065, linkstmt->label = labels[packstmt->u.ifgoto.statementnum]);
break;
case ST_SWITCH:
CInline_UnpackSwitch(linkstmt, packstmt, labels);
break;
case ST_ASM:
InlineAsm_UnpackAsmStatement(linkstmt, labels, 1, packstmt->u.asmdata.data, packstmt->u.asmdata.size);
break;
default:
CError_FATAL(3076);
}
stmtLinks = stmtLinks->next;
}
while (cinline_label_trans) {
CError_ASSERT(3083, *cinline_label_trans->labelptr = labels[cinline_label_trans->id]);
cinline_label_trans = cinline_label_trans->next;
}
return stmt;
}
static Statement *CInline_InlineFunctionStatement(Statement *stmt, Boolean *changed) {
Object *object;
CI_FuncData *funcdata;
CLabel *label;
*changed = 0;
object = stmt->expr->data.funccall.funcref->data.objref;
if (object->datatype == DALIAS)
object = object->u.alias.object;
funcdata = object->u.func.u.ifuncdata;
if (!funcdata || funcdata->can_inline < CI_CanInline3)
return stmt;
if (stmt->type != ST_EXPRESSION) {
short i;
for (i = 0; i < (funcdata->numstatements - 1); i++) {
if (funcdata->statements[i].type == ST_RETURN)
return stmt;
}
if (funcdata->statements[funcdata->numstatements - 1].type != ST_RETURN)
return stmt;
label = NULL;
} else {
label = newlabel();
}
*changed = 1;
CInline_ExpandStatements(object, stmt, funcdata, stmt->expr, label, NULL, 0);
}
static Statement *CInline_ExtractInlineFunction(Statement *stmt) {
ENode *expr;
CI_FuncData *funcdata;
short i;
Object *funcObject;
Object *resultObject;
for (i = 0; i < cinline_stmtlevelexprs; i++) {
expr = cinline_stmtlevelexpr[i];
funcObject = expr->data.funccall.funcref->data.objref;
if (funcObject->datatype == DALIAS)
funcObject = funcObject->u.alias.object;
if ((funcdata = funcObject->u.func.u.ifuncdata)) {
TypeFunc *tfunc = TYPE_FUNC(funcObject->type);
CError_ASSERT(3141, IS_TYPE_FUNC(tfunc));
if (!IS_TYPE_VOID(tfunc->functype)) {
if (CMach_GetFunctionResultClass(TYPE_FUNC(funcObject->type)) == 1)
resultObject = CInline_NewLocalObject(CDecl_NewPointerType(tfunc->functype), 0, 0, 0);
else
resultObject = CInline_NewLocalObject(tfunc->functype, 0, 0, 0);
} else {
resultObject = NULL;
}
stmt = CInline_ExpandStatements(funcObject, stmt, funcdata, expr, newlabel(), resultObject, 1);
if (resultObject)
*expr = *create_objectnode2(resultObject);
else
*expr = *nullnode();
}
}
return stmt;
}
static Statement *CInline_ExpandStatement(Statement *stmt) {
Boolean changed;
do {
changed = 0;
if (
stmt->type == ST_EXPRESSION &&
ENODE_IS(stmt->expr, EINDIRECT) &&
!CParser_IsVolatile(stmt->expr->rtype, ENODE_QUALS(stmt->expr))
)
{
stmt->expr = stmt->expr->data.monadic;
changed = 1;
if (ENODE_IS2(stmt->expr, EOBJREF, EBITFIELD))
stmt->expr = nullnode();
}
if (ENODE_IS(stmt->expr, ECOMMA)) {
Statement *newStmt = lalloc(sizeof(Statement));
*newStmt = *stmt;
stmt->next = newStmt;
stmt->type = ST_EXPRESSION;
stmt->expr = stmt->expr->data.diadic.left;
newStmt->expr = newStmt->expr->data.diadic.right;
changed = 1;
}
} while (changed);
if (
ENODE_IS2(stmt->expr, EFUNCCALL, EFUNCCALLP) &&
ENODE_IS(stmt->expr->data.funccall.funcref, EOBJREF) &&
CInline_InlineFunctionCheck(stmt->expr->data.funccall.funcref)
)
{
stmt = CInline_InlineFunctionStatement(stmt, &changed);
if (changed) {
any_inline_expanded = 1;
return stmt;
}
}
inline_expanded = 0;
cinline_unconditionalpart = 1;
cinline_serialize_stmt = 0;
cinline_stmtlevelexprs = 0;
stmt->expr = CInline_ExpandExpression(stmt->expr);
if (cinline_serialize_stmt) {
cinline_unconditionalpart = 1;
cinline_serialize_stmt = 0;
cinline_stmtlevelexprs = 0;
CInline_SerializeStatement(stmt);
stmt->expr = CInline_ExpandExpression(stmt->expr);
}
if (inline_expanded) {
stmt->expr = CInline_FoldConst(stmt->expr);
any_inline_expanded = 1;
}
if (cinline_stmtlevelexprs) {
stmt = CInline_ExtractInlineFunction(stmt);
any_inline_expanded = 1;
}
return stmt;
}
static void CInline_ForceReverseSearch(ENode *) {
cinline_funccallfound = 1;
}
static ENode *CInline_ForceReverseEvaluation(ENode *expr) {
ENode *commanodes;
ENodeList *list;
int counter;
ENode *ass;
ENode *inner;
ENode *copy;
list = expr->data.funccall.args;
counter = 0;
commanodes = NULL;
while (list) {
cinline_funccallfound = 0;
inner = list->node;
CExpr_SearchExprTree(inner, CInline_ForceReverseSearch, 2, EFUNCCALL, EFUNCCALLP);
if (cinline_funccallfound && ++counter > 0) {
inner = create_objectrefnode(create_temp_object(inner->rtype));
copy = lalloc(sizeof(ENode));
*copy = *inner;
copy = makemonadicnode(copy, EINDIRECT);
copy->rtype = TPTR_TARGET(copy->rtype);
inner = makemonadicnode(inner, EINDIRECT);
inner->rtype = TPTR_TARGET(inner->rtype);
ass = makediadicnode(inner, copy, EASS);
list->node = copy;
if (commanodes)
commanodes = makediadicnode(ass, commanodes, ECOMMA);
else
commanodes = ass;
}
list = list->next;
}
if (commanodes) {
commanodes = makediadicnode(commanodes, expr, ECOMMA);
commanodes->rtype = expr->rtype;
return commanodes;
}
return expr;
}
static void CInline_ExportCheck(ENode *expr) {
while (1) {
switch (expr->type) {
case EOBJREF:
CInline_ObjectAddrRef(expr->data.objref);
if (expr->data.objref->datatype == DALIAS) {
CExpr_AliasTransform(expr);
continue;
}
return;
ENODE_CASE_MONADIC:
expr = expr->data.monadic;
continue;
ENODE_CASE_DIADIC_ALL:
CInline_ExportCheck(expr->data.diadic.left);
expr = expr->data.diadic.right;
continue;
case EINTCONST:
case EFLOATCONST:
case ESTRINGCONST:
case EPRECOMP:
case EINSTRUCTION:
case EVECTOR128CONST:
return;
case ELABEL:
if (expr->data.label->stmt)
expr->data.label->stmt->flags |= StmtFlag_1;
return;
case EFUNCCALL:
case EFUNCCALLP: {
ENodeList *list;
TypeClass *tclass;
SInt32 index;
for (list = expr->data.funccall.args; list; list = list->next)
CInline_ExportCheck(list->node);
expr = expr->data.funccall.funcref;
if (
copts.warn_notinlined &&
!copts.dont_inline &&
ENODE_IS(expr, EOBJREF) &&
(expr->data.objref->qual & Q_INLINE) &&
expr->data.objref->datatype != DINLINEFUNC &&
!CParser_IsVirtualFunction(expr->data.objref, &tclass, &index)
)
CError_Warning(CErrorStr342, expr->data.objref);
continue;
}
case ENULLCHECK:
CInline_ExportCheck(expr->data.nullcheck.nullcheckexpr);
expr = expr->data.nullcheck.condexpr;
continue;
case EMFPOINTER:
*expr = *nullnode();
continue;
case ECOND:
CInline_ExportCheck(expr->data.cond.cond);
CInline_ExportCheck(expr->data.cond.expr1);
expr = expr->data.cond.expr2;
continue;
case EMEMBER:
if (expr->data.emember->expr) {
*expr = *expr->data.emember->expr;
continue;
}
case EOBJLIST:
*expr = *nullnode();
continue;
default:
CError_FATAL(3372);
}
}
}
static void CInline_Expand(Statement *stmt) {
Statement *scan;
if (!copts.dont_inline && copts.inlinelevel >= 0) {
if (copts.inline_bottom_up) {
inline_max_size = copts.inline_max_size;
while (inline_max_size > 1 && EstimateExpandedSizeOfFunction(stmt) > copts.inline_max_total_size)
inline_max_size >>= 1;
}
cinline_level = 0;
while (1) {
any_inline_expanded = 0;
for (scan = stmt; scan; scan = scan->next) {
switch (scan->type) {
case ST_NOP:
case ST_LABEL:
case ST_GOTO:
case ST_BEGINCATCH:
case ST_ENDCATCH:
case ST_ENDCATCHDTOR:
case ST_ASM:
break;
case ST_RETURN:
if (!scan->expr)
break;
case ST_EXPRESSION:
case ST_SWITCH:
case ST_IFGOTO:
case ST_IFNGOTO:
case ST_GOTOEXPR:
scan = CInline_ExpandStatement(scan);
break;
default:
CError_FATAL(3438);
}
}
if (!copts.inline_bottom_up && !any_inline_expanded)
break;
if (!copts.always_inline || copts.inline_bottom_up) {
if (copts.inlinelevel == 0) {
if (copts.inline_bottom_up) {
if ((cinline_level + 1) >= 8)
break;
} else {
if (cinline_level >= 3)
break;
}
} else {
if ((cinline_level + 1) >= copts.inlinelevel)
break;
}
}
if (CWDisplayLines(cparamblkptr->context, lines) != cwNoErr)
CError_UserBreak();
cinline_level++;
}
}
while (stmt) {
if (stmt->dobjstack)
CExcept_CheckStackRefs(stmt->dobjstack);
switch (stmt->type) {
case ST_NOP:
case ST_LABEL:
case ST_GOTO:
case ST_BEGINCATCH:
case ST_ENDCATCH:
case ST_ENDCATCHDTOR:
case ST_ASM:
break;
case ST_RETURN:
if (!stmt->expr)
break;
case ST_EXPRESSION:
case ST_SWITCH:
case ST_IFGOTO:
case ST_IFNGOTO:
case ST_GOTOEXPR:
CInline_ExportCheck(stmt->expr);
break;
default:
CError_FATAL(3501);
}
stmt = stmt->next;
}
}
SInt16 CInline_GetStatementNumber(Statement *first, Statement *stmt) {
SInt16 number = 0;
while (first) {
if (first == stmt)
return number;
first = first->next;
number++;
}
CError_FATAL(3517);
return 0;
}
static CI_Switch *CInline_PackSwitch(Statement *start, Statement *stmt) {
SwitchInfo *info;
SwitchCase *swcase;
short numcases;
CI_Switch *packed;
info = (SwitchInfo *) stmt->label;
swcase = info->cases;
numcases = 0;
while (swcase) {
swcase = swcase->next;
numcases++;
}
packed = galloc(sizeof(CI_Switch) + numcases * sizeof(CI_SwitchCase));
packed->expr = CInline_CopyExpression(stmt->expr, CopyMode2);
packed->defaultlabelID = CInline_GetStatementNumber(start, info->defaultlabel->stmt);
packed->unkSwitch8 = info->x8;
packed->numcases = numcases;
for (swcase = info->cases, numcases = 0; swcase; swcase = swcase->next, numcases++) {
packed->cases[numcases].labelID = CInline_GetStatementNumber(start, swcase->label->stmt);
packed->cases[numcases].min = swcase->min;
packed->cases[numcases].max = swcase->max;
}
return packed;
}
static UInt8 CInline_CanInline(Object *object, Statement *stmt) {
UInt8 resultClass;
FuncArg *arg;
UInt8 result;
resultClass = CMach_GetFunctionResultClass(TYPE_FUNC(object->type));
if (
resultClass &&
(resultClass != 1 || (IS_TYPE_CLASS(TYPE_FUNC(object->type)->functype) && CClass_Destructor(TYPE_CLASS(TYPE_FUNC(object->type)->functype))))
)
return CI_CanInline0;
for (arg = TYPE_FUNC(object->type)->args; arg; arg = arg->next) {
if (arg == &elipsis)
return CI_CanInline0;
if (arg == &oldstyle)
break;
if (IS_TYPE_CLASS(arg->type) && CClass_Destructor(TYPE_CLASS(arg->type)))
return CI_CanInline0;
}
result = CI_CanInline6;
while (stmt) {
if (stmt->dobjstack)
return CI_CanInline3;
switch (stmt->type) {
case ST_EXPRESSION:
break;
case ST_RETURN:
if (stmt->next || (stmt->expr == NULL && TYPE_FUNC(object->type)->functype != &stvoid))
result = CI_CanInline3;
break;
default:
result = CI_CanInline3;
}
stmt = stmt->next;
}
return result;
}
static ExceptionAction *CInline_PackActions(Statement *start, Statement *stmt) {
ExceptionAction *exc;
ExceptionAction *last;
ExceptionAction *packexc;
exc = stmt->dobjstack;
last = NULL;
while (exc) {
packexc = galloc(sizeof(ExceptionAction));
packexc->prev = last;
last = packexc;
packexc->type = exc->type;
switch (exc->type) {
case EAT_DESTROYLOCAL:
packexc->data.destroy_local.local = (void *) CInline_GetLocalID(exc->data.destroy_local.local);
packexc->data.destroy_local.dtor = exc->data.destroy_local.dtor;
break;
case EAT_DESTROYLOCALCOND:
packexc->data.destroy_local_cond.local = (void *) CInline_GetLocalID(exc->data.destroy_local_cond.local);
packexc->data.destroy_local_cond.dtor = exc->data.destroy_local_cond.dtor;
packexc->data.destroy_local_cond.cond = (void *) CInline_GetLocalID(exc->data.destroy_local_cond.cond);
break;
case EAT_DESTROYLOCALOFFSET:
packexc->data.destroy_local_offset.local = (void *) CInline_GetLocalID(exc->data.destroy_local_offset.local);
packexc->data.destroy_local_offset.dtor = exc->data.destroy_local_offset.dtor;
packexc->data.destroy_local_offset.offset = exc->data.destroy_local_offset.offset;
break;
case EAT_DESTROYLOCALPOINTER:
packexc->data.destroy_local_pointer.pointer = (void *) CInline_GetLocalID(exc->data.destroy_local_pointer.pointer);
packexc->data.destroy_local_pointer.dtor = exc->data.destroy_local_pointer.dtor;
break;
case EAT_DESTROYLOCALARRAY:
packexc->data.destroy_local_array.localarray = (void *) CInline_GetLocalID(exc->data.destroy_local_array.localarray);
packexc->data.destroy_local_array.dtor = exc->data.destroy_local_array.dtor;
packexc->data.destroy_local_array.elements = exc->data.destroy_local_array.elements;
packexc->data.destroy_local_array.element_size = exc->data.destroy_local_array.element_size;
break;
case EAT_DESTROYPARTIALARRAY:
packexc->data.destroy_partial_array.arraypointer = (void *) CInline_GetLocalID(exc->data.destroy_partial_array.arraypointer);
packexc->data.destroy_partial_array.arraycounter = (void *) CInline_GetLocalID(exc->data.destroy_partial_array.arraycounter);
packexc->data.destroy_partial_array.dtor = (void *) CInline_GetLocalID(exc->data.destroy_partial_array.dtor);
packexc->data.destroy_partial_array.element_size = (void *) CInline_GetLocalID(exc->data.destroy_partial_array.element_size);
break;
case EAT_DESTROYMEMBER:
case EAT_DESTROYBASE:
packexc->data.destroy_member.objectptr = (void *) CInline_GetLocalID(exc->data.destroy_member.objectptr);
packexc->data.destroy_member.dtor = exc->data.destroy_member.dtor;
packexc->data.destroy_member.offset = exc->data.destroy_member.offset;
break;
case EAT_DESTROYMEMBERCOND:
packexc->data.destroy_member_cond.objectptr = (void *) CInline_GetLocalID(exc->data.destroy_member_cond.objectptr);
packexc->data.destroy_member_cond.cond = (void *) CInline_GetLocalID(exc->data.destroy_member_cond.cond);
packexc->data.destroy_member_cond.dtor = exc->data.destroy_member_cond.dtor;
packexc->data.destroy_member_cond.offset = exc->data.destroy_member_cond.offset;
break;
case EAT_DESTROYMEMBERARRAY:
packexc->data.destroy_member_array.objectptr = (void *) CInline_GetLocalID(exc->data.destroy_member_array.objectptr);
packexc->data.destroy_member_array.dtor = exc->data.destroy_member_array.dtor;
packexc->data.destroy_member_array.offset = exc->data.destroy_member_array.offset;
packexc->data.destroy_member_array.elements = exc->data.destroy_member_array.elements;
packexc->data.destroy_member_array.element_size = exc->data.destroy_member_array.element_size;
break;
case EAT_DELETEPOINTER:
case EAT_DELETELOCALPOINTER:
packexc->data.delete_pointer.pointerobject = (void *) CInline_GetLocalID(exc->data.delete_pointer.pointerobject);
packexc->data.delete_pointer.deletefunc = exc->data.delete_pointer.deletefunc;
break;
case EAT_DELETEPOINTERCOND:
packexc->data.delete_pointer_cond.pointerobject = (void *) CInline_GetLocalID(exc->data.delete_pointer_cond.pointerobject);
packexc->data.delete_pointer_cond.deletefunc = exc->data.delete_pointer_cond.deletefunc;
packexc->data.delete_pointer_cond.cond = (void *) CInline_GetLocalID(exc->data.delete_pointer_cond.cond);
break;
case EAT_CATCHBLOCK:
packexc->data.catch_block.catch_object = (void *) CInline_GetLocalID(exc->data.catch_block.catch_object);
packexc->data.catch_block.catch_info_object = (void *) CInline_GetLocalID(exc->data.catch_block.catch_info_object);
packexc->data.catch_block.catch_label = (void *) CInline_GetStatementNumber(start->next, exc->data.catch_block.catch_label->stmt);
packexc->data.catch_block.catch_typeid = exc->data.catch_block.catch_typeid;
packexc->data.catch_block.catch_type = exc->data.catch_block.catch_type;
packexc->data.catch_block.catch_qual = exc->data.catch_block.catch_qual;
break;
case EAT_ACTIVECATCHBLOCK:
packexc->data.active_catch_block.catch_info_object = (void *) CInline_GetLocalID(exc->data.active_catch_block.catch_info_object);
packexc->data.active_catch_block.call_dtor = exc->data.active_catch_block.call_dtor;
break;
case EAT_SPECIFICATION:
packexc->data.specification.unexp_ids = exc->data.specification.unexp_ids;
packexc->data.specification.unexp_id = exc->data.specification.unexp_id;
packexc->data.specification.unexp_label = (void *) CInline_GetStatementNumber(start->next, exc->data.specification.unexp_label->stmt);
packexc->data.specification.unexp_info_object = (void *) CInline_GetLocalID(exc->data.specification.unexp_info_object);
break;
case EAT_TERMINATE:
break;
default:
CError_FATAL(3720);
}
exc = exc->prev;
}
return last;
}
void CInline_PackIFunctionData(CI_FuncData *funcdata, Statement *stmt, Object *object) {
ObjectList *list;
CI_Var *var;
Statement *scan;
CI_Statement *packstmt;
int i;
cinline_first_stmt = stmt->next;
memclrw(funcdata, sizeof(CI_FuncData));
funcdata->can_inline = CInline_CanInline(object, stmt->next);
if (copts.isGeneratingDebugInfo) {
funcdata->fileoffset = cparser_fileoffset;
funcdata->fileoffset.is_inline = 1;
funcdata->symdecloffset = symdecloffset;
funcdata->functionbodyoffset = functionbodyoffset;
funcdata->functionbodypath = functionbodypath;
funcdata->symdeclend = symdeclend;
}
list = arguments;
i = 0;
while (list) {
list = list->next;
i++;
}
if ((funcdata->numarguments = i) > 0) {
loc_args = funcdata->arguments = galloc(sizeof(CI_Var) * i);
memclrw(funcdata->arguments, sizeof(CI_Var) * i);
for (list = arguments, var = funcdata->arguments; list; list = list->next, var++) {
var->name = list->object->name;
var->type = list->object->type;
var->qual = list->object->qual;
var->sflags = CInline_GetObjectSFlags(list->object);
var->xD = 0;
var->xE = 1;
}
}
list = locals;
i = 0;
while (list) {
if (list->object->datatype == DLOCAL)
i++;
list = list->next;
}
if ((funcdata->numlocals = i) > 0) {
loc_vars = funcdata->locals = galloc(sizeof(CI_Var) * i);
memclrw(funcdata->locals, sizeof(CI_Var) * i);
for (list = locals, var = funcdata->locals; list; list = list->next) {
if (list->object->datatype == DLOCAL) {
var->name = list->object->name;
var->type = list->object->type;
var->qual = list->object->qual;
var->sflags = CInline_GetObjectSFlags(list->object);
var->xD = 0;
var->xE = 0;
var++;
}
}
}
scan = stmt->next;
i = 0;
while (scan) {
scan = scan->next;
i++;
}
funcdata->numstatements = i;
funcdata->statements = galloc(sizeof(CI_Statement) * i);
for (scan = stmt->next, packstmt = funcdata->statements; scan; scan = scan->next, packstmt++) {
packstmt->type = scan->type;
packstmt->flags = scan->flags;
packstmt->value = scan->value;
packstmt->dobjstack = CInline_PackActions(stmt, scan);
packstmt->sourceoffset = scan->sourceoffset;
packstmt->sourcefilepath = scan->sourcefilepath;
switch (scan->type) {
case ST_NOP:
case ST_LABEL:
break;
case ST_EXPRESSION:
case ST_BEGINCATCH:
case ST_ENDCATCH:
case ST_ENDCATCHDTOR:
case ST_GOTOEXPR:
packstmt->u.expr = CInline_CopyExpression(scan->expr, CopyMode2);
break;
case ST_RETURN:
if (scan->expr)
packstmt->u.expr = CInline_CopyExpression(scan->expr, CopyMode2);
else
packstmt->u.expr = NULL;
break;
case ST_GOTO:
packstmt->u.statementnum = CInline_GetStatementNumber(stmt->next, scan->label->stmt);
break;
case ST_IFGOTO:
case ST_IFNGOTO:
packstmt->u.ifgoto.expr = CInline_CopyExpression(scan->expr, CopyMode2);
packstmt->u.ifgoto.statementnum = CInline_GetStatementNumber(stmt->next, scan->label->stmt);
break;
case ST_SWITCH:
packstmt->u.switchdata = CInline_PackSwitch(stmt->next, scan);
break;
case ST_ASM:
InlineAsm_PackAsmStatement(scan, stmt->next, &packstmt->u.asmdata.data, &packstmt->u.asmdata.size);
break;
default:
CError_FATAL(3862);
}
}
}
void CInline_UnpackIFunctionData(Object *object, CI_FuncData *funcdata, Statement *firstStmt) {
CLabel **labels;
CI_Var *var;
ObjectList *last;
Statement *stmt;
CI_Statement *packstmt;
int i;
cparser_fileoffset = funcdata->fileoffset;
symdecloffset = funcdata->symdecloffset;
functionbodyoffset = funcdata->functionbodyoffset;
functionbodypath = funcdata->functionbodypath;
symdeclend = funcdata->symdeclend;
for (i = 0, var = funcdata->arguments; i < funcdata->numarguments; i++, var++) {
if (i == 0) {
last = lalloc(sizeof(ObjectList));
arguments = last;
} else {
last->next = lalloc(sizeof(ObjectList));
last = last->next;
}
object = galloc(sizeof(Object));
memclrw(object, sizeof(Object));
last->object = object;
last->next = NULL;
object->otype = OT_OBJECT;
object->access = ACCESSPUBLIC;
object->datatype = DLOCAL;
object->name = var->name;
object->type = var->type;
object->qual = var->qual;
CInline_SetObjectSFlags(object, var->sflags);
CFunc_SetupLocalVarInfo(object);
if (funcdata->fileoffset.file) {
object->u.var.info->deftoken.tokenfile = funcdata->fileoffset.file;
object->u.var.info->deftoken.tokenoffset = funcdata->functionbodyoffset;
}
}
for (i = 0, var = funcdata->locals; i < funcdata->numlocals; i++, var++) {
if (i == 0) {
last = lalloc(sizeof(ObjectList));
locals = last;
} else {
last->next = lalloc(sizeof(ObjectList));
last = last->next;
}
object = galloc(sizeof(Object));
memclrw(object, sizeof(Object));
last->object = object;
last->next = NULL;
object->otype = OT_OBJECT;
object->access = ACCESSPUBLIC;
object->datatype = DLOCAL;
object->name = var->name;
object->type = var->type;
object->qual = var->qual;
CInline_SetObjectSFlags(object, var->sflags);
CFunc_SetupLocalVarInfo(object);
if (funcdata->fileoffset.file) {
object->u.var.info->deftoken.tokenfile = funcdata->fileoffset.file;
object->u.var.info->deftoken.tokenoffset = funcdata->functionbodyoffset;
}
}
enode_idtrans = NULL;
cinline_label_trans = NULL;
labels = lalloc(sizeof(CLabel *) * funcdata->numstatements);
memclrw(labels, sizeof(CLabel *) * funcdata->numstatements);
for (i = 0, stmt = firstStmt, packstmt = funcdata->statements; i < funcdata->numstatements; i++, packstmt++) {
stmt->next = lalloc(sizeof(Statement));
stmt = stmt->next;
stmt->type = packstmt->type;
stmt->flags = packstmt->flags;
stmt->value = packstmt->value;
stmt->sourceoffset = packstmt->sourceoffset;
stmt->sourcefilepath = packstmt->sourcefilepath;
stmt->dobjstack = CInline_UnpackActions(packstmt, 0);
stmt->next = NULL;
switch (stmt->type) {
case ST_NOP:
case ST_GOTO:
case ST_ASM:
break;
case ST_EXPRESSION:
case ST_BEGINCATCH:
case ST_ENDCATCH:
case ST_ENDCATCHDTOR:
case ST_GOTOEXPR:
stmt->expr = CInline_CopyExpression(packstmt->u.expr, CopyMode3);
break;
case ST_RETURN:
if (packstmt->u.expr)
stmt->expr = CInline_CopyExpression(packstmt->u.expr, CopyMode3);
else
stmt->expr = NULL;
break;
case ST_LABEL:
labels[i] = stmt->label = newlabel();
stmt->label->stmt = stmt;
break;
case ST_IFGOTO:
case ST_IFNGOTO:
stmt->expr = CInline_CopyExpression(packstmt->u.ifgoto.expr, CopyMode3);
break;
case ST_SWITCH:
stmt->expr = CInline_CopyExpression(packstmt->u.switchdata->expr, CopyMode3);
break;
default:
CError_FATAL(4017);
}
}
for (stmt = firstStmt->next, packstmt = funcdata->statements; stmt; stmt = stmt->next, packstmt++) {
switch (stmt->type) {
case ST_GOTO:
CError_ASSERT(4024, stmt->label = labels[packstmt->u.statementnum]);
break;
case ST_IFGOTO:
case ST_IFNGOTO:
CError_ASSERT(4029, stmt->label = labels[packstmt->u.ifgoto.statementnum]);
break;
case ST_SWITCH:
CInline_UnpackSwitch(stmt, packstmt, labels);
break;
case ST_ASM:
InlineAsm_UnpackAsmStatement(stmt, labels, 0, packstmt->u.asmdata.data, packstmt->u.asmdata.size);
break;
}
}
cinline_first_stmt = firstStmt->next;
while (cinline_label_trans) {
CError_ASSERT(4045, *cinline_label_trans->labelptr = labels[cinline_label_trans->id]);
cinline_label_trans = cinline_label_trans->next;
}
}
static void CInline_GenIFunctionCode(Object *object, CI_FuncData *func, UInt8 unk) {
Boolean saveDebugInfo;
CScopeSave saveScope;
Statement firstStmt;
if (cparamblkptr->isPrecompiling != 1 && func) {
ObjGen_SetupSym();
CScope_SetFunctionScope(object, &saveScope);
CFunc_FuncGenSetup(&firstStmt, object);
CInline_UnpackIFunctionData(object, func, &firstStmt);
saveDebugInfo = copts.isGeneratingDebugInfo;
if (copts.nosyminline || (!symdecloffset && !symdeclend))
copts.isGeneratingDebugInfo = 0;
expanding_function = object;
recursive_inline = 0;
CInline_Expand(&firstStmt);
if (!anyerrors) {
if (copts.isGeneratingDebugInfo)
CPrep_SetSourceFile(&cparser_fileoffset);
CodeGen_Generator(&firstStmt, object, unk, 0);
}
CScope_RestoreScope(&saveScope);
copts.isGeneratingDebugInfo = saveDebugInfo;
}
}
void CInline_AddDefaultFunctionAction(Object *object) {
CI_Action *action;
for (action = cinline_actionlist; action; action = action->next) {
if (action->obj == object)
return;
}
action = galloc(sizeof(CI_Action));
memclrw(action, sizeof(CI_Action));
action->actiontype = CI_ActionDefaultFunc;
action->obj = object;
action->next = cinline_actionlist;
cinline_actionlist = action;
}
void CInline_AddInlineFunctionAction(Object *object, TypeClass *tclass, FileOffsetInfo *fileoffset, TStream *stream, Boolean flag) {
CI_Action *action;
for (action = flag ? cinline_tactionlist : cinline_actionlist; action; action = action->next) {
if (action->obj == object)
return;
}
CError_ASSERT(4132, IS_TYPE_FUNC(object->type));
TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_800000;
action = galloc(sizeof(CI_Action));
memclrw(action, sizeof(CI_Action));
action->actiontype = CI_ActionInlineFunc;
action->obj = object;
action->u.inlinefunc.tclass = tclass;
action->u.inlinefunc.fileoffset = *fileoffset;
action->u.inlinefunc.stream = *stream;
if (flag) {
action->next = cinline_tactionlist;
cinline_tactionlist = action;
TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_200000;
} else {
action->next = cinline_actionlist;
cinline_actionlist = action;
}
}
void CInline_AddMemberFunctionAction(Object *object, TemplClass *templ, TemplClassInst *inst, TemplateMember *tmemb) {
CI_Action *action;
for (action = cinline_tactionlist; action; action = action->next) {
if (action->obj == object)
return;
}
action = galloc(sizeof(CI_Action));
memclrw(action, sizeof(CI_Action));
action->actiontype = CI_ActionMemberFunc;
action->obj = object;
action->u.memberfunc.templ = templ;
action->u.memberfunc.inst = inst;
action->u.memberfunc.tmemb = tmemb;
action->next = cinline_tactionlist;
cinline_tactionlist = action;
TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_200000;
}
void CInline_AddTemplateFunctionAction(Object *object, TemplateFunction *func, TemplFuncInstance *inst) {
CI_Action *action;
for (action = cinline_tactionlist; action; action = action->next) {
if (action->obj == object)
return;
}
action = galloc(sizeof(CI_Action));
memclrw(action, sizeof(CI_Action));
action->actiontype = CI_ActionTemplateFunc;
action->obj = object;
action->u.templatefunc.func = func;
action->u.templatefunc.inst = inst;
action->next = cinline_tactionlist;
cinline_tactionlist = action;
TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_200000;
}
static void CInline_AddFRefList_Object(Object *object) {
ObjectList *list;
if (
!(object->datatype == DFUNC || object->datatype == DVFUNC) ||
(object->flags & OBJECT_FLAGS_4) ||
IS_TEMPL_FUNC(object->type)
)
return;
for (list = cinline_freflist; list; list = list->next) {
if (list->object == object)
return;
}
list = lalloc(sizeof(ObjectList));
list->object = object;
list->next = cinline_freflist;
cinline_freflist = list;
if ((object->qual & Q_INLINE) && object->u.func.u.ifuncdata)
CInline_AddFRefList_InlineFunc(object->u.func.u.ifuncdata);
}
static void CInline_AddFRefList_ExAction(ExceptionAction *exc) {
while (exc) {
switch (exc->type) {
case EAT_DESTROYLOCAL:
CInline_AddFRefList_Object(exc->data.destroy_local.dtor);
break;
case EAT_DESTROYLOCALCOND:
CInline_AddFRefList_Object(exc->data.destroy_local_cond.dtor);
break;
case EAT_DESTROYLOCALOFFSET:
CInline_AddFRefList_Object(exc->data.destroy_local_offset.dtor);
break;
case EAT_DESTROYLOCALPOINTER:
CInline_AddFRefList_Object(exc->data.destroy_local_pointer.dtor);
break;
case EAT_DESTROYLOCALARRAY:
CInline_AddFRefList_Object(exc->data.destroy_local_array.dtor);
break;
case EAT_DESTROYPARTIALARRAY:
CInline_AddFRefList_Object(exc->data.destroy_partial_array.dtor);
break;
case EAT_DESTROYMEMBER:
case EAT_DESTROYBASE:
CInline_AddFRefList_Object(exc->data.destroy_member.dtor);
break;
case EAT_DESTROYMEMBERCOND:
CInline_AddFRefList_Object(exc->data.destroy_member_cond.dtor);
break;
case EAT_DESTROYMEMBERARRAY:
CInline_AddFRefList_Object(exc->data.destroy_member_array.dtor);
break;
case EAT_DELETEPOINTER:
case EAT_DELETELOCALPOINTER:
CInline_AddFRefList_Object(exc->data.delete_pointer.deletefunc);
break;
case EAT_DELETEPOINTERCOND:
CInline_AddFRefList_Object(exc->data.delete_pointer_cond.deletefunc);
break;
case EAT_CATCHBLOCK:
case EAT_ACTIVECATCHBLOCK:
case EAT_SPECIFICATION:
case EAT_TERMINATE:
break;
default:
CError_FATAL(4307);
}
exc = exc->prev;
}
}
static void CInline_AddFRefList_ExprCB(ENode *expr) {
CInline_AddFRefList_Object(expr->data.objref);
}
static void CInline_AddFRefList_Expr(ENode *expr) {
CExpr_SearchExprTree(expr, CInline_AddFRefList_ExprCB, 1, EOBJREF);
}
static void CInline_AddFRefList_Statement(Statement *stmt) {
while (stmt) {
if (stmt->dobjstack)
CInline_AddFRefList_ExAction(stmt->dobjstack);
switch (stmt->type) {
case ST_NOP:
case ST_LABEL:
case ST_GOTO:
case ST_BEGINCATCH:
case ST_ENDCATCH:
case ST_ENDCATCHDTOR:
case ST_ASM:
break;
case ST_RETURN:
if (!stmt->expr)
break;
case ST_EXPRESSION:
case ST_SWITCH:
case ST_IFGOTO:
case ST_IFNGOTO:
case ST_GOTOEXPR:
CInline_AddFRefList_Expr(stmt->expr);
break;
default:
CError_FATAL(4368);
}
stmt = stmt->next;
}
}
static void CInline_AddFRefList_InlineFunc(CI_FuncData *data) {
short i;
CI_Statement *stmt;
ExceptionAction *exc;
for (i = 0; i < data->numstatements; i++) {
stmt = data->statements + i;
switch (stmt->type) {
case ST_NOP:
case ST_LABEL:
case ST_GOTO:
case ST_ASM:
break;
case ST_EXPRESSION:
case ST_BEGINCATCH:
case ST_ENDCATCH:
case ST_ENDCATCHDTOR:
case ST_GOTOEXPR:
CInline_AddFRefList_Expr(stmt->u.expr);
break;
case ST_RETURN:
if (stmt->u.expr)
CInline_AddFRefList_Expr(stmt->u.expr);
break;
case ST_IFGOTO:
case ST_IFNGOTO:
CInline_AddFRefList_Expr(stmt->u.ifgoto.expr);
break;
case ST_SWITCH:
CInline_AddFRefList_Expr(stmt->u.switchdata->expr);
break;
default:
CError_FATAL(4420);
}
for (exc = data->statements[i].dobjstack; exc; exc = exc->prev) {
switch (exc->type) {
case EAT_DESTROYLOCAL:
CInline_AddFRefList_Object(exc->data.destroy_local.dtor);
break;
case EAT_DESTROYLOCALCOND:
CInline_AddFRefList_Object(exc->data.destroy_local_cond.dtor);
break;
case EAT_DESTROYLOCALOFFSET:
CInline_AddFRefList_Object(exc->data.destroy_local_offset.dtor);
break;
case EAT_DESTROYLOCALPOINTER:
CInline_AddFRefList_Object(exc->data.destroy_local_pointer.dtor);
break;
case EAT_DESTROYLOCALARRAY:
CInline_AddFRefList_Object(exc->data.destroy_local_array.dtor);
break;
case EAT_DESTROYPARTIALARRAY:
break;
case EAT_DESTROYMEMBER:
case EAT_DESTROYBASE:
CInline_AddFRefList_Object(exc->data.destroy_member.dtor);
break;
case EAT_DESTROYMEMBERCOND:
CInline_AddFRefList_Object(exc->data.destroy_member_cond.dtor);
break;
case EAT_DESTROYMEMBERARRAY:
CInline_AddFRefList_Object(exc->data.destroy_member_array.dtor);
break;
case EAT_DELETEPOINTER:
case EAT_DELETELOCALPOINTER:
CInline_AddFRefList_Object(exc->data.delete_pointer.deletefunc);
break;
case EAT_DELETEPOINTERCOND:
CInline_AddFRefList_Object(exc->data.delete_pointer_cond.deletefunc);
break;
case EAT_CATCHBLOCK:
case EAT_ACTIVECATCHBLOCK:
case EAT_SPECIFICATION:
case EAT_TERMINATE:
break;
default:
CError_FATAL(4470);
}
}
}
}
static void CInline_GenerateTemplateInline(Object *object) {
CI_Action **ptr;
CI_Action *action;
ptr = &cinline_tactionlist;
while ((action = *ptr)) {
if (object == action->obj) {
*ptr = action->next;
action->next = cinline_actionlist;
cinline_actionlist = action;
TYPE_FUNC(object->type)->flags &= ~FUNC_FLAGS_200000;
return;
}
ptr = &action->next;
}
CError_FATAL(4499);
}
void CInline_ObjectAddrRef(Object *object) {
CI_FuncData *funcdata;
object->flags |= OBJECT_FLAGS_2;
switch (object->datatype) {
case DFUNC:
case DVFUNC:
if (
(object->qual & Q_INLINE) &&
(funcdata = object->u.func.u.ifuncdata) &&
!(object->flags & OBJECT_FLAGS_4) &&
!(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_100000)
)
{
CI_Export *export = galloc(sizeof(CI_Export));
export->object = object;
export->funcdata = funcdata;
export->xC = 0;
export->next = cinline_exportlist;
cinline_exportlist = export;
object->flags |= OBJECT_FLAGS_4;
return;
}
else if (
(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_100) &&
!(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_2)
)
{
CInline_AddDefaultFunctionAction(object);
return;
}
else if (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_200000)
{
CInline_GenerateTemplateInline(object);
return;
}
return;
case DALIAS:
CInline_ObjectAddrRef(object->u.alias.object);
return;
case DDATA:
if (object->qual & Q_10000)
CInit_ExportConst(object);
if (object->flags & OBJECT_FLAGS_8) {
object->flags &= ~OBJECT_FLAGS_8;
CParser_CallBackAction(object);
}
return;
}
}
static Boolean CInline_CheckDependencies(ObjectList *list) {
Object *object;
Boolean result;
result = 0;
while (list) {
object = list->object;
if (
(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_100) &&
!(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_2)
)
{
CInline_AddDefaultFunctionAction(object);
result = 1;
}
else if (
(object->qual & Q_400000) &&
CTempl_InlineFunctionCheck(object)
)
{
result = 1;
}
else {
CI_Action *action;
for (action = cinline_actionlist; action; action = action->next) {
if (object == action->obj) {
result = 1;
break;
}
}
if (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_200000) {
CInline_GenerateTemplateInline(object);
result = 1;
}
}
list = list->next;
}
return result;
}
static Boolean CInline_IsSmallFunction(Object *object, Statement *stmt) {
SInt32 statementCount;
ObjectList *list;
SInt32 localSize;
statementCount = 0;
while (stmt) {
if (stmt->type != ST_NOP && stmt->type != ST_LABEL)
statementCount++;
if (statementCount > 15)
return 0;
stmt = stmt->next;
}
for (list = locals, localSize = 0; list; list = list->next)
localSize += list->object->type->size;
if (localSize > 1024)
return 0;
return 1;
}
static Boolean CInline_NoFPLocals(void) {
ObjectList *list;
for (list = locals; list; list = list->next) {
if (IS_TYPE_FLOAT(list->object->type))
return 0;
}
return 1;
}
void CInline_GenFunc(Statement *stmt, Object *object, UInt8 unk) {
CI_FuncData *funcdata;
CI_Export *export;
Boolean flag24;
Boolean flag30;
TYPE_FUNC(object->type)->flags |= OBJECT_FLAGS_2;
flag24 = 0;
flag30 = 0;
if (!(object->qual & Q_INLINE)) {
if (
copts.autoinline &&
!copts.dont_inline &&
CInline_CanInline(object, stmt->next) &&
CInline_IsSmallFunction(object, stmt->next)
)
{
flag24 = 1;
flag30 = 1;
TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_800;
}
} else {
flag30 = 1;
}
if (flag30) {
COpt_SimpleOptimizer(object, stmt);
funcdata = galloc(sizeof(CI_FuncData));
CInline_PackIFunctionData(funcdata, stmt, object);
object->u.func.u.ifuncdata = funcdata;
if (!flag24 && !(object->flags & OBJECT_FLAGS_2)) {
if (cinline_gendeps) {
cinline_freflist = NULL;
CInline_AddFRefList_Statement(stmt);
CInline_CheckDependencies(cinline_freflist);
}
return;
}
}
object->flags |= OBJECT_FLAGS_4;
cinline_freflist = NULL;
CInline_AddFRefList_Statement(stmt);
if (CInline_CheckDependencies(cinline_freflist) || copts.defer_codegen) {
if (!flag30) {
funcdata = galloc(sizeof(CI_FuncData));
CInline_PackIFunctionData(funcdata, stmt, object);
} else {
funcdata = object->u.func.u.ifuncdata;
}
export = galloc(sizeof(CI_Export));
export->object = object;
export->funcdata = funcdata;
export->xC = unk;
export->next = cinline_exportlist;
cinline_exportlist = export;
return;
}
expanding_function = object;
recursive_inline = 0;
CInline_Expand(stmt);
if (copts.isGeneratingDebugInfo)
CPrep_SetSourceFile(&cparser_fileoffset);
if (!anyerrors)
CodeGen_Generator(stmt, object, unk, 0);
}
static void CInline_GenerateDefaultFunc(Object *object) {
TypeClass *tclass;
CError_ASSERT(4770, TYPE_FUNC(object->type)->flags & FUNC_FLAGS_100);
CError_ASSERT(4771, TYPE_FUNC(object->type)->flags & FUNC_FLAGS_METHOD);
tclass = TYPE_METHOD(object->type)->theclass;
if (object == CClass_DefaultConstructor(tclass)) {
if (object->u.func.defargdata)
CABI_MakeDefaultArgConstructor(tclass, object);
else
CABI_MakeDefaultConstructor(tclass, object);
} else if (object == CClass_CopyConstructor(tclass)) {
CABI_MakeDefaultCopyConstructor(tclass, object);
} else if (object == CClass_AssignmentOperator(tclass)) {
CABI_MakeDefaultAssignmentOperator(tclass, object);
} else if (object == CClass_Destructor(tclass)) {
CABI_MakeDefaultDestructor(tclass, object);
} else {
CError_FATAL(4805);
}
}
static TemplClassInst *CInline_FindNestedTemplInst(TypeClass *tclass) {
NameSpace *nspace;
while (tclass) {
if ((tclass->flags & CLASS_FLAGS_800))
return TEMPL_CLASS_INST(tclass);
if (!copts.template_patch)
break;
nspace = tclass->nspace->parent;
tclass = NULL;
while (nspace) {
if (nspace->theclass) {
tclass = nspace->theclass;
break;
}
nspace = nspace->parent;
}
}
return NULL;
}
static void CInline_GenerateInlineFunc(CI_Action *action) {
Object *object;
TemplClassInst *inst;
DeclInfo di;
SInt32 streamState;
object = action->obj;
CPrep_StreamInsert(&action->u.inlinefunc.stream, &streamState);
cparser_fileoffset = action->u.inlinefunc.fileoffset;
symdecloffset = cparser_fileoffset.tokenline;
switch ((tk = lex())) {
case ':':
case '{':
case TK_TRY:
break;
default:
CError_FATAL(4860);
}
symdecltoken = *CPrep_CurStreamElement();
TYPE_FUNC(object->type)->flags &= ~FUNC_FLAGS_2;
if (IS_TYPE_METHOD(object->type) && (inst = CInline_FindNestedTemplInst(TYPE_METHOD(object->type)->theclass))) {
CTempl_ParseInstanceScopeFunction(object, inst, NULL);
} else {
memclrw(&di, sizeof(di));
if (action->u.inlinefunc.tclass) {
if ((inst = CInline_FindNestedTemplInst(action->u.inlinefunc.tclass))) {
CTempl_ParseInstanceScopeFunction(object, inst, action->u.inlinefunc.tclass);
} else {
CFunc_ParseFuncDef(object, &di, action->u.inlinefunc.tclass, 0, 0, NULL);
}
} else {
CFunc_ParseFuncDef(object, &di, NULL, 0, 0, NULL);
}
}
CPrep_StreamRemove(&action->u.inlinefunc.stream, &streamState);
}
Boolean CInline_CanFreeLHeap(void) {
CI_Action *action;
if (!anyerrors) {
for (action = cinline_actionlist; action; action = action->next) {
if (action->actiontype == CI_ActionInlineFunc)
return 0;
}
}
return 1;
}
Boolean CInline_GenerateDeferredFuncs(void) {
CI_Action *action;
CI_Export *export;
if (!anyerrors) {
if ((action = cinline_actionlist)) {
cinline_actionlist = action->next;
cinline_gendeps = 1;
switch (action->actiontype) {
case CI_ActionDefaultFunc:
CInline_GenerateDefaultFunc(action->obj);
break;
case CI_ActionInlineFunc:
if (!(action->obj->flags & OBJECT_FLAGS_4))
CInline_GenerateInlineFunc(action);
break;
case CI_ActionMemberFunc:
if (!(TYPE_FUNC(action->obj->type)->flags & FUNC_FLAGS_2))
CTempl_InstantiateMember(
action->u.memberfunc.templ, action->u.memberfunc.inst,
action->u.memberfunc.tmemb, action->obj, 0);
break;
case CI_ActionTemplateFunc:
if (!(TYPE_FUNC(action->obj->type)->flags & FUNC_FLAGS_2) && !action->u.templatefunc.inst->is_specialized)
CTempl_GenFuncInstance(action->u.templatefunc.func, action->u.templatefunc.inst, 0);
break;
default:
CError_FATAL(5001);
}
cinline_gendeps = 0;
return 1;
} else {
if ((export = cinline_exportlist) && !copts.defer_codegen) {
cinline_exportlist = export->next;
CInline_GenIFunctionCode(export->object, export->funcdata, export->xC);
return 1;
}
}
}
return 0;
}
static InitExpr *CInline_InitTemplateData(InitExpr *init) {
Statement *stmt;
CLabel *label;
Object *object;
Object *data;
object = init->object;
data = CParser_NewCompilerDefDataObject();
data->type = TYPE(&stsignedchar);
data->name = CParser_NameConcat("__init__", CMangler_GetLinkName(object)->name);
data->qual = Q_OVERLOAD;
CInit_DeclareData(data, NULL, NULL, data->type->size);
stmt = CFunc_AppendStatement(ST_IFGOTO);
stmt->expr = create_objectnode(data);
label = newlabel();
stmt->label = label;
do {
stmt = CFunc_AppendStatement(ST_EXPRESSION);
stmt->expr = CInline_CopyExpression(init->expr, CopyMode0);
init = init->next;
} while (init && init->object == object);
stmt = CFunc_AppendStatement(ST_EXPRESSION);
stmt->expr = makediadicnode(create_objectnode(data), intconstnode(TYPE(&stsignedchar), 1), EASS);
stmt = CFunc_AppendStatement(ST_LABEL);
stmt->label = label;
label->stmt = stmt;
return init;
}
void CInline_Finish(void) {
NameSpace *nspace;
Boolean saveDebugInfo;
Statement firstStmt;
Statement *stmt;
InitExpr *init;
Boolean doMore;
if (!init_expressions || anyerrors)
return;
cinline_freflist = NULL;
for (init = init_expressions; init; init = init->next)
CInline_AddFRefList_Expr(init->expr);
CInline_CheckDependencies(cinline_freflist);
do {
doMore = CInline_GenerateDeferredFuncs();
} while (doMore);
nspace = CFunc_FuncGenSetup(&firstStmt, NULL);
saveDebugInfo = copts.isGeneratingDebugInfo;
copts.isGeneratingDebugInfo = 0;
init = init_expressions;
while (init) {
if (init->object->nspace->theclass && (init->object->nspace->theclass->flags & CLASS_FLAGS_800)) {
init = CInline_InitTemplateData(init);
} else {
stmt = CFunc_AppendStatement(ST_EXPRESSION);
stmt->expr = CInline_CopyExpression(init->expr, CopyMode0);
init = init->next;
}
}
CFunc_CodeCleanup(&firstStmt);
expanding_function = NULL;
recursive_inline = 0;
CInline_Expand(&firstStmt);
if (!anyerrors) {
if (copts.isGeneratingDebugInfo)
CPrep_SetSourceFile(&cparser_fileoffset);
CodeGen_Generator(&firstStmt, NULL, 0, 1);
}
cscope_current = nspace->parent;
copts.isGeneratingDebugInfo = saveDebugInfo;
}