text: /* Reed-Solomon encoder
   * Copyright 2004, Phil Karn, KA9Q
   * May be used under the terms of the GNU Lesser General Public License (LGPL)
   */
  #include <string.h>
  #include "fixed.h"
  #ifdef __VEC__
  #include <sys/sysctl.h>
  #endif
  
  #pragma GCC push_options
  #pragma GCC optimize ("O3")
  
  static enum {UNKNOWN=0,MMX,SSE,SSE2,ALTIVEC,PORT} cpu_mode;
  
  static void encode_rs_8_c(data_t *data, data_t *parity,int pad);
  #if __vec__
  static void encode_rs_8_av(data_t *data, data_t *parity,int pad);
  #endif
  #if __i386__
  int cpu_features(void);
  #endif
  
  void encode_rs_8(data_t *data, data_t *parity,int pad){
    if(cpu_mode == UNKNOWN){
  #ifdef __i386__
      int f;
      /* Figure out what kind of CPU we have */
      f = cpu_features();
      if(f & (1<<26)){ /* SSE2 is present */
        cpu_mode = SSE2;
      } else if(f & (1<<25)){ /* SSE is present */
        cpu_mode = SSE;
      } else if(f & (1<<23)){ /* MMX is present */
        cpu_mode = MMX;
      } else { /* No SIMD at all */
        cpu_mode = PORT;
      }
  #elif __VEC__
      /* Ask the OS if we have Altivec support */
      int selectors[2] = { CTL_HW, HW_VECTORUNIT };
      int hasVectorUnit = 0;
      size_t length = sizeof(hasVectorUnit);
      int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
      if(0 == error && hasVectorUnit)
        cpu_mode = ALTIVEC;
      else
        cpu_mode = PORT;
  #else
      cpu_mode = PORT;
  #endif
    }
    switch(cpu_mode){
  #if __vec__
    case ALTIVEC:
      encode_rs_8_av(data,parity,pad);
      return;
  #endif
  #if __i386__
    case MMX:
    case SSE:
    case SSE2:
  #endif
    default:
      encode_rs_8_c(data,parity,pad);
      return;
    }
  }
  
  #if __vec__ /* PowerPC G4/G5 Altivec instructions are available */
  
  static vector unsigned char reverse = (vector unsigned char)(0,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1);
  static vector unsigned char shift_right = (vector unsigned char)(15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30);
  
  /* Lookup table for feedback multiplications
   * These are the low half of the coefficients. Since the generator polynomial is
   * palindromic, we form the other half by reversing this one
   */
  extern static union { vector unsigned char v; unsigned char c[16]; } table[256];
  
  static void encode_rs_8_av(data_t *data, data_t *parity,int pad){
    union { vector unsigned char v[2]; unsigned char c[32]; } shift_register;
    int i;
  
    shift_register.v[0] = (vector unsigned char)(0);
    shift_register.v[1] = (vector unsigned char)(0);
  
    for(i=0;i<NN-NROOTS-pad;i++){
      vector unsigned char feedback0,feedback1;
      unsigned char f;
  
      f = data[i] ^ shift_register.c[31];
      feedback1 = table[f].v;
      feedback0 = vec_perm(feedback1,feedback1,reverse);
  
      /* Shift right one byte */
      shift_register.v[1] = vec_perm(shift_register.v[0],shift_register.v[1],shift_right) ^ feedback1;
      shift_register.v[0] = vec_sro(shift_register.v[0],(vector unsigned char)(8)) ^ feedback0;
      shift_register.c[0] = f;
    }
    for(i=0;i<NROOTS;i++)
      parity[NROOTS-i-1] = shift_register.c[i];
  }
  #endif
  
  /* Portable C version */
  static void encode_rs_8_c(data_t *data, data_t *parity,int pad){
  
  #include "encode_rs.h"
  
  }
  