#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;
}