static void *CLIAlloc( size_t size ) { void *p; p = CGAlloc( size ); return( p ); }
void *SafeRecurseCG( func_sr rtn, void *arg ) /**********************************************/ /* This code assumes NO parameters on the stack! */ { #define SAVE_SIZE 512 /* this must be smaller than the stack */ void *savearea; void *retval; mem_out_action old_action; if( stackavail() < 0x2000 ) { /* stack getting low! */ old_action = SetMemOut( MO_OK ); savearea = CGAlloc( SAVE_SIZE ); if( savearea == NULL ) { FatalError( "No memory to save stack" ); } SetMemOut( old_action ); CypCopy( bp(), savearea, SAVE_SIZE ); CypCopy( sp(), sp() + SAVE_SIZE, bp() - sp() ); setbp( bp() + SAVE_SIZE ); setsp( sp() + SAVE_SIZE ); retval = rtn( arg ); setsp( sp() - SAVE_SIZE ); CypCopy( sp() + SAVE_SIZE, sp(), bp() - sp() - SAVE_SIZE ); setbp( bp() - SAVE_SIZE ); CypCopy( savearea, bp(), SAVE_SIZE ); CGFree( savearea ); return( retval ); } else { return( rtn( arg ) ); } }
extern b *BENewBack(sym s) { //================================= b *bk; Action( "BENewBack" ); if( NewBackReturn == FAKE_NULL ) { bk = NULL; } else if( NewBackReturn != NULL ) { bk = NewBackReturn; } else { bk = CGAlloc( sizeof( b )); bk->n = BackList; bk->s = s; bk->loc = -1; bk->i = ++BackId; bk->lp = NewLabel(); BackList = bk; if( !IS_REAL_BACK( bk ) ) { CGError( "Internal error - odd memory" ); } } Action( "( %s ) -> %p%n", FEName( s ), bk ); return(bk); }
void CVBlkBeg( dbg_block *blk, offset lc ) /*******************************************/ { block_patch *bpatch; dbg_patch *dpatch; cv_out out[1]; offset start; cg_sym_handle sym; cs_block *ptr; byte *nm; bpatch = CGAlloc( sizeof( block_patch ) ); blk->patches = bpatch; NewBuff( out, CVSyms ); ptr = StartSym( out, SG_BLOCK ); ptr->pParent = 0; ptr->pEnd = 0; ptr->length = 0; ptr->offset = 0; ptr->segment = 0; nm = out->ptr; /* mark name */ CVPutNullStr( out ); EndSym( out ); dpatch = &blk->patches->patch; BuffPatchSet( CVSyms, dpatch ); BuffWrite( out, &ptr->offset ); sym = AskForLblSym( CurrProc->label ); start = lc - CurrProc->targ.debug->blk->start; SymReloc( CVSyms, sym, start ); BuffSkip( out, nm ); /* skip addr */ buffEnd( out ); DumpLocals( blk->locals ); }
pointer ScAlloc( size_t size ) /****************************/ { pointer chunk; chunk = CGAlloc( size ); return( chunk ); }
extern abspatch_handle *NextFramePatch( void ) /*********************************************/ { frame_patch *temp; temp = CGAlloc( sizeof( frame_patch ) ); temp->next = CurrProc->frame_index; CurrProc->frame_index = temp; return( &temp->patch ); }
extern void BGAddInlineParm( an addr ) { /******************************************/ inline_parm *parm; parm = CGAlloc( sizeof( *parm ) ); parm->addr = addr; parm->next = InlineStack->parms; InlineStack->parms = parm; }
static void addAutoLocn( sym s, cg_type type ) { AUTO_LOCN* curr; curr = CGAlloc( sizeof( AUTO_LOCN ) ); curr->s = s; curr->offset = next_auto_offset; curr->next = auto_locations; auto_locations = curr; next_auto_offset += _RoundUp( BETypeLength( type ), AUTO_PACK ); }
extern void BGStartInline( cg_sym_handle proc_sym ) { /*******************************************************/ inline_stack *stk; stk = CGAlloc( sizeof( *stk ) ); stk->parms = NULL; stk->tipe = NULL; stk->addr = NULL; stk->proc_sym = proc_sym; stk->next = InlineStack; InlineStack = stk; }
static select_list *NewCase( signed_32 lo, signed_32 hi, label_handle label ) /****************************************************************************/ { select_list *new_entry; new_entry = CGAlloc( sizeof( select_list ) ); new_entry->low = lo; new_entry->high = hi; new_entry->count = hi - lo + 1; new_entry->label = label; new_entry->next = NULL; return( new_entry ); }
extern l *NewLabel() { //=========================== l *nl; nl = CGAlloc( sizeof( l ) ); nl->n = LblList; nl->ddef = 0; nl->dref = 0; nl->cref = NULL; nl->cdef = NULL; LblList = nl; nl->i = ++LabelId; return(nl); }
extern select_node *BGSelInit( void ) { /************************************/ select_node *s_node; s_node = CGAlloc( sizeof( select_node ) ); s_node->num_cases = 0; s_node->other_wise = NULL; s_node->list = NULL; #ifndef NDEBUG s_node->useinfo.hdltype = NO_HANDLE; s_node->useinfo.used = FALSE; #endif return( s_node ); }
sel_handle BGSelInit( void ) /***************************/ { sel_handle s_node; s_node = CGAlloc( sizeof( select_node ) ); s_node->num_cases = 0; s_node->other_wise = NULL; s_node->list = NULL; #ifndef NDEBUG s_node->useinfo.hdltype = NO_HANDLE; s_node->useinfo.used = false; #endif return( s_node ); }
static void InitStackLocations( void ) { /**************************************/ temp_entry *temp; int i,j; STLocations = CGAlloc( MaxSeq * sizeof( *STLocations ) ); for( i = 0; i < MaxSeq; ++i ) { for( j = VIRTUAL_0; j < VIRTUAL_NONE; ++j ) { RegLoc( i, j ) = ACTUAL_NONE; } } for( temp = TempList; temp != NULL; temp = temp->next ) { temp->actual_locn = ACTUAL_NONE; } }
extern void IterBytes( offset len, byte pat ) /***********************************************/ { TellOptimizerByPassed(); if( len > MAX_HACK_LEN ) { byte *buff; buff = CGAlloc( len ); memset( buff, pat, len ); ObjBytes( buff, len ); CGFree( buff ); } else { memset( Buffer, pat, len ); ObjBytes( Buffer, len ); } TellByPassOver(); }
ins_entry *NewInstr( any_oc *oc ) /*************************************/ { ins_entry *instr; oc_length len; optbegin len = oc->oc_header.reclen + sizeof( ins_link ); if( len <= OCENTRY_SIZE ) { instr = AllocFrl( &InstrFrl, OCENTRY_SIZE ); } else { instr = CGAlloc( len ); } instr->ins.prev = NULL; instr->ins.next = NULL; Copy( oc, &instr->oc, oc->oc_header.reclen ); optreturn( instr ); }
type_class_def CallState( aux_handle aux, type_def *tipe, call_state *state ) /****************************************************************************/ { type_class_def class; uint i; hw_reg_set parms[24]; hw_reg_set *parm_src; hw_reg_set *parm_dst; state->unalterable = FixedRegs(); HW_CAsgn( state->modify, HW_FULL ); HW_TurnOff( state->modify, SavedRegs() ); HW_CTurnOff( state->modify, HW_UNUSED ); state->used = state->modify; /* anything not saved is used*/ state->attr = 0; i = 0; parm_src = ParmRegs(); parm_dst = &parms[0]; for(;;) { *parm_dst = *parm_src; if( HW_CEqual( *parm_dst, HW_EMPTY ) ) break; if( HW_Ovlap( *parm_dst, state->unalterable ) ) { FEMessage( MSG_BAD_SAVE, aux ); } HW_CTurnOff( *parm_dst, HW_UNUSED ); parm_dst++; parm_src++; i++; } i++; state->parm.table = CGAlloc( i*sizeof( hw_reg_set ) ); Copy( parms, state->parm.table, i * sizeof( hw_reg_set ) ); HW_CAsgn( state->parm.used, HW_EMPTY ); state->parm.curr_entry = state->parm.table; state->parm.offset = 0; InitPPCParmState( state ); class = ReturnClass( tipe, state->attr ); if( *(call_class *)FEAuxInfo( aux, CALL_CLASS ) & HAS_VARARGS ) { state->attr |= ROUTINE_HAS_VARARGS; } UpdateReturn( state, tipe, class, aux ); return( class ); }
extern void Conditions( void ) /********************************* Traverse the basic blocks and determine if there are any compare instructions that we can eliminate, since the condition codes are already set by a subtract instruction or something. Note that the internal instuctions with opcodes like OP_CMP_EQUAL generate both a compare and a jump. If we "DoNothing" them, they will still generate the jumps, but not the compare. In a "cc_control", we keep track of "left_op", "right_op" and "result_op" as well as "state". If "left_op" and "right_op" are set, it means that we have condition codes which would do for a comparison of "left_op" with "right_op" (subject to the signed/unsigned constraints in "state"). If "result_op" is set, it means we have condition codes set which would do for a comparison of "result_op" against zero. On the 370, which has the worlds strangest set of condition codes, we use "state"=SIGNED_CONDITIONS_SET to mean that the condition codes are alright as long as we are doing a comparison of equality or inequality. This is a misnomer, but I was in a hurry. */ { block *blk; cc_control *cc; for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) { cc = CGAlloc( sizeof( cc_control ) ); cc->state = UNKNOWN_STATE; cc->left_op = NULL; cc->right_op = NULL; cc->result_op = NULL; cc->ins = NULL; cc->op_type = XX; blk->cc = cc; _MarkBlkUnVisited( blk ); } FlowConditions(); for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) { CGFree( blk->cc ); } }
static temp_entry *AddTempEntry( name *op ) { /********************************************/ temp_entry *temp; temp = LookupTempEntry( op ); if( temp == NULL ) { temp = CGAlloc( sizeof( *temp ) ); temp->next = TempList; TempList = temp; temp->actual_op = op; if( op->n.class == N_TEMP ) op = DeAlias( op ); temp->op = op; temp->first = NULL; temp->last = NULL; temp->savings = 0; temp->actual_locn = ACTUAL_NONE; temp->savings = 0; temp->cached = FALSE; temp->defined = FALSE; temp->killed = FALSE; temp->global = FALSE; temp->whole_block = FALSE; }
static void FixFarLocalRefs( type_length size ) { /**************************************************** Turn far local references into indexed references so that we can address all of our auto variables and parms. */ block *blk; instruction *ins; int i; int offset_size; name **offsets; i = size / _4K; offset_size = (i+1) * sizeof( name** ); offsets = CGAlloc( offset_size ); while( i >= 0 ) { offsets[ i ] = NULL; --i; } blk = HeadBlock; while( blk != NULL ) { ins = blk->ins.hd.next; while( ins->head.opcode != OP_BLOCK ) { i = ins->num_operands; while( --i >= 0 ) { CheckOp( offsets, ins, &ins->operands[ i ] ); } if( ins->result != NULL ) { CheckOp( offsets, ins, &ins->result ); } ins = ins->head.next; } blk = blk->next_block; } CGFree( offsets ); }
static void *DoSortList( void *list, unsigned next_offset, bool (*before)(void *,void *), unsigned length ) { /**************************************************************************/ void **array; void **parray; void *list2; unsigned mid; int i; if( list == NULL ) return( NULL ); array = CGAlloc( length * sizeof( void * ) ); if( array == NULL ) { mid = length / 2; if( mid == 0 ) return( list ); /* FATAL ERROR! */ list2 = list; for( i = mid; i > 0; --i ) { list2 = _NEXT( list2, next_offset ); } list = DoSortList( list, next_offset, before, mid ); list2 = DoSortList( list2, next_offset, before, length - mid ); list = MergeList( list, list2, next_offset, before ); } else { list2 = list; parray = array; for( i = length; i > 0; --i ) { *parray++ = list2; list2 = _NEXT( list2, next_offset ); } ShellSort( array, length, before ); list = BuildList( array, next_offset, length ); CGFree( array ); } return( list ); }
type_class_def CallState( aux_handle aux, type_def *tipe, call_state *state ) /****************************************************************************/ { call_class cclass; type_class_def type_class; uint i; hw_reg_set parms[10]; hw_reg_set *parm_src; hw_reg_set *parm_dst; hw_reg_set *pregs; hw_reg_set tmp; state->unalterable = FixedRegs(); pregs = FEAuxInfo( aux, SAVE_REGS ); HW_CAsgn( state->modify, HW_FULL ); HW_TurnOff( state->modify, *pregs ); HW_CTurnOff( state->modify, HW_UNUSED ); state->used = state->modify; /* anything not saved is used*/ tmp = state->used; HW_TurnOff( tmp, StackReg() ); HW_CTurnOff( tmp, HW_BP ); // should be able to call routine which modifies BP if( HW_Ovlap( state->unalterable, tmp ) ) { FEMessage( MSG_BAD_SAVE, aux ); } state->attr = ROUTINE_REMOVES_PARMS; cclass = *(call_class *)FEAuxInfo( aux, CALL_CLASS ); if( cclass & INTERRUPT ) { state->attr |= ROUTINE_INTERRUPT; } else if( cclass & FAR_CALL ) { state->attr |= ROUTINE_LONG; } else if( cclass & FAR16_CALL ) { state->attr |= ROUTINE_FAR16; } if( cclass & CALLER_POPS ) { state->attr &= ~ROUTINE_REMOVES_PARMS; } if( cclass & SUICIDAL ) { state->attr |= ROUTINE_NEVER_RETURNS; } if( cclass & ROUTINE_RETURN ) { state->attr |= ROUTINE_ALLOCS_RETURN; } if( cclass & NO_STRUCT_REG_RETURNS ) { state->attr |= ROUTINE_NO_STRUCT_REG_RETURNS; } if( cclass & NO_FLOAT_REG_RETURNS ) { state->attr |= ROUTINE_NO_FLOAT_REG_RETURNS; state->attr |= ROUTINE_NO_8087_RETURNS; } if( cclass & NO_8087_RETURNS ) { state->attr |= ROUTINE_NO_8087_RETURNS; } if( cclass & MODIFY_EXACT ) { state->attr |= ROUTINE_MODIFY_EXACT; } if( cclass & NO_MEMORY_CHANGED ) { state->attr |= ROUTINE_MODIFIES_NO_MEMORY; } if( cclass & NO_MEMORY_READ ) { state->attr |= ROUTINE_READS_NO_MEMORY; } if( cclass & LOAD_DS_ON_ENTRY ) { state->attr |= ROUTINE_LOADS_DS; } if( cclass & LOAD_DS_ON_CALL ) { state->attr |= ROUTINE_NEEDS_DS_LOADED; } if( cclass & PARMS_STACK_RESERVE ) { state->attr |= ROUTINE_STACK_RESERVE; } if( cclass & PARMS_PREFER_REGS ) { state->attr |= ROUTINE_PREFER_REGS; } if( cclass & FARSS ) { state->attr |= ROUTINE_FARSS; } if( state == &CurrProc->state ) { if( cclass & ( GENERATE_STACK_FRAME | PROLOG_HOOKS | EPILOG_HOOKS ) ) { CurrProc->prolog_state |= GENERATE_FAT_PROLOG; state->attr |= ROUTINE_NEEDS_PROLOG; } if( cclass & PROLOG_HOOKS ) { CurrProc->prolog_state |= GENERATE_PROLOG_HOOKS; } if( cclass & EPILOG_HOOKS ) { CurrProc->prolog_state |= GENERATE_EPILOG_HOOKS; } if( cclass & FAT_WINDOWS_PROLOG ) { CurrProc->prolog_state |= GENERATE_FAT_PROLOG; } if( cclass & EMIT_FUNCTION_NAME ) { CurrProc->prolog_state |= GENERATE_FUNCTION_NAME; } if( cclass & THUNK_PROLOG ) { CurrProc->prolog_state |= GENERATE_THUNK_PROLOG; } if( cclass & GROW_STACK ) { CurrProc->prolog_state |= GENERATE_GROW_STACK; } if( cclass & TOUCH_STACK ) { CurrProc->prolog_state |= GENERATE_TOUCH_STACK; } if( cclass & LOAD_RDOSDEV_ON_ENTRY ) { CurrProc->prolog_state |= GENERATE_RDOSDEV_PROLOG; } } type_class = ReturnClass( tipe, state->attr ); i = 0; parm_dst = &parms[0]; for( parm_src = FEAuxInfo( aux, PARM_REGS ); !HW_CEqual( *parm_src, HW_EMPTY ); ++parm_src ) { *parm_dst = *parm_src; if( HW_Ovlap( *parm_dst, state->unalterable ) ) { FEMessage( MSG_BAD_SAVE, aux ); } HW_CTurnOff( *parm_dst, HW_UNUSED ); parm_dst++; i++; } *parm_dst = *parm_src; i++; state->parm.table = CGAlloc( i*sizeof( hw_reg_set ) ); Copy( parms, state->parm.table, i * sizeof( hw_reg_set ) ); HW_CAsgn( state->parm.used, HW_EMPTY ); state->parm.curr_entry = state->parm.table; state->parm.offset = 0; if( tipe == TypeNone ) { HW_CAsgn( state->return_reg, HW_EMPTY ); } else if( type_class == XX ) { if( cclass & SPECIAL_STRUCT_RETURN ) { pregs = FEAuxInfo( aux, STRETURN_REG ); state->return_reg = *pregs; state->attr |= ROUTINE_HAS_SPECIAL_RETURN; } else { state->return_reg = StructReg(); } if( (state->attr & ROUTINE_ALLOCS_RETURN) == 0 ) { tmp = ReturnReg( WD, false ); HW_TurnOn( state->modify, tmp ); } } else { if( cclass & SPECIAL_RETURN ) { pregs = FEAuxInfo( aux, RETURN_REG ); state->return_reg = *pregs; state->attr |= ROUTINE_HAS_SPECIAL_RETURN; } else { state->return_reg = ReturnReg( type_class, _NPX( state->attr ) ); } } UpdateReturn( state, tipe, type_class, aux ); return( type_class ); }
void FlowSave( hw_reg_set *preg ) /*******************************/ { int score; int i, j; int best; int num_blocks; int num_regs; int curr_reg; hw_reg_set *curr_push; reg_flow_info *reg_info; block *save; block *restore; instruction *ins; type_class_def reg_type; HW_CAsgn( flowedRegs, HW_EMPTY ); if( _IsntModel( FLOW_REG_SAVES ) ) return; if( !HaveDominatorInfo ) return; // we can't do this if we have push's which are 'live' at the end of a block // - this flag is set when we see a push being generated for a call in a different // block #if _TARGET & _TARG_INTEL if( CurrProc->targ.never_sp_frame ) return; #endif num_regs = CountRegs( *preg ); if( num_regs == 0 ) return; reg_info = CGAlloc( num_regs * sizeof( reg_flow_info ) ); num_blocks = CountBlocks(); InitBlockArray(); curr_push = PushRegs; for( curr_reg = 0; curr_reg < num_regs; curr_reg++ ) { while( !HW_Ovlap( *curr_push, *preg ) ) curr_push++; HW_Asgn( reg_info[curr_reg].reg, *curr_push ); reg_info[curr_reg].save = NULL; reg_info[curr_reg].restore = NULL; #if _TARGET & _TARG_INTEL if( HW_COvlap( *curr_push, HW_BP ) ) continue; // don't mess with BP - it's magical #endif GetRegUsage( ®_info[curr_reg] ); best = 0; for( i = 0; i < num_blocks; i++ ) { for( j = 0; j < num_blocks; j++ ) { if( PairOk( blockArray[i], blockArray[j], ®_info[0], curr_reg ) ) { // we use the number of blocks dominated by the save block plus // the number of blocks post-dominated by the restore block as a // rough metric for determining how much we like a given (valid) // pair of blocks - the more blocks dominated, the further 'in' // we have pushed the save, which should be good score = CountDomBits( &blockArray[i]->dom.dominator ); score += CountDomBits( &blockArray[j]->dom.post_dominator ); if( score > best ) { best = score; reg_info[curr_reg].save = blockArray[i]; reg_info[curr_reg].restore = blockArray[j]; } } } } // so now we know where we are going to save and restore the register // emit the instructions to do so, and remove reg from the set to push // in the normal prolog sequence save = reg_info[curr_reg].save; restore = reg_info[curr_reg].restore; if( ( save != NULL && save != HeadBlock ) && ( restore != NULL && !_IsBlkAttr( restore, BLK_RETURN ) ) ) { reg_type = WD; #if _TARGET & _TARG_INTEL if( IsSegReg( reg_info[curr_reg].reg ) ) { reg_type = U2; } #endif ins = MakeUnary( OP_PUSH, AllocRegName( reg_info[curr_reg].reg ), NULL, reg_type ); ResetGenEntry( ins ); PrefixIns( save->ins.hd.next, ins ); ins = MakeUnary( OP_POP, NULL, AllocRegName( reg_info[curr_reg].reg ), reg_type ); ins->num_operands = 0; ResetGenEntry( ins ); SuffixIns( restore->ins.hd.prev, ins ); HW_TurnOff( *preg, reg_info[curr_reg].reg ); HW_TurnOn( flowedRegs, reg_info[curr_reg].reg ); FixStackDepth( save, restore ); } curr_push++; } CGFree( reg_info ); }
extern type_class_def CallState( aux_handle aux, type_def *tipe, call_state *state ) /*******************************************************************/ { type_class_def class; uint i; hw_reg_set parms[20]; hw_reg_set *parm_src; hw_reg_set *parm_dst; hw_reg_set *pregs; call_class cclass; call_class *pcclass; risc_byte_seq *code; bool have_aux_code = FALSE; state->unalterable = FixedRegs(); if( FEAttr( AskForLblSym( CurrProc->label ) ) & FE_VARARGS ) { HW_TurnOn( state->unalterable, VarargsHomePtr() ); } // For code bursts only, query the #pragma aux instead of using // hardcoded calling convention. If it ever turns out that we need // to support more than a single calling convention, this will need // to change to work more like x86 if( !AskIfRTLabel( CurrProc->label ) ) { code = FEAuxInfo( aux, CALL_BYTES ); if( code != NULL ) { have_aux_code = TRUE; } } pregs = FEAuxInfo( aux, SAVE_REGS ); HW_CAsgn( state->modify, HW_FULL ); if( have_aux_code ) { HW_TurnOff( state->modify, *pregs ); } else { HW_TurnOff( state->modify, SavedRegs() ); } HW_CTurnOff( state->modify, HW_UNUSED ); state->used = state->modify; /* anything not saved is used */ state->attr = 0; pcclass = FEAuxInfo( aux, CALL_CLASS ); cclass = *pcclass; if( cclass & SETJMP_KLUGE ) { state->attr |= ROUTINE_IS_SETJMP; } if( cclass & SUICIDAL ) { state->attr |= ROUTINE_NEVER_RETURNS; } if( cclass & NO_MEMORY_CHANGED ) { state->attr |= ROUTINE_MODIFIES_NO_MEMORY; } if( cclass & NO_MEMORY_READ ) { state->attr |= ROUTINE_READS_NO_MEMORY; } i = 0; if( have_aux_code ) { parm_src = FEAuxInfo( aux, PARM_REGS ); } else { parm_src = ParmRegs(); } parm_dst = &parms[0]; for( ;; ) { *parm_dst = *parm_src; if( HW_CEqual( *parm_dst, HW_EMPTY ) ) break; if( HW_Ovlap( *parm_dst, state->unalterable ) ) { FEMessage( MSG_BAD_SAVE, aux ); } HW_CTurnOff( *parm_dst, HW_UNUSED ); parm_dst++; parm_src++; i++; } i++; state->parm.table = CGAlloc( i * sizeof( hw_reg_set ) ); Copy( parms, state->parm.table, i * sizeof( hw_reg_set ) ); HW_CAsgn( state->parm.used, HW_EMPTY ); state->parm.curr_entry = state->parm.table; state->parm.offset = 0; class = ReturnClass( tipe, state->attr ); UpdateReturn( state, tipe, class, aux ); return( class ); }
extern bool CreateBreak( void ) /*****************************************/ { block *blk; block *break_blk; block *back_break_blk; block *exit_blk; block_edge *edge; block_edge *next_edge; block_num targets; int pending; edge_list *exit_edge; if( HeadBlock == NULL ) { return( false ); } if( _IsntModel( FORTRAN_ALIASING ) ) { return( false ); } if( !FixReturns() ) { return( false ); } FixEdges(); /* Run through the blocks and find a place (break_blk) where no previous blocks are branched to from later blocks. IE: there are no backward branches around break_blk. */ _MarkBlkAllUnVisited(); break_blk = NULL; back_break_blk = NULL; pending = 0; BranchOuts = NULL; for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) { if( AskIfReachedLabel( blk->label ) && blk != HeadBlock ) break; if( (blk->edge[0].flags & BLOCK_LABEL_DIES) == 0 && blk != HeadBlock ) { _MarkBlkVisited( blk ); ++pending; } else if( pending == 0 ) { break_blk = blk; } edge = &blk->edge[0]; for( targets = blk->targets; targets > 0; --targets ) { if( edge->flags & DEST_IS_BLOCK ) { if( edge->flags & DEST_LABEL_DIES ) { if( _IsBlkVisited( edge->destination.u.blk ) ) { _MarkBlkUnVisited( edge->destination.u.blk ); if( --pending == 0 ) { back_break_blk = blk->next_block; } } } } ++edge; } } /* clean up the BLOCK_VISITED flags */ _MarkBlkAllUnVisited(); if( back_break_blk != NULL ) { break_blk = back_break_blk; /* always better to break on a back edge */ } if( break_blk == NULL ) { break_blk = HeadBlock; } if( break_blk == HeadBlock ) { break_blk = break_blk->next_block; } if( break_blk == NULL ) { UnFixEdges(); return( false ); } /* create a new block and link it after break_blk. Point Break to the rest of the blocks and unhook them from the block list. */ Break = break_blk; Curr = CurrBlock; Tail = BlockList; exit_blk = NewBlock( NULL, false ); exit_blk->gen_id = BlockList->gen_id + 1; exit_blk->id = BlockList->id + 1; exit_blk->ins.hd.line_num = 0; BlockList = exit_blk; exit_blk->prev_block = break_blk->prev_block; exit_blk->next_block = NULL; _SetBlkAttr( exit_blk, BLK_UNKNOWN_DESTINATION ); break_blk->prev_block->next_block = exit_blk; break_blk->prev_block = NULL; /* run throuch all the blocks before break_blk, and create a 'BranchOut' for and edge that goes to a block after break_blk */ for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) { edge = &blk->edge[0]; for( targets = blk->targets; targets > 0; --targets ) { if( (edge->flags & DEST_IS_BLOCK) == 0 || edge->destination.u.blk->gen_id >= break_blk->gen_id ) { exit_edge = CGAlloc( sizeof( edge_list ) ); exit_edge->edge = edge; exit_edge->next = BranchOuts; exit_edge->gen_id = blk->gen_id; BranchOuts = exit_edge; } ++edge; } } /* now, point all 'BranchOuts' at the new 'exit' block, saving their original labels in the 'lbl' field of the exit_list */ for( exit_edge = BranchOuts; exit_edge != NULL; exit_edge = exit_edge->next ) { edge = exit_edge->edge; if( edge->flags & DEST_IS_BLOCK ) { exit_edge->lbl = edge->destination.u.blk->label; RemoveInputEdge( edge ); } else { exit_edge->lbl = edge->destination.u.lbl; } edge->destination.u.blk = exit_blk; edge->flags |= DEST_IS_BLOCK; edge->next_source = exit_blk->input_edges; exit_blk->input_edges = edge; exit_blk->inputs++; } if( exit_blk->inputs == 0 ) { BlockList = exit_blk->prev_block; BlockList->next_block = NULL; exit_blk->prev_block = NULL; FreeABlock( exit_blk ); } _MarkBlkAttr( HeadBlock, BLK_BIG_LABEL ); HaveBreak = true; /* change any branches to HeadBlock from a block after break_blk into a label (~DEST_IS_BLOCK) branch. */ for( edge = HeadBlock->input_edges; edge != NULL; edge = next_edge ) { next_edge = edge->next_source; if( edge->source->gen_id >= break_blk->gen_id ) { RemoveInputEdge( edge ); edge->destination.u.lbl = edge->destination.u.blk->label; edge->flags &= ~DEST_IS_BLOCK; } } /* Now, set up a new HeadBlock, and redirect all unknowns branches to it. Known branches may still go to the old HeadBlock. This is so that HeadBlock will not be a loop header. The loop optimizer will screw up if it is. */ blk = NewBlock( NULL, false ); blk->input_edges = NULL; blk->inputs = 0; blk->label = HeadBlock->label; blk->ins.hd.line_num = HeadBlock->ins.hd.line_num; HeadBlock->ins.hd.line_num = 0; blk->gen_id = 0; blk->id = 0; HeadBlock->label = AskForNewLabel(); blk->targets = 1; _SetBlkAttr( blk, BLK_BIG_LABEL | BLK_JUMP ); _MarkBlkAttrNot( HeadBlock, BLK_BIG_LABEL ); edge = &blk->edge[0]; edge->flags = DEST_IS_BLOCK; edge->destination.u.blk = HeadBlock; edge->source = blk; edge->next_source = HeadBlock->input_edges; HeadBlock->input_edges = edge; HeadBlock->inputs++; HeadBlock->prev_block = blk; blk->prev_block = NULL; blk->next_block = HeadBlock; HeadBlock = blk; return( true ); }