#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 = ©->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; }