Patch title: i386 optimizer v24
Abstract:
Enhancements to the core optimizer for i386.
File: /pliant/language/generator/generator_context.c
Key:
    Removed line
    Added line
// Copyright  Hubert Tonneau  hubert.tonneau@pliant.cx
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// version 2 along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

/*
abstract
  text "'GeneratorContext' data type. The generator context is a structure that contains not only the list of instructions of the function to be compiled, but also a set of always up to date informations about these instructions in order to ease dealing with it."
*/
 

#ifdef _LISTING_
  static Char *registers[8]={"EAX","ECX","EDX","EBX","ESP","EBP","ESI","EDI"};

  void display_argument(struct Argument *a) {
    struct Str temp; Char buffer[16];
    if(a->where==Argument_constant && a->type==G.type_Int) {
      console(Str_map_area(&temp,buffer,Int_str2(*(Int *)a->u.constant,10,buffer))); 
    orif(a->where==Argument_register) 
      consolen(Z,registers[a->u.cpu_register],END);
    orif(a->where==Argument_indirect) 
      consolen(Z,"[",END);
      display_argument(a->u.indirect.pointer);
      consolen(Z,"+",S,Str_map_area(&temp,buffer,Int_str2(a->u.indirect.offset,10,buffer)),Z,"]",END); 
    other
      if(Str_len(&a->name)==0)
        Str_concat(&a->name,Z,a->where==Argument_a_register ? "r" : a->where==Argument_constant ? "c" : "a",S,Str_map_area(&temp,buffer,Int_str2(G.listing_counter++,10,buffer)),END); 
        Str_concat(&a->name,Z,a->where==Argument_a_register ? "r" : a->where==Argument_constant ? "c" : "a",S,Str_map_area(&temp,buffer,Int_str2(G.listing_counter++,10,buffer)),END);
      console(&a->name); }
    if(a->user_field!=null && a->user_field!=(Address)a) {
      consolen(Z,"->",END); display_argument((struct Argument *)a->user_field); } }
 

  static Void optimize_listing_instruction(struct Instruction *instr) {
    struct Function *f;
    struct Str temp; Char buffer[16]; struct Str t;
    Int i; Arrow *c;
    f=instr->function;
    consolen(Z," L",S,Str_map_area(&temp,buffer,Int_str2(instr->order,16,buffer)),Z,": ",S,&f->name,END);
    for(i=0; i<instr->arguments.nb; i++) {
      consolen(Z," ",END);
      display_argument(IARG(instr,i)); }
    if(instr->jump!=null)
      consolen(Z," => L",S,Str_map_area(&temp,buffer,Int_str2(instr->jump->order,16,buffer)),END);
    for(c=List_first(&instr->backward_jumps); c!=G.null_constant; c=List_next(c)) {
      consolen(Z," <= L",S,Str_map_area(&temp,buffer,Int_str2(((struct Instruction *)*c)->order,16,buffer)),END); }
    consolen(Z,"  (",END);
    for(i=0; i<f->nb_argres; i++)
      if(f->arguments[i].type!=null) {
        if (i==f->nb_arg)
          consolen(Z,"-> ",END);
        consolen(S,&f->arguments[i].type->name,Z," ",END); }
    Str_build(&t);
    ListingPosition_get(&f->position,&t);
    consolen(Z," ",S,&t,END);
    ListingPositions_get(&instr->position,&t);
    consolen(Z,") at ",S,&t,EOL);
    Str_destroy(&t); }

  static Void optimize_listing(struct GeneratorContext *gc) {
    struct Function *function; struct Array *arguments;
    struct Instruction *instr; struct Function *f;
    Int i; Arrow *c;
    struct Str temp; Char buffer[16]; struct Str t;
    Str_build(&t);
    function=gc->function;
    ListingPosition_get(&function->position,&t);
    consolen(S,&function->name,Z," (",S,&t,Z,")",END);
    c=Module_first(gc->module,Str_map_string(&temp,"pliant arguments")); 
    if(c!=G.null_constant) {
      arguments=(struct Array *)*c;
      for(i=0; i<function->nb_argres; i++) {
        consolen(Z," ",END);
        consolen(Z, i==function->nb_arg ? " -> " : " ",END);
        display_argument((struct Argument *)Array_get_index(arguments,i)); } }
    consolen(Z,":",EOL);
    for(instr=gc->first_instruction; instr!=null; instr=instr->next_instruction)
      if(instr->order!=0) break;
    if(instr==null)
      for(instr=gc->first_instruction,i=0; instr!=null; instr=instr->next_instruction,i++)
        instr->order=i;
    for(instr=gc->first_instruction; instr!=null; instr=instr->next_instruction) {
      f=instr->function;
      consolen(Z,"  ",S,Str_map_area(&temp,buffer,Int_str2(instr->order,10,buffer)),Z,": ",S,&f->name,END);
      for(i=0; i<instr->arguments.nb; i++) {
        consolen(Z," ",END);
        display_argument(IARG(instr,i)); }
      if(instr->jump!=null)
        consolen(Z," => ",S,Str_map_area(&temp,buffer,Int_str2(instr->jump->order,10,buffer)),END);
      for(c=List_first(&instr->backward_jumps); c!=G.null_constant; c=List_next(c)) {
        consolen(Z," <= ",S,Str_map_area(&temp,buffer,Int_str2(((struct Instruction *)*c)->order,10,buffer)),END); }
      consolen(Z,"  (",END);
      for(i=0; i<f->nb_argres; i++)
        if(f->arguments[i].type!=null)
          consolen(S,&f->arguments[i].type->name,Z," ",END);
      ListingPosition_get(&f->position,&t);
      consolen(Z," ",S,&t,END);
      ListingPositions_get(&instr->position,&t);
      consolen(Z,") at ",S,&t,EOL); }
    for(instr=gc->first_instruction; instr!=null; instr=instr->next_instruction)
      optimize_listing_instruction(instr);
    Str_destroy(&t); }


  static Void optimize_initial_listing(struct GeneratorContext *gc) {
    if(Str_len(&gc->function->name)!=0 && compare_str(&gc->function->name,&G.initial_listing_function_name)==compare_equal)
      optimize_listing(gc); }

  static Void optimize_expanded_listing(struct GeneratorContext *gc) {
    if(Str_len(&gc->function->name)!=0 && compare_str(&gc->function->name,&G.expanded_listing_function_name)==compare_equal)
      optimize_listing(gc); }

  static Void optimize_middle_listing(struct GeneratorContext *gc) {
    if(Str_len(&gc->function->name)!=0 && compare_str(&gc->function->name,&G.middle_listing_function_name)==compare_equal)
      optimize_listing(gc); }

  static Void optimize_final_listing(struct GeneratorContext *gc) {
    if(Str_len(&gc->function->name)!=0 && compare_str(&gc->function->name,&G.final_listing_function_name)==compare_equal)
      optimize_listing(gc); }
