Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
                 Crown Copyright (c) 1997
    
    This TenDRA(r) Computer Program is subject to Copyright
    owned by the United Kingdom Secretary of State for Defence
    acting through the Defence Evaluation and Research Agency
    (DERA).  It is made available to Recipients with a
    royalty-free licence for its use, reproduction, transfer
    to other parties and amendment for any purpose not excluding
    product development provided that any such use et cetera
    shall be deemed to be acceptance of the following conditions:-
    
        (1) Its Recipients shall ensure that this Notice is
        reproduced upon any copies or amended versions of it;
    
        (2) Any amended version of it shall be clearly marked to
        show both the nature of and the organisation responsible
        for the relevant amendment or amendments;
    
        (3) Its onward transfer from a recipient to another
        party shall be deemed to be that party's acceptance of
        these conditions;
    
        (4) DERA gives no warranty or assurance as to its
        quality or suitability for any purpose and DERA accepts
        no liability whatsoever in relation to any use to which
        it may be put.
*/


/*      $Id: move.c,v 1.2 1998/02/04 10:43:31 release Exp $      */

#ifndef lint
static char vcid[] = "$Id: move.c,v 1.2 1998/02/04 10:43:31 release Exp $";
#endif /* lint */

/*
$Log: move.c,v $
 * Revision 1.2  1998/02/04  10:43:31  release
 * Changes during testing.
 *
 * Revision 1.1.1.1  1998/01/17  15:56:00  release
 * First version to be checked into rolling release.
 *
 * Revision 1.13  1996/02/15  09:54:57  john
 * Fix to word load/store
 *
 * Revision 1.12  1996/01/23  16:58:16  john
 * Fix to aligments
 *
 * Revision 1.11  1995/10/30  10:17:19  john
 * Fix to unaligned loads
 *
 * Revision 1.10  1995/10/16  12:08:23  john
 * Change to alignment calculation
 *
 * Revision 1.9  1995/08/21  08:45:41  john
 * Changed include files
 *
 * Revision 1.8  1995/07/27  10:09:29  john
 * Moved register allocation
 *
 * Revision 1.7  1995/06/28  10:25:35  john
 * Reformatting
 *
 * Revision 1.6  1995/06/13  14:01:25  john
 * Fixed a pair of bugs with reg <-> memory moves
 *
 * Revision 1.5  1995/05/25  15:33:16  john
 * Cosmetic changes
 *
 * Revision 1.4  1995/05/23  10:57:12  john
 * Reformatting
 *
 * Revision 1.3  1995/05/16  10:54:02  john
 * Cosmetic change
 *
 * Revision 1.2  1995/03/29  14:03:56  john
 * Changes to keep tcheck happy
 *
 * Revision 1.1.1.1  1995/03/23  10:39:13  john
 * Entered into CVS
 *
 * Revision 1.23  1995/03/23  09:55:17  john
 * Changed handling of bitfields
 *
 * Revision 1.22  1995/01/26  13:44:55  john
 * Removed unused variables
 *
 * Revision 1.21  1995/01/12  11:49:19  john
 * Fixed assertion
 *
*/

/*
  move.c
  This file contains code to move a value from src to dest, 
  where src can be in a general purpose register, a floating 
  point register, or in store.  Delivers register used if dest 
  in store, otherwise NOREG.
*/

#include "config.h"
#include "alpha_ins.h"
#include "inst_fmt.h"
#include "addresstypes.h"
#include "procrectypes.h"
#include "fail.h"
#include "bitsmacs.h"
#include "maxminmacs.h"
#include "main.h"
#include "reg_defs.h"
#include "guard.h"
#include "locate.h"
#include "regexps.h"
#include "guard.h"
#include "getregs.h"
#include "bool.h"
#include "expmacs.h"
#include "frames.h"
#include "pseudo.h"
#include "labels.h"
#include "move.h"

/* bit masks */
#if FS_64_BIT
extern int stack_top;
INT64 word_mask=0xffffL;
INT64 long_mask=0xffffffffL;
INT64 one_64=1L;
#else /* FS_64_BIT */
INT64 word_mask={
0  0,0xffff
};

INT64 long_mask={
  0,0xffffffff
};

INT64 one_64 = {0,1};
#endif /* FS_64_BIT */

