extern an BGStopInline( call_handle handle, type_def *tipe ) { /******************************************************************/ // works if we're in the middle of a conditional??? label_handle lbl; inline_stack *junk; an retv; if( HaveCurrBlock == FALSE ) { EnLink( AskForNewLabel(), TRUE ); HaveCurrBlock = TRUE; } lbl = AskForNewLabel(); GenBlock( JUMP, 1 ); AddTarget( lbl, FALSE ); EnLink( lbl, TRUE ); InlineStack->tipe = tipe; FEGenProc( InlineStack->proc_sym, handle ); retv = InlineStack->addr; junk = InlineStack; InlineStack = InlineStack->next; CGFree( junk ); return( retv ); }
static an FlowOut( an node, type_def *tipe ) { /**************************************************/ name *temp; label_handle lbl; lbl = AskForNewLabel(); temp = BGGlobalTemp( tipe ); AddIns( MakeMove( AllocIntConst( FETrue() ), temp, temp->n.type_class ) ); *(node->u.b.t) = CurrBlock->label; GenBlock( BLK_JUMP, 1 ); AddTarget( lbl, false ); EnLink( AskForNewLabel(), true ); AddIns( MakeMove( AllocIntConst( 0 ), temp, temp->n.type_class ) ); *(node->u.b.f) = CurrBlock->label; GenBlock( BLK_JUMP, 1 ); AddTarget( lbl, false ); EnLink( lbl, true ); NamesCrossBlocks(); AddrFree( node ); return( AddrName( temp, tipe ) ); }
void BGProcDecl( cg_sym_handle sym, type_def *tipe ) /*****************************************************/ { hw_reg_set reg; name *temp; type_class_def type_class; segment_id old_segid; label_handle lbl; SaveTargetModel = TargetModel; type_class = AddCallBlock( sym, tipe ); if( tipe != TypeNone ) { if( type_class == XX ) { if( CurrProc->state.attr & ROUTINE_ALLOCS_RETURN ) { old_segid = SetOP( AskBackSeg() ); lbl = AskForNewLabel(); DataLabel( lbl ); DGUBytes( tipe->length ); CurrProc->targ.return_points = (name *)SAllocMemory( lbl, 0, CG_LBL, TypeClass( tipe ), tipe->length ); SetOP( old_segid ); } else { reg = CurrProc->state.return_reg; if( HW_CEqual( reg, HW_EMPTY ) ) { temp = DoParmDecl( NULL, TypeInteger, HW_EMPTY ); } else { temp = AllocTemp( WD ); temp->v.usage |= USE_IN_ANOTHER_BLOCK; AddIns( MakeMove( AllocRegName( reg ), temp, WD ) ); HW_TurnOn( CurrProc->state.parm.used, reg ); } CurrProc->targ.return_points = temp; } } } if( CurrProc->state.attr & ROUTINE_FARSS ) { TargetModel |= FLOATING_SS; } }
static void DoBinarySearch( an node, select_list *list, type_def *tipe, int lo, int hi, label_handle other, signed_32 lobound, signed_32 hibound, bool have_lobound, bool have_hibound ) /*************************************************************************/ { int num; int mid; select_list *mid_list; an cmp; label_handle lt; mid = lo + ( hi - lo ) / 2; mid_list = list; for( num = mid; num > 0; --num ) { mid_list = mid_list->next; } if( lo == hi ) { if( have_lobound && lobound == mid_list->low && have_hibound && hibound == mid_list->high ) { BGControl( O_GOTO, NULL, mid_list->label ); return; } else if( mid_list->low == mid_list->high ) { cmp = BGCompare( O_EQ, BGDuplicate( node ), BGInteger( mid_list->low, tipe ), NULL, tipe ); BGControl( O_IF_TRUE, cmp, mid_list->label ); BGControl( O_GOTO, NULL, other ); return; } } if( hi == mid + 1 && mid_list->next->low == mid_list->next->high ) { /* a linear sequence for three different non-sequential cases where c1<c2<c3, looks like: if( a == c3 ) goto l3; if( a == c2 ) goto l2; if( a != c1 ) goto default; l1: ... a binary sequence for these three cases looks like: if( a < c2 goto lt; \ if( a <= c2 ) goto l2; /only one cmp ins on x86 if( a == c3 ) goto l3; goto default; lt: if ( a != c1 ) goto default; l1: ... Advantage of the linear search: * 3 goto's instead of 5, resulting in smaller code. Advantage of the binary search: * Execution time for all the cases is more balanced. which one is really faster depends a lot on the CPU's branch prediction and other things that are very hard to measure here. Using a linear search here for <= 3 cases to save on code size with negligible performance loss or gain. */ mid_list = mid_list->next; cmp = BGCompare( O_EQ, BGDuplicate( node ), BGInteger( mid_list->low, tipe ), NULL, tipe ); BGControl( O_IF_TRUE, cmp, mid_list->label ); /* Because we only compared for equality, it is only possible to decrease the upper bound if it was already set and equal to the value we are comparing to. Otherwise the incoming value may still be higher, where the inner call may produce an unconditional O_GOTO to a specific case label! */ if( have_hibound && hibound == mid_list->low ) hibound--; DoBinarySearch( node, list, tipe, lo, mid, other, lobound, hibound, have_lobound, have_hibound ); return; } lt = AskForNewLabel(); if( !have_lobound || SelCompare( lobound, mid_list->low ) < 0 ) { if( have_hibound && SelCompare( hibound, mid_list->low ) < 0 ) { BGControl( O_GOTO, NULL, lt ); } else { cmp = BGCompare( O_LT, BGDuplicate( node ), BGInteger( mid_list->low, tipe ), NULL, tipe ); BGControl( O_IF_TRUE, cmp, lt ); } } if( !have_lobound || SelCompare( lobound, mid_list->high ) <= 0 ) { if( have_hibound && SelCompare( hibound, mid_list->high ) <= 0 ) { BGControl( O_GOTO, NULL, mid_list->label ); } else { cmp = BGCompare( O_LE, BGDuplicate( node ), BGInteger( mid_list->high, tipe ), NULL, tipe ); BGControl( O_IF_TRUE, cmp, mid_list->label ); } } if( mid < hi ) { DoBinarySearch( node, list, tipe, mid+1, hi, other, mid_list->high+1, hibound, true, have_hibound ); } else if( other != NULL ) { BGControl( O_GOTO, NULL, other ); } BGControl( O_LABEL, NULL, lt ); if( lo < mid ) { DoBinarySearch( node, list, tipe, lo, mid-1, other, lobound, mid_list->low-1, have_lobound, true ); } else if( other != NULL ) { BGControl( O_GOTO, NULL, other ); } }
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 ); }