#endif


/*****************************************************************************/


FUNCTION Void GeneratorContext_build(struct GeneratorContext *gc) {
  Int i; struct Argument *arg;
  Arrow_build((Arrow *)&gc->first_instruction);
  gc->last_instruction=null;
  List_build(&gc->arguments);
  Dictionary_build(&gc->locals);
  for(i=0; i<nb_register; i++) {
    Arrow_build((Arrow *)&gc->registers[i]);
    Arrow_set((Arrow *)&gc->registers[i],argument(G.type_Int,Argument_register,i)); }
  for(i=0; i<Section_nb; i++)
    gc->sections[i]=null;
  Arrow_build((Arrow *)&gc->module);
  Arrow_build((Arrow *)&gc->function); }


FUNCTION Void GeneratorContext_destroy(struct GeneratorContext *gc) {
  struct Instruction *instr; Int i;
  struct Instruction *l,*pl;
  for(instr=gc->first_instruction; instr!=null; instr=instr->next_instruction) {
    List_destroy(&instr->backward_jumps);
    List_build(&instr->backward_jumps); }
  for(;;) {
    l=gc->last_instruction; if(l==null) break;
    pl=l->previous_instruction; if(pl==null) break;
    Arrow_set((Arrow *)&pl->next_instruction,null);
    gc->last_instruction=pl; }
  Arrow_destroy((Arrow *)&gc->first_instruction);
  Dictionary_destroy(&gc->locals);
  List_destroy(&gc->arguments);
  for(i=0; i<nb_register; i++)
    Arrow_destroy((Arrow *)&gc->registers[i]);
  Arrow_destroy((Arrow *)&gc->module);
  Arrow_destroy((Arrow *)&gc->function); }