/*
  Returns TRUE if the data is aligned properly, false otherwise.
*/
static bool aligned
    PROTO_N ( ( address,al ) )
    PROTO_T ( baseoff address X int al )
{
  if((address.base<0) || (address.base > 31))
    return 1;
  return ((regexps[address.base].alignment>=al || (address.base==SP)||
           ((address.base == FP)&&Has_fp)) && ((address.offset%al)==0));
}

/*
  produces a unary representation for the number in
*/
static int unary
    PROTO_N ( ( in ) )
    PROTO_T ( int in )
{
  int result=0;
  int loop;
  Assert(in<9); /* in is a number of bytes */
  for(loop=0;loop<in;++loop){
    result <<= 1;
    result |= 1;
  }
  return result;
}
  

#define aligned_reg(X,al) (((X<0) || (X>31))?0:((regexps[X].alignment>=al)||(X==SP)||((X==FP)&&Has_fp)))

/* take account of adval here ? */
#if 1
#define address_equal(X,Y) ((X.b.base==Y.b.base) && (X.b.offset==Y.b.offset)\
                            && (((X.adval==Y.adval))||(Y.adval)))
#else
#define address_equal(X,Y) 0
#endif


int choose_block_size
    PROTO_N ( ( dest,al,size ) )
    PROTO_T ( where dest X int al )
{
  int bsize;
  if(!(insalt(dest.answhere).b.offset%8)){
    bsize = (dest.ashwhere.ashsize%64==0)?64:min(al,64);
  }
  else if(!(insalt(dest.answhere).b.offset%4)){
    bsize = (dest.ashwhere.ashsize%32==0)?32:min(al,32);
  }
  else if(!(insalt(dest.answhere).b.offset%2)){
    bsize = (dest.ashwhere.ashsize%16==0)?16:min(al,16);
  }
  else{
    bsize=8;
  }
  return bsize;
}



