mirror of https://git.wuffs.org/MWCC
4207 lines
134 KiB
C
4207 lines
134 KiB
C
#include "compiler/CInline.h"
|
|
#include "compiler/CABI.h"
|
|
#include "compiler/CClass.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CException.h"
|
|
#include "compiler/CExpr.h"
|
|
#include "compiler/CFunc.h"
|
|
#include "compiler/CInit.h"
|
|
#include "compiler/CInt64.h"
|
|
#include "compiler/CMachine.h"
|
|
#include "compiler/CMangler.h"
|
|
#include "compiler/COptimizer.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/CPrepTokenizer.h"
|
|
#include "compiler/CTemplateNew.h"
|
|
#include "compiler/CodeGen.h"
|
|
#include "compiler/CompilerTools.h"
|
|
#include "compiler/Exceptions.h"
|
|
#include "compiler/InlineAsm.h"
|
|
#include "compiler/ObjGenMachO.h"
|
|
#include "compiler/Switch.h"
|
|
#include "compiler/enode.h"
|
|
#include "compiler/objects.h"
|
|
#include "compiler/scopes.h"
|
|
#include "compiler/templates.h"
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma options align=mac68k
|
|
#endif
|
|
typedef struct IDTrans {
|
|
struct IDTrans *next;
|
|
SInt32 from;
|
|
SInt32 to;
|
|
} IDTrans;
|
|
|
|
typedef struct LabelTrans {
|
|
struct LabelTrans *next;
|
|
CLabel **labelptr;
|
|
short id;
|
|
} LabelTrans;
|
|
|
|
typedef struct UIDTemp {
|
|
struct UIDTemp *next;
|
|
Object *object;
|
|
SInt32 uid;
|
|
} UIDTemp;
|
|
|
|
typedef struct CI_Export {
|
|
struct CI_Export *next;
|
|
Object *object;
|
|
CI_FuncData *funcdata;
|
|
Boolean xC;
|
|
} CI_Export;
|
|
|
|
typedef struct AObject {
|
|
Object *object;
|
|
ENode *expr1;
|
|
ENode *expr2;
|
|
} AObject;
|
|
|
|
typedef struct CI_StmtLink {
|
|
struct CI_StmtLink *next;
|
|
Statement *stmt;
|
|
CI_Statement *ciStmt;
|
|
} CI_StmtLink;
|
|
#ifdef __MWERKS__
|
|
#pragma options align=reset
|
|
#endif
|
|
|
|
static CInlineCopyMode enode_copymode;
|
|
static Boolean enode_globalcopy;
|
|
static IDTrans *enode_idtrans;
|
|
static Object **local_dobjects;
|
|
static AObject *local_aobjects;
|
|
static CI_Var *loc_args;
|
|
static CI_Var *loc_vars;
|
|
static Boolean inline_expanded;
|
|
static Boolean any_inline_expanded;
|
|
static short cinline_level;
|
|
static LabelTrans *cinline_label_trans;
|
|
static Statement *cinline_first_stmt;
|
|
static ENode *cinline_stmtlevelexpr[16];
|
|
static short cinline_stmtlevelexprs;
|
|
static Boolean cinline_unconditionalpart;
|
|
static Boolean cinline_serialize_stmt;
|
|
static CI_Export *cinline_exportlist; // type?
|
|
static CI_Action *cinline_actionlist;
|
|
CI_Action *cinline_tactionlist;
|
|
static ObjectList *cinline_freflist;
|
|
static Boolean cinline_gendeps;
|
|
static Statement *cinline_serial_stmt;
|
|
static Statement *cinline_cur_serial_stmt;
|
|
static UIDTemp *cinline_uid_temps;
|
|
static Boolean cinline_has_sideeffect;
|
|
static SInt32 inline_max_size;
|
|
static Boolean recursive_inline;
|
|
static Object *expanding_function;
|
|
static Boolean cinline_funccallfound;
|
|
|
|
// forward decls
|
|
static ENode *CInline_FoldConst(ENode *expr);
|
|
static ENode *CInline_CopyNodes(ENode *node);
|
|
static SInt32 CInline_EstimateSizeOfFunc(CI_FuncData *funcdata, SInt32 size, SInt32 level);
|
|
static ENode *CInline_SerializeExpr(ENode *expr);
|
|
static void CInline_AddFRefList_InlineFunc(CI_FuncData *data);
|
|
|
|
void CInline_Init(void) {
|
|
cinline_exportlist = NULL;
|
|
cinline_actionlist = NULL;
|
|
cinline_tactionlist = NULL;
|
|
cinline_gendeps = 0;
|
|
}
|
|
|
|
static ENode *CInline_MakeNotNot(ENode *expr) {
|
|
expr = CInline_FoldConst(expr);
|
|
|
|
if (!ENODE_IS(expr, EINTCONST)) {
|
|
expr = makemonadicnode(expr, ELOGNOT);
|
|
expr->rtype = CParser_GetBoolType();
|
|
expr = makemonadicnode(expr, ELOGNOT);
|
|
} else {
|
|
expr->data.intval = CInt64_Not(CInt64_Not(expr->data.intval));
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
static ENode *CInline_FoldConst(ENode *expr) {
|
|
ENode *inner;
|
|
ENode *right;
|
|
ENode *left;
|
|
ENodeList *list;
|
|
|
|
switch (expr->type) {
|
|
case EINTCONST:
|
|
case EFLOATCONST:
|
|
case ESTRINGCONST:
|
|
case EOBJREF:
|
|
case EPRECOMP:
|
|
case ETEMP:
|
|
case ELABEL:
|
|
case EOBJLIST:
|
|
case EINSTRUCTION:
|
|
case EVECTOR128CONST:
|
|
return expr;
|
|
|
|
case EMONMIN:
|
|
case EBINNOT:
|
|
case ELOGNOT:
|
|
expr->data.monadic = CInline_FoldConst(expr->data.monadic);
|
|
inner = expr->data.monadic;
|
|
switch (inner->type) {
|
|
case EINTCONST:
|
|
if (!ENODE_IS(expr, ELOGNOT)) {
|
|
inner->data.intval = CMach_CalcIntMonadic(
|
|
expr->rtype, CParser_GetOperator(expr->type), inner->data.intval);
|
|
} else {
|
|
inner->data.intval = CInt64_Not(inner->data.intval);
|
|
}
|
|
inner->rtype = expr->rtype;
|
|
return inner;
|
|
|
|
case EFLOATCONST:
|
|
if (ENODE_IS(expr, ELOGNOT)) {
|
|
inner->type = EINTCONST;
|
|
CInt64_SetLong(&inner->data.intval, CMach_FloatIsZero(inner->data.floatval));
|
|
} else {
|
|
inner->data.floatval = CMach_CalcFloatMonadic(
|
|
expr->rtype, CParser_GetOperator(expr->type), inner->data.floatval);
|
|
}
|
|
inner->rtype = expr->rtype;
|
|
return inner;
|
|
}
|
|
|
|
return expr;
|
|
|
|
case ETYPCON:
|
|
expr->data.monadic = CInline_FoldConst(expr->data.monadic);
|
|
switch (expr->data.monadic->type) {
|
|
case EINTCONST:
|
|
switch (expr->rtype->type) {
|
|
case TYPEFLOAT:
|
|
expr->type = EFLOATCONST;
|
|
expr->data.floatval = CMach_CalcFloatConvertFromInt(
|
|
expr->data.monadic->rtype, expr->data.monadic->data.intval);
|
|
return expr;
|
|
|
|
case TYPEINT:
|
|
expr->type = EINTCONST;
|
|
expr->data.intval = CExpr_IntConstConvert(
|
|
expr->rtype, expr->data.monadic->rtype, expr->data.monadic->data.intval);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case EFLOATCONST:
|
|
switch (expr->rtype->type) {
|
|
case TYPEFLOAT:
|
|
expr->type = EFLOATCONST;
|
|
expr->data.floatval = CMach_CalcFloatConvert(
|
|
expr->rtype, expr->data.monadic->data.floatval);
|
|
return expr;
|
|
|
|
case TYPEINT:
|
|
expr->type = EINTCONST;
|
|
expr->data.intval = CMach_CalcIntConvertFromFloat(
|
|
expr->rtype, expr->data.monadic->data.floatval);
|
|
return expr;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return expr;
|
|
|
|
case EPOSTINC:
|
|
case EPOSTDEC:
|
|
expr->data.monadic = CInline_FoldConst(expr->data.monadic);
|
|
switch (expr->data.monadic->type) {
|
|
case EINTCONST:
|
|
case EFLOATCONST:
|
|
expr->data.monadic->rtype = expr->rtype;
|
|
return expr->data.monadic;
|
|
}
|
|
|
|
return expr;
|
|
|
|
case EPREINC:
|
|
case EPREDEC:
|
|
case EINDIRECT:
|
|
case EFORCELOAD:
|
|
case EBITFIELD:
|
|
expr->data.monadic = CInline_FoldConst(expr->data.monadic);
|
|
return expr;
|
|
|
|
case EMUL:
|
|
case EDIV:
|
|
case EMODULO:
|
|
case EADD:
|
|
case ESUB:
|
|
case ESHL:
|
|
case ESHR:
|
|
case EAND:
|
|
case EXOR:
|
|
case EOR:
|
|
expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
|
|
expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
|
|
if ((left = expr->data.diadic.left)->type == (right = expr->data.diadic.right)->type) {
|
|
switch (left->type) {
|
|
case EINTCONST:
|
|
left->data.intval = CMach_CalcIntDiadic(
|
|
expr->rtype,
|
|
expr->data.diadic.left->data.intval,
|
|
CParser_GetOperator(expr->type),
|
|
right->data.intval);
|
|
left->rtype = expr->rtype;
|
|
return left;
|
|
|
|
case EFLOATCONST:
|
|
left->data.floatval = CMach_CalcFloatDiadic(
|
|
expr->rtype,
|
|
expr->data.diadic.left->data.floatval,
|
|
CParser_GetOperator(expr->type),
|
|
right->data.floatval);
|
|
left->rtype = expr->rtype;
|
|
return left;
|
|
}
|
|
}
|
|
|
|
return expr;
|
|
|
|
case ELESS:
|
|
case EGREATER:
|
|
case ELESSEQU:
|
|
case EGREATEREQU:
|
|
case EEQU:
|
|
case ENOTEQU:
|
|
expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
|
|
expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
|
|
if ((left = expr->data.diadic.left)->type == (right = expr->data.diadic.right)->type) {
|
|
switch (left->type) {
|
|
case EINTCONST:
|
|
left->data.intval = CMach_CalcIntDiadic(
|
|
left->rtype,
|
|
expr->data.diadic.left->data.intval,
|
|
CParser_GetOperator(expr->type),
|
|
right->data.intval);
|
|
left->rtype = expr->rtype;
|
|
return left;
|
|
|
|
case EFLOATCONST:
|
|
CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(
|
|
left->rtype,
|
|
expr->data.diadic.left->data.floatval,
|
|
CParser_GetOperator(expr->type),
|
|
right->data.floatval
|
|
));
|
|
left->type = EINTCONST;
|
|
left->rtype = expr->rtype;
|
|
return left;
|
|
}
|
|
}
|
|
|
|
return expr;
|
|
|
|
case ELAND:
|
|
expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
|
|
if (iszero(expr->data.diadic.left))
|
|
return expr->data.diadic.left;
|
|
if (isnotzero(expr->data.diadic.left))
|
|
return CInline_MakeNotNot(expr->data.diadic.right);
|
|
|
|
expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
|
|
if (isnotzero(expr->data.diadic.right))
|
|
return CInline_MakeNotNot(expr->data.diadic.left);
|
|
|
|
return expr;
|
|
|
|
case ELOR:
|
|
expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
|
|
if (iszero(expr->data.diadic.left))
|
|
return CInline_MakeNotNot(expr->data.diadic.right);
|
|
if (isnotzero(expr->data.diadic.left))
|
|
return CInline_MakeNotNot(expr->data.diadic.left);
|
|
|
|
expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
|
|
if (iszero(expr->data.diadic.right))
|
|
return CInline_MakeNotNot(expr->data.diadic.left);
|
|
|
|
return expr;
|
|
|
|
case EASS:
|
|
case EMULASS:
|
|
case EDIVASS:
|
|
case EMODASS:
|
|
case EADDASS:
|
|
case ESUBASS:
|
|
case ESHLASS:
|
|
case ESHRASS:
|
|
case EANDASS:
|
|
case EXORASS:
|
|
case EORASS:
|
|
case ECOMMA:
|
|
case EROTL:
|
|
case EROTR:
|
|
expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
|
|
expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
|
|
return expr;
|
|
|
|
case ECOND:
|
|
expr->data.cond.cond = CInline_FoldConst(expr->data.cond.cond);
|
|
if (isnotzero(expr->data.cond.cond))
|
|
return CInline_FoldConst(expr->data.cond.expr1);
|
|
if (iszero(expr->data.cond.cond))
|
|
return CInline_FoldConst(expr->data.cond.expr2);
|
|
|
|
expr->data.cond.expr1 = CInline_FoldConst(expr->data.cond.expr1);
|
|
expr->data.cond.expr2 = CInline_FoldConst(expr->data.cond.expr2);
|
|
return expr;
|
|
|
|
case EMFPOINTER:
|
|
expr->data.mfpointer.accessnode = CInline_FoldConst(expr->data.mfpointer.accessnode);
|
|
expr->data.mfpointer.mfpointer = CInline_FoldConst(expr->data.mfpointer.mfpointer);
|
|
return expr;
|
|
|
|
case EFUNCCALL:
|
|
case EFUNCCALLP:
|
|
expr->data.funccall.funcref = CInline_FoldConst(expr->data.funccall.funcref);
|
|
for (list = expr->data.funccall.args; list; list = list->next)
|
|
list->node = CInline_FoldConst(list->node);
|
|
return expr;
|
|
|
|
case ENULLCHECK:
|
|
expr->data.nullcheck.nullcheckexpr = CInline_FoldConst(expr->data.nullcheck.nullcheckexpr);
|
|
expr->data.nullcheck.condexpr = CInline_FoldConst(expr->data.nullcheck.condexpr);
|
|
return expr;
|
|
|
|
case EMEMBER:
|
|
if (expr->data.emember->expr)
|
|
expr->data.emember->expr = CInline_FoldConst(expr->data.emember->expr);
|
|
return expr;
|
|
|
|
default:
|
|
CError_FATAL(421);
|
|
return expr;
|
|
}
|
|
}
|
|
|
|
// unknown name
|
|
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_FLAGS_800000;
|
|
|
|
action = galloc(sizeof(CI_Action));
|
|
memclrw(action, sizeof(CI_Action));
|
|
|
|
action->actiontype = CI_ActionInlineFunc;
|
|
action->obj = object;
|
|
action->u.inlinefunc.tclass = tclass;
|
|
action->u.inlinefunc.fileoffset = *fileoffset;
|
|
action->u.inlinefunc.stream = *stream;
|
|
|
|
if (flag) {
|
|
action->next = cinline_tactionlist;
|
|
cinline_tactionlist = action;
|
|
TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_200000;
|
|
} else {
|
|
action->next = cinline_actionlist;
|
|
cinline_actionlist = action;
|
|
}
|
|
}
|
|
|
|
void CInline_AddMemberFunctionAction(Object *object, TemplClass *templ, TemplClassInst *inst, TemplateMember *tmemb) {
|
|
CI_Action *action;
|
|
|
|
for (action = cinline_tactionlist; action; action = action->next) {
|
|
if (action->obj == object)
|
|
return;
|
|
}
|
|
|
|
action = galloc(sizeof(CI_Action));
|
|
memclrw(action, sizeof(CI_Action));
|
|
|
|
action->actiontype = CI_ActionMemberFunc;
|
|
action->obj = object;
|
|
action->u.memberfunc.templ = templ;
|
|
action->u.memberfunc.inst = inst;
|
|
action->u.memberfunc.tmemb = tmemb;
|
|
|
|
action->next = cinline_tactionlist;
|
|
cinline_tactionlist = action;
|
|
|
|
TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_200000;
|
|
}
|
|
|
|
void CInline_AddTemplateFunctionAction(Object *object, TemplateFunction *func, TemplFuncInstance *inst) {
|
|
CI_Action *action;
|
|
|
|
for (action = cinline_tactionlist; action; action = action->next) {
|
|
if (action->obj == object)
|
|
return;
|
|
}
|
|
|
|
action = galloc(sizeof(CI_Action));
|
|
memclrw(action, sizeof(CI_Action));
|
|
|
|
action->actiontype = CI_ActionTemplateFunc;
|
|
action->obj = object;
|
|
action->u.templatefunc.func = func;
|
|
action->u.templatefunc.inst = inst;
|
|
|
|
action->next = cinline_tactionlist;
|
|
cinline_tactionlist = action;
|
|
|
|
TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_200000;
|
|
}
|
|
|
|
static void CInline_AddFRefList_Object(Object *object) {
|
|
ObjectList *list;
|
|
|
|
if (
|
|
!(object->datatype == DFUNC || object->datatype == DVFUNC) ||
|
|
(object->flags & OBJECT_FLAGS_4) ||
|
|
IS_TEMPL_FUNC(object->type)
|
|
)
|
|
return;
|
|
|
|
for (list = cinline_freflist; list; list = list->next) {
|
|
if (list->object == object)
|
|
return;
|
|
}
|
|
|
|
list = lalloc(sizeof(ObjectList));
|
|
list->object = object;
|
|
list->next = cinline_freflist;
|
|
cinline_freflist = list;
|
|
|
|
if ((object->qual & Q_INLINE) && object->u.func.u.ifuncdata)
|
|
CInline_AddFRefList_InlineFunc(object->u.func.u.ifuncdata);
|
|
}
|
|
|
|
static void CInline_AddFRefList_ExAction(ExceptionAction *exc) {
|
|
while (exc) {
|
|
switch (exc->type) {
|
|
case EAT_DESTROYLOCAL:
|
|
CInline_AddFRefList_Object(exc->data.destroy_local.dtor);
|
|
break;
|
|
case EAT_DESTROYLOCALCOND:
|
|
CInline_AddFRefList_Object(exc->data.destroy_local_cond.dtor);
|
|
break;
|
|
case EAT_DESTROYLOCALOFFSET:
|
|
CInline_AddFRefList_Object(exc->data.destroy_local_offset.dtor);
|
|
break;
|
|
case EAT_DESTROYLOCALPOINTER:
|
|
CInline_AddFRefList_Object(exc->data.destroy_local_pointer.dtor);
|
|
break;
|
|
case EAT_DESTROYLOCALARRAY:
|
|
CInline_AddFRefList_Object(exc->data.destroy_local_array.dtor);
|
|
break;
|
|
case EAT_DESTROYPARTIALARRAY:
|
|
CInline_AddFRefList_Object(exc->data.destroy_partial_array.dtor);
|
|
break;
|
|
case EAT_DESTROYMEMBER:
|
|
case EAT_DESTROYBASE:
|
|
CInline_AddFRefList_Object(exc->data.destroy_member.dtor);
|
|
break;
|
|
case EAT_DESTROYMEMBERCOND:
|
|
CInline_AddFRefList_Object(exc->data.destroy_member_cond.dtor);
|
|
break;
|
|
case EAT_DESTROYMEMBERARRAY:
|
|
CInline_AddFRefList_Object(exc->data.destroy_member_array.dtor);
|
|
break;
|
|
case EAT_DELETEPOINTER:
|
|
case EAT_DELETELOCALPOINTER:
|
|
CInline_AddFRefList_Object(exc->data.delete_pointer.deletefunc);
|
|
break;
|
|
case EAT_DELETEPOINTERCOND:
|
|
CInline_AddFRefList_Object(exc->data.delete_pointer_cond.deletefunc);
|
|
break;
|
|
case EAT_CATCHBLOCK:
|
|
case EAT_ACTIVECATCHBLOCK:
|
|
case EAT_SPECIFICATION:
|
|
case EAT_TERMINATE:
|
|
break;
|
|
default:
|
|
CError_FATAL(4307);
|
|
}
|
|
exc = exc->prev;
|
|
}
|
|
}
|
|
|
|
static void CInline_AddFRefList_ExprCB(ENode *expr) {
|
|
CInline_AddFRefList_Object(expr->data.objref);
|
|
}
|
|
|
|
static void CInline_AddFRefList_Expr(ENode *expr) {
|
|
CExpr_SearchExprTree(expr, CInline_AddFRefList_ExprCB, 1, EOBJREF);
|
|
}
|
|
|
|
static void CInline_AddFRefList_Statement(Statement *stmt) {
|
|
while (stmt) {
|
|
if (stmt->dobjstack)
|
|
CInline_AddFRefList_ExAction(stmt->dobjstack);
|
|
|
|
switch (stmt->type) {
|
|
case ST_NOP:
|
|
case ST_LABEL:
|
|
case ST_GOTO:
|
|
case ST_BEGINCATCH:
|
|
case ST_ENDCATCH:
|
|
case ST_ENDCATCHDTOR:
|
|
case ST_ASM:
|
|
break;
|
|
case ST_RETURN:
|
|
if (!stmt->expr)
|
|
break;
|
|
case ST_EXPRESSION:
|
|
case ST_SWITCH:
|
|
case ST_IFGOTO:
|
|
case ST_IFNGOTO:
|
|
case ST_GOTOEXPR:
|
|
CInline_AddFRefList_Expr(stmt->expr);
|
|
break;
|
|
default:
|
|
CError_FATAL(4368);
|
|
}
|
|
|
|
stmt = stmt->next;
|
|
}
|
|
}
|
|
|
|
static void CInline_AddFRefList_InlineFunc(CI_FuncData *data) {
|
|
short i;
|
|
CI_Statement *stmt;
|
|
ExceptionAction *exc;
|
|
|
|
for (i = 0; i < data->numstatements; i++) {
|
|
stmt = data->statements + i;
|
|
|
|
switch (stmt->type) {
|
|
case ST_NOP:
|
|
case ST_LABEL:
|
|
case ST_GOTO:
|
|
case ST_ASM:
|
|
break;
|
|
case ST_EXPRESSION:
|
|
case ST_BEGINCATCH:
|
|
case ST_ENDCATCH:
|
|
case ST_ENDCATCHDTOR:
|
|
case ST_GOTOEXPR:
|
|
CInline_AddFRefList_Expr(stmt->u.expr);
|
|
break;
|
|
case ST_RETURN:
|
|
if (stmt->u.expr)
|
|
CInline_AddFRefList_Expr(stmt->u.expr);
|
|
break;
|
|
case ST_IFGOTO:
|
|
case ST_IFNGOTO:
|
|
CInline_AddFRefList_Expr(stmt->u.ifgoto.expr);
|
|
break;
|
|
case ST_SWITCH:
|
|
CInline_AddFRefList_Expr(stmt->u.switchdata->expr);
|
|
break;
|
|
default:
|
|
CError_FATAL(4420);
|
|
}
|
|
|
|
for (exc = data->statements[i].dobjstack; exc; exc = exc->prev) {
|
|
switch (exc->type) {
|
|
case EAT_DESTROYLOCAL:
|
|
CInline_AddFRefList_Object(exc->data.destroy_local.dtor);
|
|
break;
|
|
case EAT_DESTROYLOCALCOND:
|
|
CInline_AddFRefList_Object(exc->data.destroy_local_cond.dtor);
|
|
break;
|
|
case EAT_DESTROYLOCALOFFSET:
|
|
CInline_AddFRefList_Object(exc->data.destroy_local_offset.dtor);
|
|
break;
|
|
case EAT_DESTROYLOCALPOINTER:
|
|
CInline_AddFRefList_Object(exc->data.destroy_local_pointer.dtor);
|
|
break;
|
|
case EAT_DESTROYLOCALARRAY:
|
|
CInline_AddFRefList_Object(exc->data.destroy_local_array.dtor);
|
|
break;
|
|
case EAT_DESTROYPARTIALARRAY:
|
|
break;
|
|
case EAT_DESTROYMEMBER:
|
|
case EAT_DESTROYBASE:
|
|
CInline_AddFRefList_Object(exc->data.destroy_member.dtor);
|
|
break;
|
|
case EAT_DESTROYMEMBERCOND:
|
|
CInline_AddFRefList_Object(exc->data.destroy_member_cond.dtor);
|
|
break;
|
|
case EAT_DESTROYMEMBERARRAY:
|
|
CInline_AddFRefList_Object(exc->data.destroy_member_array.dtor);
|
|
break;
|
|
case EAT_DELETEPOINTER:
|
|
case EAT_DELETELOCALPOINTER:
|
|
CInline_AddFRefList_Object(exc->data.delete_pointer.deletefunc);
|
|
break;
|
|
case EAT_DELETEPOINTERCOND:
|
|
CInline_AddFRefList_Object(exc->data.delete_pointer_cond.deletefunc);
|
|
break;
|
|
case EAT_CATCHBLOCK:
|
|
case EAT_ACTIVECATCHBLOCK:
|
|
case EAT_SPECIFICATION:
|
|
case EAT_TERMINATE:
|
|
break;
|
|
default:
|
|
CError_FATAL(4470);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void CInline_GenerateTemplateInline(Object *object) {
|
|
CI_Action **ptr;
|
|
CI_Action *action;
|
|
|
|
ptr = &cinline_tactionlist;
|
|
while ((action = *ptr)) {
|
|
if (object == action->obj) {
|
|
*ptr = action->next;
|
|
action->next = cinline_actionlist;
|
|
cinline_actionlist = action;
|
|
|
|
TYPE_FUNC(object->type)->flags &= ~FUNC_FLAGS_200000;
|
|
return;
|
|
}
|
|
|
|
ptr = &action->next;
|
|
}
|
|
|
|
CError_FATAL(4499);
|
|
}
|
|
|
|
void CInline_ObjectAddrRef(Object *object) {
|
|
CI_FuncData *funcdata;
|
|
|
|
object->flags |= OBJECT_FLAGS_2;
|
|
|
|
switch (object->datatype) {
|
|
case DFUNC:
|
|
case DVFUNC:
|
|
if (
|
|
(object->qual & Q_INLINE) &&
|
|
(funcdata = object->u.func.u.ifuncdata) &&
|
|
!(object->flags & OBJECT_FLAGS_4) &&
|
|
!(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_100000)
|
|
)
|
|
{
|
|
CI_Export *export = galloc(sizeof(CI_Export));
|
|
|
|
export->object = object;
|
|
export->funcdata = funcdata;
|
|
export->xC = 0;
|
|
|
|
export->next = cinline_exportlist;
|
|
cinline_exportlist = export;
|
|
|
|
object->flags |= OBJECT_FLAGS_4;
|
|
return;
|
|
}
|
|
else if (
|
|
(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_100) &&
|
|
!(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_2)
|
|
)
|
|
{
|
|
CInline_AddDefaultFunctionAction(object);
|
|
return;
|
|
}
|
|
else if (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_200000)
|
|
{
|
|
CInline_GenerateTemplateInline(object);
|
|
return;
|
|
}
|
|
return;
|
|
|
|
case DALIAS:
|
|
CInline_ObjectAddrRef(object->u.alias.object);
|
|
return;
|
|
|
|
case DDATA:
|
|
if (object->qual & Q_10000)
|
|
CInit_ExportConst(object);
|
|
|
|
if (object->flags & OBJECT_FLAGS_8) {
|
|
object->flags &= ~OBJECT_FLAGS_8;
|
|
CParser_CallBackAction(object);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
static Boolean CInline_CheckDependencies(ObjectList *list) {
|
|
Object *object;
|
|
Boolean result;
|
|
|
|
result = 0;
|
|
|
|
while (list) {
|
|
object = list->object;
|
|
|
|
if (
|
|
(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_100) &&
|
|
!(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_2)
|
|
)
|
|
{
|
|
CInline_AddDefaultFunctionAction(object);
|
|
result = 1;
|
|
}
|
|
else if (
|
|
(object->qual & Q_400000) &&
|
|
CTempl_InlineFunctionCheck(object)
|
|
)
|
|
{
|
|
result = 1;
|
|
}
|
|
else {
|
|
CI_Action *action;
|
|
for (action = cinline_actionlist; action; action = action->next) {
|
|
if (object == action->obj) {
|
|
result = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_200000) {
|
|
CInline_GenerateTemplateInline(object);
|
|
result = 1;
|
|
}
|
|
}
|
|
|
|
list = list->next;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static Boolean CInline_IsSmallFunction(Object *object, Statement *stmt) {
|
|
SInt32 statementCount;
|
|
ObjectList *list;
|
|
SInt32 localSize;
|
|
|
|
statementCount = 0;
|
|
while (stmt) {
|
|
if (stmt->type != ST_NOP && stmt->type != ST_LABEL)
|
|
statementCount++;
|
|
if (statementCount > 15)
|
|
return 0;
|
|
stmt = stmt->next;
|
|
}
|
|
|
|
for (list = locals, localSize = 0; list; list = list->next)
|
|
localSize += list->object->type->size;
|
|
|
|
if (localSize > 1024)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static Boolean CInline_NoFPLocals(void) {
|
|
ObjectList *list;
|
|
|
|
for (list = locals; list; list = list->next) {
|
|
if (IS_TYPE_FLOAT(list->object->type))
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void CInline_GenFunc(Statement *stmt, Object *object, UInt8 unk) {
|
|
CI_FuncData *funcdata;
|
|
CI_Export *export;
|
|
Boolean flag24;
|
|
Boolean flag30;
|
|
|
|
TYPE_FUNC(object->type)->flags |= OBJECT_FLAGS_2;
|
|
|
|
flag24 = 0;
|
|
flag30 = 0;
|
|
if (!(object->qual & Q_INLINE)) {
|
|
if (
|
|
copts.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_FLAGS_4;
|
|
|
|
cinline_freflist = NULL;
|
|
CInline_AddFRefList_Statement(stmt);
|
|
|
|
if (CInline_CheckDependencies(cinline_freflist) || copts.defer_codegen) {
|
|
if (!flag30) {
|
|
funcdata = galloc(sizeof(CI_FuncData));
|
|
CInline_PackIFunctionData(funcdata, stmt, object);
|
|
} else {
|
|
funcdata = object->u.func.u.ifuncdata;
|
|
}
|
|
|
|
export = galloc(sizeof(CI_Export));
|
|
export->object = object;
|
|
export->funcdata = funcdata;
|
|
export->xC = unk;
|
|
|
|
export->next = cinline_exportlist;
|
|
cinline_exportlist = export;
|
|
|
|
return;
|
|
}
|
|
|
|
expanding_function = object;
|
|
recursive_inline = 0;
|
|
CInline_Expand(stmt);
|
|
|
|
if (copts.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_FLAGS_100);
|
|
CError_ASSERT(4771, TYPE_FUNC(object->type)->flags & FUNC_FLAGS_METHOD);
|
|
|
|
tclass = TYPE_METHOD(object->type)->theclass;
|
|
|
|
if (object == CClass_DefaultConstructor(tclass)) {
|
|
if (object->u.func.defargdata)
|
|
CABI_MakeDefaultArgConstructor(tclass, object);
|
|
else
|
|
CABI_MakeDefaultConstructor(tclass, object);
|
|
} else if (object == CClass_CopyConstructor(tclass)) {
|
|
CABI_MakeDefaultCopyConstructor(tclass, object);
|
|
} else if (object == CClass_AssignmentOperator(tclass)) {
|
|
CABI_MakeDefaultAssignmentOperator(tclass, object);
|
|
} else if (object == CClass_Destructor(tclass)) {
|
|
CABI_MakeDefaultDestructor(tclass, object);
|
|
} else {
|
|
CError_FATAL(4805);
|
|
}
|
|
}
|
|
|
|
static TemplClassInst *CInline_FindNestedTemplInst(TypeClass *tclass) {
|
|
NameSpace *nspace;
|
|
|
|
while (tclass) {
|
|
if ((tclass->flags & CLASS_FLAGS_800))
|
|
return TEMPL_CLASS_INST(tclass);
|
|
|
|
if (!copts.template_patch)
|
|
break;
|
|
|
|
nspace = tclass->nspace->parent;
|
|
tclass = NULL;
|
|
while (nspace) {
|
|
if (nspace->theclass) {
|
|
tclass = nspace->theclass;
|
|
break;
|
|
}
|
|
nspace = nspace->parent;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void CInline_GenerateInlineFunc(CI_Action *action) {
|
|
Object *object;
|
|
TemplClassInst *inst;
|
|
DeclInfo di;
|
|
SInt32 streamState;
|
|
|
|
object = action->obj;
|
|
|
|
CPrep_StreamInsert(&action->u.inlinefunc.stream, &streamState);
|
|
cparser_fileoffset = action->u.inlinefunc.fileoffset;
|
|
symdecloffset = cparser_fileoffset.tokenline;
|
|
|
|
switch ((tk = lex())) {
|
|
case ':':
|
|
case '{':
|
|
case TK_TRY:
|
|
break;
|
|
default:
|
|
CError_FATAL(4860);
|
|
}
|
|
|
|
symdecltoken = *CPrep_CurStreamElement();
|
|
|
|
TYPE_FUNC(object->type)->flags &= ~FUNC_FLAGS_2;
|
|
if (IS_TYPE_METHOD(object->type) && (inst = CInline_FindNestedTemplInst(TYPE_METHOD(object->type)->theclass))) {
|
|
CTempl_ParseInstanceScopeFunction(object, inst, NULL);
|
|
} else {
|
|
memclrw(&di, sizeof(di));
|
|
if (action->u.inlinefunc.tclass) {
|
|
if ((inst = CInline_FindNestedTemplInst(action->u.inlinefunc.tclass))) {
|
|
CTempl_ParseInstanceScopeFunction(object, inst, action->u.inlinefunc.tclass);
|
|
} else {
|
|
CFunc_ParseFuncDef(object, &di, action->u.inlinefunc.tclass, 0, 0, NULL);
|
|
}
|
|
} else {
|
|
CFunc_ParseFuncDef(object, &di, NULL, 0, 0, NULL);
|
|
}
|
|
}
|
|
|
|
CPrep_StreamRemove(&action->u.inlinefunc.stream, &streamState);
|
|
}
|
|
|
|
Boolean CInline_CanFreeLHeap(void) {
|
|
CI_Action *action;
|
|
|
|
if (!anyerrors) {
|
|
for (action = cinline_actionlist; action; action = action->next) {
|
|
if (action->actiontype == CI_ActionInlineFunc)
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
Boolean CInline_GenerateDeferredFuncs(void) {
|
|
CI_Action *action;
|
|
CI_Export *export;
|
|
|
|
if (!anyerrors) {
|
|
if ((action = cinline_actionlist)) {
|
|
cinline_actionlist = action->next;
|
|
cinline_gendeps = 1;
|
|
|
|
switch (action->actiontype) {
|
|
case CI_ActionDefaultFunc:
|
|
CInline_GenerateDefaultFunc(action->obj);
|
|
break;
|
|
case CI_ActionInlineFunc:
|
|
if (!(action->obj->flags & OBJECT_FLAGS_4))
|
|
CInline_GenerateInlineFunc(action);
|
|
break;
|
|
case CI_ActionMemberFunc:
|
|
if (!(TYPE_FUNC(action->obj->type)->flags & FUNC_FLAGS_2))
|
|
CTempl_InstantiateMember(
|
|
action->u.memberfunc.templ, action->u.memberfunc.inst,
|
|
action->u.memberfunc.tmemb, action->obj, 0);
|
|
break;
|
|
case CI_ActionTemplateFunc:
|
|
if (!(TYPE_FUNC(action->obj->type)->flags & FUNC_FLAGS_2) && !action->u.templatefunc.inst->is_specialized)
|
|
CTempl_GenFuncInstance(action->u.templatefunc.func, action->u.templatefunc.inst, 0);
|
|
break;
|
|
default:
|
|
CError_FATAL(5001);
|
|
}
|
|
|
|
cinline_gendeps = 0;
|
|
return 1;
|
|
} else {
|
|
if ((export = cinline_exportlist) && !copts.defer_codegen) {
|
|
cinline_exportlist = export->next;
|
|
CInline_GenIFunctionCode(export->object, export->funcdata, export->xC);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static InitExpr *CInline_InitTemplateData(InitExpr *init) {
|
|
Statement *stmt;
|
|
CLabel *label;
|
|
Object *object;
|
|
Object *data;
|
|
|
|
object = init->object;
|
|
|
|
data = CParser_NewCompilerDefDataObject();
|
|
data->type = TYPE(&stsignedchar);
|
|
data->name = CParser_NameConcat("__init__", CMangler_GetLinkName(object)->name);
|
|
data->qual = Q_OVERLOAD;
|
|
CInit_DeclareData(data, NULL, NULL, data->type->size);
|
|
|
|
stmt = CFunc_AppendStatement(ST_IFGOTO);
|
|
stmt->expr = create_objectnode(data);
|
|
label = newlabel();
|
|
stmt->label = label;
|
|
|
|
do {
|
|
stmt = CFunc_AppendStatement(ST_EXPRESSION);
|
|
stmt->expr = CInline_CopyExpression(init->expr, CopyMode0);
|
|
init = init->next;
|
|
} while (init && init->object == object);
|
|
|
|
stmt = CFunc_AppendStatement(ST_EXPRESSION);
|
|
stmt->expr = makediadicnode(create_objectnode(data), intconstnode(TYPE(&stsignedchar), 1), EASS);
|
|
|
|
stmt = CFunc_AppendStatement(ST_LABEL);
|
|
stmt->label = label;
|
|
label->stmt = stmt;
|
|
|
|
return init;
|
|
}
|
|
|
|
void CInline_Finish(void) {
|
|
NameSpace *nspace;
|
|
Boolean saveDebugInfo;
|
|
Statement firstStmt;
|
|
Statement *stmt;
|
|
InitExpr *init;
|
|
Boolean doMore;
|
|
|
|
if (!init_expressions || anyerrors)
|
|
return;
|
|
|
|
cinline_freflist = NULL;
|
|
|
|
for (init = init_expressions; init; init = init->next)
|
|
CInline_AddFRefList_Expr(init->expr);
|
|
|
|
CInline_CheckDependencies(cinline_freflist);
|
|
|
|
do {
|
|
doMore = CInline_GenerateDeferredFuncs();
|
|
} while (doMore);
|
|
|
|
nspace = CFunc_FuncGenSetup(&firstStmt, NULL);
|
|
saveDebugInfo = copts.filesyminfo;
|
|
copts.filesyminfo = 0;
|
|
|
|
init = init_expressions;
|
|
while (init) {
|
|
if (init->object->nspace->theclass && (init->object->nspace->theclass->flags & CLASS_FLAGS_800)) {
|
|
init = CInline_InitTemplateData(init);
|
|
} else {
|
|
stmt = CFunc_AppendStatement(ST_EXPRESSION);
|
|
stmt->expr = CInline_CopyExpression(init->expr, CopyMode0);
|
|
init = init->next;
|
|
}
|
|
}
|
|
|
|
CFunc_CodeCleanup(&firstStmt);
|
|
|
|
expanding_function = NULL;
|
|
recursive_inline = 0;
|
|
CInline_Expand(&firstStmt);
|
|
|
|
if (!anyerrors) {
|
|
if (copts.filesyminfo)
|
|
CPrep_SetSourceFile(&cparser_fileoffset);
|
|
CodeGen_Generator(&firstStmt, NULL, 0, 1);
|
|
}
|
|
|
|
cscope_current = nspace->parent;
|
|
copts.filesyminfo = saveDebugInfo;
|
|
}
|