FUNCTION Void GeneratorContext_setup(struct GeneratorContext *gc,struct Expression *expr,struct Function *function) {
  struct Instruction *ret;
  Arrow *c; struct Instruction *instr;
  Int i; struct Argument **pa,*a;
  struct ActionRecord ca; struct Str t;
  ActionRecord_build(&ca); Str_build(&t);
  ListingPosition_get(&function->position,&t);
  action_push_recordn(&ca,Z,"setup code generator for function ",S,&function->name,Z," ",S,&t,END);
  #ifdef _CHECK_
    for(c=List_first(&expr->instructions); c!=G.null_constant; c=List_next(c)) {
      check(entry_type(*c)==G.type_Instruction);
      instr=(struct Instruction *)*c;
      if(instr->next_instruction==instr) {
        ListingPositions_get(&instr->position,&t);
        error_notifyn(error_id_unexpected,Z,"setup: instruction is used twice (instruction was generated at ",S,&t,Z,")",END); }
      if(instr->next_instruction!=null || instr->previous_instruction!=null) {
        ListingPositions_get(&instr->position,&t);
        error_notifyn(error_id_unexpected,Z,"setup: instruction is aready linked (instruction was generated at ",S,&t,Z,")",END); }
      instr->next_instruction=instr;
      for(i=0; i<instr->arguments.nb; i++) {
        a=(struct Argument *)instr->arguments.references[i];
        again1:
        if(a->first_instruction!=null || a->last_instruction!=null) {
          ListingPositions_get(&instr->position,&t);
          error_notifyn(error_id_unexpected,Z,"argument is aready linked (instruction was generated at ",S,&t,Z,")",END); }
        if(a->user_field!=null) {
          ListingPositions_get(&instr->position,&t);
          error_notifyn(error_id_unexpected,Z,"argument user_field is not null (instruction was generated at ",S,&t,Z,")",END); }
        if(a->where==Argument_indirect) {
          a=a->u.indirect.pointer; goto again1; } } }
    for(c=List_first(&expr->instructions); c!=G.null_constant; c=List_next(c)) {
      instr=(struct Instruction *)*c;
      instr->next_instruction=null; }
  #endif
  Arrow_set((Arrow *)&gc->module,expr->module);
  Arrow_set((Arrow *)&gc->function,function);
  ret=instruction(G.function_do_nothing,END);
  GeneratorContext_insert_at_section_top(gc,Section_terminate,ret);
  for(c=List_first(&expr->instructions); c!=G.null_constant; c=List_next(c)) {
    instr=(struct Instruction *)*c;
    if(instr->jump==(Address)-1) Instruction_set_jump(instr,ret);
    for(i=0; i<instr->arguments.nb; i++) {
      pa=(struct Argument **)(instr->arguments.references+i);
      again:
      a=*pa;
      if(a->where==Argument_register)
        Arrow_set((Arrow *)pa,gc->registers[a->u.cpu_register]);
      if(a->where==Argument_indirect) {
        pa=&a->u.indirect.pointer; goto again; } }
    GeneratorContext_insert_at_section_bottom(gc,Section_body,instr); }
  action_pull_record(&ca);
  ActionRecord_destroy(&ca); Str_destroy(&t); }


/*****************************************************************************/


FUNCTION struct Instruction *GeneratorContext_section(struct GeneratorContext *gc,Int i) {
  check(i>=0 && i<Section_nb);
  return gc->sections[i]; }


FUNCTION struct Argument *GeneratorContext_register(struct GeneratorContext *gc,Int i) {
  check(i>=0 && i<nb_register);
  return gc->registers[i]; }


/*****************************************************************************/


static Void GeneratorContext_renumber(struct GeneratorContext *gc) {
  Int step,counter; struct Instruction *i;
  for(step=256; step!=0; step/=2) {
    counter=0;
    for(i=gc->first_instruction; i!=null; i=i->next_instruction) {
      i->order=counter;
      counter+=step; if(counter>int_max/2) break; }
    if(i==null) return; }
  error_notify_fatalz(error_id_starvation,"Failed to renumber instructions !"); }


