main.cpp
#include <stdio.h>
#include <limits>
using namespace std;
extern "C" void SseSfpCompareFloat(float a, float b, bool* results);
extern "C" void SseSfpCompareDouble(double a, double b, bool* results);
const int m = 7;
const char* OpStrings[m] = {"UO", "LT", "LE", "EQ", "NE", "GT", "GE"};
void SseSfpCompareFloat()
{
const int n = 4;
float a[n] = {120.0, 250.0, 300.0, 42.0};
float b[n] = {130.0, 240.0, 300.0, 0.0};
// Set NAN test value
b[n - 1] = numeric_limits<float>::quiet_NaN();
printf("Results for SseSfpCompareFloat()\n");
for (int i = 0; i < n; i++)
{
bool results[m];
SseSfpCompareFloat(a[i], b[i], results);
printf("a: %8f b: %8f\n", a[i], b[i]);
for (int j = 0; j < m; j++)
printf(" %s=%d", OpStrings[j], results[j]);
printf("\n");
}
}
void SseSfpCompareDouble(void)
{
const int n = 4;
double a[n] = {120.0, 250.0, 300.0, 42.0};
double b[n] = {130.0, 240.0, 300.0, 0.0};
// Set NAN test value
b[n - 1] = numeric_limits<double>::quiet_NaN();
printf("\nResults for SseSfpCompareDouble()\n");
for (int i = 0; i < n; i++)
{
bool results[m];
SseSfpCompareDouble(a[i], b[i], results);
printf("a: %8lf b: %8lf\n", a[i], b[i]);
for (int j = 0; j < m; j++)
printf(" %s=%d", OpStrings[j], results[j]);
printf("\n");
}
}
int main(int argc, char* argv[])
{
SseSfpCompareFloat();
SseSfpCompareDouble();
return 0;
}
ssescalarfloatingpointcompare.asm
; extern "C" void SseSfpCompareFloat_(float a, float b, bool* results);
;
; Description: The following function demonstrates use of the comiss
; instruction.
;
; Requires SSE
;
; extern "C" void SseSfpCompareDouble_(double a, double b, bool* results);
;
; Description: The following function demonstrates use of the comisd
; instruction.
;
; Requires SSE2
;
; Name: ssescalarfloatingpointcompare.asm
;
; Build: g++ -c -m32 main.cpp -o main.o -std=c++11
; nasm -f elf32 -o ssescalarfloatingpointcompare.o ssescalarfloatingpointcompare.asm
; g++ -m32 -o ssescalarfloatingpointcompare ssescalarfloatingpointcompare.o main.o
;
; Source: Modern x86 Assembly Language Programming p. 212
global SseSfpCompareFloat
global SseSfpCompareDouble
SseSfpCompareFloat:
%define a dword[ebp+8]
%define b dword[ebp+12]
%define results [ebp+16]
push ebp
mov ebp,esp
; Load argument values
movss xmm0,a ;xmm0 = a
movss xmm1,b ;xmm1 = b
mov edx,results ;edx = results array
; Set result flags based on compare status
comiss xmm0,xmm1
setp byte[edx] ;EFLAGS.PF = 1 if unordered
jnp .@1
xor al,al
mov byte[edx+1],al ;Use default result values
mov byte[edx+2],al
mov byte[edx+3],al
mov byte[edx+4],al
mov byte[edx+5],al
mov byte[edx+6],al
jmp .done
.@1:
setb byte[edx+1] ;set byte if a < b
setbe byte[edx+2] ;set byte if a <= b
sete byte[edx+3] ;set byte if a == b
setne byte[edx+4] ;set byte if a != b
seta byte[edx+5] ;set byte if a > b
setae byte[edx+6] ;set byte if a >= b
.done:
pop ebp
ret
SseSfpCompareDouble:
%define a qword[ebp+8]
%define b qword[ebp+16]
%define results [ebp+24]
push ebp
mov ebp,esp
; Load argument values
movsd xmm0,a ;xmm0 = a
movsd xmm1,b ;xmm1 = b
mov edx,results ;edx = results array
; Set result flags based on compare status
comisd xmm0,xmm1
setp byte[edx] ;EFLAGS.PF = 1 if unordered
jnp .@1
xor al,al
mov byte[edx+1],al ;Use default result values
mov byte[edx+2],al
mov byte[edx+3],al
mov byte[edx+4],al
mov byte[edx+5],al
mov byte[edx+6],al
jmp .done
.@1:
setb byte[edx+1] ;set byte if a < b
setbe byte[edx+2] ;set byte if a <= b
sete byte[edx+3] ;set byte if a == b
setne byte[edx+4] ;set byte if a != b
seta byte[edx+5] ;set byte if a > b
setae byte[edx+6] ;set byte if a >= b
.done:
pop ebp
ret
build
g++ -c -m32 main.cpp -o main.o -std=c++11
nasm -f elf32 -o ssescalarfloatingpointcompare.o ssescalarfloatingpointcompare.asm
g++ -m32 -o ssescalarfloatingpointcompare ssescalarfloatingpointcompare.o main.o