2016-09-25 3 views
1

Я пытаюсь очистить деление с плавающей запятой нулевым флагом, чтобы игнорировать это исключение. Я ожидаю, что с установленным флагом (без изменения поведения по умолчанию, который, как я полагаю, и комментариями ниже), мой обработчик ошибок будет срабатывать. Однако _mm_div_ss, похоже, не поднимает SIGFPE. Есть идеи?Capture SIGFPE из инструкции SIMD

#include <stdio.h> 
#include <signal.h> 
#include <string.h> 
#include <xmmintrin.h> 

static void sigaction_sfpe(int signal, siginfo_t *si, void *arg) 
{ 
    printf("inside SIGFPE handler\nexit now."); 
    exit(1); 
} 

int main() 
{ 
    struct sigaction sa; 

    memset(&sa, 0, sizeof(sa)); 
    sigemptyset(&sa.sa_mask); 
    sa.sa_sigaction = sigaction_sfpe; 
    sa.sa_flags = SA_SIGINFO; 
    sigaction(SIGFPE, &sa, NULL); 

    //_mm_setcsr(0x00001D80); // catch all FPE except divide by zero 

    __m128 s1, s2; 
    s1 = _mm_set_ps(1.0, 1.0, 1.0, 1.0); 
    s2 = _mm_set_ps(0.0, 0.0, 0.0, 0.0); 
    _mm_div_ss(s1, s2); 

    printf("done (no error).\n"); 

    return 0; 
} 

Выход из выше кода:

$ gcc a.c 
$ ./a.out 
done (no error). 

Как вы можете видеть, мой обработчик никогда не достигается. Замечание: я пробовал пару различных флагов компилятора (-msse3, -march = native) без изменений.

НКУ (Debian 5.3.1-7) 5.3.1 20160121

Некоторая информация из/Proc/CPUInfo

model name  : Intel(R) Core(TM) i3 CPU  M 380 @ 2.53GHz 
flags   : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 popcnt lahf_lm arat dtherm tpr_shadow vnmi flexpriority ept vpid 
+1

Я думаю, вам нужно разоблачить соответствующее исключение в MXCSR. Все исключения FP маскируются по умолчанию. Я не пробовал писать программу, которая генерирует сигналы из исключений FP, но я бы предположил, что ваш '_mm_setcsr' будет работать, если эта константа права. Для тестирования вы можете фактически запустить SIGFPE на x86 Linux с целым делением на ноль, хотя, как требуется POSIX. (http://stackoverflow.com/questions/37262572/on-which-platforms-does-integer-divide-by-zero-trigger-a-floating-point-exceptio) –

+0

Даже с '_mm_setcsr (0x00001F80)' ничего не происходит , Вы правы, что я могу проверить SIGFPE с целым делением на ноль, но я пытаюсь заставить MXCSR контролировать, происходит это или нет. – BurnsBA

+0

Невозможно отредактировать мой комментарий, но '_mm_setcsr (0x00000000)' имеет тот же эффект (сигнал не поднят). – BurnsBA

ответ

1

две вещи.

Во-первых, я неправильно понял документацию. Исключения должны быть unmasked быть пойманным. Вызов _mm_setcsr(0x00001D80); позволит SIGFPE стрелять по делению на ноль.

Во-вторых, gcc оптимизировал мою инструкцию по разделению даже с -O0.

Учитывая линейный источник

_mm_div_ss(s1, s2); 

Компиляция с gcc -S -O0 -msse2 a.c дает

76  movaps -24(%ebp), %xmm0 
77  movaps %xmm0, -72(%ebp) 
78  movaps -40(%ebp), %xmm0 
79  movaps %xmm0, -88(%ebp) 

a1  subl $12, %esp  ; renumbered to show insertion below 
a2  pushl $.LC2 
a3  call puts 
a4  addl $16, %esp 

В то время как линейный источник

s2 = _mm_div_ss(s1, s2); // add "s2 = " 

дает

76  movaps -24(%ebp), %xmm0 
77  movaps %xmm0, -72(%ebp) 
78  movaps -40(%ebp), %xmm0 
79  movaps %xmm0, -88(%ebp) 
     movaps -72(%ebp), %xmm0 
     divss -88(%ebp), %xmm0 
     movaps %xmm0, -40(%ebp) 
a1  subl $12, %esp 
a2  pushl $.LC2 
a3  call puts 
a4  addl $16, %esp 

С этими изменениями обработчик SIGFPE вызывается в соответствии с флагом divide-by-zero в MXCSR.

Смежные вопросы