/*
  This function moves a piece of data from one location to another.
  The parameters are as follows:
  src   :       the location of the source
  dest  :       the destination
  freeregs:     registers available for use 
  sgned:        TRUE if data is signed, FALSE otherwise
*/
int move
    PROTO_N ( ( src,dest,freeregs,sgned ) )
    PROTO_T ( ans src X where dest X space freeregs X bool sgned )
{
  int al=dest.ashwhere.ashalign;
  int size=dest.ashwhere.ashsize;
  enum {
    BYTE,WORD,LONGWORD,QUADWORD
  } datatype;
  switch(src.discrim){
    case insomereg :
    case insomefreg :{
      failer("Source reg not specified");
      break;
    }   
    case inreg :{
      int rsrc = regalt(src);
      freeregs = guardreg(rsrc,freeregs);
      switch(dest.answhere.discrim){
        case inreg:{
          /* src & dest both in a general purpose register */
          int rdest=regalt(dest.answhere);
          if(rdest!=rsrc && rdest!=NO_REG){
            operate_fmt(i_bis,rsrc,rsrc,rdest); /* dest = src OR src */
          }  
          return NOREG;
        }
        case insomereg:{
          /* can choose dest register to be source register */
          int *somereg = someregalt(dest.answhere);
          if(*somereg!=-1) failer ("somereg!=-1");
          *somereg=rsrc;
          return NOREG;
        }
        case infreg:{
          /* source in gen reg, dest in floating point */
          /* must write onto stack, load into float register, convert*/
          freg fr;
          baseoff mem_loc;
          mem_loc.base = SP;
          /* should really check that space is available on stack */
          mem_loc.offset = stack_top;           /* ? */
          fr=fregalt(dest.answhere);
          load_store((size==32)?i_stl:i_stq,rsrc,mem_loc);
          float_load_store((size==32)?i_lds:i_ldt,fr.fr,mem_loc);
          return NOREG;
        }
        case insomefreg:{
          /* source in fixed, can choose flt dest */
          somefreg sfr;
          freg fr;
          sfr = somefregalt(dest.answhere);
          if(*sfr.fr != -1) failer("Somfreg *2");
          *sfr.fr = getfreg(freeregs.flt);
          fr.fr = *sfr.fr;
          fr.type = sfr.type;
          setfregalt(dest.answhere,fr);
          return move(src,dest,freeregs,sgned);
        }
        case notinreg:{
          instore is;
          instruction st;
          is=insalt(dest.answhere);
          size=(size==0)?64:(size<8)?8:size;
          if(al == 1) al = size;
          if(size==32){
            st = i_stl;
          }
          else {
            st = aligned(is.b,8)?i_stq:i_stq_u;
            st = i_stq;
          }     
      /* add locking, etc */
      if(is.adval){
        switch(al){     /* changed from switch(size) */
          case 8:{
            /* source in register -> byte in memory */
            int byte_address = AT;
            /* use the assembler temp register to store the address.
             The system compiler uses this scheme, not sure why 
             though. */
            space gsp = guardreg(rsrc,freeregs);
            int word_containing_byte;
            int t1;
            baseoff a;
            gsp = guardreg(is.b.base,gsp);
            if(aligned_reg(is.b.base,4) && ((is.b.offset%4)==0 && 
                                            is.b.offset>0)/*aligned(is.b,4)*/){
              /*
                if the target address is aligned on a 4 byte boundary
                then we can use an optimised load sequence, 
                eliminating the lda instruction and replacing the
                ldq_u and stq_u with ldl and stl.
           */
              int r1 = getreg(gsp.fixed);
              int r2 = getreg(gsp.fixed);
              baseoff newbo;
              newbo.base = is.b.base;
              newbo.offset = (is.b.offset/4)*4;
              load_store(i_ldl,r1,newbo);
              operate_fmt_immediate(i_insbl,rsrc,is.b.offset%4,r2);
              operate_fmt_immediate(i_mskbl,r1,is.b.offset%4,r1);
              operate_fmt(i_bis,r2,r1,r1);
              load_store(i_stl,r1,newbo);
            }
            else{
              word_containing_byte = getreg(gsp.fixed);
              t1 = getreg(gsp.fixed);
              a.base = byte_address;
              a.offset = 0;
              setnoat();
              load_store(i_lda,byte_address,is.b);
              load_store(i_ldq_u,word_containing_byte,a);
              operate_fmt(i_insbl,rsrc,byte_address,t1);
              operate_fmt(i_mskbl,word_containing_byte,byte_address,
                          word_containing_byte);
              operate_fmt(i_bis,word_containing_byte,t1,word_containing_byte);
              load_store(i_stq_u,word_containing_byte,a);
              setat();
            }
            break;
          }
          case 16:{
            /* source in register -> word in memory */
            int word_address=AT;
            space ssp = guardreg(is.b.base,freeregs);
            int qw_containing_word,tmp1,tmp2,tmp3;
            ssp = guardreg(rsrc,ssp);
            qw_containing_word=getreg(ssp.fixed);
            ssp=guardreg(qw_containing_word,ssp);
            tmp1=getreg(ssp.fixed);
            ssp=guardreg(tmp1,ssp);
            tmp2=getreg(ssp.fixed);
            ssp=guardreg(tmp2,ssp);
            if(aligned_reg(is.b.base,4) && ((is.b.offset%4) == 0) &&
               is.b.offset>0) {
              /*
                see byte case above for details.
                */
              baseoff newbo;
              newbo.base = is.b.base;
              newbo.offset = (is.b.offset/4)*4;
              load_store(i_ldl,tmp1,newbo);
              operate_fmt_immediate(i_inswl,rsrc,is.b.offset%4,tmp2);
              operate_fmt_immediate(i_mskwl,tmp1,is.b.offset%4,tmp1);
              operate_fmt(i_bis,tmp2,tmp1,tmp1);
              load_store(i_stl,tmp1,newbo);
            }
            else{
              tmp3=getreg(ssp.fixed);
              setnoat();
              load_store(i_lda,word_address,is.b);
              is.b.offset++;
              load_store(i_ldq_u,qw_containing_word,is.b);
              is.b.offset--;
              load_store(i_ldq_u,tmp1,is.b);
              operate_fmt(i_inswh,rsrc,word_address,tmp2);
              operate_fmt(i_inswl,rsrc,word_address,tmp3);
              operate_fmt(i_mskwh,qw_containing_word,word_address,
                          qw_containing_word);
              operate_fmt(i_mskwl,tmp1,word_address,tmp1);
              setat();
              operate_fmt(i_bis,qw_containing_word,tmp2,qw_containing_word);
              operate_fmt(i_bis,tmp1,tmp3,tmp1);
              is.b.offset++;
              load_store(i_stq_u,qw_containing_word,is.b);
              is.b.offset--;
              load_store(i_stq_u,tmp1,is.b);
              setat();
            }
            break;
          }
          case 32:
          case 64:
          load_store(st,rsrc,is.b);
          break;
          default:
          failer("unsupported data size");
        }
      }
      else{
        ans newsrc;
        where newdest;
        baseoff tmploc;
        instore iss;
        tmploc.offset = 0;
        tmploc.base = getreg(freeregs.fixed);
        setinsalt(newsrc,is);
        setregalt(newdest.answhere,tmploc.base);
        newdest.ashwhere.ashsize=64;
        newdest.ashwhere.ashalign=64;
        (void)move(newsrc,newdest,guardreg(tmploc.base,freeregs),sgned);
        /* now src is evaluated into tmploc */
        iss.adval=1;
        iss.b = tmploc;
        newdest.ashwhere.ashsize=size;          /* ??? */
        newdest.ashwhere.ashalign=al;
        setinsalt(newdest.answhere,iss);
        setregalt(newsrc,rsrc);
        (void)move(newsrc,newdest,guardreg(tmploc.base,freeregs),sgned);
        return rsrc;
      }
      return NOREG;
    }
    }
    break;
  }
    case infreg:{
      freg fr;
      fr=fregalt(src);
      switch(dest.answhere.discrim){
        case inreg:{
          /* source in floating point, dest in fixed */
          int rdest = regalt(dest.answhere);
          if(rdest != NO_REG){
            freg fr=fregalt(src);
            int r = regalt(dest.answhere);
            baseoff mem_loc;
            mem_loc.base = SP;
            mem_loc.offset = stack_top;
            float_load_store(i_stt,fr.fr,mem_loc);
            load_store(i_ldq,r,mem_loc);
          }
          return NOREG;
        }
        case insomereg:{
          somefreg sfr;
          sfr = somefregalt(dest.answhere);
          Assert(*(sfr.fr)== -1);
          *(sfr.fr) = fr.fr;
          return NOREG;
        }
        case insomefreg:{
          /* simple - can choose destination freg */
          somefreg sfr;
          int res;
          sfr = somefregalt(dest.answhere);
          *(sfr.fr) = fregalt(src).fr;
          fr.fr = *sfr.fr;
          fr.type = sfr.type;
          setfregalt(dest.answhere,fr);
          res=move(src,dest,freeregs,sgned);
          return res;           /* ?? */
        }
        case infreg:{
          /* simple copy from one freg to another */
          freg frd;
          frd=fregalt(dest.answhere);
          if(fr.fr != frd.fr){
            float_op(i_cpys,fr.fr,fr.fr,frd.fr);
          }     
          return NOREG;
        }
        case notinreg:{
          /* forget VAX floats for the moment */
          /* src in float, dest in store */
          instruction st=(fr.type==IEEE_double)?i_stt:i_sts;
          instore is;
          if(((dest.ashwhere.ashsize==64)&&(fr.type == IEEE_single)) 
             || ((dest.ashwhere.ashsize==32) && (fr.type == IEEE_double))){
            st = (dest.ashwhere.ashsize==64)?i_stt:i_sts;
            if(dest.ashwhere.ashsize==32){
              /* .t floats must be explicitly converted to .s */
              freg frtmp;
              frtmp.fr=getfreg(freeregs.flt);
              frtmp.type = IEEE_single;
              float_convert(i_cvtts,fr.fr,frtmp.fr);
              fr=frtmp;
            }
          }
          is = insalt(dest.answhere);
          if(is.adval)
            float_load_store(st,fr.fr,is.b);
          else {
            baseoff bo;
            bo.base = getreg(freeregs.fixed);
            bo.offset = 0;
            load_store(i_ldq,bo.base,is.b);
            float_load_store(st,fr.fr,bo);
          }
          return ((fr.type == IEEE_double)?-(fr.fr+32):(fr.fr+32));
        }
      }
      break;
    }
    case notinreg:{
      /* source instore */
      instore iss;
      instruction load;
      instruction store;
      iss=insalt(src);
      if(iss.adval && iss.b.offset==0 && iss.b.base>=0 && iss.b.base<31){
        setregalt(src,iss.b.base);
        return move(src,dest,freeregs,sgned); /* ?? */
      } 
      if((size==64)||(size%64==0)){
        load=(iss.adval)?i_lda:((aligned(iss.b,8))?i_ldq:i_ldq_u);
        load = (iss.adval)? i_lda:i_ldq;
        store=i_stq;
      }
      else{
        load = (iss.adval)?i_lda:((al==32)?i_ldl:i_ldq);
        store=(iss.adval)?i_stq:((al==32)?i_stl:i_stq);
      }
      switch(al){
        case 8:
        datatype = BYTE;
        break;
        case 16:
        datatype = WORD;
        break;
        case 32:
        datatype = LONGWORD;
        break;
        default:
        datatype = QUADWORD;
      } 
      switch(dest.answhere.discrim){
        case insomefreg:{
          /* src in store, can choose freg for destination */
          somefreg sfr;
          freg fr;
          sfr=somefregalt(dest.answhere);
          if(*sfr.fr!=-1) failer("instore->some freg");
          *sfr.fr=getfreg(freeregs.flt);
          fr.fr=*sfr.fr;
          fr.type=sfr.type;
          setfregalt(dest.answhere,fr);
          return move(src,dest,freeregs,sgned);
        }
        case insomereg:{
          /* source instore, can choose destination register */
          int *sr=someregalt(dest.answhere);
          if(*sr!=-1) failer("somereg **");
          *sr=getreg(freeregs.fixed);
          setregalt(dest.answhere,*sr);
          /* continue to next case */
        }
        FALL_THROUGH;
        case inreg:{
          /* src instore, destination in general register */
          int rdest=regalt(dest.answhere);
          if(iss.b.base == rdest){
            int newbase = getreg(guardreg(rdest,freeregs).fixed);
            operate_fmt(i_bis,rdest,rdest,newbase);
            iss.b.base = newbase;
          }
          if(rdest!=NO_REG){
            if(((datatype == BYTE) || (datatype == WORD) 
               ||((datatype == LONGWORD) && (iss.b.offset%4))
               ||((datatype == QUADWORD) && (iss.b.offset%8)))
               && !(iss.adval) ){
              switch(datatype){
                case BYTE:{
                  space newspace=guardreg(rdest,freeregs);
                  int tmpreg;
                  newspace = guardreg(iss.b.base,newspace); /* error? */
                  tmpreg=getreg(newspace.fixed);
            
                  if(aligned_reg(iss.b.base,4) &&( iss.b.offset%4==0) &&
                     (iss.b.offset >= 0)){
                    /* if its address is 32 bit aligned an optimised 
                       load can be performed.  
                       (This doesn't win us much on the 21064).
                       */
                    baseoff newbo;
                    newbo.base=iss.b.base;
                    newbo.offset = (iss.b.offset/4)*4;
                    load_store(i_ldl,rdest,newbo);
                    if(sgned){
                      operate_fmt_immediate(i_sll,rdest,56-8*(iss.b.offset%4),
                                            rdest);
                      operate_fmt_immediate(i_sra,rdest,56,rdest);
                    }
                    else{
                      operate_fmt_immediate(i_extbl,rdest,(iss.b.offset%4),rdest);
                    }
                  }
                  else{
                    load_store(i_ldq_u,rdest,iss.b); /* should it be iss.b ? */
                    if(sgned){
                      iss.b.offset++;
                      load_store(i_lda,tmpreg,iss.b);
                      operate_fmt(i_extqh,rdest,tmpreg,rdest);
                      operate_fmt_immediate(i_sra,rdest,56,rdest);
                    }
                    else{
                      load_store(i_lda,tmpreg,iss.b);
                      operate_fmt(i_extbl,rdest,tmpreg,rdest);
                    }
                  }
                  clear_reg(tmpreg);
                  break;
                }
                case WORD:{
#if 0
                  space msp = guardreg(rdest,freeregs);
                  int tmpreg1=getreg(msp.fixed);
                  int tmpreg2;
                  msp = guardreg(tmpreg1,msp);
                  tmpreg2=getreg(msp.fixed);
#endif
                  if(aligned_reg(iss.b.base,4) && (iss.b.offset>=0)){
                    /* if the base address is aligned on a 32 bit boundary
                       we can use an optimised load sequence.
                       */
                    baseoff alboff;
                    alboff.base = iss.b.base;
                    alboff.offset = (iss.b.offset/4)*4;
                    load_store(i_ldl,rdest,alboff);
                    if(sgned){
                      operate_fmt_immediate(i_sll,rdest,
                                            48-8*(iss.b.offset%4),rdest);
                      operate_fmt_immediate(i_sra,rdest,48,rdest);
                    }
                    else{
                      operate_fmt_immediate(i_extwl,rdest,iss.b.offset%4,rdest);
                    }
                  }             
                  else{
                    setnoat();
                    iss.b.offset += 2;
                    load_store(i_lda,AT,iss.b);
                    iss.b.offset -= 2;
                    load_store(i_ldq_u,rdest,iss.b);
                    operate_fmt(i_extqh,rdest,AT,rdest);
                    operate_fmt_immediate(i_sra,rdest,48,rdest);
                    /* sgned ? */
                    if(!sgned) operate_fmt_immediate(i_zapnot,rdest,3,rdest);
                    setat();
                  }
                  /*
                  clear_reg(tmpreg1);
                  clear_reg(tmpreg2);
                  */
                  break;
                }
                case LONGWORD:{
                  int r2,r3;
                  space newspace = guardreg(rdest,freeregs);
                  /* treat unaligned longword access here */
                  newspace = guardreg(iss.b.base,newspace);
                  r2 = getreg(newspace.fixed);
                  r3 = getreg(newspace.fixed);
                  load_store(i_ldq_u,rdest,iss.b);
                  iss.b.offset += 3;
                  load_store(i_ldq_u,r2,iss.b);
                  iss.b.offset -= 3;
                  load_store(i_lda,r3,iss.b);
                  operate_fmt(i_extll,rdest,r3,rdest);
                  operate_fmt(i_extlh,r2,r3,r2);
                  operate_fmt(i_bis,r2,rdest,rdest);
                  if(sgned){
                    operate_fmt_immediate(i_sll,rdest,32,rdest);
                    operate_fmt_immediate(i_sra,rdest,32,rdest);
                  }
                  clear_reg(r2);
                  clear_reg(r3);
                  break;
                }
                case QUADWORD:{
                  int r2,r3;
                  space newspace = guardreg(rdest,freeregs);
                  newspace = guardreg(iss.b.base,newspace);
                  r2 = getreg(newspace.fixed);
                  r3 = getreg(newspace.fixed);
                  load_store(i_ldq_u,rdest,iss.b);
                  iss.b.offset += 7;
                  load_store(i_ldq_u,r2,iss.b);
                  iss.b.offset -= 7;
                  load_store(i_lda,r3,iss.b);
                  operate_fmt(i_extql,rdest,r3,rdest);
                  operate_fmt(i_extqh,r2,r3,r2);
                  operate_fmt(i_bis,r2,rdest,rdest);
                  clear_reg(r2);
                  clear_reg(r3);
                  break;
                }
              }
            }
            else if (iss.adval){
              load_store(i_lda,rdest,iss.b);
              switch(datatype){
                case BYTE:
                operate_fmt_immediate(i_zapnot,rdest,1,rdest);
                break;
                case WORD:
                operate_fmt_immediate(i_zapnot,rdest,2,rdest);
                break;
                case LONGWORD:
                operate_fmt_immediate(i_addl,rdest,0,rdest);
                break;
                default:;
              }
            }
            else{
              int rt=getreg(guardreg(iss.b.base,freeregs).fixed);
              if((size>64)&&((rdest<FIRST_INT_ARG)||(rdest>LAST_INT_ARG))){
                alphafail(ILLEGAL_BLOCK_COPY);
              }
              if(size>64){/* this should only occur with parameter regs */
                ans newsrc;
                where newdest;
                instore dis;
                if(al<64){
                  al=64;
                  load=i_ldq;
                }
                for(;(rdest<=LAST_INT_ARG)&&(size>0);++rdest,
                      iss.b.offset+=(al>>3)){
                  load_store(load,rdest,iss.b); 
                  size-=al;
                }
                /* once the registers have been filled, it's 
                   time to use the stack for the remaining parameters.  
                   The function calling move() must allow for 
                   this space to be used.*/
                if(size>0){
                  /*dis.b.base=(Has_fp)?FP:SP;*/
                  dis.b.base = SP;
                  dis.b.offset=0;
                  dis.adval=1;
                  setinsalt(newsrc,iss);
                  newdest.ashwhere.ashsize=size;
                  newdest.ashwhere.ashalign=64;
                  setinsalt(newdest.answhere,dis);
                  return move(newsrc,newdest,freeregs,sgned);
                }
                else{
                  return NOREG;
                }
              }
              else{
                load_store(load,rdest,iss.b);
              }
              if(ins_equal(load,i_lda) /*|| !sgned*/)
                switch(size){
                  case 8:
                  operate_fmt_immediate(i_and,rdest,0xff,rdest);
                  break;
                  case 16:
                  load_store_immediate(i_ldiq,rt,word_mask);
                  operate_fmt(i_and,rdest,rt,rdest);
                  break;
                  case 32:
                  operate_fmt_immediate(i_addl,rdest,0,rdest);
                  break;
                  default:;
                }
            }                   
          }
          return NOREG;
        }
        case infreg:{
          /* src instore, dest in floating point reg */
          freg frdest;
          frdest=fregalt(dest.answhere);
          switch(frdest.type){
            case IEEE_single:
            if(size==32){
              float_load_store(i_lds,frdest.fr,iss.b);
            }
            else{
              float_load_store(i_ldt,frdest.fr,iss.b);
              float_convert(i_cvtts,frdest.fr,frdest.fr);
            }
            break;
            case IEEE_double:   
            if(size==32)
              float_load_store(i_lds,frdest.fr,iss.b);
            else
              float_load_store(i_ldt,frdest.fr,iss.b);
            break;
            default:
            failer("VAX floating point formats not supported");
          }
          return NOREG;
        }
        case notinreg:{
          /* source and dest both instore */
          instore isdest=insalt(dest.answhere);   
          int sunit = (size>64)?choose_block_size(dest,al):
            ((dest.ashwhere.ashsize%64==0)?64:min(al,64));
          /*int sunit= ((dest.ashwhere.ashsize%64==0)?64: min(al,64));*/
          int step=sunit>>3;
          int s=(dest.ashwhere.ashsize+sunit-1)/sunit;
          bool unalign=0;
          if(sunit>al) al=sunit;
          if(al==8 && s>=8 && (aligned(isdest.b,8))){
            int rtmp = getreg(freeregs.fixed);
            unalign=1;
            if(s<=32){
              for(;s>=8;s -= 8){
                load_store(i_ldq,rtmp,iss.b);
                load_store(i_stq,rtmp,isdest.b);
                iss.b.offset += 8;
                isdest.b.offset += 8;
              }
              if(s){
                int rtmp2 = getreg(freeregs.fixed);
                load_store(i_ldq,rtmp,iss.b);
                load_store(i_ldq,rtmp2,isdest.b);
                operate_fmt_immediate(i_zap,rtmp2,unary(s),rtmp2);
                operate_fmt(i_bis,rtmp2,rtmp,rtmp2);
                load_store(i_stq,rtmp2,isdest.b);
              }
                
            }
            else{
              /* 
                 copy with loop, length in r1, to in2 from in r2 
                 if the data is aligned on 32/64 bit boundaries we can
                 do a fast copy. 
                 the code sequence produced is:

                 foreach complete 8 bytes of data
                   load/store quadword
                 foreach byte remaining
                   read bytes using ldq and zap 
                 */
              int l=new_label();
              int r1=getreg(freeregs.fixed | (1<<rtmp));
              int r2=getreg(freeregs.fixed | (1<<rtmp)|(1<<r1));
              int rd = getreg(freeregs.fixed|(1<<rtmp)|(1<<r1)|(1<<r2));
              static baseoff src;
              static baseoff dst;
              int numberofquads;        /* number of quadwords in the data */
              int numberofbytes;        /* number of remaining bytes */
              load_store(i_lda,r1,iss.b);
              numberofquads = size>>6;
              load_store((isdest.adval)?i_lda:i_ldq,rd,isdest.b);
              isdest.adval=1;
              dst.base = rd;
              dst.offset=0;
              src.base = r1;
              src.offset=0;           
              load_store_immediate(i_ldil,r2,numberofquads);
              set_label(l);
              operate_fmt_immediate(i_subq,r2,1,r2);
              load_store(i_ldq,rtmp,src);
              load_store(i_stq,rtmp,dst);
              operate_fmt_immediate(i_addq,r1,8,r1);
              operate_fmt_immediate(i_addq,rd,8,rd);
              /*             
                             dst.offset+=(8*numberofquads);
                             src.offset+=(8*numberofquads);
                             */
              integer_branch(i_bne,r2,l);
              /* now only single bytes remain */
              numberofbytes = (size - (numberofquads<<6))>>3;
              if(numberofbytes){
                /* we have trailing bytes. */
                load_store(i_ldq,r1,src);
                load_store(i_ldq,r2,dst);
                operate_fmt_immediate(i_zap,r2,unary(numberofbytes),r2);
                operate_fmt(i_bis,r2,r1,r2);
                load_store(i_stq,r2,dst);
              }
            }
            return NOREG;
          }
          if(s<=inlineassign){
            int r=getreg(freeregs.fixed);
            if(!isdest.adval){
              int rtmp = getreg(freeregs.fixed);
              load_store(i_ldq,rtmp,isdest.b);/* fix: was load not i_ldq */
              isdest.b.base=rtmp;
              isdest.b.offset=0;
              isdest.adval=1;           /* added (is this correct?) */
            }
            if(s==1){
              ans newsrc;
              where newdest;
              setinsalt(newsrc,iss);
              setregalt(newdest.answhere,r);
              newdest.ashwhere.ashsize=size;
              newdest.ashwhere.ashalign=al;
              (void)move(newsrc,newdest,freeregs,sgned);
              setregalt(newsrc,r);
              setinsalt(newdest.answhere,isdest);
              newdest.ashwhere.ashsize=size;
              newdest.ashwhere.ashalign=al;
              (void)move(newsrc,newdest,freeregs,sgned);
              return (unalign)?NOREG:r;
            }
            else{
              int er = getreg(freeregs.fixed|(1<<r));
              int nr=r;
              if(!address_equal(iss,isdest)){
                for(;s>0;--s){
                  ans newsrc;
                  where newdest;
                  setinsalt(newsrc,iss);
                  setregalt(newdest.answhere,r);
                  newdest.ashwhere.ashsize=sunit;       /* in 64 byte chunks */
                  newdest.ashwhere.ashalign=sunit;
                  /* put value into register r */
                  (void)move(newsrc,newdest,freeregs,sgned); 
                  setregalt(newsrc,r);
                  setinsalt(newdest.answhere,isdest);
                  (void)move(newsrc,newdest,freeregs,sgned);
                  /*load_store(load,nr,iss.b);
                    load_store(store,nr,isdest.b);*/
                  iss.b.offset += step;
                  isdest.b.offset += step;
                  if(nr == r){
                    nr = er;
                  }
                  else{
                    nr = r;
                  }
                }
              }
              return NOREG;
            }
          }     
          else{
            int a = getreg(freeregs.fixed);
            int address_reg = getreg(freeregs.fixed);
            int rtmp = getreg(freeregs.fixed);
            int l=new_label();
            int r1=getreg(freeregs.fixed);
            static baseoff src;
            static baseoff dst;
            INT64 loop_count;
            src.base = address_reg;
            src.offset = 0;
            dst.base = rtmp;
            dst.offset=0;
            load_store((isdest.adval)?i_lda:i_ldq,rtmp,isdest.b);
            load_store(i_lda,address_reg,iss.b);
            loop_count=make_INT64((s&0x80000000)?0xffffffff:0,s);
            load_store_immediate(i_ldiq,r1,loop_count); /* loop counter */
            set_label(l);
            load_store(load,a,src);
            operate_fmt_immediate(i_addq,address_reg,step,address_reg);
            load_store(store,a,dst);
            operate_fmt_immediate(i_addq,rtmp,step,rtmp);
            operate_fmt_immediate(i_subq,r1,1,r1);
            integer_branch(i_bgt,r1,l);
            return NOREG;
          }
        }
      }
    }
  }
  return NOREG;
}