#include "compiler/IroVars.h" #include "compiler/IroDump.h" #include "compiler/IroFlowgraph.h" #include "compiler/IroJump.h" #include "compiler/IroLinearForm.h" #include "compiler/IroMalloc.h" #include "compiler/IroPointerAnalysis.h" #include "compiler/IroUtil.h" #include "compiler/IROUseDef.h" #include "compiler/CClass.h" #include "compiler/CError.h" #include "compiler/CExpr.h" #include "compiler/CFunc.h" #include "compiler/CParser.h" #include "compiler/CompilerTools.h" #include "compiler/Exceptions.h" #include "compiler/objects.h" #include "compiler/InlineAsm.h" #include "compiler/InlineAsmPPC.h" #include "compiler/BitVector.h" #ifdef __MWERKS__ #pragma options align=mac68k #endif typedef struct IndirectRecordMatch { IROLinear *nd; struct IndirectRecordMatch *otherMatches; } IndirectRecordMatch; typedef struct IndirectRecord { IROLinear *linear; unsigned char flags; VarRecord *var; SInt32 addend; SInt32 size; int startbit; int endbit; Type *type; struct IndirectRecord *next; IndirectRecordMatch *matches; IROLinear *x26; } IndirectRecord; #ifdef __MWERKS__ #pragma options align=reset #endif static IndirectRecord *IRO_FirstIndirectRecord; static IndirectRecord *IRO_LastIndirectRecord; static IROLinear *TheBaseTerm; VarRecord *IRO_FirstVar; VarRecord *IRO_LastVar; SInt32 IRO_NumVars; Boolean IRO_IsBitField; SInt32 IRO_BaseTerms; SInt32 IRO_VarTerms; Boolean IRO_IsModifyOp[MAXEXPR]; Boolean IRO_IsAssignOp[MAXEXPR]; // forward decls static Boolean CheckAddress(IROLinear *nd, Boolean *resultFlag); static Boolean CheckAddressConsistency(IROLinear *nd, VarRecord *var, SInt32 addend, Type *type); static void DisableEntries(IndirectRecord *irec); static void DisableAddressedEntries(void); static UInt32 ObjectIsArg(Object *obj); void IRO_InitializeIRO_IsModifyOpArray(void) { int i; for (i = 0; i < MAXEXPR; i++) IRO_IsModifyOp[i] = 0; IRO_IsModifyOp[EPOSTINC] = 1; IRO_IsModifyOp[EPOSTDEC] = 1; IRO_IsModifyOp[EPREINC] = 1; IRO_IsModifyOp[EPREDEC] = 1; IRO_IsModifyOp[EINDIRECT] = 0; IRO_IsModifyOp[EMONMIN] = 0; IRO_IsModifyOp[EBINNOT] = 0; IRO_IsModifyOp[ELOGNOT] = 0; IRO_IsModifyOp[EFORCELOAD] = 0; IRO_IsModifyOp[EMUL] = 0; IRO_IsModifyOp[EMULV] = 0; IRO_IsModifyOp[EDIV] = 0; IRO_IsModifyOp[EMODULO] = 0; IRO_IsModifyOp[EADDV] = 0; IRO_IsModifyOp[ESUBV] = 0; IRO_IsModifyOp[EADD] = 0; IRO_IsModifyOp[ESUB] = 0; IRO_IsModifyOp[ESHL] = 0; IRO_IsModifyOp[ESHR] = 0; IRO_IsModifyOp[ELESS] = 0; IRO_IsModifyOp[EGREATER] = 0; IRO_IsModifyOp[ELESSEQU] = 0; IRO_IsModifyOp[EGREATEREQU] = 0; IRO_IsModifyOp[EEQU] = 0; IRO_IsModifyOp[ENOTEQU] = 0; IRO_IsModifyOp[EAND] = 0; IRO_IsModifyOp[EXOR] = 0; IRO_IsModifyOp[EOR] = 0; IRO_IsModifyOp[ELAND] = 0; IRO_IsModifyOp[ELOR] = 0; IRO_IsModifyOp[EASS] = 0; IRO_IsModifyOp[EMULASS] = 1; IRO_IsModifyOp[EDIVASS] = 1; IRO_IsModifyOp[EMODASS] = 1; IRO_IsModifyOp[EADDASS] = 1; IRO_IsModifyOp[ESUBASS] = 1; IRO_IsModifyOp[ESHLASS] = 1; IRO_IsModifyOp[ESHRASS] = 1; IRO_IsModifyOp[EANDASS] = 1; IRO_IsModifyOp[EXORASS] = 1; IRO_IsModifyOp[EORASS] = 1; IRO_IsModifyOp[ECOMMA] = 0; IRO_IsModifyOp[EPMODULO] = 1; IRO_IsModifyOp[EROTL] = 1; IRO_IsModifyOp[EROTR] = 1; IRO_IsModifyOp[EBCLR] = 1; IRO_IsModifyOp[EBTST] = 1; IRO_IsModifyOp[EBSET] = 1; IRO_IsModifyOp[ETYPCON] = 0; IRO_IsModifyOp[EBITFIELD] = 0; IRO_IsModifyOp[EINTCONST] = 0; IRO_IsModifyOp[EFLOATCONST] = 0; IRO_IsModifyOp[ESTRINGCONST] = 0; IRO_IsModifyOp[ECOND] = 0; IRO_IsModifyOp[EFUNCCALL] = 0; IRO_IsModifyOp[EFUNCCALLP] = 0; IRO_IsModifyOp[EOBJREF] = 0; IRO_IsModifyOp[EMFPOINTER] = 0; IRO_IsModifyOp[ENULLCHECK] = 0; IRO_IsModifyOp[EPRECOMP] = 0; IRO_IsModifyOp[ETEMP] = 0; IRO_IsModifyOp[EARGOBJ] = 0; IRO_IsModifyOp[ELOCOBJ] = 0; IRO_IsModifyOp[ELABEL] = 0; IRO_IsModifyOp[ESETCONST] = 0; IRO_IsModifyOp[ENEWEXCEPTION] = 0; IRO_IsModifyOp[ENEWEXCEPTIONARRAY] = 0; IRO_IsModifyOp[EOBJLIST] = 0; IRO_IsModifyOp[EMEMBER] = 0; IRO_IsModifyOp[ETEMPLDEP] = 0; IRO_IsModifyOp[EINSTRUCTION] = 0; IRO_IsModifyOp[EDEFINE] = 0; IRO_IsModifyOp[EREUSE] = 0; IRO_IsModifyOp[EASSBLK] = 0; IRO_IsModifyOp[EVECTOR128CONST] = 0; IRO_IsModifyOp[ECONDASS] = 1; } void IRO_InitializeIRO_IsAssignOpArray(void) { int i; for (i = 0; i < MAXEXPR; i++) IRO_IsAssignOp[i] = 0; IRO_IsAssignOp[EPOSTINC] = 1; IRO_IsAssignOp[EPOSTDEC] = 1; IRO_IsAssignOp[EPREINC] = 1; IRO_IsAssignOp[EPREDEC] = 1; IRO_IsAssignOp[EINDIRECT] = 0; IRO_IsAssignOp[EMONMIN] = 0; IRO_IsAssignOp[EBINNOT] = 0; IRO_IsAssignOp[ELOGNOT] = 0; IRO_IsAssignOp[EFORCELOAD] = 0; IRO_IsAssignOp[EMUL] = 0; IRO_IsAssignOp[EMULV] = 0; IRO_IsAssignOp[EDIV] = 0; IRO_IsAssignOp[EMODULO] = 0; IRO_IsAssignOp[EADDV] = 0; IRO_IsAssignOp[ESUBV] = 0; IRO_IsAssignOp[EADD] = 0; IRO_IsAssignOp[ESUB] = 0; IRO_IsAssignOp[ESHL] = 0; IRO_IsAssignOp[ESHR] = 0; IRO_IsAssignOp[ELESS] = 0; IRO_IsAssignOp[EGREATER] = 0; IRO_IsAssignOp[ELESSEQU] = 0; IRO_IsAssignOp[EGREATEREQU] = 0; IRO_IsAssignOp[EEQU] = 0; IRO_IsAssignOp[ENOTEQU] = 0; IRO_IsAssignOp[EAND] = 0; IRO_IsAssignOp[EXOR] = 0; IRO_IsAssignOp[EOR] = 0; IRO_IsAssignOp[ELAND] = 0; IRO_IsAssignOp[ELOR] = 0; IRO_IsAssignOp[EASS] = 1; IRO_IsAssignOp[EMULASS] = 1; IRO_IsAssignOp[EDIVASS] = 1; IRO_IsAssignOp[EMODASS] = 1; IRO_IsAssignOp[EADDASS] = 1; IRO_IsAssignOp[ESUBASS] = 1; IRO_IsAssignOp[ESHLASS] = 1; IRO_IsAssignOp[ESHRASS] = 1; IRO_IsAssignOp[EANDASS] = 1; IRO_IsAssignOp[EXORASS] = 1; IRO_IsAssignOp[EORASS] = 1; IRO_IsAssignOp[ECOMMA] = 0; IRO_IsAssignOp[EPMODULO] = 1; IRO_IsAssignOp[EROTL] = 1; IRO_IsAssignOp[EROTR] = 1; IRO_IsAssignOp[EBCLR] = 1; IRO_IsAssignOp[EBTST] = 1; IRO_IsAssignOp[EBSET] = 1; IRO_IsAssignOp[ETYPCON] = 0; IRO_IsAssignOp[EBITFIELD] = 0; IRO_IsAssignOp[EINTCONST] = 0; IRO_IsAssignOp[EFLOATCONST] = 0; IRO_IsAssignOp[ESTRINGCONST] = 0; IRO_IsAssignOp[ECOND] = 0; IRO_IsAssignOp[EFUNCCALL] = 0; IRO_IsAssignOp[EFUNCCALLP] = 0; IRO_IsAssignOp[EOBJREF] = 0; IRO_IsAssignOp[EMFPOINTER] = 0; IRO_IsAssignOp[ENULLCHECK] = 0; IRO_IsAssignOp[EPRECOMP] = 0; IRO_IsAssignOp[ETEMP] = 0; IRO_IsAssignOp[EARGOBJ] = 0; IRO_IsAssignOp[ELOCOBJ] = 0; IRO_IsAssignOp[ELABEL] = 0; IRO_IsAssignOp[ESETCONST] = 0; IRO_IsAssignOp[ENEWEXCEPTION] = 0; IRO_IsAssignOp[ENEWEXCEPTIONARRAY] = 0; IRO_IsAssignOp[EOBJLIST] = 0; IRO_IsAssignOp[EMEMBER] = 0; IRO_IsAssignOp[ETEMPLDEP] = 0; IRO_IsAssignOp[EINSTRUCTION] = 0; IRO_IsAssignOp[EDEFINE] = 0; IRO_IsAssignOp[EREUSE] = 0; IRO_IsAssignOp[EASSBLK] = 0; IRO_IsAssignOp[EVECTOR128CONST] = 0; IRO_IsAssignOp[ECONDASS] = 1; } VarRecord *IRO_FindVar(Object *object, Boolean flag1, Boolean flag2) { VarRecord *var; VarInfo *vi; var = object->varptr; if (!var && flag1) { vi = NULL; if (object->datatype == DLOCAL) vi = object->u.var.info; if (vi) vi->usage = 0; var = oalloc(sizeof(VarRecord)); var->object = object; var->index = ++IRO_NumVars; var->x6 = 0; var->xA = 0; var->next = NULL; var->defs = NULL; var->uses = NULL; var->x1A = NULL; var->x1E = NULL; var->xB = 0; if (IRO_FirstVar) IRO_LastVar->next = var; else IRO_FirstVar = var; IRO_LastVar = var; object->varptr = var; } if (var && !flag2) { var->xB = 1; if (object->datatype == DLOCAL && object->u.var.info && object->u.var.info->noregister == 0) object->u.var.info->noregister = 2; } return var; } static void ResetVars(void) { VarRecord *var; for (var = IRO_FirstVar; var; var = var->next) { var->xB = 0; if (var->object && var->object->datatype == DLOCAL && var->object->u.var.info) { if (var->object->u.var.info->noregister == 2) var->object->u.var.info->noregister = 0; } } } static void IRO_HandleExceptionActions(IROLinear *linear) { ExceptionAction *action; for (action = linear->stmt->dobjstack; action; action = action->prev) { switch (action->type) { case EAT_DESTROYLOCAL: IRO_FindVar(action->data.destroy_local.local, 1, 0); break; case EAT_DESTROYLOCALCOND: IRO_FindVar(action->data.destroy_local_cond.local, 1, 0); break; case EAT_DESTROYLOCALOFFSET: IRO_FindVar(action->data.destroy_local_offset.local, 1, 0); break; case EAT_DESTROYLOCALARRAY: IRO_FindVar(action->data.destroy_local_array.localarray, 1, 0); break; case EAT_DESTROYMEMBER: case EAT_DESTROYBASE: IRO_FindVar(action->data.destroy_member.objectptr, 1, 0); break; case EAT_DESTROYMEMBERCOND: IRO_FindVar(action->data.destroy_member_cond.objectptr, 1, 0); break; case EAT_DESTROYMEMBERARRAY: IRO_FindVar(action->data.destroy_member_array.objectptr, 1, 0); break; case EAT_CATCHBLOCK: if (action->data.catch_block.catch_object) IRO_FindVar(action->data.catch_block.catch_object, 1, 0); IRO_FindVar(action->data.catch_block.catch_info_object, 1, 0); break; case EAT_ACTIVECATCHBLOCK: IRO_FindVar(action->data.active_catch_block.catch_info_object, 1, 0); break; } } } void IRO_FindAllVars(void) { IROLinear *linear; VarRecord *var; linear = IRO_FirstLinear; IRO_NumVars = 0; IRO_FirstVar = IRO_LastVar = NULL; while (linear) { if (IS_LINEAR_ENODE(linear, EOBJREF)) { if (Inline_IsObjectData(linear->u.node->data.objref) || linear->u.node->data.objref->datatype == DLOCAL) IRO_FindVar(linear->u.node->data.objref, 1, (linear->flags & IROLF_Ind) != 0); else linear->u.node->data.objref->varptr = NULL; } else if (linear->type == IROLinearFunccall) { if (linear->stmt && IRO_FunctionCallMightThrowException(linear)) IRO_HandleExceptionActions(linear); } else if (linear->type == IROLinearAsm) { IAEffects effects; int i; CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects); for (i = 0; i < effects.numoperands; i++) IRO_FindVar(effects.operands[i].object, 1, effects.operands[i].type != IAEffect_3); } linear = linear->next; } var = IRO_FirstVar; Bv_AllocVector(&IRO_FuncKills, IRO_NumVars + 1); Bv_SetBit(0, IRO_FuncKills); while (var) { if (Inline_IsObjectData(var->object) || var->xB) Bv_SetBit(var->index, IRO_FuncKills); var = var->next; } IRO_CheckForUserBreak(); } void IRO_ZapVarPtrs(void) { VarRecord *var; for (var = IRO_FirstVar; var; var = var->next) var->object->varptr = NULL; } void IRO_UpdateVars(void) { IROLinear *linear; VarRecord *var; ResetVars(); for (linear = IRO_FirstLinear; linear; linear = linear->next) { if (IS_LINEAR_ENODE(linear, EOBJREF)) { if (Inline_IsObjectData(linear->u.node->data.objref) || linear->u.node->data.objref->datatype == DLOCAL) IRO_FindVar(linear->u.node->data.objref, 0, (linear->flags & IROLF_Ind) || !(linear->flags & IROLF_Reffed)); } else if (linear->type == IROLinearFunccall) { if (linear->stmt && IRO_FunctionCallMightThrowException(linear)) IRO_HandleExceptionActions(linear); } else if (linear->type == IROLinearAsm) { IAEffects effects; int i; CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects); for (i = 0; i < effects.numoperands; i++) IRO_FindVar(effects.operands[i].object, 0, effects.operands[i].type != IAEffect_3); } } var = IRO_FirstVar; Bv_AllocVector(&IRO_FuncKills, IRO_NumVars + 1); Bv_SetBit(0, IRO_FuncKills); while (var) { if (Inline_IsObjectData(var->object) || var->xB) Bv_SetBit(var->index, IRO_FuncKills); var = var->next; } } void IRO_AddElmToList(IROLinear *linear, IROElmList **list) { IROElmList *l = oalloc(sizeof(IROElmList)); l->element = linear; l->next = NULL; if (!*list) { *list = l; } else { l->next = *list; *list = l; } } void IRO_DecomposeAddressExpression(IROLinear *linear, IROAddrRecord *rec) { if (IS_LINEAR_DIADIC(linear->u.diadic.left, EADD)) { IRO_DecomposeAddressExpression(linear->u.diadic.left, rec); } else if (IS_LINEAR_ENODE(linear->u.diadic.left, EINTCONST)) { rec->numInts++; IRO_AddElmToList(linear->u.diadic.left, &rec->ints); } else if (IS_LINEAR_ENODE(linear->u.diadic.left, EOBJREF)) { rec->numObjRefs++; IRO_AddElmToList(linear->u.diadic.left, &rec->objRefs); } else { rec->numMisc++; IRO_AddElmToList(linear->u.diadic.left, &rec->misc); } if (IS_LINEAR_DIADIC(linear->u.diadic.right, EADD)) { IRO_DecomposeAddressExpression(linear->u.diadic.right, rec); } else if (IS_LINEAR_ENODE(linear->u.diadic.right, EINTCONST)) { rec->numInts++; IRO_AddElmToList(linear->u.diadic.right, &rec->ints); } else if (IS_LINEAR_ENODE(linear->u.diadic.right, EOBJREF)) { rec->numObjRefs++; IRO_AddElmToList(linear->u.diadic.right, &rec->objRefs); } else { rec->numMisc++; IRO_AddElmToList(linear->u.diadic.right, &rec->misc); } } void IRO_DecomposeAddressExpression_Cheap(IROLinear *linear) { if (IS_LINEAR_DIADIC(linear->u.diadic.left, EADD)) { IRO_DecomposeAddressExpression_Cheap(linear->u.diadic.left); } else if (!IS_LINEAR_ENODE(linear->u.diadic.left, EINTCONST)) { if (IS_LINEAR_ENODE(linear->u.diadic.left, EOBJREF)) { IRO_BaseTerms++; TheBaseTerm = linear->u.diadic.left; } else { IRO_VarTerms++; } } if (IS_LINEAR_DIADIC(linear->u.diadic.right, EADD)) { IRO_DecomposeAddressExpression_Cheap(linear->u.diadic.right); } else if (!IS_LINEAR_ENODE(linear->u.diadic.right, EINTCONST)) { if (IS_LINEAR_ENODE(linear->u.diadic.right, EOBJREF)) { IRO_BaseTerms++; TheBaseTerm = linear->u.diadic.right; } else { IRO_VarTerms++; } } } VarRecord *IRO_FindAssigned(IROLinear *linear) { VarRecord *rec; IRO_IsBitField = 0; if (linear->type == IROLinearOp2Arg) linear = linear->u.diadic.left; else if (linear->type == IROLinearOp1Arg) linear = linear->u.monadic; else CError_FATAL(818); if (IS_LINEAR_MONADIC(linear, EINDIRECT)) linear = linear->u.monadic; if (IS_LINEAR_MONADIC(linear, EBITFIELD)) { IRO_IsBitField = 1; linear = linear->u.monadic; } if (IS_LINEAR_DIADIC(linear, EADD)) { if (IS_LINEAR_ENODE(linear->u.diadic.left, EOBJREF) && IS_LINEAR_ENODE(linear->u.diadic.right, EINTCONST)) { linear = linear->u.diadic.left; } else { IRO_BaseTerms = 0; IRO_DecomposeAddressExpression_Cheap(linear); if (IRO_BaseTerms == 1) linear = TheBaseTerm; } } if (!IS_LINEAR_ENODE(linear, EOBJREF)) return NULL; if ((rec = IRO_FindVar(linear->u.node->data.objref, 0, 1))) return rec; else return NULL; } static void GetKillsByIndirectAssignment(IROLinear *linear) { IROListNode *resultList; IROLinear *nd; IROListNode *list; IROListNode *scan; IROLinear *inner; Boolean result; Boolean foundLinear; result = 0; if (linear->type == IROLinearOp2Arg) linear = linear->u.diadic.left; else linear = linear->u.monadic; if ( linear && linear->type == IROLinearOp1Arg && linear->nodetype == EINDIRECT && (inner = linear->u.monadic) && copts.opt_pointer_analysis && inner->pointsToFunction && FunctionName ) { resultList = NULL; PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, inner, &resultList); if ((list = resultList)) { for (scan = list; scan; scan = scan->nextList) { if (!scan->list.head || !scan->list.tail) { result = 1; break; } foundLinear = 0; for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) { if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { foundLinear = 1; break; } } if (!foundLinear) { result = 1; break; } } if (!result) { while (list) { for (nd = list->list.head; nd != list->list.tail->next; nd = nd->next) { if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { Object *obj; VarRecord *var; int index; obj = nd->u.node->data.objref; CError_ASSERT(952, obj != NULL); var = IRO_FindVar(obj, 1, 1); CError_ASSERT(954, var != NULL); index = var->index; CError_ASSERT(956, index != 0); Bv_SetBit(index, IRO_VarKills); } } list = list->nextList; } } while (resultList) { IROListNode *next = resultList->nextList; IRO_free(resultList); resultList = next; } } else { result = 1; } } else { result = 1; } if (result) Bv_Or(IRO_FuncKills, IRO_VarKills); } static void GetKillsByFunctionCall(IROLinear *linear) { IROListNode *resultList; IROLinear *nd; IROListNode *list; IROListNode *scan; IROLinear *inner; Boolean result; Boolean foundLinear; Object *obj; ObjectList *killList; ObjectList *olist; result = 0; if ( (inner = linear->u.funccall.linear8) && copts.opt_pointer_analysis && inner->pointsToFunction && FunctionName ) { resultList = NULL; PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, inner, &resultList); if (resultList) { for (scan = resultList; scan; scan = scan->nextList) { if (!scan->list.head || !scan->list.tail) { result = 1; break; } foundLinear = 0; for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) { if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { foundLinear = 1; obj = nd->u.node->data.objref; CError_ASSERT(1028, obj != NULL); killList = NULL; PointerAnalysis_GetFunctionKills(obj, linear, &killList); for (olist = killList; olist; olist = olist->next) { if (!olist->object) { result = 1; break; } } while (killList) { ObjectList *next = killList->next; IRO_free(killList); killList = next; } if (result) break; } } if (!foundLinear) result = 1; if (result) break; } if (!result) { for (scan = resultList; scan; scan = scan->nextList) { for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) { if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { obj = nd->u.node->data.objref; killList = NULL; PointerAnalysis_GetFunctionKills(obj, linear, &killList); for (olist = killList; olist; olist = olist->next) { VarRecord *var; int index; var = IRO_FindVar(olist->object, 1, 1); CError_ASSERT(1079, var != NULL); index = var->index; CError_ASSERT(1081, index != 0); Bv_SetBit(index, IRO_VarKills); } while (killList) { ObjectList *next = killList->next; IRO_free(killList); killList = next; } } } } } while (resultList) { IROListNode *next = resultList->nextList; IRO_free(resultList); resultList = next; } } else { result = 1; } } else { result = 1; } if (result) Bv_Or(IRO_FuncKills, IRO_VarKills); } void IRO_GetKills(IROLinear *linear) { VarRecord *var; switch (linear->type) { case IROLinearOp1Arg: case IROLinearOp2Arg: if (IRO_IsAssignOp[linear->nodetype]) { IROLinear *assigned; int index; var = IRO_FindAssigned(linear); index = 0; if (var) index = var->index; Bv_SetBit(index, IRO_VarKills); if (!index) GetKillsByIndirectAssignment(linear); } break; case IROLinearFunccall: GetKillsByFunctionCall(linear); break; case IROLinearAsm: { IAEffects effects; int i; CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects); for (i = 0; i < effects.numoperands; i++) { switch (effects.operands[i].type) { case IAEffect_1: case IAEffect_2: case IAEffect_4: if ((var = IRO_FindVar(effects.operands[i].object, 0, 1))) Bv_SetBit(var->index, IRO_VarKills); break; } } if (effects.x1 || effects.x4) Bv_Or(IRO_FuncKills, IRO_VarKills); break; } } } void IRO_CheckInit(void) { IRONode *fnode; IROLinear *nd; VarRecord *var; ObjectList *olist; int flag; int i; BitVector *bv; IRO_MakeReachable(IRO_FirstNode); fnode = IRO_FirstNode; Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1); while (fnode) { Bv_AllocVector(&fnode->x16, IRO_NumVars + 1); Bv_AllocVector(&fnode->x1E, IRO_NumVars + 1); for (nd = fnode->first; nd; nd = nd->next) { if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { if (nd->flags & IROLF_Ind) { if (!(nd->flags & IROLF_Assigned) || (nd->flags & IROLF_Used)) { if ((var = IRO_FindVar(nd->u.node->data.objref, 0, 1))) { if (!Bv_IsBitSet(var->index, fnode->x1E)) Bv_SetBit(var->index, fnode->x16); } } } else { if ((var = IRO_FindVar(nd->u.node->data.objref, 0, 0))) { Bv_SetBit(var->index, fnode->x1E); } } } else if (nd->type == IROLinearOp2Arg && nd->nodetype == EASS) { if ((var = IRO_FindAssigned(nd))) Bv_SetBit(var->index, fnode->x1E); } else if (nd->type == IROLinearAsm) { IAEffects effects; CodeGen_GetAsmEffects(nd->u.asm_stmt, &effects); for (i = 0; i < effects.numoperands; i++) { var = IRO_FindVar(effects.operands[i].object, 0, 1); switch (effects.operands[i].type) { case IAEffect_1: case IAEffect_2: case IAEffect_4: Bv_SetBit(var->index, fnode->x1E); break; } } } if (nd == fnode->last) break; } fnode = fnode->nextnode; } Bv_AllocVector(&bv, IRO_NumVars + 1); do { flag = 0; for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { Bv_Copy(fnode->x1E, bv); for (i = 0; i < fnode->numpred; i++) Bv_Or(IRO_NodeTable[fnode->pred[i]]->x1E, bv); if (!Bv_Compare(bv, fnode->x1E)) { Bv_Copy(bv, fnode->x1E); flag = 1; } } } while (flag); Bv_Clear(IRO_VarKills); for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { if (fnode->x36) { Bv_Copy(fnode->x16, bv); for (i = 0; i < fnode->numpred; i++) Bv_Minus(IRO_NodeTable[fnode->pred[i]]->x1E, bv); Bv_Or(bv, IRO_VarKills); } } for (olist = locals; olist; olist = olist->next) { if ((var = IRO_FindVar(olist->object, 0, 1)) && Bv_IsBitSet(var->index, IRO_VarKills)) { VarInfo *vi = olist->object->u.var.info; if (!IsTempName(olist->object->name) && !is_volatile_object(olist->object)) { if (!IS_TYPE_CLASS(olist->object->type) || !CClass_IsEmpty(TYPE_CLASS(olist->object->type))) { CError_SetErrorToken(&vi->deftoken); CError_Warning(CErrorStr185, olist->object->name->name); } } } } IRO_CheckForUserBreak(); } static void RewriteIndDec(void) { IROLinear *add; IROLinear *indirect; IROLinear *Int; IROLinear *nd; CInt64 value; IROList list; for (nd = IRO_FirstLinear; nd; nd = nd->next) { if ( nd->type == IROLinearOp1Arg && (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC) && !(nd->flags & IROLF_Reffed) ) { indirect = nd->u.monadic; if ( indirect->type == IROLinearOp1Arg && indirect->nodetype == EINDIRECT && indirect->u.monadic->type == IROLinearOp1Arg && indirect->u.monadic->nodetype == EBITFIELD ) { value = IRO_GetSelfAssignmentVal(nd); IRO_InitList(&list); nd->type = IROLinearOp2Arg; nd->nodetype = EASS; nd->u.diadic.left = indirect; IRO_DuplicateExpr(indirect, &list); Int = IRO_NewIntConst(value, indirect->rtype); Int->flags |= IROLF_Used | IROLF_Reffed; add = IRO_NewLinear(IROLinearOp2Arg); add->nodetype = EADD; add->u.diadic.left = list.tail; add->u.diadic.left->flags = 0; add->u.diadic.left->flags |= IROLF_Used | IROLF_Reffed; add->u.diadic.right = Int; add->rtype = indirect->rtype; add->flags = 0; add->flags |= IROLF_Used | IROLF_Reffed; nd->u.diadic.right = add; IRO_AddToList(Int, &list); IRO_AddToList(add, &list); IRO_PasteAfter(list.head, list.tail, indirect); } } } } void IRO_RewriteBitFieldTemps(void) { IROLinear *nd; IROLinear *expr2; Object *obj; VarRecord *var; IROList list; for (nd = IRO_FirstLinear; nd; nd = nd->next) { if ((obj = IRO_IsVariable(nd)) && (nd->flags & IROLF_BitfieldIndirect)) { var = IRO_FindVar(obj, 0, 1); CError_ASSERT(1526, var != NULL); expr2 = var->x1E; CError_ASSERT(1532, expr2 != NULL); IRO_InitList(&list); IRO_DuplicateExpr(expr2, &list); IRO_NopOut(nd->u.monadic); nd->u.monadic = list.tail; IRO_Paste(list.head, list.tail, nd); } } } static Boolean FunctionCallMightUseOrKillAnyAddressedVar(IROLinear *funccall) { IROLinear *funcnd; IROLinear *nd; IROListNode *scan; IROListNode *resultList; ObjectList *olist; ObjectList *killList; VarRecord *var; Boolean result; Boolean foundObjRef; Object *obj; result = 0; funcnd = funccall->u.funccall.linear8; if (funcnd && copts.opt_pointer_analysis && funcnd->pointsToFunction && FunctionName) { resultList = NULL; PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, funcnd, &resultList); if (resultList) { for (scan = resultList; scan; scan = scan->nextList) { if (!scan->list.head || !scan->list.tail) { result = 1; break; } foundObjRef = 0; for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) { if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { foundObjRef = 1; obj = nd->u.node->data.objref; CError_ASSERT(1592, obj != NULL); killList = NULL; PointerAnalysis_GetFunctionKills(obj, funccall, &killList); for (olist = killList; olist; olist = olist->next) { if (!olist->object) { result = 1; } else { var = IRO_FindVar(olist->object, 1, 1); CError_ASSERT(1604, var != NULL); if (var->xB) result = 1; } if (result) break; } while (killList) { ObjectList *next = killList->next; IRO_free(killList); killList = next; } if (!result) { killList = NULL; PointerAnalysis_GetFunctionDependencies(obj, funccall, &killList); for (olist = killList; olist; olist = olist->next) { if (!olist->object) { result = 1; } else { var = IRO_FindVar(olist->object, 1, 1); CError_ASSERT(1632, var != NULL); if (var->xB) result = 1; } if (result) break; } while (killList) { ObjectList *next = killList->next; IRO_free(killList); killList = next; } } if (result) break; } } if (!foundObjRef) result = 1; if (result) break; } while (resultList) { IROListNode *next = resultList->nextList; IRO_free(resultList); resultList = next; } } else { result = 1; } } else { result = 1; } return result; } static Boolean IndirectMightUseOrKillAnyAddressedVar(IROLinear *indirect) { Boolean result; IROLinear *inner; IROLinear *nd; IROListNode *scan; IROListNode *resultList; Boolean foundObjRef; Object *obj; VarRecord *var; result = 0; if ( indirect && indirect->type == IROLinearOp1Arg && indirect->nodetype == EINDIRECT && (inner = indirect->u.monadic) && copts.opt_pointer_analysis && inner->pointsToFunction && FunctionName ) { resultList = NULL; PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, inner, &resultList); if (resultList) { for (scan = resultList; scan; scan = scan->nextList) { if (!scan->list.head || !scan->list.tail) { result = 1; break; } foundObjRef = 0; for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) { if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { foundObjRef = 1; obj = nd->u.node->data.objref; CError_ASSERT(1723, obj != NULL); var = IRO_FindVar(obj, 1, 1); CError_ASSERT(1725, var != NULL); if (var->xB) result = 1; } } if (!foundObjRef) result = 1; if (result) break; } while (resultList) { IROListNode *next = resultList->nextList; IRO_free(resultList); resultList = next; } } else { result = 1; } } else { result = 1; } return result; } void IRO_ScalarizeClassDataMembers(void) { IROLinear *nd; VarRecord *var; Boolean flag; Object *obj; IndirectRecord *irec; IndirectRecordMatch *match; IROLinear *tmp; nd = IRO_FirstLinear; IRO_FirstIndirectRecord = NULL; IRO_LastIndirectRecord = NULL; RewriteIndDec(); IRO_DumpAfterPhase("RewriteIndDec", 0); flag = 0; while (nd) { if (nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT) { CheckAddress(nd, &flag); } if (nd->type == IROLinearAsm) { IAEffects effects; int i; CodeGen_GetAsmEffects(nd->u.asm_stmt, &effects); for (i = 0; i < effects.numoperands; i++) { if ((var = IRO_FindVar(effects.operands[i].object, 0, 1))) CheckAddressConsistency(nd, var, -1, &stvoid); else CError_FATAL(1823); } } if (nd->type == IROLinearFunccall && !flag) flag = FunctionCallMightUseOrKillAnyAddressedVar(nd); nd = nd->next; } if (flag) DisableAddressedEntries(); for (irec = IRO_FirstIndirectRecord; irec; irec = irec->next) { if (!(irec->flags & 1)) { IROList list1; IROList list2; obj = create_temp_object(irec->type); var = IRO_FindVar(obj, 1, 1); for (match = irec->matches; match; match = match->otherMatches) { IRO_InitList(&list1); IRO_InitList(&list2); IRO_DuplicateExpr(match->nd, &list1); IRO_DuplicateExpr(match->nd, &list2); if (match->nd->type == IROLinearOperand && match->nd->u.node->type == EOBJREF) { tmp = IRO_LocateFather(match->nd); if (irec->flags & 2) { tmp->flags |= IROLF_BitfieldIndirect; var->x1A = match->nd->rtype; var->x1E = list2.tail; } match->nd->u.node = create_objectrefnode(obj); irec->x26 = list2.tail; } else { tmp = IRO_LocateFather(match->nd); if (irec->flags & 2) { tmp->flags |= IROLF_BitfieldIndirect; var->x1A = match->nd->rtype; var->x1E = list2.tail; } irec->x26 = list2.tail; IRO_NopOut(tmp->u.monadic); tmp->u.monadic = IRO_NewLinear(IROLinearOperand); tmp->u.monadic->u.node = create_objectrefnode(obj); tmp->u.monadic->rtype = match->nd->rtype; tmp->u.monadic->index = ++IRO_NumLinear; tmp->u.monadic->flags |= IROLF_Ind | IROLF_Reffed; IRO_NopOut(match->nd); IRO_PasteAfter(tmp->u.monadic, tmp->u.monadic, match->nd); } } if (ObjectIsArg(irec->var->object)) { IROLinear *op1; IROLinear *op2; IROLinear *op3; IROLinear *op4; IROLinear *op5; op1 = IRO_NewLinear(IROLinearOperand); op1->u.node = create_objectrefnode(obj); op1->rtype = op1->u.node->data.objref->type; op1->index = ++IRO_NumLinear; op1->flags |= IROLF_Ind | IROLF_Assigned; op2 = list1.tail; op3 = IRO_NewLinear(IROLinearOp1Arg); op3->nodetype = EINDIRECT; op3->rtype = irec->type; op3->u.monadic = op1; op3->index = ++IRO_NumLinear; op3->flags |= IROLF_Assigned; op4 = IRO_NewLinear(IROLinearOp1Arg); op4->nodetype = EINDIRECT; op4->rtype = irec->type; op4->u.monadic = op2; op4->index = ++IRO_NumLinear; op4->flags |= IROLF_Reffed; op5 = IRO_NewLinear(IROLinearOp2Arg); op5->nodetype = EASS; op5->u.diadic.left = op3; op5->u.diadic.right = op4; op5->rtype = irec->type; op5->index = ++IRO_NumLinear; op2->next = op4; op4->next = op1; op1->next = op3; op3->next = op5; IRO_PasteAfter(list1.head, op5, IRO_FirstLinear); } } } IRO_CheckForUserBreak(); } static Boolean CheckAddress(IROLinear *nd, Boolean *resultFlag) { IROLinear *inner; VarRecord *var; Boolean result; inner = nd->u.monadic; if (inner->type == IROLinearOp1Arg && inner->nodetype == EBITFIELD) inner = inner->u.monadic; result = 0; if (inner->type == IROLinearOperand && inner->u.node->type == EOBJREF) { if (IS_TYPE_CLASS(inner->u.node->data.objref->type) || IS_TYPE_STRUCT(inner->u.node->data.objref->type) || IS_TYPE_ARRAY(inner->u.node->data.objref->type)) { if (inner->u.node->data.objref->datatype == DLOCAL) { var = IRO_FindVar(inner->u.node->data.objref, 0, 1); CError_ASSERT(2240, var != NULL); CheckAddressConsistency(nd, var, 0, nd->rtype); result = 1; } } } else if ( inner->type == IROLinearOp2Arg && inner->nodetype == EADD && inner->u.diadic.left->type == IROLinearOperand && inner->u.diadic.left->u.node->type == EOBJREF) { if ( inner->u.diadic.right->type == IROLinearOperand && inner->u.diadic.right->u.node->type == EINTCONST && inner->u.diadic.right->u.node->data.intval.hi == 0) { if ( IS_TYPE_CLASS(inner->u.diadic.left->u.node->data.objref->type) || IS_TYPE_STRUCT(inner->u.diadic.left->u.node->data.objref->type) || IS_TYPE_ARRAY(inner->u.diadic.left->u.node->data.objref->type) ) { if (inner->u.diadic.left->u.node->data.objref->datatype == DLOCAL) { var = IRO_FindVar(inner->u.diadic.left->u.node->data.objref, 0, 1); CError_ASSERT(2267, var != NULL); CheckAddressConsistency(nd, var, inner->u.diadic.right->u.node->data.intval.lo, nd->rtype); result = 1; } } } else { if ( IS_TYPE_CLASS(inner->u.diadic.left->u.node->data.objref->type) || IS_TYPE_STRUCT(inner->u.diadic.left->u.node->data.objref->type) || IS_TYPE_ARRAY(inner->u.diadic.left->u.node->data.objref->type) ) { if (inner->u.diadic.left->u.node->data.objref->datatype == DLOCAL) { var = IRO_FindVar(inner->u.diadic.left->u.node->data.objref, 0, 1); CheckAddressConsistency(nd, var, -1, nd->rtype); result = 1; } } } } if (!result && !*resultFlag) { *resultFlag = IndirectMightUseOrKillAnyAddressedVar(nd); } return 0; } static Boolean CheckAddressConsistency(IROLinear *nd, VarRecord *var, SInt32 addend, Type *type) { IndirectRecord *rp; IndirectRecordMatch *match; UInt32 flag; IROLinear *inner; UInt32 start_bit; UInt32 end_bit; flag = 0; inner = nd->u.monadic; if (inner->type == IROLinearOp1Arg && inner->nodetype == EBITFIELD) { start_bit = TYPE_BITFIELD(inner->rtype)->unkA + 8 * addend; end_bit = start_bit + TYPE_BITFIELD(inner->rtype)->unkB - 1; } else { start_bit = 8 * addend; end_bit = start_bit + 8 * type->size - 1; } if (var->xB && !copts.opt_pointer_analysis) return 0; if (nd->rtype && CParser_IsVolatile(nd->rtype, nd->nodeflags & ENODE_FLAG_QUALS)) addend = -1; if (is_volatile_object(var->object)) addend = -1; for (rp = IRO_FirstIndirectRecord; rp; rp = rp->next) { if (rp->var->index == var->index) { if (rp->flags & 1) return 0; if (addend == -1) { flag = 1; break; } if (IRO_TypesEqual(rp->type, type) && rp->startbit == start_bit && rp->endbit == end_bit) { match = oalloc(sizeof(IndirectRecordMatch)); match->nd = inner; match->otherMatches = NULL; if (!rp->matches) { rp->matches = match; } else { match->otherMatches = rp->matches; rp->matches = match; } IRO_Dump("Exact Match of Type and bits at %d and %d\n", rp->linear->index, nd->index); IRO_Dump("Rp->startbit=%d,Rp->endbit=%d,start_bit=%d,end_bit=%d\n", rp->startbit, rp->endbit, start_bit, end_bit); return 1; } if (rp->startbit == start_bit && rp->endbit == end_bit && !IRO_TypesEqual(rp->type, type)) { IRO_Dump("match on bits but mismatch on type %d and %d\n", rp->linear->index, nd->index); IRO_Dump("Rp->startbit=%d,Rp->endbit=%d,start_bit=%d,end_bit=%d\n", rp->startbit, rp->endbit, start_bit, end_bit); flag = 1; break; } if (rp->startbit >= start_bit && end_bit >= rp->startbit) { IRO_Dump("Overlap detected --1 %d and %d\n", rp->linear->index, nd->index); IRO_Dump("Rp->startbit=%d,Rp->endbit=%d,start_bit=%d,end_bit=%d\n", rp->startbit, rp->endbit, start_bit, end_bit); flag = 1; break; } if (rp->startbit < start_bit && rp->endbit >= start_bit) { IRO_Dump("Overlap detected --2 %d and %d\n", rp->linear->index, nd->index); IRO_Dump("Rp->startbit=%d,Rp->endbit=%d,start_bit=%d,end_bit=%d\n", rp->startbit, rp->endbit, start_bit, end_bit); flag = 1; break; } } } if (flag) { DisableEntries(rp); if (addend >= 0) return 0; } IRO_Dump("Create Entry at %d\n", nd->index); IRO_Dump("start_bit=%d,end_bit=%d\n", start_bit, end_bit); rp = oalloc(sizeof(IndirectRecord)); rp->linear = nd; rp->flags = 0; rp->var = var; rp->addend = addend; rp->size = type->size; rp->type = type; rp->next = NULL; rp->matches = oalloc(sizeof(IndirectRecordMatch)); rp->matches->nd = inner; rp->matches->otherMatches = NULL; rp->startbit = start_bit; rp->endbit = end_bit; if (nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT && nd->u.monadic->type == IROLinearOp1Arg && nd->u.monadic->nodetype == EBITFIELD) rp->flags |= 2; if (!(IS_TYPE_FLOAT(type) || IS_TYPE_INT(type) || IS_TYPE_POINTER_ONLY(type)) || addend == -1 || ((inner->flags & IROLF_4000) && ObjectIsArg(var->object))) rp->flags |= 1; if (IRO_FirstIndirectRecord) IRO_LastIndirectRecord->next = rp; else IRO_FirstIndirectRecord = rp; IRO_LastIndirectRecord = rp; return 1; } static void DisableEntries(IndirectRecord *irec) { IndirectRecord *scan; for (scan = IRO_FirstIndirectRecord; scan; scan = scan->next) { if (irec->var->index == scan->var->index) scan->flags |= 1; } } static void DisableAddressedEntries(void) { IndirectRecord *scan; for (scan = IRO_FirstIndirectRecord; scan; scan = scan->next) { if (scan->var->xB) scan->flags |= 1; } } static UInt32 ObjectIsArg(Object *obj) { ObjectList *scan; for (scan = arguments; scan; scan = scan->next) { if (scan->object == obj) return 1; } return 0; }