#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. */ 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.25f, 1.5f, 2.5f, 1.75f, -1.25f, -1.5f, -2.5f, -1.75f, 0.0f, }; static const double dval[] = { 1.25, 1.5, 2.5, 1.75, -1.25, -1.5, -2.5, -1.75, 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; }