static bool ZapsMemory( name *result, name *op, bool for_index ) { /********************************************************************* Could redefining "result" redefine N_MEMORY name "op"? */ switch( result->n.class ) { case N_TEMP: return( false ); case N_MEMORY: if( result->v.symbol != op->v.symbol ) return( false ); /* can be used for memory ops as well */ if( for_index ) return( true ); return( TempsOverlap( result, op ) ); case N_INDEXED: if( result->i.base == NULL ) { if( _IsModel( FORTRAN_ALIASING ) ) return( false ); if( op->v.usage & USE_ADDRESS ) return( true ); return( _IsntModel( RELAX_ALIAS ) ); } if( result->i.base->n.class == N_TEMP ) { return( _IsntModel( RELAX_ALIAS ) ); } else { /* it must be N_MEMORY*/ return( ZapsMemory( result->i.base, op, true ) ); } case N_REGISTER: return( false ); default: _Zoiks( ZOIKS_023 ); return( false ); }
static void PreOptimize( void ) /*****************************************/ { bool change; if( _IsntModel( NO_OPTIMIZATION ) ) { // CharsAndShortsToInts(); MakeMovAddrConsts(); PushPostOps(); DeadTemps(); InsDead(); MakeFlowGraph(); BlockTrim(); CommonSex( _IsModel( LOOP_OPTIMIZATION ) ); SetOnCondition(); BlockTrim(); AddANop(); if( _IsModel( LOOP_OPTIMIZATION ) ) { change = FALSE; if( TransLoops( FALSE ) ) { change = TRUE; } if( LoopInvariant() ) { change = TRUE; } if( change ) { CommonSex(TRUE); InsDead(); CommonInvariant(); } if( IndVars() ) { CommonSex(FALSE); InsDead(); change = TRUE; } BlockTrim(); if( TransLoops( TRUE ) ) { BlockTrim(); CommonSex( FALSE ); change = TRUE; } if( change ) { ReConstFold(); } LoopEnregister(); if( change ) { BlockTrim(); } } MulToShiftAdd(); KillMovAddrConsts(); FindReferences(); } else { MakeFlowGraph(); AddANop(); FindReferences(); } }
static bool FlushSomeOpt( pointer_int size ) /**********************************************/ { seg_id old; bool freed; if( InOptimizer == 0 && HaveCodeSeg() ) { old = SetOP( AskCodeSeg() ); freed = ShrinkQueue( size ); SetOP( old ); if( _IsntModel( NO_OPTIMIZATION ) && IckyWicky == FALSE ) { IckyWicky = TRUE; FEMessage( MSG_PEEPHOLE_FLUSHED, NULL ); } } else { freed = FALSE; } return( freed ); }
static void BlockToCode( bool partly_done ) /*********************************************/ { block_num inputs; block_num targets; block_edge *input_edges; conflict_node *curr; conflict_node **owner; conflict_node *conflist; block_num id; /* try to get back some memory*/ _MemLow; /* make the block look like an entire procedure*/ HeadBlock = CurrBlock; BlockList = CurrBlock; HeadBlock->prev_block = NULL; if( HeadBlock->next_block != NULL ) { HeadBlock->next_block->prev_block = NULL; } /* Kludge - need a pointer to the next block for CALL_LABEL - puke! */ if( HeadBlock->class & CALL_LABEL ) { HeadBlock->v.next = HeadBlock->next_block; } HeadBlock->next_block = NULL; /* force anything that spans blocks to memory */ HeadBlock->u.partition = HeadBlock; ConstFold( HeadBlock ); HeadBlock->u.partition = NULL; ForceTempsMemory(); if( partly_done == FALSE ) { FixMemRefs(); HaveLiveInfo = FALSE; if( _IsntModel( NO_OPTIMIZATION | FORTRAN_ALIASING ) ) { FindReferences(); CommonSex(FALSE); PushPostOps(); } FindReferences(); DeadTemps(); if( _IsModel( NO_OPTIMIZATION ) ) { SetInOut( HeadBlock ); } else { MakeConflicts(); } MakeLiveInfo(); HaveLiveInfo = TRUE; AxeDeadCode(); FixIndex(); FixSegments(); FPRegAlloc(); RegAlloc( TRUE ); FreeConflicts(); HaveLiveInfo = FALSE; } else { conflist = NULL; owner = &ConfList; for( ;; ) { curr = *owner; if( curr == NULL ) break; if( curr->start_block == HeadBlock ) { *owner = curr->next_conflict; curr->next_conflict = conflist; conflist = curr; } else { owner = &curr->next_conflict; } } curr = ConfList; ConfList = conflist; RegAlloc( TRUE ); FreeConflicts(); ConfList = curr; } input_edges = HeadBlock->input_edges; inputs = HeadBlock->inputs; targets = HeadBlock->targets; HeadBlock->inputs = 0; HeadBlock->input_edges = NULL; HeadBlock->targets = 0; FPParms(); PostOptimize(); HeadBlock->input_edges = input_edges; HeadBlock->inputs = inputs; HeadBlock->targets = targets; /* generate a prolog that saves all registers*/ if( ( CurrProc->prolog_state & GENERATED_PROLOG ) == 0 ) { CurrProc->state.used = AllCacheRegs(); GenProlog(); } id = CurrBlock->id; AssgnMoreTemps( id ); OptSegs(); /* generate the code for the block*/ if( CurrBlock->class & RETURN ) { GenObject(); FiniStackMap(); FreeProc(); } else {
static void PostOptimize( void ) /******************************************/ { if( _IsntModel( NO_OPTIMIZATION ) ) { // Run peephole optimizer again. Important: It is critical that the // new instructions can be directly generated because RegAlloc is // done by now. PeepOpt() is responsible for verifying that. if( PeepOpt( HeadBlock, NextBlock, NULL, TRUE ) ) { LiveInfoUpdate(); } // this is important as BuildIndex cannot handle instructions with no operands DeadInstructions(); BuildIndex(); DeadInstructions(); } MergeIndex(); if( _IsntModel( NO_OPTIMIZATION ) ) { #if !(_TARGET & _TARG_RISC) // // Calling Conditions() at this point has nice optimization effect, // but doesn't working correctly right now. It optimizes conditions // making them dependent from previous conditions codes, but riscifier // generates XOR's which will trash cond. codes. Either Conditions() // either riscifier must be fixed to handle this situation. // #if 0 // Get rid of unused conditions on variables level // to decrease number of referenced vars in LdStAlloc() and Score() if( _IsntTargetModel( STATEMENT_COUNTING ) ) { Conditions(); DeadInstructions(); // cleanup junk after Conditions() } #endif #endif // OptCloseMoves(); // todo: merge constant moves before riscifier LdStAlloc(); Score(); DeadInstructions(); // cleanup junk after Score() // deRISCify before LoopRegInvariant() or Shedule() are run: // they're moving RISCified pair. LdStCompress(); // Reuse registers freed by deriscifier Score(); DeadInstructions(); // cleanup junk after Score() if( !BlockByBlock ) LoopRegInvariant(); #if !(_TARGET & _TARG_RISC) // Get rid of remaining unused conditions on register level. if( _IsntTargetModel( STATEMENT_COUNTING ) ) { Conditions(); } #endif } FPExpand(); if( _IsntModel( NO_OPTIMIZATION ) ) { DeadInstructions(); // cleanup junk after Conditions() // Run scheduler last, when all instructions are stable if( _IsModel( INS_SCHEDULING ) ) { HaveLiveInfo = FALSE; Schedule(); /* NOTE: Schedule messes up live information */ LiveInfoUpdate(); HaveLiveInfo = TRUE; } // run this again in case Scheduler messed around with indices if( PeepOpt( HeadBlock, NextBlock, NULL, TRUE ) ) { LiveInfoUpdate(); } } FPOptimize(); }
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 void DFObjInitDbgInfo( void ) { /*****************************************************/ /* called by objinit to init segments and dwarf writing library */ static const dw_funcs cli_funcs = { CLIReloc, CLIWrite, CLISeek, CLITell, CLIAlloc, CLIFree }; dw_init_info info; cg_sym_handle abbrev_sym; cg_sym_handle debug_pch; fe_attr attr; if( _IsntModel( DBG_LOCALS | DBG_TYPES ) ){ return; } info.compiler_options = DW_CM_DEBUGGER; info.abbrev_sym = 0; info.producer_name = SetDwarfProducer(); info.language = SetLang(); if( setjmp( info.exception_handler ) == 0 ) { info.funcs = cli_funcs; InitSegBck(); // start each seg with a ref label if( _IsModel( DBG_PREDEF ) ) { abbrev_sym = FEAuxInfo( NULL, DBG_PREDEF_SYM ); info.abbrev_sym = (dw_sym_handle)abbrev_sym; attr = FEAttr( abbrev_sym ); if( (attr & FE_IMPORT) ) { info.compiler_options |= DW_CM_ABBREV_PRE; }else{ back_handle bck; segment_id old; info.compiler_options |= DW_CM_ABBREV_GEN; bck = FEBack( abbrev_sym ); // dump out export label bck->seg = DwarfSegs[DW_DEBUG_ABBREV].seg; old = SetOP( DwarfSegs[DW_DEBUG_ABBREV].seg ); DataLabel( bck->lbl ); SetOP( old ); } } debug_pch = FEAuxInfo( NULL, DBG_PCH_SYM ); if( debug_pch != NULL ){ attr = FEAttr( debug_pch ); if( !(attr & FE_IMPORT) ) { back_handle bck; segment_id old; bck = FEBack( debug_pch ); bck->seg = DwarfSegs[DW_DEBUG_INFO].seg; old = SetOP( DwarfSegs[DW_DEBUG_INFO].seg ); DataLabel( bck->lbl ); SetOP( old ); debug_pch = NULL; } } Client = DWInit( &info ); if( Client == NULL ) { Zoiks( ZOIKS_107 ); /* Bad */ } DFBegCCU( AskCodeSeg(), (dw_sym_handle)debug_pch ); } else { Zoiks( ZOIKS_107 ); /* Big Error */ } }
extern void DFBegCCU( segment_id code, dw_sym_handle dbg_pch ) /****************************************************************/ // Call when codeseg hase been defined { dw_cu_info cu; back_handle bck; segment_id old; type_def *tipe_addr; if( _IsntModel( DBG_LOCALS | DBG_TYPES ) ) { return; } if( CcuDef ) { cu.source_filename = FEAuxInfo( NULL, SOURCE_NAME ); cu.directory = ""; cu.dbg_pch = dbg_pch; cu.inc_list = NULL; cu.inc_list_len = 0; old = SetOP( code ); #if _TARGET & ( _TARG_IAPX86 | _TARG_80386 ) if( _IsTargetModel( FLAT_MODEL ) ) { bck = MakeLabel(); OutLabel( bck->lbl ); Pc_Low = bck; Pc_High = MakeLabel(); // Emitting DW_AT_low_pc and DW_AT_high_pc is valid *only* if the // compilation unit's code is in a single contiguous block (see // DWARF 2, section 3.1). // I don't know how to find out at the time of this call if there's // only one code segment or not, hence these attributes are always // disabled. The low/high pc attribs should probably be handled by // the linker. cu.flags = false; cu.segment_size = 0; } else { bck = NULL; cu.flags = false; Pc_Low = NULL; Pc_High = NULL; cu.segment_size = 2; } #else bck = MakeLabel(); OutLabel( bck->lbl ); Pc_Low = bck; Pc_High = MakeLabel(); cu.flags = true; cu.segment_size = 0; #endif SetOP( old ); Comp_High = Pc_High; tipe_addr = TypeAddress( TY_NEAR_POINTER ); cu.offset_size = tipe_addr->length; switch( GetMemModel() ) { case 'h': cu.model = DW_MODEL_HUGE; break; case 'l': cu.model = DW_MODEL_LARGE; break; case 'f': cu.model = DW_MODEL_FLAT; break; case 's': cu.model = DW_MODEL_SMALL; break; default: cu.model = DW_MODEL_NONE; break; } DWBeginCompileUnit( Client, &cu ); if( cu.flags ) { BEFreeBack( bck ); } } else { CcuDef = true; } }
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 ); }