1#include <assert.h> 2#include <stdlib.h> 3#include <stdio.h> 4#include <stdint.h> 5#include <inttypes.h> 6#include "opcodes.h" 7#include "rounding.h" 8 9/* Test "convert to fixed" with rounding mode given in insn (m3 field) 10 Covers all generally available rounding modes that can be mapped to 11 IRRoundingMode. As a consequence m3=1 which is "round to nearest with 12 ties away from 0" is not tested here. 13*/ 14 15const char * 16rtext(unsigned m3_round) 17{ 18 switch (m3_round) { 19 case 0: return "[-> per fpc]"; 20 case 1: return "[-> nearest away]"; 21 case 3: return "[-> prepare short]"; // floating point extension fac needed 22 case 4: return "[-> nearest even]"; 23 case 5: return "[-> 0]"; 24 case 6: return "[-> +inf]"; 25 case 7: return "[-> -inf]"; 26 } 27 assert(0); 28} 29 30#define convert_to_int(opcode,src_type,dst_type,dst_fmt,round,value) \ 31do { \ 32 src_type src = value; \ 33 dst_type dst; \ 34 unsigned cc; \ 35 \ 36 __asm__ volatile (opcode " %[dst]," #round ",%[src]\n\t" \ 37 "ipm %[cc]\n\t" \ 38 "srl %[cc],28\n\t" \ 39 : [dst] "=d"(dst), [cc] "=d"(cc) \ 40 : [src] "f"(src) \ 41 : "cc"); \ 42 \ 43 printf("%s %f\t-> %"dst_fmt"\tcc = %u %s\n", \ 44 opcode, src, dst, cc, rtext(round)); \ 45} while (0) 46 47 48#define cfebr(value, round) \ 49 convert_to_int("cfebr",float,int32_t,PRId32,round,value) 50#define cfdbr(value, round) \ 51 convert_to_int("cfdbr",double,int32_t,PRId32,round,value) 52#define cgebr(value, round) \ 53 convert_to_int("cgebr",float,int64_t,PRId64,round,value) 54#define cgdbr(value, round) \ 55 convert_to_int("cgdbr",double,int64_t,PRId64,round,value) 56 57void 58set_rounding_mode(unsigned mode) 59{ 60 register unsigned r asm("1") = mode; 61 __asm__ volatile ( SFPC(1) : : "d"(r) ); 62} 63 64 65int main(void) 66{ 67 int j; 68 static const float fval[] = { 69 1.25f, 1.5f, 2.5f, 1.75f, -1.25f, -1.5f, -2.5f, -1.75f, 0.0f, 70 }; 71 static const double dval[] = { 72 1.25, 1.5, 2.5, 1.75, -1.25, -1.5, -2.5, -1.75, 0.0, 73 }; 74 75 /* Note when testing M3_NEAR need to set the FPC rounding mode 76 to something else. FPC rounding mode is NEAR by default. 77 Setting the FPC rounding mode to != NEAR is the only way to make 78 sure the M3 field is not ignored. */ 79 80 /* f32 -> i32 */ 81 for (j = 0; j < sizeof fval / sizeof fval[0]; ++j) { 82 set_rounding_mode(FPC_BFP_ROUND_ZERO); 83 cfebr(fval[j], M3_BFP_ROUND_NEAREST_EVEN); 84 set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN); 85 cfebr(fval[j], M3_BFP_ROUND_ZERO); 86 cfebr(fval[j], M3_BFP_ROUND_POSINF); 87 cfebr(fval[j], M3_BFP_ROUND_NEGINF); 88 } 89 90 /* f32 -> i64 */ 91 for (j = 0; j < sizeof fval / sizeof fval[0]; ++j) { 92 set_rounding_mode(FPC_BFP_ROUND_ZERO); 93 cgebr(fval[j], M3_BFP_ROUND_NEAREST_EVEN); 94 set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN); 95 cgebr(fval[j], M3_BFP_ROUND_ZERO); 96 cgebr(fval[j], M3_BFP_ROUND_POSINF); 97 cgebr(fval[j], M3_BFP_ROUND_NEGINF); 98 } 99 100 /* f64 -> i32 */ 101 for (j = 0; j < sizeof dval / sizeof dval[0]; ++j) { 102 set_rounding_mode(FPC_BFP_ROUND_ZERO); 103 cfdbr(dval[j], M3_BFP_ROUND_NEAREST_EVEN); 104 set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN); 105 cfdbr(dval[j], M3_BFP_ROUND_ZERO); 106 cfdbr(dval[j], M3_BFP_ROUND_POSINF); 107 cfdbr(dval[j], M3_BFP_ROUND_NEGINF); 108 } 109 110 /* f64 -> i64 */ 111 for (j = 0; j < sizeof dval / sizeof dval[0]; ++j) { 112 set_rounding_mode(FPC_BFP_ROUND_ZERO); 113 cgdbr(dval[j], M3_BFP_ROUND_NEAREST_EVEN); 114 set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN); 115 cgdbr(dval[j], M3_BFP_ROUND_ZERO); 116 cgdbr(dval[j], M3_BFP_ROUND_POSINF); 117 cgdbr(dval[j], M3_BFP_ROUND_NEGINF); 118 } 119 120 return 0; 121} 122