#
# gcc compiler optimizations plugin
#

compiler_gcc_optimize_defaults()
{
  # default optimizations
  BOPT=Faster
  SPD=( Noplt Exceptions )
  CC_OPTS=( Pipe Fortify ClashProtection )
  CPU=$(arch | sed 's;_;-;')
}

plugin_compiler_gcc_optimize()
{
  debug_msg "plugin_compiler_gcc_optimize($@)"

  compiler_gcc_optimize_defaults

  if [ -f /etc/lunar/local/optimizations.GCC ]; then
    . /etc/lunar/local/optimizations.GCC
  fi

  # some local macro's
  cflags_add()
  {
    CFLAGS="$CFLAGS $@"
  }

  cxxflags_add()
  {
    CXXFLAGS="$CXXFLAGS $@"
  }

  cppflags_add()
  {
    CPPFLAGS="$CPPFLAGS $@"
  }

  c_cxx_flags_add()
  {
    cflags_add $@
    cxxflags_add $@
  }

  # CFLAGS/CXXFLAGS - base optimization
  case $BOPT in
    None)    c_cxx_flags_add "-O0" ;;
    Small)   c_cxx_flags_add "-Os" ;;
    Fast)    c_cxx_flags_add "-O1" ;;
    Faster)  c_cxx_flags_add "-O2" ;;
    Fastest) c_cxx_flags_add "-O3" ;;
    Insane)  c_cxx_flags_add "-Ofast" ;;
  esac

  # CFLAGS -march cpu-specific optimization
  if [ "$CPU" != "None" -a -n "$CPU" ]; then
    c_cxx_flags_add "-march=$CPU"
  fi
  # CFLAGS -mtune cpu-specific tuning
  if [ "$CPUTUNE" != "None" -a -n "$CPUTUNE" ]; then
    c_cxx_flags_add "-mtune=$CPUTUNE"
  fi

  # GCC specific extra optimizations
  for SP in ${SPD[@]}; do
    case $SP in
      Speedy)     c_cxx_flags_add "-funroll-loops" ;;
      Regparm)    c_cxx_flags_add "-mregparm=3" ;;
      Risky)      c_cxx_flags_add "-ffast-math" ;;
      Pointers)   c_cxx_flags_add "-fomit-frame-pointer" ;;
      Siblings)   c_cxx_flags_add "-foptimize-sibling-calls" ;;
      Profiling)
        c_cxx_flags_add "-fprofile-arcs"
        set_local_config "KEEP_SOURCE" "on"
      ;;
      Branching)  c_cxx_flags_add "-fbranch-probabilities" ;;
      Aliasing)   c_cxx_flags_add "-fstrict-aliasing" ;;
      Cprop)      c_cxx_flags_add "-fno-cprop-registers" ;;
      Float)      c_cxx_flags_add "-ffloat-store" ;;
      Address)    c_cxx_flags_add "-fforce-addr" ;;
      Align)      c_cxx_flags_add "-falign-functions -falign-loops -falign-jumps" ;;
      Expensive)  c_cxx_flags_add "-fexpensive-optimizations" ;;
      Doubles)    c_cxx_flags_add "-malign-double" ;;
      Tracer)     c_cxx_flags_add "-ftracer" ;;
      Blocks)     c_cxx_flags_add "-freorder-blocks" ;;
      Noplt)      c_cxx_flags_add "-fno-plt" ;;
      Exceptions) c_cxx_flags_add "-fexceptions" ;;
    esac
  done

  for XTR in ${XTRA[@]}; do
    case $XTR in
      MMX)     c_cxx_flags_add "-mmmx" ;;
      SSE)     c_cxx_flags_add "-msse" ;;
      SSE2)    c_cxx_flags_add "-msse2" ;;
      SSE3)    c_cxx_flags_add "-msse3" ;;
      SSSE3)   c_cxx_flags_add "-mssse3" ;;
      SSE4)    c_cxx_flags_add "-msse4" ;;
      SSE4.1)  c_cxx_flags_add "-msse4.1" ;;
      SSE4.2)  c_cxx_flags_add "-msse4.2" ;;
      SSE4A)   c_cxx_flags_add "-msse4a" ;;
      SSE5)    c_cxx_flags_add "-msse5" ;;
      3dnow)   c_cxx_flags_add "-m3dnow" ;;
      Altivec) c_cxx_flags_add "-maltivec" ;;
      AVX)     c_cxx_flags_add "-mavx" ;;
      AES)     c_cxx_flags_add "-maes" ;;
      PCLMUL)  c_cxx_flags_add "-mpclmul" ;;
      POPCNT)  c_cxx_flags_add "-mpopcnt" ;;
      LZCNT)   c_cxx_flags_add "-mlzcnt" ;;
    esac
  done

  case $FPM in
    x387) c_cxx_flags_add "-mfpmath=387" ;;
    SSE)  c_cxx_flags_add "-mfpmath=sse" ;;
    Both) c_cxx_flags_add "-mfpmath=both" ;;
  esac

  for OPT in ${CC_OPTS[@]}; do
    case $OPT in
      Deprecated)
        cxxflags_add "-Wno-deprecated"
        ;;
      Debug)
        c_cxx_flags_add "-g"
        ;;
      Pipe)
        c_cxx_flags_add "-pipe"
        ;;
      Fortify)
        c_cxx_flags_add "-Wp,-D_FORTIFY_SOURCE=2"
        ;;
      StackProt)
        c_cxx_flags_add "-fstack-protector"
        ;;
      StackProtStrong)
        c_cxx_flags_add "-fstack-protector-strong"
        ;;
      ClashProtection)
        c_cxx_flags_add "-fstack-clash-protection"
        ;;
      ControlFlowProt)
        c_cxx_flags_add "-fcf-protection"
        ;;
    esac
  done

  CC=gcc
  CXX=g++
  CPP=cpp

  if [ -n "$MYCFLAGS" ]; then
    CFLAGS=$MYCFLAGS
    CXXFLAGS=$MYCFLAGS
  fi
  if [ -n "$MYCXXFLAGS" ]; then
    CXXFLAGS=$MYCXXFLAGS
  fi

  export CFLAGS CXXFLAGS
  export CC CXX CPP

  verbose_msg "CC=\"$CC\""
  verbose_msg "CXX=\"$CXX\""
  verbose_msg "CPP=\"$CPP\""
  verbose_msg "CFLAGS=\"$CFLAGS\""
  verbose_msg "CXXFLAGS=\"$CXXFLAGS\""

  return 2
}