static Void GeneratorContext_insert0(struct GeneratorContext *gc,Int section,struct Instruction *insertafter,struct Instruction *instr) {
  struct Instruction *i1,*i2;
  Int order1,order2,order;
  Int i; struct Argument *arg;
  Arrow *c;
  check(instr->previous_instruction==null && instr->next_instruction==null);
  check(entry_type(instr)==G.type_Instruction);
  Function_terminate_arguments_prototypes(instr->function,0);
  retry:
  if(insertafter==null) {
    i1=gc->first_instruction;
    order2=(i1!=null ? i1->order : 256);
    order=order2-256;
    if(order>=order2) { GeneratorContext_renumber(gc); goto retry; }
  orif(insertafter->next_instruction!=null)
    order1=insertafter->order;
    order2=insertafter->next_instruction->order;
    order=(order1+order2)/2;
    if(order==order1 || order==order2) { GeneratorContext_renumber(gc); goto retry; }
  other
    order=insertafter->order+256;
    if(order<=insertafter->order) { GeneratorContext_renumber(gc); goto retry; } }
  if(ListingPositions_size(&instr->position)==0 && insertafter!=null)
    ListingPositions_copy(&insertafter->position,&instr->position);
  instr->section=section,instr->order=order;
  Arrow_set((Arrow *)&instr->next_instruction,insertafter!=null ? insertafter->next_instruction : gc->first_instruction);
  instr->previous_instruction=insertafter;
  i2=(insertafter!=null ? insertafter->next_instruction : gc->first_instruction);
  if(i2!=null) i2->previous_instruction=instr; else gc->last_instruction=instr;
  Arrow_set((Arrow *)(insertafter!=null ? &insertafter->next_instruction : &gc->first_instruction),instr);
  for(i=0; i<instr->arguments.nb; i++) {
    arg=IARG(instr,i);
    somemore:
    check(arg!=null);
    check(entry_type(arg)==G.type_Argument);
    if(arg->first_instruction!=null) {
      if(order<arg->first_instruction->order) arg->first_instruction=instr;
      if(order>arg->last_instruction->order) arg->last_instruction=instr;
      #ifdef _CHECK_
        for(c=List_first(&gc->arguments); c!=G.null_constant; c=List_next(c))
          if(*c==arg) break;
        check(c!=G.null_constant);
      #endif
    other
      for(c=List_first(&gc->arguments); c!=G.null_constant; c=List_next(c))
        if(*c==arg) break;
      if(c==G.null_constant)
        List_append(&gc->arguments,arg);
      arg->first_instruction=arg->last_instruction=instr; }
    if(arg->where==Argument_indirect) { arg=arg->u.indirect.pointer; goto somemore; } }
  if(instr->jump!=null) {
    for(c=List_last(&instr->jump->backward_jumps); c!=G.null_constant; c=List_previous(c))
      if(order>((struct Instruction *)*c)->order) break;
    List_insert_after(&instr->jump->backward_jumps,c,instr); }
  if(gc->sections[section]!=null) {
    if(insertafter==gc->sections[section]) gc->sections[section]=instr;
  other
    gc->sections[section]=instr; } }


FUNCTION struct Instruction *GeneratorContext_insert_at_section_top(struct GeneratorContext *gc,Int section,struct Instruction *instr) {
  Int i; struct Instruction *insertafter;
  check(section>=0 && section<Section_nb);
  for(i=section-1; i>=0; i--)
    if(gc->sections[i]!=null) break;
  GeneratorContext_insert0(gc,section,i>=0 ? gc->sections[i] : null,instr);
  return instr; }


FUNCTION struct Instruction *GeneratorContext_insert_at_section_bottom(struct GeneratorContext *gc,Int section,struct Instruction *instr) {
  Int i; struct Instruction *insertafter;
  check(section>=0 && section<Section_nb);
  for(i=section; i>=0; i--)
    if(gc->sections[i]!=null) break;
  GeneratorContext_insert0(gc,section,i>=0 ? gc->sections[i] : null,instr);
  return instr; }


FUNCTION struct Instruction *GeneratorContext_insert_before_instruction(struct GeneratorContext *gc,struct Instruction *insertbefore,struct Instruction *instr) {
  Arrow *c; struct Instruction *j;
  check(insertbefore!=null);
  instr->stackdelta=insertbefore->stackdelta;
  GeneratorContext_insert0(gc,insertbefore->section,insertbefore->previous_instruction,instr);
  for(c=List_first(&insertbefore->backward_jumps); c!=G.null_constant; c=List_remove(&insertbefore->backward_jumps,c)) {
    j=(struct Instruction *)*c;
    j->jump=instr;
    List_append(&instr->backward_jumps,j); }
  return instr; }


