読者です 読者をやめる 読者になる 読者になる

標準出力

新しいもの、変わらないこと 自分の頭を通して考えてみました (stdout)

Unmask floating point exception #2

この投稿の追加投稿。

Gcc 4.4.7 にて下記の除算のみを行うソースをコンパイルして逆アセンブルすると除算は、SSE2の命令である"DIVSD" (*1 p.728)が出力されていることが確認できます。

-div.c-
#include

int
main(void)
{
  double a,b,c;

  a=3.0;
  b=0.0;
  c=a/b;

  return 0;
}

$ gcc -o div div.c
$ objdump -d div > div.d

-div.d のmainの一部-
  40048f:       f2 0f 10 45 e8          movsd  -0x18(%rbp),%xmm0
  400494:       f2 0f 5e 45 f0          divsd  -0x10(%rbp),%xmm0
  400499:       f2 0f 11 45 f8          movsd  %xmm0,-0x8(%rbp)



 前回投稿したコードは、x87 FPUのFPE(Floating Point Exception)のマスクを解除するものであり、当たり前ですがSSE2のFPEを解除しているわけではないので、mainの最後でdouble同士の除算をしてもSSE2の命令が出力されているのでFPEは発生しません。

今回は、SSE2のFPEのマスクを外すコードをメモ。
 - sse2.c -
     1    #include

     2   
     3    int
     4    main(void)
     5    {
     6      double a,b,c;
     7      unsigned char buff[512] __attribute__*1;
    26   
    27      c = a/b;
    28   
    29      return 0;
    30    }


fxsave(*1 P.846)/fxstor(*1 P.843) は、指定されたメモリ領域から/にMXCSR(*1 P.230)というSSE2浮動小数点演算時に用いる情報を保持するレジスターに/の値を保存する。
20行目で該当するビットをクリアすることで、ゼロ割によるFPEのマスクを外している。

$ gcc --o sse2 sse2.c
$ ./sse2
SSE2 FPE bit mask= 1F
SSE2 FPE bit mask= 1D
Floating exception (core dumped)

[補足]
ちなみに、-mfpmath=387 というオプションをつけてコンパイルするとx87 FPUの除算命令を出力する。




*1 Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined Volumes: 1, 2A, 2B, 2C, 3A, 3B, and 3C

*1:aligned(16)));
     8   
     9      a=3.0;
    10      b=0.0;
    11      c=1.0;
    12   
    13      c = a/b;
    14   
    15      asm volatile(
    16        "fxsave %0" // get valueof mxcsr register
    17        :"=m"(buff):);
    18   
    19      printf("SSE2 FPE bit mask= %X\n", buff[25]);
    20      buff[25] = buff[25] ^ 0x2;
    21      printf("SSE2 FPE bit mask= %X\n", buff[25]);
    22   
    23      asm volatile(
    24        "fxrstor %0"  // set operand to mxcsr register
    25        : :"m"(*buff