Skip to contentSkip to conversation

fixing delayed exceptions in hppa

parisc-linux Carlos O'Donell 3 participants 9 messages Aug 22, 2003 – Aug 30, 2003

lore
Share & tools
lore
#0 lore raw

parisc-linux,

Just a quick RFC on this patch. I've generated a register interlock on the previous exception raising result register. This _should_ cause delayed exceptions to be flushed immediately on all processors.

Under my C3K testsetup it fixes the test-fenv failure that was specifically related to "child raises exception, exception comes in late and kills parent after child called join."

Comments more than welcome, I'll be submitting this upstream if nobody has any quibles with my gcc asm :)

c.

sysdeps/hppa/fpu/fraiseexcpt.c +12 -10
@@ -25,6 +25,8 @@
 int
 feraiseexcept (int excepts)
 {
+  /* Used in the trap barrier */
+	double dummy;
   /* Raise exceptions represented by EXCEPTS.  But we must raise only one
      signal at a time.  It is important that if the overflow/underflow
      exception and the divide by zero exception are given at the same
@@ -42,17 +44,17 @@ feraiseexcept (int excepts)
     {
       /* One example of a invalid operation is 0 * Infinity.  */
       double d = HUGE_VAL;
-      __asm__ __volatile__ ("fmpy,dbl %1,%%fr0,%0\n\t"
+      __asm__ __volatile__ ("fmpy,dbl %2,%%fr0,%0\n\t"
 			    /* FIXME: is this a proper trap barrier? */
-			    "fcpy,dbl %%fr0,%%fr0" : "=f" (d) : "0" (d));
+			    "fcpy,dbl %0,%1" : "=f" (d), "=f" (dummy) : "0" (d));
     }
 
   /* Next: division by zero.  */
   if (excepts & FE_DIVBYZERO)
     {
       double d = 1.0;
-      __asm__ __volatile__ ("fdiv,dbl %1,%%fr0,%0\n\t"
-			    "fcpy,dbl %%fr0,%%fr0" : "=f" (d) : "0" (d));
+      __asm__ __volatile__ ("fdiv,dbl %2,%%fr0,%0\n\t"
+			    "fcpy,dbl %2,%1" : "=f" (d), "=f" (dummy) : "0" (d));
     }
 
   /* Next: overflow.  */
@@ -61,8 +63,8 @@ feraiseexcept (int excepts)
     {
       double d = DBL_MAX;
 
-      __asm__ __volatile__ ("fmpy,dbl %1,%1,%0\n\t"
-			    "fcpy,dbl %%fr0,%%fr0" : "=f" (d) : "0" (d));
+      __asm__ __volatile__ ("fmpy,dbl %2,%2,%0\n\t"
+			    "fcpy,dbl %2,%1" : "=f" (d), "=f" (dummy) : "0" (d));
     }
 
   /* Next: underflow.  */
@@ -71,8 +73,8 @@ feraiseexcept (int excepts)
       double d = DBL_MIN;
       double e = 69.69;
 
-      __asm__ __volatile__ ("fdiv,dbl %1,%2,%0\n\t"
-			    "fcpy,dbl %%fr0,%%fr0" : "=f" (d) : "0" (d), "f" (e));
+      __asm__ __volatile__ ("fdiv,dbl %2,%3,%0\n\t"
+			    "fcpy,dbl %2,%1" : "=f" (d), "=f" (dummy) : "0" (d), "f" (e));
     }
 
   /* Last: inexact.  */
@@ -81,8 +83,8 @@ feraiseexcept (int excepts)
       double d = 1.0;
       double e = M_PI;
 
-      __asm__ __volatile__ ("fdiv,dbl %1,%2,%0\n\t"
-			    "fcpy,dbl %%fr0,%%fr0" : "=f" (d) : "0" (d), "f" (e));
+      __asm__ __volatile__ ("fdiv,dbl %2,%3,%0\n\t"
+			    "fcpy,dbl %2,%1" : "=f" (d), "=f" (dummy) : "0" (d), "f" (e));
     }
 
   /* Success.  */
#1 lore raw
Quoted 7 lines · Carlos O'Donell