FUNCTION struct Instruction *GeneratorContext_insert_after_instruction(struct GeneratorContext *gc,struct Instruction *insertafter,struct Instruction *instr) {
  check(insertafter!=null);
  instr->stackdelta=insertafter->stackdelta;
  GeneratorContext_insert0(gc,insertafter->section,insertafter,instr);
  return instr; }


FUNCTION struct Instruction *GeneratorContext_remove(struct GeneratorContext *gc,struct Instruction *instr) {
  Int i; struct Argument *arg;
  struct Instruction *t; Int j; struct Argument *a;
  struct Instruction *next;
  Arrow *c,*c2;
  check(instr->next_instruction!=null || gc->last_instruction==instr);
  check(instr->previous_instruction!=null || gc->first_instruction==instr);
  for(i=0; i<instr->arguments.nb; i++) {
    arg=IARG(instr,i);
    somemore:
    if(instr==arg->first_instruction && instr==arg->last_instruction) {
      arg->first_instruction=arg->last_instruction=null;
    orif(instr==arg->first_instruction)
      for(t=instr->next_instruction;; t=t->next_instruction) {
        check(t!=null);
        for(j=0; j<t->arguments.nb; j++) {
          a=IARG(t,j);
          again1:
          if(a==arg) goto ok1;
          if(a->where==Argument_indirect) { a=a->u.indirect.pointer; goto again1; } } }
      ok1:
      arg->first_instruction=t;
    orif(instr==arg->last_instruction)
      for(t=instr->previous_instruction;; t=t->previous_instruction) {
        check(t!=null);
        for(j=0; j<t->arguments.nb; j++) {
          a=IARG(t,j);
          again2:
          if(a==arg) goto ok2;
          if(a->where==Argument_indirect) { a=a->u.indirect.pointer; goto again2; } } }
      ok2:
      arg->last_instruction=t; }
    if(arg->where==Argument_indirect) {
      arg=arg->u.indirect.pointer; goto somemore; } }
  if(instr->jump!=null) {
    for(c=List_first(&instr->jump->backward_jumps); *c!=instr; c=List_next(c)) check(c!=G.null_constant);
    List_remove(&instr->jump->backward_jumps,c); }
  next=instr->next_instruction;
  if(next==null) {
    Instruction_set_function(instr,G.function_do_nothing);
    instr->jump=null;
    return null; }
  for(c=List_first(&instr->backward_jumps); c!=G.null_constant; c=List_next(c)) {
    t=(struct Instruction *)*c; check(t->jump==instr);
    t->jump=next;
    for(c2=List_last(&next->backward_jumps); c2!=G.null_constant; c2=List_previous(c2))
      if(t->order>((struct Instruction *)*c2)->order) break;
    List_insert_after(&next->backward_jumps,c2,t); }
  if(instr==gc->sections[instr->section]) {
    t=instr->previous_instruction;
    gc->sections[instr->section]=(t!=null && t->section==instr->section ? t : null); }
  entry_lock(instr);
  Arrow_set((Arrow *)(instr->previous_instruction!=null ? &instr->previous_instruction->next_instruction : &gc->first_instruction),next);
  if(next!=null) next->previous_instruction=instr->previous_instruction; else gc->last_instruction=instr->previous_instruction;
  Arrow_set((Arrow *)&instr->next_instruction,null); instr->previous_instruction=null;
  entry_unlock(instr);
  return next; }


/*****************************************************************************/


