diff options
Diffstat (limited to 'compiler_and_linker/FrontEnd/C/CInline.c')
-rw-r--r-- | compiler_and_linker/FrontEnd/C/CInline.c | 4206 |
1 files changed, 4206 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CInline.c b/compiler_and_linker/FrontEnd/C/CInline.c new file mode 100644 index 0000000..de51ab7 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CInline.c @@ -0,0 +1,4206 @@ +#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 +CW_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.alwaysinline) + 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; + return 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.dontinline && + 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.dontinline && copts.inlinelevel >= 0) { + if (copts.inline_bottom_up) { + inline_max_size = copts.inlinemaxsize; + while (inline_max_size > 1 && EstimateExpandedSizeOfFunction(stmt) > copts.inlinemaxtotalsize) + 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.alwaysinline || 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.filesyminfo) { + 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->precompile != 1 && func) { + ObjGen_SetupSym(); + CScope_SetFunctionScope(object, &saveScope); + CFunc_FuncGenSetup(&firstStmt, object); + CInline_UnpackIFunctionData(object, func, &firstStmt); + + saveDebugInfo = copts.filesyminfo; + if (copts.nosyminline || (!symdecloffset && !symdeclend)) + copts.filesyminfo = 0; + + expanding_function = object; + recursive_inline = 0; + CInline_Expand(&firstStmt); + + if (!anyerrors) { + if (copts.filesyminfo) + CPrep_SetSourceFile(&cparser_fileoffset); + CodeGen_Generator(&firstStmt, object, unk, 0); + } + + CScope_RestoreScope(&saveScope); + copts.filesyminfo = 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, TokenStream *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_IS_TEMPL_INSTANCE; + + 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_DEFINED) || + 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_DEFINED) && + !(TYPE_FUNC(object->type)->flags & FUNC_IS_TEMPL) + ) + { + 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_DEFINED; + return; + } + else if ( + (TYPE_FUNC(object->type)->flags & FUNC_AUTO_GENERATED) && + !(TYPE_FUNC(object->type)->flags & FUNC_DEFINED) + ) + { + 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_INLINE_DATA) + CInit_ExportConst(object); + + if (object->flags & OBJECT_LAZY) { + object->flags &= ~OBJECT_LAZY; + 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_AUTO_GENERATED) && + !(TYPE_FUNC(object->type)->flags & FUNC_DEFINED) + ) + { + CInline_AddDefaultFunctionAction(object); + result = 1; + } + else if ( + (object->qual & Q_IS_TEMPLATED) && + 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.auto_inline && + !copts.dontinline && + 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_DEFINED; + + 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.filesyminfo) + 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_AUTO_GENERATED); + CError_ASSERT(4771, TYPE_FUNC(object->type)->flags & FUNC_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_IS_TEMPL_INST)) + 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_DEFINED; + 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_DEFINED)) + CInline_GenerateInlineFunc(action); + break; + case CI_ActionMemberFunc: + if (!(TYPE_FUNC(action->obj->type)->flags & FUNC_DEFINED)) + 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_DEFINED) && !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_WEAK; + 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.filesyminfo; + copts.filesyminfo = 0; + + init = init_expressions; + while (init) { + if (init->object->nspace->theclass && (init->object->nspace->theclass->flags & CLASS_IS_TEMPL_INST)) { + 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.filesyminfo) + CPrep_SetSourceFile(&cparser_fileoffset); + CodeGen_Generator(&firstStmt, NULL, 0, 1); + } + + cscope_current = nspace->parent; + copts.filesyminfo = saveDebugInfo; +} |