Patch title: i386 optimizer v24
Abstract:
Enhancements to the core optimizer for i386.
File: /pliant/language/compiler/argument/argument.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 "'Argument' data type"
*/


FUNCTION Void Argument_build(struct Argument *arg) {
  Arrow_build((Arrow *)&arg->type);
  arg->where=Argument_undefined;
  Str_build(&arg->name);
  Dictionary_build(&arg->properties);
  List_build(&arg->requires);
  arg->first_instruction=arg->last_instruction=null;
  arg->user_field=null; }


FUNCTION Void Argument_destroy(struct Argument *arg) {
  Argument_locate(arg,null,Argument_undefined);
  Arrow_destroy((Arrow *)&arg->type);
  Str_destroy(&arg->name);
  Dictionary_destroy(&arg->properties);
  List_destroy(&arg->requires); }


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


FUNCTION Arrow *Argument_constant_field(struct Argument *a) {
  check(a->where==Argument_constant);
  return &a->u.constant; }


FUNCTION Int *Argument_register_field(struct Argument *a) {
  check(a->where==Argument_register);
  return &a->u.cpu_register; }


FUNCTION struct Argument **Argument_pointer_field(struct Argument *a) {
  check(a->where==Argument_indirect);
  return &a->u.indirect.pointer; }


FUNCTION Int *Argument_offset_field(struct Argument *a) {
  check(a->where==Argument_indirect);
  return &a->u.indirect.offset; }


FUNCTION Int *Argument_possible_registers_field(struct Argument *a) {
  check(a->where==Argument_a_register);
  return &a->u.possible_registers; }


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


FUNCTION Void Argument_locate(struct Argument *arg,struct Type *type,Int where) {
  if(arg->where==Argument_constant)
    Arrow_destroy(&arg->u.constant);
  if(arg->where==Argument_indirect)
    Arrow_destroy((Arrow *)&arg->u.indirect.pointer);
  arg->where=where;
  if(where==Argument_constant)
    Arrow_build(&arg->u.constant);
  if(where==Argument_indirect) {
    Arrow_build((Arrow *)&arg->u.indirect.pointer);
    arg->u.indirect.offset=0; }
  #ifdef _i386_
    if(where==Argument_a_register)
      arg->u.possible_registers=(1<<nb_register)-1-(1<<Register_ESP);
  #endif
  #ifdef _ALPHA_
    if(where==Argument_a_register)
      arg->u.possible_registers=(1L<<nb_register)-1-(1<<30)-(1<<29)-(1<<27)-(1<<26);
  #endif
  #if !defined(_i386_) && !defined(_ALPHA_)
    FIXME
  #endif
  Arrow_set((Arrow *)&arg->type,type); }


FUNCTION Bool Argument_is_shared(struct Argument *arg1,struct Argument *arg2) {
  if(arg1==arg2) {
    return true;
  orif(arg1->where!=arg2->where)
    return false;
  orif(arg1->where==Argument_constant)
    return arg1->u.constant==arg2->u.constant;
  orif(arg1->where==Argument_register)
    return arg1->u.cpu_register==arg2->u.cpu_register;
  orif(arg1->where==Argument_indirect)
    if(arg1->u.indirect.pointer->where==Argument_constant && arg2->u.indirect.pointer->where==Argument_constant)
      return *(Int *)arg1->u.indirect.pointer->u.constant+arg1->u.indirect.offset==*(Int *)arg2->u.indirect.pointer->u.constant+arg2->u.indirect.offset;
    else
      return arg1->u.indirect.pointer==arg2->u.indirect.pointer && arg1->u.indirect.offset==arg2->u.indirect.offset;
  other
    return false; } }


FUNCTION Bool Argument_is_shared_with_instruction(struct Argument *arg1,struct Instruction *instr) {
  Int index;
  for(index=0;index<instr->arguments.nb;index++) {
    if(Argument_is_shared(arg1,(struct Argument *)Array_get_index(&instr->arguments,index)))
      return true; }
  return false; }