FUNCTION Void GeneratorContext_suckup(struct GeneratorContext *gc,struct Argument *suckedup,struct Argument *master) {
  struct Instruction *instr;
  Int i; struct Argument *arg;
  Arrow *c; struct Str temp;
  Str_concat(&master->name,S,&master->name,Z,Str_len(&master->name)!=0 && Str_len(&suckedup->name)!=0 ? "+" : "",S,&suckedup->name,END);
  if(suckedup->first_instruction==null) return;
  entry_lock(suckedup);
  check(suckedup->where!=Argument_indirect);
  for(instr=suckedup->first_instruction;; instr=instr->next_instruction) {
    for(i=0; i<instr->arguments.nb; i++) {
      arg=IARG(instr,i);
      if(arg==suckedup)
        Array_set_index(&instr->arguments,i,master);
      while(arg->where==Argument_indirect)
        if(arg->u.indirect.pointer==suckedup) {
          Arrow_set((Arrow *)&arg->u.indirect.pointer,master);
          break;
        other
          arg=arg->u.indirect.pointer; } }
    if(instr==suckedup->last_instruction) break; }
  again:
  #ifdef _CHECK_
    for(c=List_first(&gc->arguments); c!=G.null_constant; c=List_next(c))
      if(*c==master) break;
    check(master->first_instruction==null || c!=G.null_constant);
  #endif
  if(master->first_instruction==null) {
    check(master->last_instruction==null);
    for(c=List_first(&gc->arguments); c!=G.null_constant; c=List_next(c))
      if(*c==master) break;
    if(c==G.null_constant)
      List_append(&gc->arguments,master);
    master->first_instruction=suckedup->first_instruction;
    master->last_instruction=suckedup->last_instruction;
  other
    if(master->first_instruction->order>suckedup->first_instruction->order)
      master->first_instruction=suckedup->first_instruction;
    if(master->last_instruction->order<suckedup->last_instruction->order)
      master->last_instruction=suckedup->last_instruction; }
  if(master->where==Argument_indirect) { master=master->u.indirect.pointer; goto again; }
  check(suckedup->where!=Argument_indirect);
  suckedup->first_instruction=suckedup->last_instruction=null; 
  for(c=List_first(&suckedup->requires); c!=G.null_constant; c=List_next(c))
    List_append(&master->requires,*c); 
  entry_unlock(suckedup); }


static Void GeneratorContext_rebuild(struct GeneratorContext *gc) {
  Arrow *c; struct Argument *arg;
  struct Instruction *instr; Int i;
  for(instr=gc->first_instruction; instr!=null; instr=instr->next_instruction)
    for(i=0; i<instr->arguments.nb; i++) {
      arg=IARG(instr,i);
      somemore:
      arg->first_instruction=null,arg->last_instruction=null;
      if(arg->where==Argument_indirect) { arg=arg->u.indirect.pointer; goto somemore; } } 
  for(i=0; i<nb_register; i++)
    gc->registers[i]->first_instruction=null,gc->registers[i]->last_instruction=null;
  List_destroy(&gc->arguments); List_build(&gc->arguments);
  for(instr=gc->first_instruction; instr!=null; instr=instr->next_instruction)
    for(i=0; i<instr->arguments.nb; i++) {
      arg=IARG(instr,i);
      somemore2:
      if(arg->first_instruction==null) {
        arg->first_instruction=instr;
        List_append(&gc->arguments,arg); }
      arg->last_instruction=instr;
      if(arg->where==Argument_indirect) { arg=arg->u.indirect.pointer; goto somemore2; } } }


/*****************************************************************************/


