Help me get \"y = ((x & 0xf3ff) | (roundingMode))\" into assembly code please! d
ID: 3670003 • Letter: H
Question
Help me get "y = ((x & 0xf3ff) | (roundingMode))" into assembly code please!
double roundD(double n, RoundingMode roundingMode)
{
RoundingMode x, y;
__asm__(
"fstcw %w0 " //stores the FPU control word into a 2-byte memory area
///////////////////////////////////////////
"y = ((x & 0xf3ff) | (roundingMode))"
//////////////////////////////////////////
"fldcw %w0" //loads value out of memory and stores it into the FPU control word
"frndint " //rounds the contents of ST0 to an integer and stores the result back in ST0.
"fldcw %w0 " // load value and store it into FPU control word
: "=m" (x): "m" (y): "=&t" (n): "m" (x));
return n;
}
Explanation / Answer
#include <stdio.h>
#include <stdlib.h>
#define PRECISION 3
#define RND_CTL_BIT_SHIFT 10
// floating point rounding modes: IA-32 Manual, Vol. 1, p. 4-20
typedef enum {
ROUND_NEAREST_EVEN = 0 << RND_CTL_BIT_SHIFT,
ROUND_MINUS_INF = 1 << RND_CTL_BIT_SHIFT,
ROUND_PLUS_INF = 2 << RND_CTL_BIT_SHIFT,
ROUND_TOWARD_ZERO = 3 << RND_CTL_BIT_SHIFT
} RoundingMode;
double roundD(double n, RoundingMode roundingMode)
{
// do not change anything above this comment
// Control Word storage; CW is mem16
char *cw2 = malloc(4*sizeof(char));
short *newCW = malloc(sizeof(short));
short *oldCW = malloc(sizeof(short));
// n = 2.500; // for testing purposes
// I suspect at least some of this is redundant, but it works
// If you'd like to critique it, feel free
asm("fstcw %5;" // store control word in oldCW
"mov %5, %4;" // copy control word into cw2
"or %2, %4;" // put new mode into rounding control bits
"mov %4, %3;" // copy cw2 into newCW
"fldcw %3;" // Loads newCW into Control
"fldl %0;" // load n into st(0)
"frndint;" // round n
"fstpl %0;" // load st(0) back into n
"fldcw %5;" // load the old control word from cw
: "=m" (n)
: "m" (n), "m" (roundingMode),
"m" (newCW), "r" (cw2), "m" (oldCW) // mov requires one argument in a register
);
// Cleanup, aisle7
oldCW = NULL;
free (oldCW);
newCW = NULL;
free (newCW);
cw2 = NULL;
free (cw2);
return n;
}
int main(int argc, char **argv)
{
double n = 0.0;
if (argc > 1)
n = atof(argv[1]);
printf("roundD even %.*f = %.*f ",
PRECISION, n, PRECISION, roundD(n, ROUND_NEAREST_EVEN));
printf("roundD down %.*f = %.*f ",
PRECISION, n, PRECISION, roundD(n, ROUND_MINUS_INF));
printf("roundD up %.*f = %.*f ",
PRECISION, n, PRECISION, roundD(n, ROUND_PLUS_INF));
printf("roundD zero %.*f = %.*f ",
PRECISION, n, PRECISION, roundD(n, ROUND_TOWARD_ZERO));
return 0;
}
output
roundD even 0.000 = 0.000
roundD down 0.000 = 0.000
roundD up 0.000 = 0.000
roundD zero 0.000 = 0.000
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.