s390x: Testcases for floating point 32/64-bit. Related to VEX r2525.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@12966 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/none/tests/s390x/Makefile.am b/none/tests/s390x/Makefile.am
index da22c4b..f03c58c 100644
--- a/none/tests/s390x/Makefile.am
+++ b/none/tests/s390x/Makefile.am
@@ -9,7 +9,7 @@
              trto trot trtt tr tre cij cgij clij clgij crj cgrj clrj clgrj \
              cs csg cds cdsg cu21 cu21_1 cu24 cu24_1 cu42 cu12 cu12_1 \
              ex_sig ex_clone cu14 cu14_1 cu41 fpconv ecag fpext fpext_warn \
-	     rounding-1
+	     rounding-1 rounding-2 rounding-3 rounding-4 rounding-5 bfp-1
 
 check_PROGRAMS = $(INSN_TESTS) \
 		 allexec \
diff --git a/none/tests/s390x/bfp-1.c b/none/tests/s390x/bfp-1.c
new file mode 100644
index 0000000..2cf558e
--- /dev/null
+++ b/none/tests/s390x/bfp-1.c
@@ -0,0 +1,93 @@
+#include <stdio.h>
+
+/* Simple test to see that basic operators are mapped
+   correctly. Uses default rounding mode. */
+
+volatile double d1, d2;
+volatile float f1, f2;
+
+void fadd8(void)
+{
+   printf("%f + %f = %f\n", d1, d2, d1 + d2);
+}
+
+void fsub8(void)
+{
+   printf("%f - %f = %f\n", d1, d2, d1 - d2);
+}
+
+void fmul8(void)
+{
+   printf("%f * %f = %f\n", d1, d2, d1 * d2);
+}
+
+void fdiv8(void)
+{
+   printf("%f / %f = %f\n", d1, d2, d1 / d2);
+}
+
+void fadd4(void)
+{
+   register float r1 asm("f1") = f1;
+   register float r2 asm("f2") = f2;
+
+   __asm__ volatile ("aebr %[r1],%[r2]\n\t"
+                     : [r1] "+f"(r1)
+                     : [r2] "f"(r2) : "cc");
+   printf("%f + %f = %f\n", f1, f2, r1);
+}
+
+void fsub4(void)
+{
+   register float r1 asm("f1") = f1;
+   register float r2 asm("f2") = f2;
+
+   __asm__ volatile ("sebr %[r1],%[r2]\n\t"
+                     : [r1] "+f"(r1)
+                     : [r2] "f"(r2) : "cc");
+   printf("%f - %f = %f\n", f1, f2, r1);
+}
+
+void fmul4(void)
+{
+   register float r1 asm("f1") = f1;
+   register float r2 asm("f2") = f2;
+
+   __asm__ volatile ("meebr %[r1],%[r2]\n\t"
+                     : [r1] "+f"(r1)
+                     : [r2] "f"(r2) : "cc");
+   printf("%f * %f = %f\n", f1, f2, r1);
+}
+
+void fdiv4(void)
+{
+   register float r1 asm("f1") = f1;
+   register float r2 asm("f2") = f2;
+
+   __asm__ volatile ("debr %[r1],%[r2]\n\t"
+                     : [r1] "+f"(r1)
+                     : [r2] "f"(r2) : "cc");
+   printf("%f / %f = %f\n", f1, f2, r1);
+}
+
+
+int main()
+{
+   printf("double arithmetic\n");
+   d1 = 10.5;
+   d2 =  1.25;
+   fadd8();
+   fsub8();
+   fmul8();
+   fdiv8();
+
+   printf("float arithmetic\n");
+   f1 = 10.5f;
+   f2 =  1.25f;
+   fadd4();
+   fsub4();
+   fmul4();
+   fdiv4();
+
+   return 0;
+}
diff --git a/none/tests/s390x/bfp-1.stderr.exp b/none/tests/s390x/bfp-1.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/none/tests/s390x/bfp-1.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/s390x/bfp-1.stdout.exp b/none/tests/s390x/bfp-1.stdout.exp
new file mode 100644
index 0000000..023c598
--- /dev/null
+++ b/none/tests/s390x/bfp-1.stdout.exp
@@ -0,0 +1,10 @@
+double arithmetic
+10.500000 + 1.250000 = 11.750000
+10.500000 - 1.250000 = 9.250000
+10.500000 * 1.250000 = 13.125000
+10.500000 / 1.250000 = 8.400000
+float arithmetic
+10.500000 + 1.250000 = 11.750000
+10.500000 - 1.250000 = 9.250000
+10.500000 * 1.250000 = 13.125000
+10.500000 / 1.250000 = 8.400000
diff --git a/none/tests/s390x/bfp-1.vgtest b/none/tests/s390x/bfp-1.vgtest
new file mode 100644
index 0000000..9d67c4a
--- /dev/null
+++ b/none/tests/s390x/bfp-1.vgtest
@@ -0,0 +1 @@
+prog: bfp-1
diff --git a/none/tests/s390x/opcodes.h b/none/tests/s390x/opcodes.h
index 8dd6097..1d0daaf 100644
--- a/none/tests/s390x/opcodes.h
+++ b/none/tests/s390x/opcodes.h
@@ -52,6 +52,7 @@
             ".long  0x" #i4 #m3 #u0 #op2 "\n\t"
 #define RRE_RR(op,u0,r1,r2)  ".long 0x" #op #u0 #r1 #r2 "\n\t"
 #define RRE_RERE(op,r1,r2)  ".long 0x" #op "00" #r1 #r2 "\n\t"