#ifdef _CHECK_
  FUNCTION Void GeneratorContext_checkup(struct GeneratorContext *gc) {
    Arrow *c; struct Instruction *instr; struct Argument *arg;
    Int mini_order,mini_section;
    Int i; struct Argument *a;
    Arrow *c2;
    mini_order=int_min,mini_section=0;
    for(instr=gc->first_instruction; instr!=null; instr=instr->next_instruction) {
      check(entry_type(instr)==G.type_Instruction);
      if(instr->previous_instruction!=null)
        check(instr->previous_instruction->next_instruction==instr);
      else
        check(gc->first_instruction==instr);
      if(instr->next_instruction!=null)
        check(instr->next_instruction->previous_instruction==instr);
      else
        check(gc->last_instruction==instr);
      check(instr->order>=mini_order);
      check(instr->section>=mini_section);
      check(instr->section<Section_nb);
      if(instr->next_instruction==null || instr->next_instruction->section!=instr->section)
        check(gc->sections[instr->section]==instr);
      for(i=0; i<instr->arguments.nb; i++) {
        arg=IARG(instr,i);
        check(arg->where!=Argument_register || arg==gc->registers[arg->u.cpu_register]);
        check(arg->first_instruction!=null && arg->last_instruction!=null);
        check(arg->first_instruction->order<=instr->order);
        check(arg->last_instruction->order>=instr->order);
        for(c2=List_first(&gc->arguments); c2!=G.null_constant; c2=List_next(c2))
          if((struct Argument *)*c2==arg)
            break;
        check(c2!=G.null_constant); }
      if(gc->function->exe_size==0)
        mini_order=instr->order+1;
      mini_section=instr->section; }
    for(c=List_first(&gc->arguments); c!=G.null_constant; c=List_next(c)) {
      arg=(struct Argument *)*c;
      if(arg->first_instruction==null) {
        check(arg->last_instruction==null);
        continue; }
      for(instr=gc->first_instruction; instr!=null; instr=instr->next_instruction)
        if(instr==arg->first_instruction)
          break;
      check(instr!=null);
      instr=arg->first_instruction;
      for(i=0; i<instr->arguments.nb; i++) {
        a=IARG(instr,i);
        somemore:
        if(a==arg) break;
        if(a->where==Argument_indirect) { a=a->u.indirect.pointer; goto somemore; } }
      check(i<instr->arguments.nb);
      for(instr=gc->first_instruction; instr!=null; instr=instr->next_instruction)
        if(instr==arg->last_instruction)
          break;
      check(instr!=null);
      instr=arg->last_instruction;
      for(i=0; i<instr->arguments.nb; i++) {
        a=IARG(instr,i);
        somemore2:
        if(a==arg) break;
        if(a->where==Argument_indirect) { a=a->u.indirect.pointer; goto somemore2; } }
      check(i<instr->arguments.nb); } }
#endif


FUNCTION Void GeneratorContext_optimize(struct GeneratorContext *gc) {
  struct List *sections; struct Str *section; struct ActionRecord ca,ca2;
  Arrow *c; struct Str temp; Arrow *c2,*c3; struct Function *f;
  struct Str t;
  ActionRecord_build(&ca); 
  Str_build(&t);
  ListingPosition_get(&gc->function->position,&t);
  action_push_recordn(&ca,Z,"generate code for function ",S,&gc->function->name,Z," ",S,&t,END);
  Str_destroy(&t);
  ActionRecord_build(&ca2);
  c=Module_first(gc->module,Str_map_string(&temp,"pliant optimizer sections"));
  if(c!=G.null_constant && entry_type(*c)==G.type_GlobalVariable) c=&((struct GlobalVariable *)*c)->variable;
  if(c==G.null_constant || entry_type(*c)!=G.type_List) {
    error_notifyn(error_id_missing,Z,"'pliant optimizer sections' identifier is missing",END);
    return; }
  sections=(struct List *)*c;
  for(c=List_first(sections); c!=G.null_constant; c=List_next(c))
    if(entry_type(*c)==G.type_Str) {
      section=(struct Str *)*c;
      for(c2=Module_first(gc->module,section); c2!=G.null_constant; c2=Module_next(gc->module,section,c2))
        if(entry_type(*c2)==G.type_Function) {
          f=(struct Function *)*c2;
          for(c3=List_first(G.generator_context_begin_hooks); c3!=G.null_constant; c3=List_next(c3)) {
            check(entry_type(*c3)==G.type_Function);
            ((GeneratorContextBeginPrototype)((struct Function *)*c3)->exe)(gc,section,f); } 
          if(!error_notified()) {
            Str_build(&t);
            ListingPosition_get(&f->position,&t);
            action_push_recordn(&ca2,Z,"run code generator function ",S,&f->name,Z," ",S,&t,Z," in section ",S,section,END);
            Str_destroy(&t);
            ((FunctionOptimizePrototype)f->exe)(gc);
            action_pull_record(&ca2); }
          for(c3=List_first(G.generator_context_end_hooks); c3!=G.null_constant; c3=List_next(c3)) {
            check(entry_type(*c2)==G.type_Function);
            ((GeneratorContextBeginPrototype)((struct Function *)*c3)->exe)(gc,section,f); } 
          _check_( if(G.debugging_level>=3) GeneratorContext_checkup(gc); )
          if(error_notified()) {
            #if defined(_CHECK_) && defined(_LISTING_)
              optimize_listing(gc);
            #endif
            goto escape; } } }
  escape:
  ActionRecord_destroy(&ca2);
  action_pull_record(&ca);
  ActionRecord_destroy(&ca); }