Just a quick RFC on this patch. I've generated a register interlock on the previous exception raising result register. This _should_ cause delayed exceptions to be flushed immediately on all processors.

Under my C3K testsetup it fixes the test-fenv failure that was specifically related to "child raises exception, exception comes in late and kills parent after child called join."

Yay.

Quoted 2 lines

Comments more than welcome, I'll be submitting this upstream if nobody has any quibles with my gcc asm :)

I can quibble!

sysdeps/hppa/fpu/fraiseexcpt.c feraiseexcept (int excepts) · line 50

Quoted 8 lines
       /* One example of a invalid operation is 0 * Infinity.  */
       double d = HUGE_VAL;
sysdeps/hppa/fpu/fraiseexcpt.c +2 -2
-      __asm__ __volatile__ ("fmpy,dbl %1,%%fr0,%0\n\t"
+      __asm__ __volatile__ ("fmpy,dbl %2,%%fr0,%0\n\t"
 			    /* FIXME: is this a proper trap barrier? */
-			    "fcpy,dbl %%fr0,%%fr0" : "=f" (d) : "0" (d));
+			    "fcpy,dbl %0,%1" : "=f" (d), "=f" (dummy) : "0" (d));
     }

Surely this, and all the others, would be clearer written as:

	__asm__ __volatile__ (
		"	fmpy,dbl %0,%%fr0,%0\n"
		"	fcpy,dbl %0,%1\n"
		: "+f" (d), "=f" (dummy));

ie turn the \t into a literal tab, and use the "+" syntax rather than the "=" and "0" syntax.

Signature · 3 lines
"It's not Hollywood.  War is real, war is primarily not about defeat or
victory, it is about death.  I've seen thousands and thousands of dead bodies.
Do you think I want to have an academic debate on this subject?" -- Robert Fisk
#3 lore raw
Quoted 4 lines · John David Anglin
Quoted 2 lines

Comments more than welcome, I'll be submitting this upstream if nobody has any quibles with my gcc asm :)

See <http://lists.parisc-linux.org/hypermail/parisc-linux/10549.html>.

I took this into account, and the fcpy of a non fr0 is working better than before precisely for the reasons you list your original email.

Should I instead spill the value into memory at dummy's address?

c.

#4 lore raw
Quoted 4 lines

I took this into account, and the fcpy of a non fr0 is working better than before precisely for the reasons you list your original email.

Should I instead spill the value into memory at dummy's address?

Based on what Jim Hull said, I believe that would be better. I was using

"fldd 0(%%sr0,%%sp),%0" : "=f" (d) : "0" (d)

There isn't a true dependency in the above but I believe that any load to the destination register will raise the exception.

Dave

#5 lore raw
Quoted 6 lines · John David Anglin

Based on what Jim Hull said, I believe that would be better. I was using

"fldd 0(%%sr0,%%sp),%0" : "=f" (d) : "0" (d)

There isn't a true dependency in the above but I believe that any load to the destination register will raise the exception.

Dave, I'm sorry if you sent me a patch and I dropped it :( Did I ever receive a diff for this from you?

It's rather vague at times because the spec says "or an operation which depends on a pending, trapping insn." I think DHD, and perhaps myself got caught up on the "load or store" which probably means only register->memory (memory->register too) and not register->register.

I'll rewrite this patch to do an fldd and see what the tests say. I'm toatally under the assumption that this operation doesn't need to be optimal :) (e.g. If you use feraiseexcept a lot you are not a high-performance program).

c.

#6 lore raw
Quoted 10 lines · John David Anglin
Quoted 6 lines

Based on what Jim Hull said, I believe that would be better. I was using

"fldd 0(%%sr0,%%sp),%0" : "=f" (d) : "0" (d)

There isn't a true dependency in the above but I believe that any load to the destination register will raise the exception.

Dave, I'm sorry if you sent me a patch and I dropped it :( Did I ever receive a diff for this from you?

I can't recall but I probably did send it last November. My email machine is still down because of the blackout.

Quoted 4 lines