plugin_compiler_gcc_menu()
{
  # The main code calls this function WITHOUT $1 to find out which
  # compiler optimization plugins exist. It then returns the plugin
  # identifier which can be saved in $LUNAR_COMPILER as the user's
  # choice for COMPILERS
  if [ -z "$1" ]; then
    echo "GCC"
    echo "GNU C Compiler suite"
    return 2
  elif [ "$1" != "GCC" ]; then
    # we don't display anything when the user selected a
    # different menu
    return 2
  fi

  # now we are done with determining if we are really the menu
  # that the user wants - so we can display it
  menu()
  {
    unset RESULT
    if [ "$1" == "checklist" ]; then
      RESULT=$($DIALOG --no-cancel --item-help --separate-output --checklist "$2" 0 0 0 "${OPTIONS[@]}")
      if [ $? != 0 ]; then
        return 1
      fi
    elif [ "$1" == "radiolist" ]; then
      RESULT=$($DIALOG --no-cancel --item-help --radiolist "$2" 0 0 0 "${OPTIONS[@]}")
      if [ $? != 0 ]; then
        return 1
      fi
    fi
    RESULT=$(echo $RESULT | sed -e 's:^"::' -e 's:"$::')
    return 0
  }

  save_optimizations()
  {
    debug_msg "save_optimizations($@)"
    cat >/etc/lunar/local/optimizations.GCC <<EOF
CPU=$CPU
CPUTUNE=$CPUTUNE
BOPT=$BOPT
SPD=( $(echo ${SPD[@]} ) )
XTRA=( $(echo ${XTRA[@]}) )
FPM=$FPM
CC_OPTS=( $(echo ${CC_OPTS[@]} ) )
EOF
  }

  compiler_gcc_optimize_defaults

  if [ -f /etc/lunar/local/optimizations.GCC ]; then
    . /etc/lunar/local/optimizations.GCC
  fi

  export IFS=$'\t\n'
  TITLE="Lunar Compiler Optimizations"

  SAFE_OPTIMIZATIONS=${SAFE_OPTIMIZATIONS:-on}

  while true; do
    unset OPTIONS
    IS_DEFAULT=$([ "$(get_local_config LUNAR_COMPILER)" == "GCC" ] && echo DEFAULT || get_local_config LUNAR_COMPILER)
    DEFAULT=${CHOICE:-safe}
    CHOICE=$($DIALOG --title "$TITLE" --ok-label "Select" --cancel-label "Close" --default-item "$DEFAULT" --item-help --menu "" 0 0 0 $(
      echo "default"
      echo "Set this compiler as default  [$IS_DEFAULT]"
      echo "Enables you to substitute the default C compiler"
      if [ "$SAFE_OPTIMIZATIONS" == "off" ]; then
        echo "safe"
        echo "Turn on optimization safety   [$SAFE_OPTIMIZATIONS]"
        echo "Only allow safe optimizations (removes dangerous settings!)"
      else
        echo "safe"
        echo "Turn off optimization safety  [$SAFE_OPTIMIZATIONS]"
        echo "Allow potentially unsafe optimizations (DANGEROUS!)"
      fi
      echo "bopt"
      echo "Base speed optimization       [$BOPT]"
      echo "Select the base optimization from -Os, -O0, -O1 etc"
      echo "cpu"
      echo "CPU base arch selection       [$CPU]"
      echo "Select the target CPU type"
      if [ "$SAFE_OPTIMIZATIONS" == "off" ]; then
        echo "cputune"
        echo "CPU arch tune selection       [$CPUTUNE]"
        echo "Select the CPU tuning type"
      fi
      echo "xtra"
      echo "CPU extensions                [${XTRA[@]}]"
      echo "Select CPU extensions"
      echo "spd"
      echo "Specialized optimizations     [${SPD[@]}]"
      echo "Select specific compiler flags for expensive and risky optimizations"
      echo "fpm"
      echo "Floating point optimizations  [$FPM]"
      echo "enable specific floating point optimizations"
      echo "cc_opt"
      echo "General C/C++ options         [${CC_OPTS[@]}]"
      echo "Select named pipes, warnings on deprecated symbols"))
      if [ $? != 0 ]; then
        save_optimizations
        set_local_config SAFE_OPTIMIZATIONS $SAFE_OPTIMIZATIONS
        return
      fi

      case $CHOICE in
        default)
          if [ "$IS_DEFAULT" != "DEFAULT" ]; then
            set_local_config LUNAR_COMPILER GCC
            $DIALOG --msgbox "GCC is now the default compiler!" 6 60
          fi
          ;;
        safe)
          if [ "$SAFE_OPTIMIZATIONS" == "off" ]; then
            SAFE_OPTIMIZATIONS=on
            unset SPD XTRA STACK
            FPM=("None")
            BOPT=${BOPT//Fastest/Faster}
          else
            $DIALOG --defaultno --yes-label "No" --no-label "Yes" --colors --yesno " \Z1*** WARNING ***\n\n\ZnPlease read this carefully. You are about to turn off the optimization safety. This means that you can possibly turn on compiler or linker optimizations that can and will break your box. Not only will the problem most likely occur only days, weeks or months after you turn this switch, but also it can corrupt all your personal data, make your machine unbootable, and cause serious personal distress, headache, loss of vision, heart failure, loss of income, or otherwise very bad things. Before you turn off this option, please think for yourself for a minute and ask yourself: Is it worth it?\n\nOnly use safe optimizations?" 20 70
            if [ $? == 0 ]; then
              SAFE_OPTIMIZATIONS=off
            fi
          fi
        ;;
        bopt)
          OPTIONS=(
            "None" "-O0" $( [ "$BOPT" == "None" ] && echo "on" || echo "off" ) "Only default optimizations"
            "Fast" "-O1" $( [ "$BOPT" == "Fast" ] && echo "on" || echo "off" ) "-O1"
            "Faster" "-O2" $( [ "$BOPT" == "Faster" ] && echo "on" || echo "off" ) "-O2"
            )
          if [ "$SAFE_OPTIMIZATIONS" == "off" ]; then
          OPTIONS+=(
            "Fastest" "-O3" $( [ "$BOPT" == "Fastest" ] && echo "on" || echo "off" ) "-O3"
            "Insane" "-Ofast" $( [ "$BOPT" == "Insane" ] && echo "on" || echo "off" ) "-Ofast"
            )
          fi
          OPTIONS+=(
            "Small" "-Os" $( [ "$BOPT" == "Small" ] && echo "on" || echo "off" ) "-Os"
            )
          menu radiolist "Choose the base compile-time optimization. Most people will use -O2 or -O3. Note that some modules set their own level." &&
          BOPT=$RESULT
        ;;
        cputune|cpu)
          case $CHOICE in
            cpu)
              VAL=$CPU
              ;;
            cputune)
              VAL=$CPUTUNE
              ;;
            esac
          case $PLATFORM in
            x86)
              OPTIONS=(
                "None" "" $( [ ! "$VAL" ] && echo "on" || echo "off" ) "All processor types"
                "native" "autodetect" $( [ "$VAL" == "native" ] && echo "on" || echo "off" ) "autodetect CPU at compile time - recommended"
              )
              if [ "$SAFE_OPTIMIZATIONS" == "off" ]; then
              OPTIONS+=(
                "i386" "i386" $( [ "$VAL" == "i386" ] && echo "on" || echo "off" ) "i386 processors"
                "i486" "i486" $( [ "$VAL" == "i486" ] && echo "on" || echo "off" ) "i486 processors"
                "i586" "i586 (Pentium)" $( [ "$VAL" == "i586" ] && echo "on" || echo "off" ) "i586 processors, identical to 'pentium'"
                "pentium-mmx" "pentium-mmx" $( [ "$VAL" == "pentium-mmx" ] && echo "on" || echo "off" ) "Pentium processors with mmx"
                "i686" "i686 (PentiumPro)" $( [ "$VAL" == "i686" ] && echo "on" || echo "off" ) "i686 processors, identical to 'pentiumpro'"
                "pentium2" "P2" $( [ "$VAL" == "pentium2" ] && echo "on" || echo "off" ) "Pentium II processors"
                "pentium3" "P3 (Celeron)" $( [ "$VAL" == "pentium3" ] && echo "on" || echo "off" ) "Pentium III processors"
                "pentium3m" "P3 mobile (Celeron)" $( [ "$VAL" == "pentium3m" ] && echo "on" || echo "off" ) "Pentium III Mobile processors"
                "pentium-m" "P3 mobile (Celeron) Low power version" $( [ "$VAL" == "pentium-m" ] && echo "on" || echo "off" ) "Pentium III Mobile processor - low power versions"
                "pentium4" "P4" $( [ "$VAL" == "pentium4" ] && echo "on" || echo "off" ) "Pentium 4 processors"
                "pentium4m" "P4 mobile" $( [ "$VAL" == "pentium4m" ] && echo "on" || echo "off" ) "Pentium 4 mobile processors"
                "core2" "Core 2" $( [ "$VAL" == "core2" ] && echo "on" || echo "off" ) "Intel Core 2 processors"
                "nehalem" "Intel Nehalem" $( [ "$VAL" == "nehalem" ] && echo "on" || echo "off" ) "Intel Nehalem CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT."
                "westmere" "Intel Westmare" $( [ "$VAL" == "westmere" ] && echo "on" || echo "off" ) "Intel Westmere CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PCLMUL."
                "sandybridge" "Intel Sandy Bridge" $( [ "$VAL" == "sandybridge" ] && echo "on" || echo "off" ) "Intel Sandy Bridge CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AES, PCLMUL."
                "ivybridge" "Intel Ivy Bridge" $( [ "$VAL" == "ivybridge" ] && echo "on" || echo "off" ) "Intel Ivy Bridge CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AES, PCLMUL, FSGSBASE, RDRND, F16C."
                "haswell" "Intel Haswell" $( [ "$VAL" == "haswell" ] && echo "on" || echo "off" ) "Intel Haswell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C"
                "broadwell" "Intel Broadwell" $( [ "$VAL" == "broadwell" ] && echo "on" || echo "off" ) "Intel Broadwell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW"
                "skylake" "Intel Skylake" $( [ "$VAL" == "skylake" ] && echo "on" || echo "off" ) "Intel Skylake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES"
                "skylake-avx512" "Intel Skylake (AVX-512)" $( [ "$VAL" == "skylake-axv512" ] && echo "on" || echo "off" ) "Intel Skylake Server CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD"
                "prescott" "Xeon" $( [ "$VAL" == "prescott" ] && echo "on" || echo "off" ) "Newer Xeons with sse3"
                "nocona" "nocona" $( [ "$VAL" == "nocona" ] && echo "on" || echo "off" ) "Newer Xeons with sse3 and em64t"
                "k6" "k6" $( [ "$VAL" == "k6" ] && echo "on" || echo "off" ) "AMD K6 processors"
                "k6-2" "k6-2" $( [ "$VAL" == "k6-2" ] && echo "on" || echo "off" ) "AMD K6-2 processors"
                "k6-3" "k6-3" $( [ "$VAL" == "k6-3" ] && echo "on" || echo "off" ) "AMD K6-3 processors"
                "athlon" "athlon" $( [ "$VAL" == "athlon" ] && echo "on" || echo "off" ) "AMD Athlon processors"
                "athlon-tbird" "athlon-tbird" $( [ "$VAL" == "athlon-tbird" ] && echo "on" || echo "off" ) "AMD Athlon Thunderbird processors"
                "athlon-4" "athlon-4" $( [ "$VAL" == "athlon-4" ] && echo "on" || echo "off" ) "AMD Athlon 4 processors"
                "athlon-xp" "athlon-xp" $( [ "$VAL" == "athlon-xp" ] && echo "on" || echo "off" ) "AMD Athlon XP processors"
                "athlon-mp" "athlon-mp" $( [ "$VAL" == "athlon-mp" ] && echo "on" || echo "off" ) "AMD athlon MP processors"
                "k8" "k8" $( [ "$VAL" == "k8" ] && echo "on" || echo "off" ) "AMD K8 processors"
                "opteron" "opteron" $( [ "$VAL" == "opteron" ] && echo "on" || echo "off" ) "AMD opteron processors"
                "athlon64" "athlon64" $( [ "$VAL" == "athlon64" ] && echo "on" || echo "off" ) "AMD Athlon 64 processors"
                "athlon-fx" "athlon-fx" $( [ "$VAL" == "athlon-fx" ] && echo "on" || echo "off" ) "AMD Athlon fx processors"
                "k8-sse3" "k8-sse3" $( [ "$VAL" == "k8-sse3" ] && echo "on" || echo "off" ) "AMD K8 processors with SSE3"
                "opteron-sse3" "opteron-sse3" $( [ "$VAL" == "opteron-sse3" ] && echo "on" || echo "off" ) "AMD opteron processors with SSE3"
                "athlon64-sse3" "athlon64-sse3" $( [ "$VAL" == "athlon64-sse3" ] && echo "on" || echo "off" ) "AMD Athlon 64 processors with SSE3"
                "amdfam10" "AMD K10 Phenom/new K10 based Opteron family" $( [ "$VAL" == "amdfam10" ] && echo "on" || echo "off" ) "AMD K10 family: Phenom1,2 Athlon2, new Opteron K10 based processors with SSE4A ABM"
                "barcelona" "barcelona" $( [ "$VAL" == "barcelona" ] && echo "on" || echo "off" ) "AMD K10 family: barcelona core processors with SSE4A ABM"
                "geode" "geode" $( [ "$VAL" == "geode" ] && echo "on" || echo "off" ) "AMD Geode processors"
                "winchip-c6" "winchip-c6" $( [ "$VAL" == "winchip-c6" ] && echo "on" || echo "off" ) "IDT Winchip C6 CPU (a 486)"
                "winchip2" "winchip2" $( [ "$VAL" == "winchip2" ] && echo "on" || echo "off" ) "IDT Winchip2 CPU (a 486)"
                "c3" "c3" $( [ "$VAL" == "c3" ] && echo "on" || echo "off" ) "Via C3 CPU with MMX and 3dNOW"
                "c3-2" "c3-2" $( [ "$VAL" == "c3-2" ] && echo "on" || echo "off" ) "Via C3-2 CPU with MMX and SSE"
                )
              fi
            ;;
            Alpha)
              OPTIONS=(
                "None" "" $( [ ! "$VAL" ] && echo "on" || echo "off" ) "All processor types"
                "ev4" "ev4" $( [ "$VAL" == "ev4" ] && echo "on" || echo "off" ) "Alpha EV4 (21064)"
                "ev45" "ev45" $( [ "$VAL" == "ev45" ] && echo "on" || echo "off" ) "Alpha EV45 (21064a)"
                "ev5" "ev5" $( [ "$VAL" == "ev5" ] && echo "on" || echo "off" ) "Alpha EV5 (21164)"
                "ev56" "ev56" $( [ "$VAL" == "ev56" ] && echo "on" || echo "off" ) "Alpha EV56 (21164a)"
                "pca56" "pca56" $( [ "$VAL" == "pca56" ] && echo "on" || echo "off" ) "Alpha pca56 (21164PC)"
                "ev6" "ev6" $( [ "$VAL" == "ev6" ] && echo "on" || echo "off" ) "Alpha EV6 (21264)"
                "ev67" "ev67" $( [ "$VAL" == "ev67" ] && echo "on" || echo "off" ) "Alpha EV67 (21264a)"
                "ev68" "ev68" $( [ "$VAL" == "ev68" ] && echo "on" || echo "off" ) "Alpha EV68 (21264b)"
                )
            ;;
            PowerPC)
              OPTIONS=(
                "None" "" $( [ ! "$VAL" ] && echo "on" || echo "off" ) "All processor types"
                "common" "common" $( [ "$VAL" == "common" ] && echo "on" || echo "off" ) "Common PowerPC"
                "rios" "rios" $( [ "$VAL" == "rios" ] && echo "on" || echo "off" ) "Rios PowerPC"
                "rios1" "rios1" $( [ "$VAL" == "rios1" ] && echo "on" || echo "off" ) "Rios1 PowerPC"
                "rsc" "rsc" $( [ "$VAL" == "rsc" ] && echo "on" || echo "off" ) "RSC PowerPC"
                "rios2" "rios2" $( [ "$VAL" == "rios2" ] && echo "on" || echo "off" ) "Rios2 PowerPC"
                "rs64a" "rs64a" $( [ "$VAL" == "rs64a" ] && echo "on" || echo "off" ) "RS64a PowerPC"
                "403" "403" $( [ "$VAL" == "403" ] && echo "on" || echo "off" ) "403 PowerPC"
                "505" "505" $( [ "$VAL" == "505" ] && echo "on" || echo "off" ) "505 PowerPC"
                "601" "601" $( [ "$VAL" == "601" ] && echo "on" || echo "off" ) "601 PowerPC"
                "602" "602" $( [ "$VAL" == "602" ] && echo "on" || echo "off" ) "602 PowerPC"
                "603" "603" $( [ "$VAL" == "603" ] && echo "on" || echo "off" ) "603 PowerPC"
                "603a" "603a" $( [ "$VAL" == "603a" ] && echo "on" || echo "off" ) "603a PowerPC"
                "604" "604" $( [ "$VAL" == "604" ] && echo "on" || echo "off" ) "604 PowerPC"
                "604e" "604e" $( [ "$VAL" == "604e" ] && echo "on" || echo "off" ) "604e PowerPC"
                "620" "620" $( [ "$VAL" == "620" ] && echo "on" || echo "off" ) "620 PowerPC"
                "630" "630" $( [ "$VAL" == "630" ] && echo "on" || echo "off" ) "630 PowerPC"
                "740" "740" $( [ "$VAL" == "740" ] && echo "on" || echo "off" ) "740 PowerPC"
                "7400" "7400" $( [ "$VAL" == "7400" ] && echo "on" || echo "off" ) "7400 PowerPC"
                "7450" "7450" $( [ "$VAL" == "7450" ] && echo "on" || echo "off" ) "7450 PowerPC"
                "750" "750" $( [ "$VAL" == "750" ] && echo "on" || echo "off" ) "750 PowerPC"
                "801" "801" $( [ "$VAL" == "801" ] && echo "on" || echo "off" ) "801 PowerPC"
                "821" "821" $( [ "$VAL" == "821" ] && echo "on" || echo "off" ) "821 PowerPC"
                "823" "823" $( [ "$VAL" == "823" ] && echo "on" || echo "off" ) "823 PowerPC"
                "Power" "Power" $( [ "$VAL" == "Power" ] && echo "on" || echo "off" ) "Power PowerPC"
                "Power2" "Power2" $( [ "$VAL" == "Power2" ] && echo "on" || echo "off" ) "Power2 PowerPC"
                "PowerPC" "PowerPC" $( [ "$VAL" == "PowerPC" ] && echo "on" || echo "off" ) "IBM and Apple hardware (Power and PowerPC)"
                )
            ;;
            SPARC)
              OPTIONS=(
                "None" "" $( [ ! "$VAL" ] && echo "on" || echo "off" ) "All processor types"
                "v7" "v7" $( [ "$VAL" == "v7" ] && echo "on" || echo "off" ) "V7 SPARC"
                "cypress" "cypress" $( [ "$VAL" == "cypress" ] && echo "on" || echo "off" ) "Cypress SPARC"
                "v8" "v8" $( [ "$VAL" == "v8" ] && echo "on" || echo "off" ) "V8 SPARC"
                "supersparc" "supersparc" $( [ "$VAL" == "supersparc" ] && echo "on" || echo "off" ) "SuperSPARC"
                "sparclite" "sparclite" $( [ "$VAL" == "sparclite" ] && echo "on" || echo "off" ) "SPARCLite"
                "hypersparc" "hypersparc" $( [ "$VAL" == "hypersparc" ] && echo "on" || echo "off" ) "HyperSPARC"
                "sparclite86x" "sparclite86x" $( [ "$VAL" == "sparclite86x" ] && echo "on" || echo "off" ) "SPARCLite86x"
                "f930" "f930" $( [ "$VAL" == "f930" ] && echo "on" || echo "off" ) "f930 SPARC"
                "f934" "f934" $( [ "$VAL" == "f934" ] && echo "on" || echo "off" ) "f934 SPARC"
                "sparclet" "sparclet" $( [ "$VAL" == "sparclet" ] && echo "on" || echo "off" ) "SPARCLet"
                "tsc701" "tsc701" $( [ "$VAL" == "tsc701" ] && echo "on" || echo "off" ) "tsc701"
                "v9" "v9" $( [ "$VAL" == "v9" ] && echo "on" || echo "off" ) "V9 SPARC"
                "ultrasparc" "ultrasparc" $( [ "$VAL" == "ultrasparc" ] && echo "on" || echo "off" ) "ULTRASPARC"
                )
            ;;
            x86_64)
              OPTIONS=(
                "None" "" $( [ ! "$VAL" ] && echo "on" || echo "off" ) "All processor types"
                "native" "autodetect" $( [ "$VAL" == "native" ] && echo "on" || echo "off" ) "autodetect CPU at compile time - recommended"
              )
              if [ "$SAFE_OPTIMIZATIONS" == "off" ]; then
              OPTIONS+=(
                "x86-64" "x86-64" $( [ "$VAL" == "x86-64" ] && echo "on" || echo "off" ) "Both AMD64 and Intel EM64T machines"
                "nocona" "nocona" $( [ "$VAL" == "nocona" ] && echo "on" || echo "off" ) "Newer Xeons with sse3 and em64t"
                "core2" "core2" $( [ "$VAL" == "core2" ] && echo "on" || echo "off" ) "Intel Core2 CPU with em64t SSE3 and SSSE3"
                "nehalem" "Intel Nehalem" $( [ "$VAL" == "nehalem" ] && echo "on" || echo "off" ) "Intel Nehalem CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT."
                "westmere" "Intel Westmare" $( [ "$VAL" == "westmere" ] && echo "on" || echo "off" ) "Intel Westmere CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PCLMUL."
                "sandybridge" "Intel Sandy Bridge" $( [ "$VAL" == "sandybridge" ] && echo "on" || echo "off" ) "Intel Sandy Bridge CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AES, PCLMUL."
                "ivybridge" "Intel Ivy Bridge" $( [ "$VAL" == "ivybridge" ] && echo "on" || echo "off" ) "Intel Ivy Bridge CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AES, PCLMUL, FSGSBASE, RDRND, F16C."
                "haswell" "Intel Haswell" $( [ "$VAL" == "haswell" ] && echo "on" || echo "off" ) "Intel Haswell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C"
                "broadwell" "Intel Broadwell" $( [ "$VAL" == "broadwell" ] && echo "on" || echo "off" ) "Intel Broadwell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW"
                "skylake" "Intel Skylake" $( [ "$VAL" == "skylake" ] && echo "on" || echo "off" ) "Intel Skylake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES"
                "skylake-avx512" "Intel Skylake (AVX-512)" $( [ "$VAL" == "skylake-axv512" ] && echo "on" || echo "off" ) "Intel Skylake Server CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD"
                "k8" "k8" $( [ "$VAL" == "k8" ] && echo "on" || echo "off" ) "AMD K8 processors"
                "opteron" "opteron" $( [ "$VAL" == "opteron" ] && echo "on" || echo "off" ) "AMD opteron processors"
                "athlon64" "athlon64" $( [ "$VAL" == "athlon64" ] && echo "on" || echo "off" ) "AMD Athlon 64 processors"
                "athlon-fx" "athlon-fx" $( [ "$VAL" == "athlon-fx" ] && echo "on" || echo "off" ) "AMD Athlon fx processors"
                "k8-sse3" "k8-sse3" $( [ "$VAL" == "k8-sse3" ] && echo "on" || echo "off" ) "AMD K8 processors with SSE3"
                "opteron-sse3" "opteron-sse3" $( [ "$VAL" == "opteron-sse3" ] && echo "on" || echo "off" ) "AMD opteron processors with SSE3"
                "athlon64-sse3" "athlon64-sse3" $( [ "$VAL" == "athlon64-sse3" ] && echo "on" || echo "off" ) "AMD Athlon 64 processors with SSE3"
                "amdfam10" "AMD K10 family Phenom/new  K10 based Opteron" $( [ "$VAL" == "amdfam10" ] && echo "on" || echo "off" ) "AMD K10 family: Phenom1,2 Athlon2, new Opteron K10 family processors with SSE4A ABM"
                "barcelona" "barcelona" $( [ "$VAL" == "barcelona" ] && echo "on" || echo "off" ) "AMD K10 family: barcelona core processors with SSE4A ABM"
                )
              fi
            ;;
          esac
          menu radiolist "CPU, according to the kernel you have a$(cat /proc/cpuinfo | grep 'model name' | cut -d: -f2 | head -n 1). If you are unsure, use autodetect - anything other is not safe." &&
          case $CHOICE in
            cpu)
              CPU=$RESULT
              ;;
            cputune)
              CPUTUNE=$RESULT
              ;;
            esac
        ;;
        spd)
          # safe list derived from `gcc -c -Q -O2 --help=optimizers`
          OPTIONS=(
            "Pointers" "-fomit-frame-pointer" $( echo ${SPD[@]} | grep -q "Pointers" && echo "on" || echo "off" ) "Optimize by omitting frame pointers"
            "Siblings" "-foptimize-sibling-calls" $( echo ${SPD[@]} | grep -q "Siblings" && echo "on" || echo "off" ) "Optimize sibling calls"
            "Aliasing" "-fstrict-aliasing" $( echo ${SPD[@]} | grep -q "Aliasing" && echo "on" || echo "off" ) "Enable strict aliasing (enabled by default -O1 and above)"
            "Align" "-falign-functions" $( echo ${SPD[@]} | grep -q "Align" && echo "on" || echo "off" ) "Align functions, loops, and jumps"
            "Expensive" "-fexpensive-optimizations" $( echo ${SPD[@]} | grep -q "Expensive" && echo "on" || echo "off" ) "Perform expensive optimizations"
            "Blocks" "-freorder-blocks" $( echo ${SPD[@]} | grep -q "Blocks" && echo "on" || echo "off" ) "Reorder basic blocks in order to reduce number of taken branches."
            "Noplt" "-fno-plt" $( echo ${SPD[@]} | grep -q "Noplt" && echo "on" || echo "off" ) "Do not use the PLT for external function calls in position-independent code."
            "Exceptions" "-fexceptions" $( echo ${SPD[@]} | grep -q "Exceptions" && echo "on" || echo "off" ) "Enable exception handling. Generates extra code needed to propagate exceptions."
          )
          if [ "$SAFE_OPTIMIZATIONS" == "off" ]; then
          OPTIONS+=(
            "Speedy" "-funroll-loops" $( echo ${SPD[@]} | grep -q "Speedy" && echo "on" || echo "off" ) "Optimize to increase performance of generated code"
            "Regparm" "-mregparm=3" $( echo ${SPD[@]} | grep -q "Regparm" && echo "on" || echo "off" ) "Pass up to 3 function arguments in registers instead of stack"
            "Risky" "-ffast-math" $( echo ${SPD[@]} | grep -q "Risky" && echo "on" || echo "off" ) "Optimize to increase performance ... by violating ANSI and IEEE FP rules"
            "Profiling" "-fprofile-arcs" $( echo ${SPD[@]} | grep -q "Profiling" && echo "on" || echo "off" ) "Generate profiles (For later use with Branching)"
            "Branching" "-fbranching-probabilities" $( echo ${SPD[@]} | grep -q "Branching" && echo "on" || echo "off" ) "Predict branching (For using profiled sources)"
            "Cprop" "-fno-cprop-registers" $( echo ${SPD[@]} | grep -q "Cprop" && echo "on" || echo "off" ) "Reduce scheduling dependencies and remove copies"
            "Float" "-ffloat-store" $( echo ${SPD[@]} | grep -q "Float" && echo "on" || echo "off" ) "Enable float store"
            "Address" "-fforce-addr" $( echo ${SPD[@]} | grep -q "Address" && echo "on" || echo "off" ) "Force memory address"
            "Doubles" "-malign-double" $( echo ${SPD[@]} | grep -q "Doubles" && echo "on" || echo "off" ) "Align double, long double, and long long on two word boundaries"
            "Tracer" "-ftracer" $( echo ${SPD[@]} | grep -q "Tracer" && echo "on" || echo "off" ) "Perform tail duplication to enlarge superblock size."
            )
          fi
          menu checklist "Select additional flags to optimize specific areas of the created code. Note that some of these flags are turned on automatically with -O2 or -O3. See 'man gcc' for more information." &&
          SPD=($RESULT)
        ;;
        fpm)
          OPTIONS=(
            "None" "Use compiler default" $([ "$FPM" == "None" ] && echo "on" || echo "off" ) "Use compiler default"
            )
          case $PLATFORM in
            x86|x86_64)
              if grep '^fpu' /proc/cpuinfo | grep -qw yes; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "x387" "Floating point coprocessor" $([ "$FPM" == "x387" ] && echo "on" || echo "off" ) "Classic 387 or higher Floating Point Co-Processor"
                  )
              fi
              if grep -qw sse /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "SSE" "Streaming SIMD Extensions" $([ "$FPM" == "SSE" ] && echo "on" || echo "off" ) "Streaming SIMD (Single Instruction, Multiple Data)"
                  )
              fi
              if grep '^fpu' /proc/cpuinfo | grep -qw yes; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "Both" "x387 and SSE" $([ "$FPM" == "Both" ] && echo "on" || echo "off" ) "Both SSE and 387"
                  )
              fi
            ;;
            PowerPC)
              if grep -qw altivec /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "Altivec" "PowerPC only" $([ "$FPM" == "Altivec" ] && echo "on" || echo "off" ) "Altivec"
                  )
              fi
            ;;
          esac
          unset FLAGS
          for EXT in fpu sse altivec ; do
            if grep -qw "$EXT" /proc/cpuinfo ; then
              FLAGS="$FLAGS $EXT"
            fi
          done
          FLAGS=${FLAGS/fpu/387}
          FLAGS=${FLAGS/387 sse/387 and sse (both)}
          menu radiolist "Select available Floating Point Math compile extensions. The kernel reports that this system has: $FLAGS." &&
          FPM=$RESULT
        ;;
        xtra)
          unset OPTIONS
          case $PLATFORM in
            x86|x86_64)
              if grep -qw mmx /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "MMX" "MMX" $( echo ${XTRA[@]} | grep -q "MMX" && echo "on" || echo "off" ) "Multi-Media instruction code eXtensions"
                  )
              fi
              if grep -qw sse /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "SSE" "SSE" $( echo ${XTRA[@]} | grep -q "SSE" && echo "on" || echo "off" ) "Streaming SIMD (Single Instruction, Multiple Data) Extensions"
                  )
              fi
              if grep -qw sse2 /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "SSE2" "SSE2" $( echo ${XTRA[@]} | grep -q "SSE2" && echo "on" || echo "off" ) "Streaming SIMD (Single Instruction, Multiple Data) Extensions v2"
                  )
              fi
              if grep -qw pni /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "SSE3" "SSE3" $( echo ${XTRA[@]} | grep -q "SSE3" && echo "on" || echo "off" ) "Streaming SIMD (Single Instruction, Multiple Data) Extensions v3"
                  )
              fi
              if grep -qw ssse3 /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "SSSE3" "SSSE3" $( echo ${XTRA[@]} | grep -q "SSSE3" && echo "on" || echo "off" ) "Supplemental Streaming SIMD (Single Instruction, Multiple Data) Extensions v3"
                  )
              fi
              if grep -qw sse4_1 /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "SSE4.1" "SSE4.1" $( echo ${XTRA[@]} | grep -q "SSE4.1" && echo "on" || echo "off" ) "Streaming SIMD (Single Instruction, Multiple Data) Extensions v4 part 1"
                  )
              fi
              if grep -qw sse4_2 /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "SSE4.2" "SSE4.2" $( echo ${XTRA[@]} | grep -q "SSE4.2" && echo "on" || echo "off" ) "Streaming SIMD (Single Instruction, Multiple Data) Extensions v4 part 2"
                  )
              fi
              if grep -qw sse4_1\ sse4_2 /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "SSE4" "SSE4" $( echo ${XTRA[@]} | grep -q "SSE4" && echo "on" || echo "off" ) "Streaming SIMD (Single Instruction, Multiple Data) Extensions v4 full: part 1 + part 2"
                  )
              fi
              if grep -qw 3dnow /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "3dnow" "3dnow" $( echo ${XTRA[@]} | grep -q "3dnow" && echo "on" || echo "off" ) "3dnow"
                  )
              fi
              if grep -qw popcnt /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "popcnt" "popcnt" $( echo ${XTRA[@]} | grep -q "popcnt" && echo "on" || echo "off" ) "population count mnemonic"
                  )
              fi
              if grep -qw sse4a /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "SSE4A" "SSE4A" $( echo ${XTRA[@]} | grep -q "SSE4A" && echo "on" || echo "off" ) "AMD Streaming SIMD (Single Instruction, Multiple Data) Extensions v4"
                  )
              fi
              if grep -qw avx /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "AVX" "AVX" $( echo ${XTRA[@]} | grep -q "AVX" && echo "on" || echo "off" ) "AVX - Advanced Vector eXtensions (Extended SSE registers)"
                  )
              fi
				  # abm consists of popcnt and lzcnt, but we handle popcnt separately and lzcnt does not have its own flag
              if grep -qw abm /proc/cpuinfo; then
                OPTIONS=(
                  ${OPTIONS[@]}
                  "LZCNT" "LZCNT" $( echo ${XTRA[@]} | grep -q "LZCNT" && echo "on" || echo "off" ) "leading-zero count (together with popcnt it constitutes ABM)"
                  )
              fi
            ;;
            PowerPC)
              if grep -qw altivec /proc/cpuinfo; then
                OPTIONS=(
                  "Altivec" "Altivec" $( echo ${XTRA[@]} | grep -q "Altivec" && echo "on" || echo "off" ) "Altivec"
                  )
              fi
            ;;
          esac
          unset FLAGS
          for EXT in mmx sse sse2 pni 3dnow altivec popcnt sse4a abm ssse3 sse4_1 sse4_2 sse4_1\ sse4_2; do
            if grep -qw "$EXT" /proc/cpuinfo ; then
              echo $EXT
              FLAGS="$FLAGS $EXT"
            fi
          done
          FLAGS=${FLAGS/pni/sse3}
          FLAGS=${FLAGS/sse4_1\ sse4_2/sse4}
          menu checklist "Select compiler use of extra instruction sets. The kernel reports that this system has: $FLAGS. None of these are safe." &&
          XTRA=($RESULT)
        ;;
        cc_opt)
          OPTIONS=(
            "Deprecated" "-Wno-deprecated for C++" $( echo ${CC_OPTS[@]} | grep -qw "Deprecated" && echo "on" || echo "off" ) "Disable warnings of deprecated symbols in C++"
            "Debug" "-g" $( echo ${CC_OPTS[@]} | grep -qw "Debug" && echo "on" || echo "off" ) "Add debug symbols"
            "Pipe" "-pipe (RECOMMENDED)" $( echo ${CC_OPTS[@]} | grep -qw "Pipe" && echo "on" || echo "off" ) "Enable cc to use named pipes."
            "Fortify" "-Wp,-D_FORTIFY_SOURCE=2" $( echo ${CC_OPTS[@]} | grep -qw "Fortify" && echo "on" || echo "off" ) "Stack protector checking (run-time buffer overflow detection )"
            "ClashProtection" "-fstack-clash-protection" $( echo ${CC_OPTS[@]} | grep -q "ClashProtection" && echo "on" || echo "off" ) "Increased reliability of stack overflow detection."
            )
          if [ "$SAFE_OPTIMIZATIONS" == "off" ]; then
          OPTIONS+=(
            "StackProt" "-fstack-protector" $( echo ${CC_OPTS[@]} | grep -qw "StackProt" && echo "on" || echo "off" ) "Gcc Stack protector checking (UNSAFE)"
            "StackProtStrong" "-fstack-protector-strong" $( echo ${CC_OPTS[@]} | grep -qw "StackProtStrong" && echo "on" || echo "off" ) "Stack smashing protector"
            "ControlFlowProt" "-fcf-protection" $( echo ${CC_OPTS[@]} | grep -qw "ControlFlowProt" && echo "on" || echo "off" ) "Control flow integrity protection"
            "MindirectBranchThunk" "-mindirect-branch=thunk" $( echo ${CC_OPTS[@]} | grep -qw "MindirectBranchThunk" && echo "on" || echo "off" ) "Spectre V2 mitigation - creates retpoline for indirect calls"
            "MfunctionReturnThunk" "-mfunction-return=thunk" $( echo ${CC_OPTS[@]} | grep -qw "MfunctionReturnThunk" && echo "on" || echo "off" ) "Spectre V2 mitigation - use retpolines for every function return (for CPU that predicts return)"
            "MindirectBranchRegister" "-mindirect-branch-register" $( echo ${CC_OPTS[@]} | grep -qw "MindirectBranchRegister" && echo "on" || echo "off" ) "Spectre V2 mitigation - use register instead of stack to store address of indirect call"
            )
          fi
          menu checklist "General C/C++ compiler settings" &&
          CC_OPTS=($RESULT)
        ;;
      esac
  done

  save_optimizations
}


plugin_register BUILD_BUILD plugin_compiler_gcc_optimize
plugin_register OPTIMIZE_MENU plugin_compiler_gcc_menu