// MAX: does this catch all cases? (see optimize_remove_nouse_instructions)
FUNCTION Bool Argument_is_shared_or_dependent(struct Argument *arg1,struct Argument *arg2) {
  if(arg1==arg2)
    return true;
  while(arg1->where==Argument_indirect)
    arg1=arg1->u.indirect.pointer;
  while(arg2->where==Argument_indirect)
    arg2=arg2->u.indirect.pointer;
  if(arg1==arg2)
    return true;
  if(arg1->where!=arg2->where)
    return false;
  if(arg1->where==Argument_constant)
    return arg1->u.constant==arg2->u.constant;
  if(arg1->where==Argument_register)
    return arg1->u.cpu_register==arg2->u.cpu_register;
  return false; }

FUNCTION Bool Argument_is_shared_or_dependent_with_instruction(struct Argument *arg1,struct Instruction *instr) {
  Int index;
  for(index=0;index<instr->arguments.nb;index++) {
    if(Argument_is_shared_or_dependent(arg1,(struct Argument *)Array_get_index(&instr->arguments,index)))
      return true; }
  return false; }

INLINE Bool Argument_is_dependent(struct Argument *arg1,struct Argument *arg2) {
  return !Argument_is_shared(arg1,arg2) &&
    Argument_is_shared_or_dependent(arg1,arg2); }

FUNCTION Bool Argument_is_dependent_with_instruction(struct Argument *arg1,struct Instruction *instr) {
  Int index;
  for(index=0;index<instr->arguments.nb;index++) {
    if(Argument_is_dependent(arg1,(struct Argument *)Array_get_index(&instr->arguments,index)))
      return true; }
  return false; }

FUNCTION Bool Argument_is_dependent_on_ESP(struct Argument *arg1) {
  while(arg1->where==Argument_indirect)
    arg1=arg1->u.indirect.pointer;
  if(arg1->where==Argument_register && arg1->u.cpu_register==Register_ESP)
    return true;
  return false; }

FUNCTION struct Argument *Argument_copy(struct Argument *src,struct Relation *relation) {
  struct Argument *dest;
  dest=(struct Argument *)Relation_query(relation,src,null);
  if(dest==null) {
    dest=entry_new(G.type_Argument);
    Relation_define(relation,src,null,dest);
    Argument_locate(dest,src->type,src->where);
    switch(dest->where) {
      case Argument_constant:
        Arrow_copy((Arrow *)&src->u.constant,(Arrow *)&dest->u.constant);
        break;
      case Argument_register:
        dest->u.cpu_register=src->u.cpu_register;
        break;
      case Argument_indirect:
        Arrow_set((Arrow *)&dest->u.indirect.pointer,Argument_copy(src->u.indirect.pointer,relation));
        dest->u.indirect.offset=src->u.indirect.offset;
        break;
      case Argument_a_register:
        dest->u.possible_registers=src->u.possible_registers;
        break; }
    Str_copy(&src->name,&dest->name);
    List_copy(&src->requires,&dest->requires); }
  return dest; }


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

#include <stdarg.h>


FUNCTION struct Argument *argument(struct Type *type,Int where, ...) {
  struct Argument *arg;
  va_list arguments; Address a; Int o;
  arg=(struct Argument *)entry_new(G.type_Argument);
  Argument_locate(arg,type,where);
  va_start(arguments,where);
  switch(where) {
    case Argument_constant:
      a=va_arg(arguments,Address); check(entry_type(a)==type);
      Arrow_set(&arg->u.constant,a);
      break;
    case Argument_register:
      o=va_arg(arguments,Int); check(o>=0 && o<nb_register);
      arg->u.cpu_register=o;
      break;
    case Argument_indirect:
      a=va_arg(arguments,Address); check(entry_type(a)==G.type_Argument);
      o=va_arg(arguments,Int);
      Arrow_set((Arrow *)&arg->u.indirect.pointer,a);
      arg->u.indirect.offset=o;
      break;
    case Argument_local:
    case Argument_a_register:
    case Argument_undefined:
      break;
    default:
      error_notifyn(error_id_unexpected,Z,"unexpected argument location",END); }
  va_end(arguments);
  return arg; }


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


FUNCTION Void Argument2_build(struct Argument2 *arg2) {
  Arrow_build((Arrow *)&arg2->argument); }


FUNCTION Void Argument2_destroy(struct Argument2 *arg2) {
  Arrow_destroy((Arrow *)&arg2->argument); }