It's rather vague at times because the spec says "or an operation which depends on a pending, trapping insn." I think DHD, and perhaps myself got caught up on the "load or store" which probably means only register->memory (memory->register too) and not register->register.

Yes. If you follow the thread that I sent you, Jim Hull comments on this and offers a rewrite of the sentence that you quoted. I believe that referencing memory is important as this makes the operation visible to another processor. A register->register operation doesn't do this.

Dave

#7 lore raw
Quoted 6 lines

Yes. If you follow the thread that I sent you, Jim Hull comments on this and offers a rewrite of the sentence that you quoted. I believe that referencing memory is important as this makes the operation visible to another processor. A register->register operation doesn't do this.

I implemented and tested 3 versions, fcpy doesn't work on my c3k, but the fstd and fldd does. Any recommendations on which to take. I'm tempted to leave all this in and send the patch like this upstream, so I don't forget what the other versions looked like :)

Comments welcome.

c.

sysdeps/hppa/fpu/fraiseexcpt.c +98 -14
diff -u -p -r1.4 fraiseexcpt.c
@@ -22,9 +22,27 @@
 #include <float.h>
 #include <math.h>
 
+/* We implement three methods for flushing delayed exceptions. The first
+   is an interlocked register copy with the destination register of the 
+   trapping insn. This method is not recommended, and may not work in all
+   situations. The last two, either loading or storing a value from memory
+   into the destination register of the trapping insn will work, here we
+   choose to store the value to memory.
+  
+   Please see section 10, 
+   page 10-5 "Delayed Trapping" in the PA-RISC 2.0 Architecture manual */
+
+#undef BARRIER_FCPY
+#define BARRIER_FSTD
+#undef BARRIER_FLDD
+
 int
 feraiseexcept (int excepts)
 {
+  /* Provides a place to fake our write for flushing the delayed trap */
+   double dmem = 0;
+   double * pmem = &dmem;
+	
   /* Raise exceptions represented by EXCEPTS.  But we must raise only one
      signal at a time.  It is important that if the overflow/underflow
      exception and the divide by zero exception are given at the same
@@ -33,26 +51,49 @@ feraiseexcept (int excepts)
 
   /* We do these bits in assembly to be certain GCC doesn't optimize
      away something important, and so we can force delayed traps to
-     occur.  */
-
-  /* FIXME: These all need verification! */
+     occur. */
 
   /* First: invalid exception.  */
   if (excepts & FE_INVALID)
     {
       /* One example of a invalid operation is 0 * Infinity.  */
       double d = HUGE_VAL;
-      __asm__ __volatile__ ("fmpy,dbl %1,%%fr0,%0\n\t"
-			    /* FIXME: is this a proper trap barrier? */
-			    "fcpy,dbl %%fr0,%%fr0" : "=f" (d) : "0" (d));
+      __asm__ __volatile__ (
+		"	fmpy,dbl %0,%%fr0,%0\n"
+#ifdef BARRIER_FCPY
+		"	fcpy,dbl %0,%1"
+		: "+f" (d), "=f" (dmem)
+#endif
+#ifdef BARRIER_FSTD
+		"	fstd,dbl %0,%1"
+		: "+f" (d), "=m" (*pmem)
+#endif
+#ifdef BARRIER_FLDD
+		"	fldd,dbl 0(%%sr0,%%sp),%0"
+		: "+f" (d)
+#endif
+	);
     }
 
   /* Next: division by zero.  */
   if (excepts & FE_DIVBYZERO)
     {
       double d = 1.0;
-      __asm__ __volatile__ ("fdiv,dbl %1,%%fr0,%0\n\t"
-			    "fcpy,dbl %%fr0,%%fr0" : "=f" (d) : "0" (d));
+      __asm__ __volatile__ (
+		"	fdiv,dbl %0,%%fr0,%0\n"
+#ifdef BARRIER_FCPY		
+		"	fcpy,dbl %0,%1"
+		: "+f" (d), "=f" (dmem)
+#endif
+#ifdef BARRIER_FSTD
+		"	fstd,dbl %0,%1"
+		: "+f" (d), "=m" (*pmem)
+#endif
+#ifdef BARRIER_FLDD
+		"	fldd,dbl 0(%%sr0,%%sp),%0"
+		: "+f" (d)
+#endif		
+	);
     }
 
   /* Next: overflow.  */
@@ -61,8 +102,21 @@ feraiseexcept (int excepts)
     {
       double d = DBL_MAX;
 
-      __asm__ __volatile__ ("fmpy,dbl %1,%1,%0\n\t"
-			    "fcpy,dbl %%fr0,%%fr0" : "=f" (d) : "0" (d));
+      __asm__ __volatile__ (
+		"	fmpy,dbl %0,%0,%0\n"
+#ifdef BARRIER_FCPY		
+		"	fcpy,dbl %0,%1"
+		: "+f" (d), "=f" (dmem)
+#endif
+#ifdef BARRIER_FSTD
+		"	fstd,dbl %0,%1"
+		: "+f" (d), "=m" (*pmem)
+#endif
+#ifdef BARRIER_FLDD
+		"	fldd,dbl 0(%%sr0,%%sp),%0"
+		: "+f" (d)
+#endif		
+	);
     }
 
   /* Next: underflow.  */
@@ -71,8 +125,23 @@ feraiseexcept (int excepts)
       double d = DBL_MIN;
       double e = 69.69;
 
-      __asm__ __volatile__ ("fdiv,dbl %1,%2,%0\n\t"
-			    "fcpy,dbl %%fr0,%%fr0" : "=f" (d) : "0" (d), "f" (e));
+      __asm__ __volatile__ (
+#ifdef BARRIER_FCPY		
+		"	fdiv,dbl %0,%2,%0\n"
+		"	fcpy,dbl %0,%1"
+		: "+f" (d), "=f" (dmem) : "f" (e)
+#endif
+#ifdef BARRIER_FSTD
+		"	fdiv,dbl %0,%2,%0\n"
+		"	fstd,dbl %0,%1"
+		: "+f" (d), "=m" (*pmem) : "f" (e)
+#endif
+#ifdef BARRIER_FLDD
+		"	fdiv,dbl %0,%1,%0\n"
+		"	fldd,dbl 0(%%sr0,%%sp),%0"
+		: "+f" (d) : "f" (e)
+#endif		
+	);
     }
 
   /* Last: inexact.  */
