FIX: floating point values not returned correctly on the ARM

Dirk Grunwald grunwald at pa.dec.com
Sun Jan 3 17:11:07 PST 1999


I noticed this problem while trying to determine why my pop up menus
are causing me to core dump (still...stupid missing symbol, I think).

The following tests failed...

class domath{
  public static void main (String args[]) {
    System.out.println("Hello World!");
    System.out.println("Sqrt(10) is " + java.lang.Math.sqrt(10));
    System.out.println("sin(10) is " + java.lang.Math.sin(10));
  }
}

also, when you run "TestNative" from the regression directory, it
fails as well. There's still one anomoly that I haven't figured out in
with TestNative (actually, a modified JNI version). The last test

	d = test16floatdouble(
	  -1.2f, 0.2, 3.3, 4.5, 5.6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16

returns

j = 10.00
k = 0.00
l = 12.00
m = 13.00
n = 14.00
o = 15.00
p = 16.00
test16floatdouble returned 120.40000282

Notice that "k = 0.00", rather than "k = 11.0" as expected. I have no
idea why this would occur -- it's way past the point of the special
cases for the first four arguments, which are passed in registers.

The following version of "arm/common.h" should fix it. The primary fix
is adding the floating point store's at the end of the function.



//-*-c++-*-
#ifndef _arm_common_h_
#define _arm_common_h_
/*
 * arm/common.h
 * ARM common information.
 *
 * Copyright (c) 1996, 1997
 *	Transvirtual Technologies, Inc.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution 
 * of this file. 
 */

/* The ARM we never align to more than a 4 byte boundary. */
#define	ALIGNMENT_OF_SIZE(S)	((S) < 4 ? (S) : 4)

/*
 * The calling convention is such that the first four 32bit values are
 * passed in r0-r3, and the remainder goes on the stack.
 * Floating point values are passed in integer registers.
 *
 * This machine is a little endian machine, but double floating point 
 * values are stored in big endian *word* order.  Note that we do not
 * have to take this into account here.  It is a convention of the
 * software floating point libraries and the build tools.
 */

#define	sysdepCallMethod(CALL) do {					\
  int nrargs = (CALL) -> nrargs; \
  int i; \
    register double f0 asm("f0");					\
    register int r0 asm("r0");						\
    register int r1 asm("r1");						\
    register int r2 asm("r2");						\
    register int r3 asm("r3");						\
    register unsigned long *nsp;				\
    register unsigned long *osp;				\
    int *res;								\
if (0) {\
fprintf(stderr,"Call with %d args\n", nrargs); \
for (i = 0; i < nrargs; i++) { \
fprintf(stderr,"Arg %d size %d = %p\n", i, ((CALL) -> callsize[i]), ((CALL)->args[i])); \
}\
}\
    asm __volatile__("mov %0, sp" : "=r" (osp)); \
    nsp = (nrargs > 3) ? osp - ((nrargs-3) * 2) : osp ;\
  switch(nrargs) {						        \
  default:								\
    {									\
      int *args = nsp;						        \
      int argidx = 4; 							\
      if ((CALL)->callsize[3] == 2) args++;				\
      for(; argidx < (CALL)->nrargs; ++argidx) {			\
	if ((CALL)->callsize[argidx]) { 				\
	  *args++ = (CALL)->args[argidx].i;				\
	  if ((CALL)->callsize[argidx] == 2) 				\
	    *args++ = ((CALL)->args[argidx].j) >> 32;			\
	} 								\
      }									\
    }									\
    /* Fall through ... */						\
  case 4:								\
    if ((CALL)->callsize[3]) {						\
      r3 = (CALL)->args[3].i;						\
      if ((CALL)->callsize[3] == 2) {					\
        nsp[0] = ((CALL)->args[3].j) >> 32; 			\
      }									\
    }									\
    /* Fall through ... */						\
  case 3:								\
    if ((CALL)->callsize[2]) {						\
      r2 = (CALL)->args[2].i;						\
      if ((CALL)->callsize[2] == 2) {					\
        r3 = ((CALL)->args[2].j) >> 32; 				\
      }									\
    }									\
    /* Fall through ... */						\
  case 2:								\
    if ((CALL)->callsize[1]) {						\
      r1 = (CALL)->args[1].i;						\
      if ((CALL)->callsize[1] == 2) {					\
        r2 = ((CALL)->args[1].j) >> 32; 				\
      }									\
    }									\
    /* Fall through ... */						\
  case 1:								\
    if ((CALL)->callsize[0]) {						\
      r0 = (CALL)->args[0].i;						\
      if ((CALL)->callsize[0] == 2) {					\
        r1 = ((CALL)->args[0].j) >> 32; 				\
      }									\
    }									\
    /* Fall through ... */						\
  case 0:								\
    asm ("\n\
	  mov sp, %4\n\
	  mov lr, pc\n\
	  mov pc, %3\n\
	  mov %5, sp\n"\
        : "=r" (r0), "=r" (r1), "=f" (f0)				\
	: "r" ((CALL)->function), "r" (nsp), "r" (osp),			\
	  "0" (r0), "1" (r1), "r" (r2), "r" (r3) 			\
	: "sp","ip", "rfp", "sl", "fp", "lr" \
	);								\
    res = (int *)(CALL)->ret; 						\
    res[0] = r0; 							\
    res[1] = r1; 							\
    /* Store floating point return value over (default) integer value ...   */\
    if ((CALL)->rettype == 'D') asm("stfd %1,%0" : "=m" ((CALL)->ret->d) : "f" (f0));    \
    if ((CALL)->rettype == 'F') asm("stfs %1,%0" : "=m" ((CALL)->ret->f) : "f" (f0));    \
    break;								\
  }									\
} while (0)								\


typedef struct _machineStackFrame {
	void*		ret_fp;
	void*		ret_sp;
	void*		ret_pc;
} machineStackFrame;

#define	NF(F)			((F)-1)
#define	STACK_FRAME(F)		(NF(F)->ret_fp)
#define	STACK_PC(F)		(NF(F)->ret_pc)
#define	STACK_CURRENT_FRAME()	({ void* v ; asm volatile("mov %0,fp" : "=r" (v)) ; v; })

/*
 * The ARM is odd - doubles are stored big endian even when the machine
 * is little endian.
 */
#define	DOUBLE_WORDS_BIG_ENDIAN		1

#endif


More information about the kaffe mailing list