/******************************** -*- C -*- ****************************
 *
 *	Fast versions of memset(s, 0, n)
 *
 *	$Revision: 1.7.5$
 *	$Date: 2000/05/28 16:56:52$
 *	$Author: pb$
 *
 ***********************************************************************/

/***********************************************************************
 *
 * Copyright 1988-92, 1994-95, 1999, 2000 Free Software Foundation, Inc.
 * Written by Paolo Bonzini.  Inspired by the Linux source code.
 *
 * This file is part of GNU Smalltalk.
 *
 * GNU Smalltalk is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2, or (at your option) any later 
 * version.
 * 
 * GNU Smalltalk 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 along with
 * GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
 *
 */

#ifndef __MEMZERO_H
#define __MEMZERO_H

#include "gst.h"

/*** ### should include at least a SPARC version */

/**************************************** not GCC ************************/

#ifndef __GNUC__
/* Fool the preprocessor and make it discard the following code */
#define __MEMZERO_DONE
#endif

/**************************************** MIPS ***************************/

#if defined(__mips) || defined(mips)
#ifndef __MEMZERO_DONE
#define __MEMZERO_DONE
static inline void
memzero(s, count)
     voidPtr s;
     register long count;
{
  if (!count)
    return;

  /* hmmm... this zeroes memory a byte at a time... I wonder whether it
   * is really faster than the generic version... */
  __asm__ __volatile__(
	".set	noreorder"			"\n"
"1:	sb	%3,(%0)"			"\n"
"	bne	%0,%1,1b"			"\n"
"	addiu	%0,%0,1"			"\n"
"	.set	treorder"
	: "=r" (s), "=r" (count)
        : "0" (s), "r" (0L), "1" (s + count - 1)
	: "memory");
}
#endif
#endif

/**************************************** Intel x86 **********************/

#if defined(__i386__) || defined(__i386) || defined(i386)
#ifndef __MEMZERO_DONE
#define __MEMZERO_DONE
static inline void
memzero(s, count)
     voidPtr s;
     long count;
{
int d0, d1;
__asm__ __volatile__(
	"cld"			"\n"
"	rep ; stosl"		"\n"
"	testb $2,%b3"		"\n"
"	je 1f"			"\n"
"	stosw"			"\n"
"1:	testb $1,%b3"		"\n"
"	je 2f"			"\n"
"	stosb"			"\n"
"2:"
	: "=&c" (d0), "=&D" (d1)
	:"a" (0L), "q" (count), "0" (count/4), "1" ((long) s)
	:"memory");
}
#endif
#endif

/**************************************** Default implementation *********/

#if !defined(__MEMZERO_DONE) || !defined(__GNUC__)
static inline void
memzero(s, count)
     register voidPtr s;
     register long count;
{
  /* Any decently cunning compiler will assign the same register to
   * all of these variables and the `s' parameter. */
  register char *cs1, *cs2;
  register short *ss1, *ss2;
#if SIZEOF_LONG == 8
  register int *is1, *is2;
#endif
  register long *ls;
  long temp;

  if (!count)
    return;

  if ((long) s & 1) {
    cs1 = s;
    *cs1++ = 0;
    s = cs1;
    count--;
  }
  if (count > 2 && (long) s & 2) {
    ss1 = s;
    *ss1++ = 0;
    s = ss1;
    count -= 2;
  }
#if SIZEOF_LONG == 8
  if (count > 4 && (long) s & 4) {
    is1 = s;
    *is1++ = 0;
    s = is1;
    count -= 4;
  }
#endif
  temp = count;
  count >>= LONG_SHIFT;
  if (count) {
    ls = s;
    while(count--) {
      *ls++ = 0L;
    }
    s = ls;
  }
  count = temp;
#if SIZEOF_LONG == 8
  if (count & 4) {
    is2 = s;
    *is2++ = 0;
    s = is2;
    count -= 4;
  }
#endif
  if (count & 2) {
    ss2 = s;
    *ss2++ = 0;
    s = ss2;
  }
  if (count & 1) {
    cs2 = s;
    *cs2 = 0;
  }
}
#endif

#undef __MEMZERO_DONE

#endif /* __MEMZERO_H */