+#define RRE_R0(op,r1)       ".long 0x" #op "00" #r1 "0" "\n\t"
 #define SIL_RDU(op,b1,d1,i2)  \
             ".short 0x" #op "\n\t"  \
             ".long  0x" #b1 #d1 #i2 "\n\t"
@@ -299,6 +300,7 @@
 #define RNSBG(r1,r2,i3,i4,i5)           RIE_RRUUU(ec,r1,r2,i3,i4,i5,54)
 #define ROSBG(r1,r2,i3,i4,i5)           RIE_RRUUU(ec,r1,r2,i3,i4,i5,56)
 #define RXSBG(r1,r2,i3,i4,i5)           RIE_RRUUU(ec,r1,r2,i3,i4,i5,57)
+#define SFPC(r1)                        RRE_R0(b384,r1)
 #define SGRK(r3,r1,r2)                  RRF_R0RR2(b9e9,r3,0,r1,r2)
 #define SHHHR(r3,r1,r2)                 RRF_R0RR2(b9c9,r3,0,r1,r2)
 #define SHHLR(r3,r1,r2)                 RRF_R0RR2(b9d9,r3,0,r1,r2)
diff --git a/none/tests/s390x/rounding-2.c b/none/tests/s390x/rounding-2.c
new file mode 100644
index 0000000..ecc5a19
--- /dev/null
+++ b/none/tests/s390x/rounding-2.c
@@ -0,0 +1,41 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "opcodes.h"
+
+/* Basic test that we can set the rounding mode in the FPC and
+   query it. Covers only generally available rounding modes. */
+
+void
+set_rounding_mode(unsigned mode)
+{
+   register unsigned r asm("1") = mode;
+   __asm__ volatile ( SFPC(1) : : "d"(r) );
+}
+
+unsigned
+get_rounding_mode(void)
+{
+   unsigned fpc;
+
+   __asm__ volatile ("stfpc  %0\n\t" : "=m"(fpc));
+
+   return fpc & 0x7;
+}
+
+
+int main(void)
+{
+   int i;
+   const unsigned rmodes[] = { 0, 1, 2, 3 };
+
+   printf("initial rounding mode: %u\n", get_rounding_mode());
+
+   for (i = 0; i < sizeof rmodes / sizeof rmodes[0]; ++i) {
+      printf("setting rounding mode to %u\n", rmodes[i]);
+      set_rounding_mode(rmodes[i]);
+      printf("...checking: %u\n", get_rounding_mode());
+   }
+
+   return 0;
+}
diff --git a/none/tests/s390x/rounding-2.stderr.exp b/none/tests/s390x/rounding-2.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/none/tests/s390x/rounding-2.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/s390x/rounding-2.stdout.exp b/none/tests/s390x/rounding-2.stdout.exp
new file mode 100644
index 0000000..e0da369
--- /dev/null
+++ b/none/tests/s390x/rounding-2.stdout.exp
@@ -0,0 +1,9 @@
+initial rounding mode: 0
+setting rounding mode to 0
+...checking: 0
+setting rounding mode to 1
+...checking: 1
+setting rounding mode to 2
+...checking: 2
+setting rounding mode to 3
+...checking: 3
diff --git a/none/tests/s390x/rounding-2.vgtest b/none/tests/s390x/rounding-2.vgtest
new file mode 100644
index 0000000..c6e067d
--- /dev/null
+++ b/none/tests/s390x/rounding-2.vgtest
@@ -0,0 +1 @@
+prog: rounding-2
diff --git a/none/tests/s390x/rounding-3.c b/none/tests/s390x/rounding-3.c
new file mode 100644
index 0000000..4c12f9c
--- /dev/null
+++ b/none/tests/s390x/rounding-3.c
@@ -0,0 +1,116 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include "opcodes.h"
+
+/* Test "convert to fixed"  with "per fpc" rounding.
+   Covers all generally available rounding modes.
+
+   Note, that "convert to fixed" with rounding mode specified as
+   part of the insn is already tested in fpconv.c
+*/
+
+void
+set_rounding_mode(unsigned mode)
+{
+   register unsigned r asm("1") = mode;
+   __asm__ volatile ( SFPC(1) : : "d"(r) );
+}
+
+unsigned
+get_rounding_mode(void)
+{
+   unsigned fpc;
+
+   __asm__ volatile ("stfpc  %0\n\t" : "=m"(fpc));
+
+   return fpc & 0x7;
+}
+
+
+const char *
+rtext(unsigned fpc_round)
+{
+   switch (fpc_round) {
+   case 0: return "[-> near]";
+   case 1: return "[-> zero]";
+   case 2: return "[-> +inf]";
+   case 3: return "[-> -inf]";
+   }
+   assert(0);
+}
+
+#define convert_to_int(opcode,src_type,dst_type,dst_fmt,round,value) \
+do { \
+   src_type src = value; \
+   dst_type dst;         \
+   unsigned cc;          \
+                         \
+   __asm__ volatile (opcode " %[dst]," #round ",%[src]\n\t"     \
+                     "ipm %[cc]\n\t"                  \
+                     "srl %[cc],28\n\t"               \
+                     : [dst] "=d"(dst), [cc] "=d"(cc) \
+                     : [src] "f"(src)                 \
+                     : "cc");                         \
+                                                      \
+   printf("%s %f\t-> %"dst_fmt"\tcc = %u\n",    \
+          opcode, src, dst, cc);        \
+} while (0)
+
+
+#define cfebr(value) \
+        convert_to_int("cfebr",float,int32_t,PRId32,0,value)
+#define cfdbr(value) \
+        convert_to_int("cfdbr",double,int32_t,PRId32,0,value)
+#define cgebr(value) \
+        convert_to_int("cgebr",float,int64_t,PRId64,0,value)
+#define cgdbr(value) \
+        convert_to_int("cgdbr",double,int64_t,PRId64,0,value)
+
+int main(void)
+{
+   int i, j;
+   static const unsigned rmodes[] = { 0, 1, 2, 3 };
+   static const float fval[] = {
+      1.4f, 1.5f, 2.5f, 1.6f, -1.4f, -1.5f, -2.5f, -1.6f, 0.0f,
+   };
+   static const double dval[] = {
+      1.4, 1.5, 2.5, 1.6, -1.4, -1.5, -2.5, -1.6, 0.0,
+   };
+
+
+   for (i = 0; i < sizeof rmodes / sizeof rmodes[0]; ++i) {
+      printf("setting rounding mode to %s\n", rtext(rmodes[i]));
+      set_rounding_mode(rmodes[i]);
+      assert(get_rounding_mode() == rmodes[i]);
+
+      /* f32 -> i32 */
+      for (j = 0; j < sizeof fval / sizeof fval[0]; ++j) {
+         cfebr(fval[j]);
+         assert(get_rounding_mode() == rmodes[i]);
+      }
+
+      /* f32 -> i64 */
+      for (j = 0; j < sizeof fval / sizeof fval[0]; ++j) {
+         cgebr(fval[j]);
+         assert(get_rounding_mode() == rmodes[i]);
+      }
+
+      /* f64 -> i32 */
+      for (j = 0; j < sizeof dval / sizeof dval[0]; ++j) {
+         cfdbr(dval[j]);
+         assert(get_rounding_mode() == rmodes[i]);
+      }
+
+      /* f64 -> i64 */
+      for (j = 0; j < sizeof dval / sizeof dval[0]; ++j) {
+         cgdbr(dval[j]);
+         assert(get_rounding_mode() == rmodes[i]);
+      }
+
+   }
+
+   return 0;
+}
diff --git a/none/tests/s390x/rounding-3.stderr.exp b/none/tests/s390x/rounding-3.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/none/tests/s390x/rounding-3.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/s390x/rounding-3.stdout.exp b/none/tests/s390x/rounding-3.stdout.exp
new file mode 100644
index 0000000..5b08525
--- /dev/null
+++ b/none/tests/s390x/rounding-3.stdout.exp
@@ -0,0 +1,148 @@
+setting rounding mode to [-> near]
+cfebr 1.400000	-> 1	cc = 2
+cfebr 1.500000	-> 2	cc = 2
+cfebr 2.500000	-> 2	cc = 2
+cfebr 1.600000	-> 2	cc = 2
+cfebr -1.400000	-> -1	cc = 1
+cfebr -1.500000	-> -2	cc = 1
+cfebr -2.500000	-> -2	cc = 1
+cfebr -1.600000	-> -2	cc = 1
+cfebr 0.000000	-> 0	cc = 0
+cgebr 1.400000	-> 1	cc = 2
+cgebr 1.500000	-> 2	cc = 2
+cgebr 2.500000	-> 2	cc = 2
+cgebr 1.600000	-> 2	cc = 2
+cgebr -1.400000	-> -1	cc = 1
+cgebr -1.500000	-> -2	cc = 1
+cgebr -2.500000	-> -2	cc = 1
+cgebr -1.600000	-> -2	cc = 1
+cgebr 0.000000	-> 0	cc = 0
+cfdbr 1.400000	-> 1	cc = 2
+cfdbr 1.500000	-> 2	cc = 2
+cfdbr 2.500000	-> 2	cc = 2
+cfdbr 1.600000	-> 2	cc = 2
+cfdbr -1.400000	-> -1	cc = 1
+cfdbr -1.500000	-> -2	cc = 1
+cfdbr -2.500000	-> -2	cc = 1
+cfdbr -1.600000	-> -2	cc = 1
+cfdbr 0.000000	-> 0	cc = 0
+cgdbr 1.400000	-> 1	cc = 2
+cgdbr 1.500000	-> 2	cc = 2
+cgdbr 2.500000	-> 2	cc = 2
+cgdbr 1.600000	-> 2	cc = 2
+cgdbr -1.400000	-> -1	cc = 1
+cgdbr -1.500000	-> -2	cc = 1
+cgdbr -2.500000	-> -2	cc = 1
+cgdbr -1.600000	-> -2	cc = 1
+cgdbr 0.000000	-> 0	cc = 0
+setting rounding mode to [-> zero]
+cfebr 1.400000	-> 1	cc = 2
+cfebr 1.500000	-> 1	cc = 2
+cfebr 2.500000	-> 2	cc = 2
+cfebr 1.600000	-> 1	cc = 2
+cfebr -1.400000	-> -1	cc = 1
+cfebr -1.500000	-> -1	cc = 1
+cfebr -2.500000	-> -2	cc = 1
+cfebr -1.600000	-> -1	cc = 1
+cfebr 0.000000	-> 0	cc = 0
+cgebr 1.400000	-> 1	cc = 2
+cgebr 1.500000	-> 1	cc = 2
+cgebr 2.500000	-> 2	cc = 2
+cgebr 1.600000	-> 1	cc = 2
+cgebr -1.400000	-> -1	cc = 1
+cgebr -1.500000	-> -1	cc = 1
+cgebr -2.500000	-> -2	cc = 1
+cgebr -1.600000	-> -1	cc = 1
+cgebr 0.000000	-> 0	cc = 0
+cfdbr 1.400000	-> 1	cc = 2
+cfdbr 1.500000	-> 1	cc = 2
+cfdbr 2.500000	-> 2	cc = 2
+cfdbr 1.600000	-> 1	cc = 2
+cfdbr -1.400000	-> -1	cc = 1
+cfdbr -1.500000	-> -1	cc = 1
+cfdbr -2.500000	-> -2	cc = 1
+cfdbr -1.600000	-> -1	cc = 1
+cfdbr 0.000000	-> 0	cc = 0
+cgdbr 1.400000	-> 1	cc = 2
+cgdbr 1.500000	-> 1	cc = 2
+cgdbr 2.500000	-> 2	cc = 2
+cgdbr 1.600000	-> 1	cc = 2
+cgdbr -1.400000	-> -1	cc = 1
+cgdbr -1.500000	-> -1	cc = 1
+cgdbr -2.500000	-> -2	cc = 1
+cgdbr -1.600000	-> -1	cc = 1
+cgdbr 0.000000	-> 0	cc = 0
+setting rounding mode to [-> +inf]
+cfebr 1.400000	-> 2	cc = 2
+cfebr 1.500000	-> 2	cc = 2
+cfebr 2.500000	-> 3	cc = 2
+cfebr 1.600000	-> 2	cc = 2
+cfebr -1.400000	-> -1	cc = 1
+cfebr -1.500000	-> -1	cc = 1
+cfebr -2.500000	-> -2	cc = 1
+cfebr -1.600000	-> -1	cc = 1
+cfebr 0.000000	-> 0	cc = 0
+cgebr 1.400000	-> 2	cc = 2
+cgebr 1.500000	-> 2	cc = 2
+cgebr 2.500000	-> 3	cc = 2
+cgebr 1.600000	-> 2	cc = 2
+cgebr -1.400000	-> -1	cc = 1
+cgebr -1.500000	-> -1	cc = 1
+cgebr -2.500000	-> -2	cc = 1
+cgebr -1.600000	-> -1	cc = 1
+cgebr 0.000000	-> 0	cc = 0
+cfdbr 1.400000	-> 2	cc = 2
+cfdbr 1.500000	-> 2	cc = 2
+cfdbr 2.500000	-> 3	cc = 2
+cfdbr 1.600000	-> 2	cc = 2
+cfdbr -1.400000	-> -1	cc = 1
+cfdbr -1.500000	-> -1	cc = 1
+cfdbr -2.500000	-> -2	cc = 1
+cfdbr -1.600000	-> -1	cc = 1
+cfdbr 0.000000	-> 0	cc = 0
+cgdbr 1.400000	-> 2	cc = 2
+cgdbr 1.500000	-> 2	cc = 2
+cgdbr 2.500000	-> 3	cc = 2
+cgdbr 1.600000	-> 2	cc = 2
+cgdbr -1.400000	-> -1	cc = 1
+cgdbr -1.500000	-> -1	cc = 1
+cgdbr -2.500000	-> -2	cc = 1
+cgdbr -1.600000	-> -1	cc = 1
+cgdbr 0.000000	-> 0	cc = 0
+setting rounding mode to [-> -inf]
+cfebr 1.400000	-> 1	cc = 2
+cfebr 1.500000	-> 1	cc = 2
+cfebr 2.500000	-> 2	cc = 2
+cfebr 1.600000	-> 1	cc = 2
+cfebr -1.400000	-> -2	cc = 1
+cfebr -1.500000	-> -2	cc = 1
+cfebr -2.500000	-> -3	cc = 1
+cfebr -1.600000	-> -2	cc = 1
+cfebr 0.000000	-> 0	cc = 0
+cgebr 1.400000	-> 1	cc = 2
+cgebr 1.500000	-> 1	cc = 2
+cgebr 2.500000	-> 2	cc = 2
+cgebr 1.600000	-> 1	cc = 2
+cgebr -1.400000	-> -2	cc = 1
+cgebr -1.500000	-> -2	cc = 1
+cgebr -2.500000	-> -3	cc = 1
+cgebr -1.600000	-> -2	cc = 1
+cgebr 0.000000	-> 0	cc = 0
+cfdbr 1.400000	-> 1	cc = 2
+cfdbr 1.500000	-> 1	cc = 2
+cfdbr 2.500000	-> 2	cc = 2
+cfdbr 1.600000	-> 1	cc = 2
+cfdbr -1.400000	-> -2	cc = 1
+cfdbr -1.500000	-> -2	cc = 1
+cfdbr -2.500000	-> -3	cc = 1
+cfdbr -1.600000	-> -2	cc = 1
+cfdbr 0.000000	-> 0	cc = 0
+cgdbr 1.400000	-> 1	cc = 2
+cgdbr 1.500000	-> 1	cc = 2
+cgdbr 2.500000	-> 2	cc = 2
+cgdbr 1.600000	-> 1	cc = 2
+cgdbr -1.400000	-> -2	cc = 1
+cgdbr -1.500000	-> -2	cc = 1
+cgdbr -2.500000	-> -3	cc = 1
+cgdbr -1.600000	-> -2	cc = 1
+cgdbr 0.000000	-> 0	cc = 0
diff --git a/none/tests/s390x/rounding-3.vgtest b/none/tests/s390x/rounding-3.vgtest
new file mode 100644
index 0000000..8168710
--- /dev/null
+++ b/none/tests/s390x/rounding-3.vgtest
@@ -0,0 +1 @@
+prog: rounding-3
diff --git a/none/tests/s390x/rounding-4.c b/none/tests/s390x/rounding-4.c
new file mode 100644
index 0000000..e0a3cb3
--- /dev/null
+++ b/none/tests/s390x/rounding-4.c
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <assert.h>
+#include "opcodes.h"
+
+/* Test "load rounded" with universally available rounding modes.
+   Rounding mode is provided via FPC.
+   Also test "load lengthened" (which is independent of rounding modes). */
+
+volatile double d;
+volatile float f;
+
+const char *
+rtext(unsigned fpc_round)
+{
+   switch (fpc_round) {
+   case 0: return "[-> near]";
+   case 1: return "[-> zero]";
+   case 2: return "[-> +inf]";
+   case 3: return "[-> -inf]";
+   }
+   assert(0);
+}
+
+void
+set_rounding_mode(unsigned mode)
+{
+   printf("setting FPC rounding mode to %s\n", rtext(mode));
+   register unsigned r asm("1") = mode;
+   __asm__ volatile ( SFPC(1) : : "d"(r) );
+}
+
+
+void
+load_rounded(void)
+{
+   f = d;
+   printf("load rounded  d = %22.20g    f = %22.20g\n", d, f);
+}
+
+void
+load_lengthened(void)
+{
+   d = f;
+   printf("load lengthened  d = %22.20g    f = %22.20g\n", d, f);
+}
+
+/* Tests for load rounded and load lengthened */
+int main()
+{
+   d = 12345678.98765432E21;
+   set_rounding_mode(0);
+   load_rounded();
+   set_rounding_mode(1);
+   load_rounded();
+   set_rounding_mode(2);
+   load_rounded();
+   set_rounding_mode(3);
+   load_rounded();
+   printf("\n");
+
+   d = -12345678.98765432E21;
+   set_rounding_mode(0);
+   load_rounded();
+   set_rounding_mode(1);
+   load_rounded();
+   set_rounding_mode(2);
+   load_rounded();
+   set_rounding_mode(3);
+   load_rounded();
+   printf("\n");
+
+   load_lengthened();
+
+   return 0;
+}
diff --git a/none/tests/s390x/rounding-4.stderr.exp b/none/tests/s390x/rounding-4.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/none/tests/s390x/rounding-4.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/s390x/rounding-4.stdout.exp b/none/tests/s390x/rounding-4.stdout.exp
new file mode 100644
index 0000000..a1e5d6e
--- /dev/null
+++ b/none/tests/s390x/rounding-4.stdout.exp
@@ -0,0 +1,19 @@
+setting FPC rounding mode to [-> near]
+load rounded  d = 1.2345678987654319598e+28    f = 1.234567915439125133e+28
+setting FPC rounding mode to [-> zero]
+load rounded  d = 1.2345678987654319598e+28    f = 1.2345677973799630613e+28
+setting FPC rounding mode to [-> +inf]
+load rounded  d = 1.2345678987654319598e+28    f = 1.234567915439125133e+28
+setting FPC rounding mode to [-> -inf]
+load rounded  d = 1.2345678987654319598e+28    f = 1.2345677973799630613e+28
+
+setting FPC rounding mode to [-> near]
+load rounded  d = -1.2345678987654319598e+28    f = -1.234567915439125133e+28
+setting FPC rounding mode to [-> zero]
+load rounded  d = -1.2345678987654319598e+28    f = -1.2345677973799630613e+28
+setting FPC rounding mode to [-> +inf]
+load rounded  d = -1.2345678987654319598e+28    f = -1.2345677973799630613e+28
+setting FPC rounding mode to [-> -inf]
+load rounded  d = -1.2345678987654319598e+28    f = -1.234567915439125133e+28
+
+load lengthened  d = -1.234567915439125133e+28    f = -1.234567915439125133e+28
diff --git a/none/tests/s390x/rounding-4.vgtest b/none/tests/s390x/rounding-4.vgtest
new file mode 100644
index 0000000..e264b57
--- /dev/null
+++ b/none/tests/s390x/rounding-4.vgtest
@@ -0,0 +1 @@
+prog: rounding-4
diff --git a/none/tests/s390x/rounding-5.c b/none/tests/s390x/rounding-5.c
new file mode 100644
index 0000000..e1eab40
--- /dev/null
+++ b/none/tests/s390x/rounding-5.c
@@ -0,0 +1,93 @@
+#include <stdio.h>
+#include <assert.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include "opcodes.h"
+
+/* Test "convert from fixed" with universally available rounding modes.
+   Rounding mode is provided via FPC. */
+
+volatile int32_t i32;
+volatile int64_t i64;
+
+const char *
+rtext(unsigned fpc_round)
+{
+   switch (fpc_round) {
+   case 0: return "[-> near]";
+   case 1: return "[-> zero]";
+   case 2: return "[-> +inf]";
+   case 3: return "[-> -inf]";
+   }
+   assert(0);
+}
+
+void
+set_rounding_mode(unsigned mode)
+{
+   printf("setting FPC rounding mode to %s\n", rtext(mode));
+   register unsigned r asm("1") = mode;
+   __asm__ volatile ( SFPC(1) : : "d"(r) );
+}
+
+void cefbr(unsigned mode)
+{
+   set_rounding_mode(mode);
+
+   float out;
+
+   __asm__ volatile("cefbr %[r1],%[r2]" : [r1] "=f"(out) : [r2] "d"(i32));
+   printf("cefbr:  %"PRId32" -> %f\n", i32, out);
+}
+
+void cegbr(unsigned mode)
+{
+   set_rounding_mode(mode);
+
+   float out;
+
+   __asm__ volatile("cegbr %[r1],%[r2]" : [r1] "=f"(out) : [r2] "d"(i64));
+   printf("cegbr:  %"PRId64" -> %f\n", i64, out);
+}
+
+void cdgbr(unsigned mode)
+{
+   set_rounding_mode(mode);
+
+   double out;
+
+   __asm__ volatile("cdgbr %[r1],%[r2]" : [r1] "=f"(out) : [r2] "d"(i64));
+   printf("cegbr:  %"PRId64" -> %f\n", i64, out);
+}
+
+
+int main()
+{
+   int mode;
+
+   /* i32 -> f32 */
+   i32 = INT32_MAX;
+   for (mode = 0; mode <= 3; ++mode) cefbr(mode);
+   printf("\n");
+   i32 = INT32_MIN;
+   for (mode = 0; mode <= 3; ++mode) cefbr(mode);
+   printf("\n");
+
+   /* i64 -> f32 */
+   i64 = INT64_MAX;
+   for (mode = 0; mode <= 3; ++mode) cegbr(mode);
+   printf("\n");
+   i64 = INT64_MIN;
+   for (mode = 0; mode <= 3; ++mode) cegbr(mode);
+   printf("\n");
+
+   /* i64 -> f64 */
+   i64 = INT64_MAX;
+   for (mode = 0; mode <= 3; ++mode) cdgbr(mode);
+   printf("\n");
+   i64 = INT64_MIN;
+   for (mode = 0; mode <= 3; ++mode) cdgbr(mode);
+   printf("\n");
+
+   return 0;
+}
diff --git a/none/tests/s390x/rounding-5.stderr.exp b/none/tests/s390x/rounding-5.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/none/tests/s390x/rounding-5.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/s390x/rounding-5.stdout.exp b/none/tests/s390x/rounding-5.stdout.exp
new file mode 100644
index 0000000..80e55f6
--- /dev/null
+++ b/none/tests/s390x/rounding-5.stdout.exp
@@ -0,0 +1,54 @@
+setting FPC rounding mode to [-> near]
+cefbr:  2147483647 -> 2147483648.000000
+setting FPC rounding mode to [-> zero]
+cefbr:  2147483647 -> 2147483520.000000
+setting FPC rounding mode to [-> +inf]
+cefbr:  2147483647 -> 2147483648.000000
+setting FPC rounding mode to [-> -inf]
+cefbr:  2147483647 -> 2147483520.000000
+
+setting FPC rounding mode to [-> near]
+cefbr:  -2147483648 -> -2147483648.000000
+setting FPC rounding mode to [-> zero]
+cefbr:  -2147483648 -> -2147483648.000000
+setting FPC rounding mode to [-> +inf]
+cefbr:  -2147483648 -> -2147483648.000000
+setting FPC rounding mode to [-> -inf]
+cefbr:  -2147483648 -> -2147483648.000000
+
+setting FPC rounding mode to [-> near]
+cegbr:  9223372036854775807 -> 9223372036854775808.000000
+setting FPC rounding mode to [-> zero]
+cegbr:  9223372036854775807 -> 9223371487098961920.000000
+setting FPC rounding mode to [-> +inf]
+cegbr:  9223372036854775807 -> 9223372036854775808.000000
+setting FPC rounding mode to [-> -inf]
+cegbr:  9223372036854775807 -> 9223371487098961920.000000
+
+setting FPC rounding mode to [-> near]
+cegbr:  -9223372036854775808 -> -9223372036854775808.000000
+setting FPC rounding mode to [-> zero]
+cegbr:  -9223372036854775808 -> -9223372036854775808.000000
+setting FPC rounding mode to [-> +inf]
+cegbr:  -9223372036854775808 -> -9223372036854775808.000000
+setting FPC rounding mode to [-> -inf]
+cegbr:  -9223372036854775808 -> -9223372036854775808.000000
+
+setting FPC rounding mode to [-> near]
+cegbr:  9223372036854775807 -> 9223372036854775808.000000
+setting FPC rounding mode to [-> zero]
+cegbr:  9223372036854775807 -> 9223372036854774784.000000
+setting FPC rounding mode to [-> +inf]
+cegbr:  9223372036854775807 -> 9223372036854775808.000000
+setting FPC rounding mode to [-> -inf]
+cegbr:  9223372036854775807 -> 9223372036854774784.000000
+
+setting FPC rounding mode to [-> near]
+cegbr:  -9223372036854775808 -> -9223372036854775808.000000
+setting FPC rounding mode to [-> zero]
+cegbr:  -9223372036854775808 -> -9223372036854775808.000000
+setting FPC rounding mode to [-> +inf]
+cegbr:  -9223372036854775808 -> -9223372036854775808.000000
+setting FPC rounding mode to [-> -inf]
+cegbr:  -9223372036854775808 -> -9223372036854775808.000000
+
diff --git a/none/tests/s390x/rounding-5.vgtest b/none/tests/s390x/rounding-5.vgtest
new file mode 100644
index 0000000..51f3021
--- /dev/null
+++ b/none/tests/s390x/rounding-5.vgtest
@@ -0,0 +1 @@
+prog: rounding-5