#include <stdio.h>
#include <signal.h>
#include <assert.h>

#include <setjmp.h> // For jmp_buf

#define True 1
#define False 0

static jmp_buf env_sigill;
static void handler_sigill ( int x ) { longjmp(env_sigill,1); }

int machine_get_hwcaps( void )
{
  /* ppc32 doesn't seem to have a sane way to find out what insn
     sets the CPU supports.  So we have to arse around with
     SIGILLs.  Yuck. */
  sigset_t         saved_set, tmp_set;
  struct sigaction saved_act, tmp_act;

  volatile int have_F, have_V, have_FX, have_GX;

  int r;

  sigemptyset(&tmp_set);
  sigaddset(&tmp_set, SIGILL);

  r = sigprocmask(SIG_UNBLOCK, &tmp_set, &saved_set);
  assert(r == 0);

  r = sigaction(SIGILL, NULL, &saved_act);
  assert(r == 0);
  tmp_act = saved_act;

  /* NODEFER: signal handler does not return (from the kernel's point of
     view), hence if it is to successfully catch a signal more than once,
     we need the NODEFER flag. */
  tmp_act.sa_flags &= ~SA_RESETHAND;
  tmp_act.sa_flags &= ~SA_SIGINFO;
  tmp_act.sa_flags |=  SA_NODEFER;

  /* standard FP insns */
  have_F = True;
  puts("test float");
  tmp_act.sa_handler = handler_sigill;
  r = sigaction(SIGILL, &tmp_act, NULL);
  assert(r == 0);

     if (setjmp(env_sigill)) {
        have_F = False;
        puts("sigill float");
     } else {
        __asm__ __volatile__("fmr 0,0");
	puts("done float");
     }



  puts("test fsqrt");
     /* General-Purpose optional (fsqrt, fsqrts) */
     have_FX = True;
     tmp_act.sa_handler = handler_sigill;
     r = sigaction(SIGILL, &tmp_act, NULL);
     assert(r == 0);
     if (setjmp(env_sigill)) {
        have_FX = False;
        puts("sigill fsqrt");
     } else {
        __asm__ __volatile__("fsqrt 0,0");
	puts("done fsqrt");
     }


     puts("test frsqrte");
     /* Graphics optional (stfiwx, fres, frsqrte, fsel) */
     have_GX = True;
     tmp_act.sa_handler = handler_sigill;
     r = sigaction(SIGILL, &tmp_act, NULL);
     assert(r == 0);
     if (setjmp(env_sigill)) {
        have_GX = False;
        puts("sigill frsqrte");
     } else {
        __asm__ __volatile__("frsqrte 0,0");
	puts("done frsqrte");
     }


  puts("test altivec");
     /* Altivec insns */
     have_V = True;
     tmp_act.sa_handler = handler_sigill;
     r = sigaction(SIGILL, &tmp_act, NULL);
     assert(r == 0);
     if (setjmp(env_sigill)) {
        have_V = False;
        puts("sigill altivec");
     } else {
        /* Unfortunately some older assemblers don't speak Altivec (or
           choose not to), so to be safe we directly emit the 32-bit
           word corresponding to "vor 0,0,0".  This fixes a build
           problem that happens on Debian 3.1 (ppc32), and probably
           various other places. */
        __asm__ __volatile__(".long 0x10000484"); /*vor 0,0,0*/
	puts("done altivec");
     }


     r = sigaction(SIGILL, &saved_act, NULL);
     assert(r == 0);
     r = sigprocmask(SIG_SETMASK, &saved_set, NULL);
     assert(r == 0);
     puts("Done all!");

        printf("F %d V %d FX %d GX %d\n", 
                    (int)have_F, (int)have_V, (int)have_FX, (int)have_GX);

     /* Make FP a prerequisite for VMX (bogusly so), and for FX and GX. */
     if (have_V && !have_F)
        have_V = False;
     if (have_FX && !have_F)
        have_FX = False;
     if (have_GX && !have_F)
        have_GX = False;

     int machine_ppc32_has_FP  = have_F ? 1 : 0;
     int machine_ppc32_has_VMX = have_V ? 1 : 0;

     return 1;
   }

   int main(int c, char *v[]) {
     int i = 0;
     i = machine_get_hwcaps();
     exit(i);
   }

