@@ -81,8 +150,23 @@ feraiseexcept (int excepts)
       double d = 1.0;
       double e = M_PI;
 
-      __asm__ __volatile__ ("fdiv,dbl %1,%2,%0\n\t"
-			    "fcpy,dbl %%fr0,%%fr0" : "=f" (d) : "0" (d), "f" (e));
+      __asm__ __volatile__ (
+#ifdef BARRIER_FCPY		
+		"	fdiv,dbl %0,%2,%0\n"
+		"	fcpy,dbl %0,%1"
+		: "+f" (d), "=f" (dmem) : "f" (e)
+#endif
+#ifdef BARRIER_FSTD
+		"	fdiv,dbl %0,%2,%0\n"
+		"	fstd,dbl %0,%1"
+		: "+f" (d), "=m" (*pmem) : "f" (e)
+#endif
+#ifdef BARRIER_FLDD
+		"	fdiv,dbl %0,%1,%0\n"
+		"	fldd,dbl 0(%%sr0,%%sp),%0"
+		: "+f" (d) : "f" (e)
+#endif		
+	);
     }
 
   /* Success.  */
#8 lore raw
Quoted 10 lines
Quoted 5 lines

Yes. If you follow the thread that I sent you, Jim Hull comments on this and offers a rewrite of the sentence that you quoted. I believe that referencing memory is important as this makes the operation visible to another processor. A register->register operation doesn't do this.

I implemented and tested 3 versions, fcpy doesn't work on my c3k, but the fstd and fldd does. Any recommendations on which to take. I'm tempted to leave all this in and send the patch like this upstream, so I don't forget what the other versions looked like :)

The FSTD barrier looks fine to me. The fcpy version doesn't work, so I wouldn't keep it around. You might add a comment that fcpy doesn't work on at least some implementations.

Dave