# Determine the host CPU feature set and determine the best set of compiler
# flags to enable all supported SIMD relevant features. Alternatively, the
# target CPU can be explicitly selected (for generating more generic binaries
# or for targeting a different system).
# Compilers provide e.g. the -march=native flag to achieve a similar result.
# This fails to address the need for building for a different microarchitecture
# than the current host.
# The script tries to deduce all settings from the model and family numbers of
# the CPU instead of reading the CPUID flags from e.g. /proc/cpuinfo. This makes
# the detection more independent from the CPUID code in the kernel (e.g. avx2 is
# not listed on older kernels).
#
# Usage:
# OptimizeForArchitecture()
#
# Optional inputs:
# TARGET_ARCHITECTURE=<name> specifies the target architecture (default=auto)
# TARGET_PROFILER=<name>     specifies the target profiler     (default=none)
#
# If any of these flags are defined and set, the OptimizeForArchitecture
# macro will consequently disable the relevant features via compiler flags.
#
# For x86_64/x68:
# OFA_AVX512_INTRINSICS_BROKEN
# OFA_AVX2_INTRINSICS_BROKEN
# OFA_AVX_INTRINSICS_BROKEN
# OFA_FMA4_INTRINSICS_BROKEN
# OFA_SSE_INTRINSICS_BROKEN
# OFA_XOP_INTRINSICS_BROKEN
#
# For ARM:
# no options defined yet
#
# For PPC64:
# no options defined yet
#
# Output:
# OFA_ARCHITECTURE_FLAGS compiler flags optimized for the target architecture

#=============================================================================
# Copyright 2010-2016 Matthias Kretz <kretz@kde.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#  * Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
#  * Neither the names of contributing organizations nor the
#    names of its contributors may be used to endorse or promote products
#    derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================

#=============================================================================
# Extension of the original version by Matthias Moller <m.moller@tudelft.nl>
#
# Changelog:
# - Update of CPUIDs for latest Intel and AMD processors
# - Support for PPC64 (Clang, GCC, IBM XLC)
# - Support for ARM (Clang, GCC, ARM Clang)
#=============================================================================

get_filename_component(_currentDir "${CMAKE_CURRENT_LIST_FILE}" PATH)
include("${_currentDir}/AddCompilerFlag.cmake")
include(CheckIncludeFileCXX)

macro(_my_find _list _value _ret)
  list(FIND ${_list} "${_value}" _found)
  if(_found EQUAL -1)
    set(${_ret} FALSE)
  else()
    set(${_ret} TRUE)
  endif()
endmacro(_my_find)

macro(OFA_AutodetectX86)
  set(_vendor_id)
  set(_cpu_family)
  set(_cpu_model)
  set(_cpu_stepping)
  if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
    file(READ "/proc/cpuinfo" _cpuinfo)
    string(REGEX REPLACE ".*vendor_id[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*" "\\1" _vendor_id "${_cpuinfo}")
    string(REGEX REPLACE ".*cpu family[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*" "\\1" _cpu_family "${_cpuinfo}")
    string(REGEX REPLACE ".*model[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*" "\\1" _cpu_model "${_cpuinfo}")
    string(REGEX REPLACE ".*stepping[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*" "\\1" _cpu_stepping "${_cpuinfo}")
    string(REGEX REPLACE ".*flags[ \t]*:[ \t]+([^\n]+).*" "\\1" _cpu_flags "${_cpuinfo}")
  elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
    exec_program("/usr/sbin/sysctl -n machdep.cpu.vendor machdep.cpu.family machdep.cpu.model machdep.cpu.stepping machdep.cpu.features" OUTPUT_VARIABLE _sysctl_output_string)
    string(REPLACE "\n" ";" _sysctl_output ${_sysctl_output_string})
    list(GET _sysctl_output 0 _vendor_id)
    list(GET _sysctl_output 1 _cpu_family)
    list(GET _sysctl_output 2 _cpu_model)
    list(GET _sysctl_output 3 _cpu_stepping)
    list(GET _sysctl_output 4 _cpu_flags)
    string(TOLOWER "${_cpu_flags}" _cpu_flags)
    string(REPLACE "." "_" _cpu_flags "${_cpu_flags}")
  elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
    get_filename_component(_vendor_id "[HKEY_LOCAL_MACHINE\\Hardware\\Description\\System\\CentralProcessor\\0;VendorIdentifier]" NAME CACHE)
    get_filename_component(_cpu_id "[HKEY_LOCAL_MACHINE\\Hardware\\Description\\System\\CentralProcessor\\0;Identifier]" NAME CACHE)
    mark_as_advanced(_vendor_id _cpu_id)
    string(REGEX REPLACE ".* Family ([0-9]+) .*" "\\1" _cpu_family "${_cpu_id}")
    string(REGEX REPLACE ".* Model ([0-9]+) .*" "\\1" _cpu_model "${_cpu_id}")
    string(REGEX REPLACE ".* Stepping ([0-9]+) .*" "\\1" _cpu_mstepping "${_cpu_id}")
  endif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
  if(_vendor_id STREQUAL "GenuineIntel")
    if(_cpu_family EQUAL 6)
      # taken from the Intel ORM
      # http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html
      # CPUID Signature Values of Of Recent Intel Microarchitectures
      # 4E 5E       | Skylake microarchitecture
      # 3D 47 56    | Broadwell microarchitecture
      # 3C 45 46 3F | Haswell microarchitecture
      # 3A 3E       | Ivy Bridge microarchitecture
      # 2A 2D       | Sandy Bridge microarchitecture
      # 25 2C 2F    | Intel microarchitecture Westmere
      # 1A 1E 1F 2E | Intel microarchitecture Nehalem
      # 17 1D       | Enhanced Intel Core microarchitecture
      # 0F          | Intel Core microarchitecture
      #
      # Intel SDM Vol. 3C 35-1 / December 2016:
      # 57          | Xeon Phi 3200, 5200, 7200  [Knights Landing]
      # 85          | Future Xeon Phi
      # 8E 9E       | 7th gen. Core              [Kaby Lake]
      # 55          | Future Xeon                [Skylake w/ AVX512]
      # 4E 5E       | 6th gen. Core / E3 v5      [Skylake w/o AVX512]
      # 56          | Xeon D-1500                [Broadwell]
      # 4F          | Xeon E5 v4, E7 v4, i7-69xx [Broadwell]
      # 47          | 5th gen. Core / Xeon E3 v4 [Broadwell]
      # 3D          | M-5xxx / 5th gen.          [Broadwell]
      # 3F          | Xeon E5 v3, E7 v3, i7-59xx [Haswell-E]
      # 3C 45 46    | 4th gen. Core, Xeon E3 v3  [Haswell]
      # 3E          | Xeon E5 v2, E7 v2, i7-49xx [Ivy Bridge-E]
      # 3A          | 3rd gen. Core, Xeon E3 v2  [Ivy Bridge]
      # 2D          | Xeon E5, i7-39xx           [Sandy Bridge]
      # 2F          | Xeon E7
      # 2A          | Xeon E3, 2nd gen. Core     [Sandy Bridge]
      # 2E          | Xeon 7500, 6500 series
      # 25 2C       | Xeon 3600, 5600 series, Core i7, i5 and i3
      #
      # Values from the Intel SDE:
      # 5C | Goldmont
      # 5A | Silvermont
      # 57 | Knights Landing
      # 66 | Cannonlake
      # 55 | Skylake Server
      # 4E | Skylake Client
      # 3C | Broadwell (likely a bug in the SDE)
      # 3C | Haswell
      #
      # Latest updates taken from https://en.wikichip.org/wiki/intel/cpuid
      if(_cpu_model EQUAL 133) # 85
        set(TARGET_ARCHITECTURE "knm")  # Knights Mill

      elseif(_cpu_model EQUAL 87) # 57
        set(TARGET_ARCHITECTURE "knl")  # Knights Landing

      elseif(_cpu_model EQUAL 134)
        set(TARGET_ARCHITECTURE "tremont")

      elseif(_cpu_model EQUAL 122)
        set(TARGET_ARCHITECTURE "goldmont-plus")

      elseif(_cpu_model EQUAL 92 OR _cpu_model EQUAL 95)
        set(TARGET_ARCHITECTURE "goldmont")

      elseif(_cpu_model EQUAL 90 OR _cpu_model EQUAL 93 OR _cpu_model EQUAL 74 OR _cpu_model EQUAL 76 OR _cpu_model EQUAL 77 OR _cpu_model EQUAL 55)
        set(TARGET_ARCHITECTURE "silvermont")

      elseif(_cpu_model EQUAL 28 OR _cpu_model EQUAL 38 OR _cpu_model EQUAL 39 OR _cpu_model EQUAL 53 OR _cpu_model EQUAL 54)
        set(TARGET_ARCHITECTURE "bonnell")

        #         elseif(_cpu_model EQUAL X)
        #            set(TARGET_ARCHITECTURE "sapphirerapids")

        #         elseif(_cpu_model EQUAL X)
        #            set(TARGET_ARCHITECTURE "alderlake")

      elseif(_cpu_model EQUAL 140)
        set(TARGET_ARCHITECTURE "tigerlake")

      elseif(_cpu_model EQUAL 106 OR _cpu_model EQUAL 108)
        set(TARGET_ARCHITECTURE "icelake-avx512")

      elseif(_cpu_model EQUAL 125 OR _cpu_model EQUAL 126)
        set(TARGET_ARCHITECTURE "icelake")

      elseif(_cpu_model EQUAL 102)
        set(TARGET_ARCHITECTURE "cannonlake")

      elseif(_cpu_model EQUAL 142 OR _cpu_model EQUAL 158 OR _cpu_model EQUAL 165) # 8E, 9E
        set(TARGET_ARCHITECTURE "kabylake")

      elseif(_cpu_model EQUAL 85) # 55
        if(_cpu_stepping LESS 5)
          set(TARGET_ARCHITECTURE "skylake-avx512")
        elseif(_cpu_stepping LESS 8)
          set(TARGET_ARCHITECTURE "cascadelake")
        else()
          set(TARGET_ARCHITECTURE "cooperlake")
        endif()

      elseif(_cpu_model EQUAL 78 OR _cpu_model EQUAL 94) # 4E, 5E
        set(TARGET_ARCHITECTURE "skylake")

      elseif(_cpu_model EQUAL 61 OR _cpu_model EQUAL 71 OR _cpu_model EQUAL 79 OR _cpu_model EQUAL 86) # 3D, 47, 4F, 56
        set(TARGET_ARCHITECTURE "broadwell")

      elseif(_cpu_model EQUAL 60 OR _cpu_model EQUAL 69 OR _cpu_model EQUAL 70 OR _cpu_model EQUAL 63)
        set(TARGET_ARCHITECTURE "haswell")

      elseif(_cpu_model EQUAL 58 OR _cpu_model EQUAL 62)
        set(TARGET_ARCHITECTURE "ivybridge")

      elseif(_cpu_model EQUAL 42 OR _cpu_model EQUAL 45)
        set(TARGET_ARCHITECTURE "sandybridge")

      elseif(_cpu_model EQUAL 37 OR _cpu_model EQUAL 44 OR _cpu_model EQUAL 47)
        set(TARGET_ARCHITECTURE "westmere")

      elseif(_cpu_model EQUAL 26 OR _cpu_model EQUAL 30 OR _cpu_model EQUAL 31 OR _cpu_model EQUAL 46)
        set(TARGET_ARCHITECTURE "nehalem")

      elseif(_cpu_model EQUAL 23 OR _cpu_model EQUAL 29)
        set(TARGET_ARCHITECTURE "penryn")

      elseif(_cpu_model EQUAL 15 OR _cpu_model EQUAL 22)
        set(TARGET_ARCHITECTURE "merom")

      elseif(_cpu_model EQUAL 28)
        set(TARGET_ARCHITECTURE "atom")

      elseif(_cpu_model EQUAL 14)
        set(TARGET_ARCHITECTURE "core")

      elseif(_cpu_model LESS 14)
        message(WARNING "Your CPU (family ${_cpu_family}, model ${_cpu_model}) is not known. Auto-detection of optimization flags failed and will use the generic CPU settings with SSE2.")
        set(TARGET_ARCHITECTURE "generic")
      else()
        message(WARNING "Your CPU (family ${_cpu_family}, model ${_cpu_model}) is not known. Auto-detection of optimization flags failed and will use the 65nm Core 2 CPU settings.")
        set(TARGET_ARCHITECTURE "merom")
      endif()

    elseif(_cpu_family EQUAL 7) # Itanium (not supported)
      message(WARNING "Your CPU (Itanium: family ${_cpu_family}, model ${_cpu_model}) is not supported by OptimizeForArchitecture.cmake.")

    elseif(_cpu_family EQUAL 15) # NetBurst
      list(APPEND _available_vector_units_list "sse" "sse2")
      if(_cpu_model GREATER 2) # Not sure whether this must be 3 or even 4 instead
        list(APPEND _available_vector_units_list "sse" "sse2" "sse3")
      endif()

    endif()

  elseif(_vendor_id STREQUAL "AuthenticAMD")
    # taken from the list of AMD CPU microarchitectures
    # https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures
    # CPUID Signature Values of Of Recent AMD Microarchitectures
    # 05 05h      | K6
    # 06 06h      | K7
    # 15 0Fh      | K8 / Hammer
    # 16 10h      | K10
    # 17 11h      | K8 & K10 "hybrid"
    # 18 12h      | K10 (Llano) / K12 (ARM based AMD cpu)
    # 20 14h      | Bobcat
    # 21 15h      | Bulldozer / Piledriver / Steamroller / Excavator
    # 22 16h      | Jaguar / Puma
    # 23 17h      | Zen / Zen+ / Zen 2
    # 24 18h      | Hygon Dhyana
    # 25 19h      | Zen 3

    if(_cpu_family EQUAL 25) # 19h
      set(TARGET_ARCHITECTURE "zen3") # planned

    elseif(_cpu_family EQUAL 24) # 18h
      set(TARGET_ARCHITECTURE "zen")

    elseif(_cpu_family EQUAL 23) # 17h
      if(_cpu_model LESS 64)
        set(TARGET_ARCHITECTURE "zen")
      else()
        set(TARGET_ARCHITECTURE "zen2")
      endif()

    elseif(_cpu_family EQUAL 22) # 16h
      set(TARGET_ARCHITECTURE "amd16h")

    elseif(_cpu_family EQUAL 21) # 15h
      if(_cpu_model LESS 16)
        set(TARGET_ARCHITECTURE "bulldozer")
      elseif(_cpu_model LESS 32)
        set(TARGET_ARCHITECTURE "piledriver")
      elseif(_cpu_model LESS 64)
        set(TARGET_ARCHITECTURE "steamroller")
      else()
        set(TARGET_ARCHITECTURE "excavator")
      endif()

    elseif(_cpu_family EQUAL 20) # 14h
      set(TARGET_ARCHITECTURE "amd14h")

    elseif(_cpu_family EQUAL 18) # 12h (K10 / K12)

    elseif(_cpu_family EQUAL 17) # 12h (K8 & K10 hybrid)

    elseif(_cpu_family EQUAL 16) # 10h (K10)
      set(TARGET_ARCHITECTURE "barcelona")

    elseif(_cpu_family EQUAL 15) # 0Fh (K8 / Hammer)
      if(_cpu_model LESS 39)
        set(TARGET_ARCHITECTURE "k8")
      else()
        set(TARGET_ARCHITECTURE "k8-sse3")
      endif()

    elseif(_cpu_family EQUAL 6) # 06h (K7)
    elseif(_cpu_family EQUAL 5) # 05h (K6)

    endif()
  endif()
endmacro(OFA_AutodetectX86)

macro(OFA_AutodetectArm)
  set(_cpu_implementer)
  set(_cpu_architecture)
  set(_cpu_variant)
  set(_cpu_part)
  set(_cpu_revision)
  if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
    file(READ "/proc/cpuinfo" _cpuinfo)
    string(REGEX REPLACE ".*CPU implementer[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*" "\\1" _cpu_implementer "${_cpuinfo}")
    string(REGEX REPLACE ".*CPU architecture[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*" "\\1" _cpu_architecture "${_cpuinfo}")
    string(REGEX REPLACE ".*CPU variant[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*" "\\1" _cpu_variant "${_cpuinfo}")
    string(REGEX REPLACE ".*CPU part[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*" "\\1" _cpu_part "${_cpuinfo}")
    string(REGEX REPLACE ".*CPU revision[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*" "\\1" _cpu_revision "${_cpuinfo}")
    string(REGEX REPLACE ".*Features[ \t]*:[ \t]+([^\n]+).*" "\\1" _cpu_flags "${_cpuinfo}")
  elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
    exec_program("/usr/sbin/sysctl -n -n hw.cputype hw.cputype hw.cpusubtype hw.cpufamily hw.cpusubfamily" OUTPUT_VARIABLE _sysctl_output_string)
    string(REPLACE "\n" ";" _sysctl_output ${_sysctl_output_string})
    list(GET _sysctl_output 0 _cpu_implementer)
    list(GET _sysctl_output 1 _cpu_architecture)
    list(GET _sysctl_output 2 _cpu_variant)
    list(GET _sysctl_output 3 _cpu_part)
    list(GET _sysctl_output 4 _cpu_revision)
  elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  endif(CMAKE_SYSTEM_NAME STREQUAL "Linux")

  # Taken from https://github.com/karelzak/util-linux/blob/master/sys-utils/lscpu-arm.c
  # and https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
  if(_cpu_implementer STREQUAL "0x41")     # ARM
    if(_cpu_part STREQUAL "0x810")
      set(TARGET_ARCHITECTURE "arm810")
    elseif(_cpu_part STREQUAL "0x920")
      set(TARGET_ARCHITECTURE "arm920t")
    elseif(_cpu_part STREQUAL "0x922")
      set(TARGET_ARCHITECTURE "arm922t")
    elseif(_cpu_part STREQUAL "0x926")
      set(TARGET_ARCHITECTURE "arm926ej-s")
    elseif(_cpu_part STREQUAL "0x940")
      set(TARGET_ARCHITECTURE "arm940t")
    elseif(_cpu_part STREQUAL "0x946")
      set(TARGET_ARCHITECTURE "arm946e-s")
    elseif(_cpu_part STREQUAL "0x966")
      set(TARGET_ARCHITECTURE "arm966e-s")
    elseif(_cpu_part STREQUAL "0xa20")
      set(TARGET_ARCHITECTURE "arm1020e")
    elseif(_cpu_part STREQUAL "0xa22")
      set(TARGET_ARCHITECTURE "arm1022e")
    elseif(_cpu_part STREQUAL "0xa26")
      set(TARGET_ARCHITECTURE "arm1026ej-s")
    elseif(_cpu_part STREQUAL "0xb02")
      set(TARGET_ARCHITECTURE "mpcore")
    elseif(_cpu_part STREQUAL "0xb36")
      set(TARGET_ARCHITECTURE "arm1136jf-s")
    elseif(_cpu_part STREQUAL "0xb56")
      set(TARGET_ARCHITECTURE "arm1156t2f-s")
    elseif(_cpu_part STREQUAL "0xb76")
      set(TARGET_ARCHITECTURE "arm1176jzf-s")
    elseif(_cpu_part STREQUAL "0xc05")
      set(TARGET_ARCHITECTURE "cortex-a5")
    elseif(_cpu_part STREQUAL "0xc07")
      set(TARGET_ARCHITECTURE "cortex-a7")
    elseif(_cpu_part STREQUAL "0xc08")
      set(TARGET_ARCHITECTURE "cortex-a8")
    elseif(_cpu_part STREQUAL "0xc09")
      set(TARGET_ARCHITECTURE "cortex-a9")
    elseif(_cpu_part STREQUAL "0xc0d")
      set(TARGET_ARCHITECTURE "cortex-a12")
    elseif(_cpu_part STREQUAL "0xc0f")
      set(TARGET_ARCHITECTURE "cortex-a15")
    elseif(_cpu_part STREQUAL "0xc0e")
      set(TARGET_ARCHITECTURE "cortex-a17")
    elseif(_cpu_part STREQUAL "0xc14")
      set(TARGET_ARCHITECTURE "cortex-r4f")
    elseif(_cpu_part STREQUAL "0xc15")
      set(TARGET_ARCHITECTURE "cortex-r5")
    elseif(_cpu_part STREQUAL "0xc17")
      set(TARGET_ARCHITECTURE "cortex-r7")
    elseif(_cpu_part STREQUAL "0xc18")
      set(TARGET_ARCHITECTURE "cortex-r8")
    elseif(_cpu_part STREQUAL "0xc20")
      set(TARGET_ARCHITECTURE "cortex-m0")
    elseif(_cpu_part STREQUAL "0xc21")
      set(TARGET_ARCHITECTURE "cortex-m1")
    elseif(_cpu_part STREQUAL "0xc23")
      set(TARGET_ARCHITECTURE "cortex-m3")
    elseif(_cpu_part STREQUAL "0xc24")
      set(TARGET_ARCHITECTURE "cortex-m4")
    elseif(_cpu_part STREQUAL "0xc27")
      set(TARGET_ARCHITECTURE "cortex-m7")
    elseif(_cpu_part STREQUAL "0xc60")
      set(TARGET_ARCHITECTURE "cortex-m0plus")
    elseif(_cpu_part STREQUAL "0xd01")
      set(TARGET_ARCHITECTURE "cortex-a32")
    elseif(_cpu_part STREQUAL "0xd02")
      set(TARGET_ARCHITECTURE "cortex-a34")
    elseif(_cpu_part STREQUAL "0xd03")
      set(TARGET_ARCHITECTURE "cortex-a53")
    elseif(_cpu_part STREQUAL "0xd04")
      set(TARGET_ARCHITECTURE "cortex-a35")
    elseif(_cpu_part STREQUAL "0xd05")
      set(TARGET_ARCHITECTURE "cortex-a55")
    elseif(_cpu_part STREQUAL "0xd07")
      set(TARGET_ARCHITECTURE "cortex-a57")
    elseif(_cpu_part STREQUAL "0xd08")
      set(TARGET_ARCHITECTURE "cortex-a72")
    elseif(_cpu_part STREQUAL "0xd09")
      set(TARGET_ARCHITECTURE "cortex-a73")
    elseif(_cpu_part STREQUAL "0xd0a")
      set(TARGET_ARCHITECTURE "cortex-a75")
    elseif(_cpu_part STREQUAL "0xd0b")
      set(TARGET_ARCHITECTURE "cortex-a76")
    elseif(_cpu_part STREQUAL "0xd0c")
      set(TARGET_ARCHITECTURE "neoverse-n1")
    elseif(_cpu_part STREQUAL "0xd0d")
      set(TARGET_ARCHITECTURE "cortex-a77")
    elseif(_cpu_part STREQUAL "0xd0e")
      set(TARGET_ARCHITECTURE "cortex-a76ae")
    elseif(_cpu_part STREQUAL "0xd13")
      set(TARGET_ARCHITECTURE "cortex-r52")
    elseif(_cpu_part STREQUAL "0xd20")
      set(TARGET_ARCHITECTURE "cortex-m23")
    elseif(_cpu_part STREQUAL "0xd21")
      set(TARGET_ARCHITECTURE "cortex-m33")
    elseif(_cpu_part STREQUAL "0xd4a")
      set(TARGET_ARCHITECTURE "neoverse-e1")
    endif()

  elseif(_cpu_implementer STREQUAL "0x42") # Broadcom
    if(_cpu_part STREQUAL "0x0f")
      set(TARGET_ARCHITECTURE "brahma-b15")
    elseif(_cpu_part STREQUAL "0x100")
      set(TARGET_ARCHITECTURE "brahma-b53")
    elseif(_cpu_part STREQUAL "0x516")
      set(TARGET_ARCHITECTURE "thunderx2")
    endif()

  elseif(_cpu_implementer STREQUAL "0x43") # Cavium
    if(_cpu_part STREQUAL "0x0a0")
      set(TARGET_ARCHITECTURE "thunderx")
    elseif(_cpu_part STREQUAL "0x0a1")
      set(TARGET_ARCHITECTURE "thunderxt88")
    elseif(_cpu_part STREQUAL "0x0a2")
      set(TARGET_ARCHITECTURE "thunderxt81")
    elseif(_cpu_part STREQUAL "0x0a3")
      set(TARGET_ARCHITECTURE "thunderxt83")
    elseif(_cpu_part STREQUAL "0x0af")
      set(TARGET_ARCHITECTURE "thunderx2t99")
    endif()

  elseif(_cpu_implementer STREQUAL "0x44") # DEC
    if(_cpu_part STREQUAL "0xa10")
      set(TARGET_ARCHITECTURE "strongarm110")
    elseif(_cpu_part STREQUAL "0xa11")
      set(TARGET_ARCHITECTURE "strongarm1100")
    endif()

  elseif(_cpu_implementer STREQUAL "0x46") # FUJITSU
    if(_cpu_part STREQUAL "0x001")
      set(TARGET_ARCHITECTURE "a64fx")
    endif()

  elseif(_cpu_implementer STREQUAL "0x48") # HiSilicon
    if(_cpu_part STREQUAL "0xd01")
      set(TARGET_ARCHITECTURE "tsv110")
    endif()

  elseif(_cpu_implementer STREQUAL "0x4e") # Nvidia
    if(_cpu_part STREQUAL "0x000")
      set(TARGET_ARCHITECTURE "denver")
    elseif(_cpu_part STREQUAL "0x003")
      set(TARGET_ARCHITECTURE "denver2")
    elseif(_cpu_part STREQUAL "0x004")
      set(TARGET_ARCHITECTURE "carmel")
    endif()

  elseif(_cpu_implementer STREQUAL "0x50") # APM
    if(_cpu_part STREQUAL "0x000")
      set(TARGET_ARCHITECTURE "xgene1")
    endif()

  elseif(_cpu_implementer STREQUAL "0x51") # Qualcomm
    if(_cpu_part STREQUAL "0x00f")
      set(TARGET_ARCHITECTURE "scorpion")
    elseif(_cpu_part STREQUAL "0x02d")
      set(TARGET_ARCHITECTURE "scorpion")
    elseif(_cpu_part STREQUAL "0x04d")
      set(TARGET_ARCHITECTURE "krait")
    elseif(_cpu_part STREQUAL "0x06f")
      set(TARGET_ARCHITECTURE "krait")
    elseif(_cpu_part STREQUAL "0x201")
      set(TARGET_ARCHITECTURE "kryo")
    elseif(_cpu_part STREQUAL "0x205")
      set(TARGET_ARCHITECTURE "kryo")
    elseif(_cpu_part STREQUAL "0x211")
      set(TARGET_ARCHITECTURE "kryo")
    elseif(_cpu_part STREQUAL "0x800")
      set(TARGET_ARCHITECTURE "falkor")
    elseif(_cpu_part STREQUAL "0x801")
      set(TARGET_ARCHITECTURE "kryo2")
    elseif(_cpu_part STREQUAL "0xc00")
      set(TARGET_ARCHITECTURE "falkor")
    elseif(_cpu_part STREQUAL "0xc01")
      set(TARGET_ARCHITECTURE "saphira")
    endif()

  elseif(_cpu_implementer STREQUAL "0x53") # Samsung
    if(_cpu_part STREQUAL "0x001")
      set(TARGET_ARCHITECTURE "exynos-m1")
    endif()

  elseif(_cpu_implementer STREQUAL "0x56") # Marvell
    if(_cpu_part STREQUAL "0x131")
      set(TARGET_ARCHITECTURE "marvell-f")
    elseif(_cpu_part STREQUAL "0x581")
      set(TARGET_ARCHITECTURE "marvell-pj4")
    elseif(_cpu_part STREQUAL "0x584")
      set(TARGET_ARCHITECTURE "marvell-pj4")
    endif()

  elseif(_cpu_implementer STREQUAL "0x66") # Faraday
    if(_cpu_part STREQUAL "0x526")
      set(TARGET_ARCHITECTURE "fa526")
    elseif(_cpu_part STREQUAL "0x626")
      set(TARGET_ARCHITECTURE "fa626")
    endif()

  elseif(_cpu_implementer STREQUAL "0x69") # Intel
    if(_cpu_part STREQUAL "0x200")
      set(TARGET_ARCHITECTURE "i80200")
    elseif(_cpu_part STREQUAL "0x210")
      set(TARGET_ARCHITECTURE "pxa250a")
    elseif(_cpu_part STREQUAL "0x212")
      set(TARGET_ARCHITECTURE "pxa210a")
    elseif(_cpu_part STREQUAL "0x242")
      set(TARGET_ARCHITECTURE "i80321-400")
    elseif(_cpu_part STREQUAL "0x243")
      set(TARGET_ARCHITECTURE "i80321-600")
    elseif(_cpu_part STREQUAL "0x290")
      set(TARGET_ARCHITECTURE "pxa250b")
    elseif(_cpu_part STREQUAL "0x292")
      set(TARGET_ARCHITECTURE "pxa210b")
    elseif(_cpu_part STREQUAL "0x2c2")
      set(TARGET_ARCHITECTURE "i80321-400-b0")
    elseif(_cpu_part STREQUAL "0x2c3")
      set(TARGET_ARCHITECTURE "i80321-600-b0")
    elseif(_cpu_part STREQUAL "0x2d0")
      set(TARGET_ARCHITECTURE "pxa250c")
    elseif(_cpu_part STREQUAL "0x2d2")
      set(TARGET_ARCHITECTURE "pxa210c")
    elseif(_cpu_part STREQUAL "0x411")
      set(TARGET_ARCHITECTURE "pxa27x")
    elseif(_cpu_part STREQUAL "0x41c")
      set(TARGET_ARCHITECTURE "ipx425-533")
    elseif(_cpu_part STREQUAL "0x41d")
      set(TARGET_ARCHITECTURE "ipx425-400")
    elseif(_cpu_part STREQUAL "0x41f")
      set(TARGET_ARCHITECTURE "ipx425-266")
    elseif(_cpu_part STREQUAL "0x682")
      set(TARGET_ARCHITECTURE "pxa32x")
    elseif(_cpu_part STREQUAL "0x683")
      set(TARGET_ARCHITECTURE "pxa930")
    elseif(_cpu_part STREQUAL "0x688")
      set(TARGET_ARCHITECTURE "pxa30x")
    elseif(_cpu_part STREQUAL "0x689")
      set(TARGET_ARCHITECTURE "pxa31x")
    elseif(_cpu_part STREQUAL "0xb11")
      set(TARGET_ARCHITECTURE "sa1110")
    elseif(_cpu_part STREQUAL "0xc12")
      set(TARGET_ARCHITECTURE "ipx1200")
    endif()

    # Taken from /Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/mach/machine.h
  elseif(_cpu_implementer STREQUAL "16777228" OR _cpu_implementer STREQUAL "0x100000C")    # Apple ARM64
    if(_cpu_part STREQUAL "0x1e2d6381"     OR _cpu_part STREQUAL "506291073")              # Swift (A6)
      set(TARGET_ARCHITECTURE "apple-a6")
    elseif(_cpu_part STREQUAL "0x37a09642" OR _cpu_part STREQUAL "933271106")              # Cyclone (A7)
      set(TARGET_ARCHITECTURE "apple-a7")
    elseif(_cpu_part STREQUAL "0x2c91a47e" OR _cpu_part STREQUAL "747742334")              # Typhoon (A8)
      set(TARGET_ARCHITECTURE "apple-a8")
    elseif(_cpu_part STREQUAL "0x92fb37c8" OR _cpu_part STREQUAL "2465937352")             # Twister (A9)
      set(TARGET_ARCHITECTURE "apple-a9")
    elseif(_cpu_part STREQUAL "0x67ceee93" OR _cpu_part STREQUAL "1741614739")             # Hurrican (A10)
      set(TARGET_ARCHITECTURE "apple-a10")
    elseif(_cpu_part STREQUAL "0xe81e7ef6" OR _cpu_part STREQUAL "3894312694")             # Monsoon Mistral (A11)
      set(TARGET_ARCHITECTURE "apple-a11")
    elseif(_cpu_part STREQUAL "0x07d34b9f" OR _cpu_part STREQUAL "131287967")              # Vortex Tempest (A12)
      set(TARGET_ARCHITECTURE "apple-a12")
    elseif(_cpu_part STREQUAL "0x462504d2" OR _cpu_part STREQUAL "1176831186")             # Lightning Thunder (A13)
      set(TARGET_ARCHITECTURE "apple-a13")
    elseif(_cpu_part STREQUAL "0x1b588bb3" OR _cpu_part STREQUAL "458787763")              # Firestorm Icestorm (M1)
      set(TARGET_ARCHITECTURE "apple-m1")
    endif()
  endif()  
endmacro(OFA_AutodetectArm)

macro(OFA_AutodetectPpc)
  set(_cpu)

  if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
    file(READ "/proc/cpuinfo" _cpuinfo)
    string(REGEX REPLACE ".*cpu[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*" "\\1" _cpu "${_cpuinfo}")
    if(_cpu STREQUAL "POWER8" OR _cpu STREQUAL "POWER8NVL")
      set(TARGET_ARCHITECTURE "power8")
    elseif(_cpu STREQUAL "POWER9" OR _cpu STREQUAL "POWER9NVL")
      set(TARGET_ARCHITECTURE "power9")
    elseif(_cpu STREQUAL "POWER10" OR _cpu STREQUAL "POWER10NVL")
      set(TARGET_ARCHITECTURE "power10")
    endif()
  elseif(CMAKE_SYSTEM_NAME STREQUAL "AIX")
  endif()
endmacro(OFA_AutodetectPpc)

macro(OFA_AutodetectHostArchitecture)
  set(TARGET_ARCHITECTURE "generic")
  set(OFA_ARCHITECTURE_FLAGS)
  if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "i686.*|i386.*|x86.*|amd64.*|x86_64.*|AMD64.*")
    OFA_AutodetectX86()
  elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "^(arm.*|ARM.*|aarch64.*|AARCH64.*)")
    OFA_AutodetectArm()
  elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "^(powerpc|ppc)64.*")
    OFA_AutodetectPpc()
  else()
    message(FATAL_ERROR "OptimizeForArchitecture.cmake does not implement support for CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}")
  endif()
endmacro(OFA_AutodetectHostArchitecture)

macro(OFA_HandleX86Options)
  set(_march_flag_list)
  set(_available_vector_units_list)
  macro(_nehalem)
    list(APPEND _march_flag_list "nehalem")
    list(APPEND _march_flag_list "corei7")
    list(APPEND _march_flag_list "core2")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3" "sse4.1" "sse4.2")
  endmacro()
  macro(_westmere)
    list(APPEND _march_flag_list "westmere")
    _nehalem()
  endmacro()
  macro(_sandybridge)
    list(APPEND _march_flag_list "sandybridge")
    list(APPEND _march_flag_list "corei7-avx")
    _westmere()
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3" "sse4.1" "sse4.2" "avx")
  endmacro()
  macro(_ivybridge)
    list(APPEND _march_flag_list "ivybridge")
    list(APPEND _march_flag_list "core-avx-i")
    _sandybridge()
    list(APPEND _available_vector_units_list "rdrnd" "f16c")
  endmacro()
  macro(_haswell)
    list(APPEND _march_flag_list "haswell")
    list(APPEND _march_flag_list "core-avx2")
    _ivybridge()
    list(APPEND _available_vector_units_list "avx2" "fma" "bmi" "bmi2")
  endmacro()
  macro(_broadwell)
    list(APPEND _march_flag_list "broadwell")
    _haswell()
    list(APPEND _available_vector_units_list "rdseed")
  endmacro()
  macro(_skylake)
    list(APPEND _march_flag_list "skylake")
    _broadwell()
  endmacro()
  macro(_skylake_avx512)
    list(APPEND _march_flag_list "skylake-avx512")
    _skylake()
    list(APPEND _available_vector_units_list "avx512f" "avx512cd" "avx512dq" "avx512bw" "avx512vl")
  endmacro()
  macro(_cascadelake)
    list(APPEND _march_flag_list "cascadelake")
    _skylake_avx512()
    list(APPEND _available_vector_units_list "avx512vnni")
  endmacro()
  macro(_cooperlake)
    list(APPEND _march_flag_list "cooperlake")
    _skylake_avx512()
    list(APPEND _available_vector_units_list "avx512bf16" "avx512vnni")
  endmacro()
  macro(_cannonlake)
    list(APPEND _march_flag_list "cannonlake")
    _skylake_avx512()
    list(APPEND _available_vector_units_list "avx512ifma" "avx512vbmi")
  endmacro()
  macro(_icelake)
    list(APPEND _march_flag_list "icelake-client")
    _skylake_avx512()
    list(APPEND _available_vector_units_list "avx512bitalg" "avx512ifma" "avx512vbmi2" "avx512vbmi" "avx512vnni" "avx512vpopcntdq" "rdpid")
  endmacro()
  macro(_icelake_avx512)
    list(APPEND _march_flag_list "icelake-server")
    _skylake_avx512()
    list(APPEND _available_vector_units_list "avx512bitalg" "avx512ifma" "avx512vbmi2" "avx512vbmi" "avx512vnni" "avx512vpopcntdq" "rdpid")
  endmacro()
  macro(_tigerlake)
    list(APPEND _march_flag_list "tigerlake")
    _icelake()
    list(APPEND _available_vector_units_list "avx512vp2intersect")
  endmacro()
  macro(_alderlake)
    list(APPEND _march_flag_list "alderlake")
    _tigerlake()
  endmacro()
  macro(_sapphirerapids)
    list(APPEND _march_flag_list "sapphirerapids")
    _icelake_avx512()
  endmacro()
  macro(_knightslanding)
    list(APPEND _march_flag_list "knl")
    _broadwell()
    list(APPEND _available_vector_units_list "avx512f" "avx512pf" "avx512er" "avx512cd")
  endmacro()
  macro(_knightsmill)
    list(APPEND _march_flag_list "knm")
    _broadwell()
    list(APPEND _available_vector_units_list "avx512f" "avx512pf" "avx512er" "avx512cd" "avx5124fmaps" "avx5124vnni" "avx512vpopcntdq")
  endmacro()
  macro(_silvermont)
    list(APPEND _march_flag_list "silvermont")
    _westmere()
    list(APPEND _available_vector_units_list "rdrnd")
  endmacro()
  macro(_goldmont)
    list(APPEND _march_flag_list "goldmont")
    _silvermont()
    list(APPEND _available_vector_units_list "rdseed")
  endmacro()
  macro(_goldmont_plus)
    list(APPEND _march_flag_list "goldmont-plus")
    _goldmont()
    list(APPEND _available_vector_units_list "rdpid")
  endmacro()
  macro(_tremont)
    list(APPEND _march_flag_list "tremont")
    _goldmont_plus()
  endmacro()

  if(TARGET_ARCHITECTURE STREQUAL "core")
    list(APPEND _march_flag_list "core2")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3")
  elseif(TARGET_ARCHITECTURE STREQUAL "merom")
    list(APPEND _march_flag_list "merom")
    list(APPEND _march_flag_list "core2")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3")
  elseif(TARGET_ARCHITECTURE STREQUAL "penryn")
    list(APPEND _march_flag_list "penryn")
    list(APPEND _march_flag_list "core2")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3")
    message(STATUS "Sadly the Penryn architecture exists in variants with SSE4.1 and without SSE4.1.")
    if(_cpu_flags MATCHES "sse4_1")
      message(STATUS "SSE4.1: enabled (auto-detected from this computer's CPU flags)")
      list(APPEND _available_vector_units_list "sse4.1")
    else()
      message(STATUS "SSE4.1: disabled (auto-detected from this computer's CPU flags)")
    endif()
  elseif(TARGET_ARCHITECTURE STREQUAL "knm")
    _knightsmill()
  elseif(TARGET_ARCHITECTURE STREQUAL "knl")
    _knightslanding()
  elseif(TARGET_ARCHITECTURE STREQUAL "sapphirerapids")
    _sapphirerapids()
  elseif(TARGET_ARCHITECTURE STREQUAL "alderlake")
    _alderlake()
  elseif(TARGET_ARCHITECTURE STREQUAL "tigerlake")
    _tigerlake()
  elseif(TARGET_ARCHITECTURE STREQUAL "icelake")
    _icelake()
  elseif(TARGET_ARCHITECTURE STREQUAL "icelake-xeon" OR TARGET_ARCHITECTURE STREQUAL "icelake-avx512")
    _icelake_avx512()
  elseif(TARGET_ARCHITECTURE STREQUAL "cannonlake")
    _cannonlake()
  elseif(TARGET_ARCHITECTURE STREQUAL "cooperlake")
    _cooperlake()
  elseif(TARGET_ARCHITECTURE STREQUAL "cascadelake")
    _cascadelake()
  elseif(TARGET_ARCHITECTURE STREQUAL "kabylake")
    _skylake()
  elseif(TARGET_ARCHITECTURE STREQUAL "skylake-xeon" OR TARGET_ARCHITECTURE STREQUAL "skylake-avx512")
    _skylake_avx512()
  elseif(TARGET_ARCHITECTURE STREQUAL "skylake")
    _skylake()
  elseif(TARGET_ARCHITECTURE STREQUAL "broadwell")
    _broadwell()
  elseif(TARGET_ARCHITECTURE STREQUAL "haswell")
    _haswell()
  elseif(TARGET_ARCHITECTURE STREQUAL "ivybridge")
    _ivybridge()
  elseif(TARGET_ARCHITECTURE STREQUAL "sandybridge")
    _sandybridge()
  elseif(TARGET_ARCHITECTURE STREQUAL "westmere")
    _westmere()
  elseif(TARGET_ARCHITECTURE STREQUAL "nehalem")
    _nehalem()
  elseif(TARGET_ARCHITECTURE STREQUAL "tremont")
    _tremont()
  elseif(TARGET_ARCHITECTURE STREQUAL "goldmont-plus")
    _goldmont_plus()
  elseif(TARGET_ARCHITECTURE STREQUAL "goldmont")
    _goldmont()
  elseif(TARGET_ARCHITECTURE STREQUAL "silvermont")
    _silvermont()
  elseif(TARGET_ARCHITECTURE STREQUAL "bonnell")
    list(APPEND _march_flag_list "bonnell")
    list(APPEND _march_flag_list "atom")
    list(APPEND _march_flag_list "core2")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3")
  elseif(TARGET_ARCHITECTURE STREQUAL "atom")
    list(APPEND _march_flag_list "atom")
    list(APPEND _march_flag_list "core2")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3")
  elseif(TARGET_ARCHITECTURE STREQUAL "k8")
    list(APPEND _march_flag_list "k8")
    list(APPEND _available_vector_units_list "sse" "sse2")
  elseif(TARGET_ARCHITECTURE STREQUAL "k8-sse3")
    list(APPEND _march_flag_list "k8-sse3")
    list(APPEND _march_flag_list "k8")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3")
  elseif(TARGET_ARCHITECTURE STREQUAL "amd16h")
    list(APPEND _march_flag_list "btver2")
    list(APPEND _march_flag_list "btver1")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3" "sse4a" "sse4.1" "sse4.2" "avx" "f16c")
  elseif(TARGET_ARCHITECTURE STREQUAL "amd14h")
    list(APPEND _march_flag_list "btver1")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3" "sse4a")
  elseif(TARGET_ARCHITECTURE STREQUAL "zen3")
    list(APPEND _march_flag_list "znver2")
    list(APPEND _march_flag_list "znver1")
    _skylake()
    list(APPEND _available_vector_units_list "sse4a")
  elseif(TARGET_ARCHITECTURE STREQUAL "zen2")
    list(APPEND _march_flag_list "znver2")
    list(APPEND _march_flag_list "znver1")
    _skylake()
    list(APPEND _available_vector_units_list "sse4a")
  elseif(TARGET_ARCHITECTURE STREQUAL "zen")
    list(APPEND _march_flag_list "znver1")
    _skylake()
    list(APPEND _available_vector_units_list "sse4a")
  elseif(TARGET_ARCHITECTURE STREQUAL "excavator")
    list(APPEND _march_flag_list "bdver4")
    list(APPEND _march_flag_list "bdver3")
    list(APPEND _march_flag_list "bdver2")
    list(APPEND _march_flag_list "bdver1")
    list(APPEND _march_flag_list "bulldozer")
    list(APPEND _march_flag_list "barcelona")
    list(APPEND _march_flag_list "core2")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3" "sse4a" "sse4.1" "sse4.2" "avx" "avx2" "xop" "fma4" "fma" "f16c" "bmi" "bmi2" "rdrnd")
  elseif(TARGET_ARCHITECTURE STREQUAL "steamroller")
    list(APPEND _march_flag_list "bdver3")
    list(APPEND _march_flag_list "bdver2")
    list(APPEND _march_flag_list "bdver1")
    list(APPEND _march_flag_list "bulldozer")
    list(APPEND _march_flag_list "barcelona")
    list(APPEND _march_flag_list "core2")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3" "sse4a" "sse4.1" "sse4.2" "avx" "xop" "fma4" "fma" "f16c" "bmi")
  elseif(TARGET_ARCHITECTURE STREQUAL "piledriver")
    list(APPEND _march_flag_list "bdver2")
    list(APPEND _march_flag_list "bdver1")
    list(APPEND _march_flag_list "bulldozer")
    list(APPEND _march_flag_list "barcelona")
    list(APPEND _march_flag_list "core2")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3" "sse4a" "sse4.1" "sse4.2" "avx" "xop" "fma4" "fma" "f16c" "bmi")
  elseif(TARGET_ARCHITECTURE STREQUAL "interlagos")
    list(APPEND _march_flag_list "bdver1")
    list(APPEND _march_flag_list "bulldozer")
    list(APPEND _march_flag_list "barcelona")
    list(APPEND _march_flag_list "core2")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3" "sse4a" "sse4.1" "sse4.2" "avx" "xop" "fma4")
  elseif(TARGET_ARCHITECTURE STREQUAL "bulldozer")
    list(APPEND _march_flag_list "bdver1")
    list(APPEND _march_flag_list "bulldozer")
    list(APPEND _march_flag_list "barcelona")
    list(APPEND _march_flag_list "core2")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3" "sse4a" "sse4.1" "sse4.2" "avx" "xop" "fma4")
  elseif(TARGET_ARCHITECTURE STREQUAL "barcelona")
    list(APPEND _march_flag_list "barcelona")
    list(APPEND _march_flag_list "core2")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "sse4a")
  elseif(TARGET_ARCHITECTURE STREQUAL "istanbul")
    list(APPEND _march_flag_list "barcelona")
    list(APPEND _march_flag_list "core2")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "sse4a")
  elseif(TARGET_ARCHITECTURE STREQUAL "magny-cours")
    list(APPEND _march_flag_list "barcelona")
    list(APPEND _march_flag_list "core2")
    list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "sse4a")
  elseif(TARGET_ARCHITECTURE STREQUAL "generic")
    list(APPEND _march_flag_list "generic")
  elseif(TARGET_ARCHITECTURE STREQUAL "native")
    list(APPEND _march_flag_list "native")
  elseif(TARGET_ARCHITECTURE STREQUAL "none")
    # add this clause to remove it from the else clause
  else()
    message(FATAL_ERROR "Unknown target architecture: \"${TARGET_ARCHITECTURE}\". Please set TARGET_ARCHITECTURE to a supported value.")
  endif()

  if(TARGET_ARCHITECTURE STREQUAL "native")
    if(MSVC)
      message(FATAL_ERROR, "MSVC does not support \"native\" flag.")
    elseif(CMAKE_CXX_COMPILER MATCHES "/(icpc|icc)$")
      # ICC (on Linux)
      AddCompilerFlag("-xHOST" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
    elseif(CMAKE_CXX_COMPILER MATCHES "/(icl\\.exe)$")
      # ICC (on Windows)
      AddCompilerFlag("/QxHOST" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
    elseif(CMAKE_CXX_COMPILER MATCHES "/(pgcc|pgc\\+\\+)$")
      # PGI (on Linux)
      AddCompilerFlag("-tp=native" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
    elseif(CMAKE_CXX_COMPILER MATCHES "/(suncc|sunCC)$")
      # Sun/Oracle Studio (on Linux/Sun OS)
      AddCompilerFlag("-native" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
    else()
      AddCompilerFlag("-march=native" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
    endif()
  elseif(NOT TARGET_ARCHITECTURE STREQUAL "none")
    set(_disable_vector_unit_list)
    set(_enable_vector_unit_list)
    if(DEFINED OFA_SSE_INTRINSICS_BROKEN AND OFA_SSE_INTRINSICS_BROKEN)
      message(STATUS "SSE disabled because of old/broken toolchain")
      set(_sse_broken true)
      set(_avx_broken true)
      set(_avx2_broken true)
      set(_avx512_broken true)
      set(_fma4_broken true)
      set(_xop_broken true)
    elseif(DEFINED OFA_AVX_INTRINSICS_BROKEN AND OFA_AVX_INTRINSICS_BROKEN)
      message(STATUS "AVX disabled because of old/broken toolchain")
      set(_sse_broken false)
      set(_avx_broken true)
      set(_avx2_broken true)
      set(_avx512_broken true)
      set(_fma4_broken true)
      set(_xop_broken true)
    else()
      set(_sse_broken false)
      set(_avx_broken false)
      if(DEFINED OFA_FMA4_INTRINSICS_BROKEN AND OFA_FMA4_INTRINSICS_BROKEN)
        message(STATUS "FMA4 disabled because of old/broken toolchain")
        set(_fma4_broken true)
      else()
        set(_fma4_broken false)
      endif()
      if(DEFINED OFA_XOP_INTRINSICS_BROKEN AND OFA_XOP_INTRINSICS_BROKEN)
        message(STATUS "XOP disabled because of old/broken toolchain")
        set(_xop_broken true)
      else()
        set(_xop_broken false)
      endif()
      if(DEFINED OFA_AVX2_INTRINSICS_BROKEN AND OFA_AVX2_INTRINSICS_BROKEN)
        message(STATUS "AVX2 disabled because of old/broken toolchain")
        set(_avx2_broken true)
      else()
        set(_avx2_broken false)
      endif()
      if(DEFINED OFA_AVX512_INTRINSICS_BROKEN AND OFA_AVX512_INTRINSICS_BROKEN)
        message(STATUS "AVX512 disabled because of old/broken toolchain")
        set(_avx512_broken true)
      else()
        set(_avx512_broken false)
      endif()
    endif()

    macro(_enable_or_disable _name _flag _documentation _broken)
      if(_broken)
        set(_found false)
      else()
        _my_find(_available_vector_units_list "${_flag}" _found)
      endif()
      set(USE_${_name} ${_found} CACHE BOOL "${documentation}" ${_force})
      mark_as_advanced(USE_${_name})
      if(USE_${_name})
        list(APPEND _enable_vector_unit_list "${_flag}")
      else()
        list(APPEND _disable_vector_unit_list "${_flag}")
      endif()
    endmacro()
    _enable_or_disable(AVX "avx" "Use AVX. This will all floating-point vector sizes relative to SSE." _avx_broken)
    _enable_or_disable(AVX2 "avx2" "Use AVX2. This will double all of the vector sizes relative to SSE." _avx2_broken)
    _enable_or_disable(AVX512BF16 "avx512bf16" "Use AVX512BF16." _avx512_broken)
    _enable_or_disable(AVX512BITALG "avx512bitalg" "Use AVX512BITALG." _avx512_broken)
    _enable_or_disable(AVX512BW "avx512bw" "Use AVX512BW." _avx512_broken)
    _enable_or_disable(AVX512CD "avx512cd" "Use AVX512CD." _avx512_broken)
    _enable_or_disable(AVX512DQ "avx512dq" "Use AVX512DQ." _avx512_broken)
    _enable_or_disable(AVX512ER "avx512er" "Use AVX512ER. This enables exponential and reciprocal instructions." _avx512_broken)
    _enable_or_disable(AVX512F "avx512f" "Use AVX512F. This will double all floating-point vector sizes relative to AVX2." _avx512_broken)
    _enable_or_disable(AVX512IFMA "avx512ifma" "Use AVX512IFMA." _avx512_broken)
    _enable_or_disable(AVX512PF "avx512pf" "Use AVX512PF. This enables prefetch instructions for gathers and scatters." _avx512_broken)
    _enable_or_disable(AVX512VBMI "avx512vbmi" "Use AVX512VBMI." _avx512_broken)
    _enable_or_disable(AVX512VBMI2 "avx512vbmi2" "Use AVX512VBMI2." _avx512_broken)
    _enable_or_disable(AVX512VL "avx512vl" "Use AVX512VL. This enables 128- and 256-bit vector length instructions with EVEX coding (improved write-masking & more vector registers)." _avx2_broken)
    _enable_or_disable(AVX512VNNI "avx512vnni" "Use AVX512VNNI." _avx512_broken)
    _enable_or_disable(AVX512VP2INTERSECT "avx512vp2intersect" "Use AVX512VP2INTERSECT." _avx512_broken)
    _enable_or_disable(AVX512VPOPCNTDQ "avx512vpopcntdq" "Use AVX512VPOPCNTDQ." _avx512_broken)
    _enable_or_disable(BMI "bmi2" "Use BMI." _avx_broken)
    _enable_or_disable(BMI2 "bmi2" "Use BMI2." _avx_broken)
    _enable_or_disable(FMA "fma" "Use FMA." _avx_broken)
    _enable_or_disable(FMA4 "fma4" "Use FMA4." _fma4_broken)
    _enable_or_disable(SSE2 "sse2" "Use SSE2. If SSE2 instructions are not enabled the SSE implementation will be disabled." _sse_broken)
    _enable_or_disable(SSE3 "sse3" "Use SSE3. If SSE3 instructions are not enabled they will be emulated." _sse_broken)
    _enable_or_disable(SSE4_1 "sse4.1" "Use SSE4.1. If SSE4.1 instructions are not enabled they will be emulated." _sse_broken)
    _enable_or_disable(SSE4_2 "sse4.2" "Use SSE4.2. If SSE4.2 instructions are not enabled they will be emulated." _sse_broken)
    _enable_or_disable(SSE4a "sse4a" "Use SSE4a. If SSE4a instructions are not enabled they will be emulated." _sse_broken)
    _enable_or_disable(SSSE3 "ssse3" "Use SSSE3. If SSSE3 instructions are not enabled they will be emulated." _sse_broken)
    _enable_or_disable(XOP "xop" "Use XOP." _xop_broken)

    if(MSVC AND MSVC_VERSION GREATER 1700)
      # MSVC on 32 bit can select /arch:SSE2 (since 2010 also /arch:AVX)
      # MSVC on 64 bit cannot select anything (should have changed with MSVC 2010)
      _my_find(_enable_vector_unit_list "avx2" _found)
      if(_found)
        AddCompilerFlag("/arch:AVX2" CXX_FLAGS OFA_ARCHITECTURE_FLAGS CXX_RESULT _found)
      endif()
      if(NOT _found)
        _my_find(_enable_vector_unit_list "avx" _found)
        if(_found)
          AddCompilerFlag("/arch:AVX" CXX_FLAGS OFA_ARCHITECTURE_FLAGS CXX_RESULT _found)
        endif()
      endif()
      if(NOT _found)
        _my_find(_enable_vector_unit_list "sse2" _found)
        if(_found)
          AddCompilerFlag("/arch:SSE2" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
        endif()
      endif()
      foreach(_flag ${_enable_vector_unit_list})
        string(TOUPPER "${_flag}" _flag)
        string(REPLACE "." "_" _flag "__${_flag}__")
        add_definitions("-D${_flag}")
      endforeach(_flag)
    elseif(CMAKE_CXX_COMPILER MATCHES "/(icpc|icc)$") # ICC (on Linux)
      set(OFA_map_knl "-xMIC-AVX512")
      set(OFA_map_knm "-xMIC-AVX512")
      set(OFA_map_sapphirerapids "-xCORE-AVX512")
      set(OFA_map_alderlake "-xCORE-AVX512")
      set(OFA_map_tigerlake "-xCORE-AVX512")
      set(OFA_map_icelake-avx512 "-xCORE-AVX512")
      set(OFA_map_icelake "-xCORE-AVX512")
      set(OFA_map_cannonlake "-xCORE-AVX512")
      set(OFA_map_cooperlake "-xCORE-AVX512")
      set(OFA_map_cascadelake "-xCORE-AVX512")
      set(OFA_map_skylake-avx512 "-xCORE-AVX512")
      set(OFA_map_skylake "-xCORE-AVX2")
      set(OFA_map_broadwell "-xCORE-AVX2")
      set(OFA_map_haswell "-xCORE-AVX2")
      set(OFA_map_ivybridge "-xCORE-AVX-I")
      set(OFA_map_sandybridge "-xAVX")
      set(OFA_map_westmere "-xSSE4.2")
      set(OFA_map_nehalem "-xSSE4.2")
      set(OFA_map_penryn "-xSSSE3")
      set(OFA_map_merom "-xSSSE3")
      set(OFA_map_core2 "-xSSE3")
      set(_ok FALSE)
      foreach(arch ${_march_flag_list})
        if(DEFINED OFA_map_${arch})
          AddCompilerFlag(${OFA_map_${arch}} CXX_FLAGS OFA_ARCHITECTURE_FLAGS CXX_RESULT _ok)
          if(_ok)
            break()
          endif()
        endif()
      endforeach()
      if(NOT _ok)
        # This is the Intel compiler, so SSE2 is a very reasonable baseline.
        message(STATUS "Did not recognize the requested architecture flag, falling back to SSE2")
        AddCompilerFlag("-xSSE2" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
      endif()
    else() # not MSVC and not ICC => GCC, Clang, Open64
      foreach(_flag ${_march_flag_list})
        AddCompilerFlag("-march=${_flag}" CXX_RESULT _good CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
        if(_good)
          break()
        endif(_good)
      endforeach(_flag)
      foreach(_flag ${_enable_vector_unit_list})
        AddCompilerFlag("-m${_flag}" CXX_RESULT _result)
        if(_result)
          set(_header FALSE)
          if(_flag STREQUAL "sse3")
            set(_header "pmmintrin.h")
          elseif(_flag STREQUAL "ssse3")
            set(_header "tmmintrin.h")
          elseif(_flag STREQUAL "sse4.1")
            set(_header "smmintrin.h")
          elseif(_flag STREQUAL "sse4.2")
            set(_header "nmmintrin.h")
          elseif(_flag STREQUAL "sse4a")
            set(_header "ammintrin.h")
          elseif(_flag STREQUAL "avx")
            set(_header "immintrin.h")
          elseif(_flag STREQUAL "avx2")
            set(_header "immintrin.h")
          elseif(_flag STREQUAL "avx512*")
            set(_header "immintrin.h")
          elseif(_flag STREQUAL "fma4")
            set(_header "x86intrin.h")
          elseif(_flag STREQUAL "xop")
            set(_header "x86intrin.h")
          elseif(_flag STREQUAL "bmi")
            set(_header "ammintrin.h")
          elseif(_flag STREQUAL "bmi2")
            set(_header "ammintrin.h")
          elseif(_flag STREQUAL "rdrnd")
            set(_header "immintrin.h")
          elseif(_flag STREQUAL "rdpid")
            set(_header "immintrin.h")
          elseif(_flag STREQUAL "rdseed")
            set(_header "immintrin.h")
          endif()
          set(_resultVar "HAVE_${_header}")
          string(REPLACE "." "_" _resultVar "${_resultVar}")
          if(_header)
            CHECK_INCLUDE_FILE_CXX("${_header}" ${_resultVar} "-m${_flag}")
            if(NOT ${_resultVar})
              set(_useVar "USE_${_flag}")
              string(TOUPPER "${_useVar}" _useVar)
              string(REPLACE "." "_" _useVar "${_useVar}")
              message(STATUS "disabling ${_useVar} because ${_header} is missing")
              set(${_useVar} FALSE)
              list(APPEND _disable_vector_unit_list "${_flag}")
            endif()
          endif()
          if(NOT _header OR ${_resultVar})
            list(APPEND OFA_ARCHITECTURE_FLAGS "-m${_flag}")
          endif()
        endif()
      endforeach(_flag)
      foreach(_flag ${_disable_vector_unit_list})
        AddCompilerFlag("-mno-${_flag}" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
      endforeach(_flag)
    endif()
  endif()

  # Compile code with profiling instrumentation
  if(TARGET_PROFILER STREQUAL "gprof")
    AddCompilerFlag("-pg" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
  elseif(TARGET_PROFILER STREQUAL "vtune" AND CMAKE_CXX_COMPILER MATCHES "/(icpc|icc)$")
    AddCompilerFlag("-g" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
    AddCompilerFlag("-debug inline-debug-info" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
    AddCompilerFlag("-D TBB_USE_THREADING_TOOLS" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
    AddCompilerFlag("-parallel-source-info=2" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
    AddCompilerFlag("-gline-tables-only" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
    AddCompilerFlag("-fdebug-info-for-profiling" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
    AddCompilerFlag("-Xsprofile" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
  endif()
endmacro(OFA_HandleX86Options)

macro(OFA_HandleArmOptions)
  set(_march_flag_list)
  set(_mtune_flag_list)
  set(_available_vector_units_list)

  if(TARGET_ARCHITECTURE STREQUAL "strongarm") # ARM
    list(APPEND _mtune_flag_list "strongarm")
    list(APPEND _march_flag_list "armv4")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm8")
    list(APPEND _mtune_flag_list "arm8")
    list(APPEND _march_flag_list "armv4")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm810")
    list(APPEND _mtune_flag_list "arm810")
    list(APPEND _march_flag_list "armv4")
  elseif(TARGET_ARCHITECTURE STREQUAL "fa526")
    list(APPEND _mtune_flag_list "fa526")
    list(APPEND _march_flag_list "armv4")
  elseif(TARGET_ARCHITECTURE STREQUAL "fa626")
    list(APPEND _mtune_flag_list "fa626")
    list(APPEND _march_flag_list "armv4")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm7tdmi")
    list(APPEND _mtune_flag_list "arm7tdmi")
    list(APPEND _march_flag_list "armv4t")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm7tdmi-s")
    list(APPEND _mtune_flag_list "arm7tdmi-s")
    list(APPEND _march_flag_list "armv4t")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm710t")
    list(APPEND _mtune_flag_list "arm710t")
    list(APPEND _march_flag_list "armv4t")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm720t")
    list(APPEND _mtune_flag_list "arm720t")
    list(APPEND _march_flag_list "armv4t")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm740t")
    list(APPEND _mtune_flag_list "arm740t")
    list(APPEND _march_flag_list "armv4t")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm9")
    list(APPEND _mtune_flag_list "arm9")
    list(APPEND _march_flag_list "armv4t")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm9tdmi")
    list(APPEND _mtune_flag_list "arm9tdmi")
    list(APPEND _march_flag_list "armv4t")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm920")
    list(APPEND _mtune_flag_list "arm920")
    list(APPEND _march_flag_list "armv4t")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm920t")
    list(APPEND _mtune_flag_list "arm920t")
    list(APPEND _march_flag_list "armv4t")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm922t")
    list(APPEND _mtune_flag_list "arm922t")
    list(APPEND _march_flag_list "armv4t")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm940t")
    list(APPEND _mtune_flag_list "arm940t")
    list(APPEND _march_flag_list "armv4t")

  elseif(TARGET_ARCHITECTURE STREQUAL "arm1020t")
    list(APPEND _mtune_flag_list "arm1020t")
    list(APPEND _march_flag_list "armv5t")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm10tdmi")
    list(APPEND _mtune_flag_list "arm10tdmi")
    list(APPEND _march_flag_list "armv5t")

  elseif(TARGET_ARCHITECTURE STREQUAL "arm9e")
    list(APPEND _mtune_flag_list "arm9e")
    list(APPEND _march_flag_list "armv5te")
    list(APPEND _available_vector_units_list "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm946e-s")
    list(APPEND _mtune_flag_list "arm946e-s")
    list(APPEND _march_flag_list "armv5te")
    list(APPEND _available_vector_units_list "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm966e-s")
    list(APPEND _mtune_flag_list "arm966e-s")
    list(APPEND _march_flag_list "armv5te")
    list(APPEND _available_vector_units_list "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm968e-s")
    list(APPEND _mtune_flag_list "arm968e-s")
    list(APPEND _march_flag_list "armv5te")
    list(APPEND _available_vector_units_list "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm10e")
    list(APPEND _mtune_flag_list "arm10e")
    list(APPEND _march_flag_list "armv5te")
    list(APPEND _available_vector_units_list "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm1020e")
    list(APPEND _mtune_flag_list "arm1020e")
    list(APPEND _march_flag_list "armv5te")
    list(APPEND _available_vector_units_list "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm1022e")
    list(APPEND _mtune_flag_list "arm1022e")
    list(APPEND _march_flag_list "armv5te")
    list(APPEND _available_vector_units_list "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "xscale")
    list(APPEND _mtune_flag_list "xscale")
    list(APPEND _march_flag_list "armv5te")
  elseif(TARGET_ARCHITECTURE STREQUAL "iwmmxt")
    list(APPEND _mtune_flag_list "iwmmxt")
    list(APPEND _march_flag_list "armv5te")
  elseif(TARGET_ARCHITECTURE STREQUAL "iwmmxt2")
    list(APPEND _mtune_flag_list "iwmmxt2")
    list(APPEND _march_flag_list "armv5te")
  elseif(TARGET_ARCHITECTURE STREQUAL "fa606te")
    list(APPEND _mtune_flag_list "fa606te")
    list(APPEND _march_flag_list "armv5te")
  elseif(TARGET_ARCHITECTURE STREQUAL "fa626te")
    list(APPEND _mtune_flag_list "fa626te")
    list(APPEND _march_flag_list "armv5te")
  elseif(TARGET_ARCHITECTURE STREQUAL "fmp626")
    list(APPEND _mtune_flag_list "fmp626")
    list(APPEND _march_flag_list "armv5te")
  elseif(TARGET_ARCHITECTURE STREQUAL "fa726te")
    list(APPEND _mtune_flag_list "fa726te")
    list(APPEND _march_flag_list "armv5te")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm926ej-s")
    list(APPEND _mtune_flag_list "arm926ej-s")
    list(APPEND _march_flag_list "armv5tej")
    list(APPEND _available_vector_units_list "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm1026ej-s")
    list(APPEND _mtune_flag_list "arm1026ej-s")
    list(APPEND _march_flag_list "armv5tej")
    list(APPEND _available_vector_units_list "fp")

  elseif(TARGET_ARCHITECTURE STREQUAL "mpcore")
    list(APPEND _mtune_flag_list "mpcore")
    list(APPEND _march_flag_list "armv6k")
    list(APPEND _available_vector_units_list "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm1136j-s")
    list(APPEND _mtune_flag_list "arm1136j-s")
    list(APPEND _march_flag_list "armv6j")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm1136jf-s")
    list(APPEND _mtune_flag_list "arm1136jf-s")
    list(APPEND _march_flag_list "armv6j")
    list(APPEND _available_vector_units_list "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm1156t2-s")
    list(APPEND _mtune_flag_list "arm1156t2-s")
    list(APPEND _march_flag_list "armv6t2")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm1156t2f-s")
    list(APPEND _mtune_flag_list "arm1156t2f-s")
    list(APPEND _march_flag_list "armv6t2")
    list(APPEND _available_vector_units_list "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm1176jz-s")
    list(APPEND _mtune_flag_list "arm1176jz-s")
    list(APPEND _march_flag_list "armv6kz")
  elseif(TARGET_ARCHITECTURE STREQUAL "arm1176jzf-s")
    list(APPEND _mtune_flag_list "arm1176jzf-s")
    list(APPEND _march_flag_list "armv6kz")
    list(APPEND _available_vector_units_list "fp")

  elseif(TARGET_ARCHITECTURE STREQUAL "generic-armv7-a")
    list(APPEND _mtune_flag_list "generic-armv7-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "mp" "sec" "vfpv3-d16" "vfpv3" "vfpv3-d16-fp16" "vfpv3-fp16" "vfpv4-d16" "vfpv4" "simd" "neon-fp16" "neon-vfpv4")

  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a5")
    list(APPEND _mtune_flag_list "cortex-a5")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "mp" "sec" "neon-fp16")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a7")
    list(APPEND _mtune_flag_list "cortex-a7")
    list(APPEND _march_flag_list "armv7ve")
    list(APPEND _available_vector_units_list "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a8")
    list(APPEND _mtune_flag_list "cortex-a8")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "sec" "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a9")
    list(APPEND _mtune_flag_list "cortex-a9")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "mp" "sec" "neon-fp16")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a12")
    list(APPEND _mtune_flag_list "cortex-a12")
    list(APPEND _march_flag_list "armv7ve")
    list(APPEND _available_vector_units_list "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a15")
    list(APPEND _mtune_flag_list "cortex-a15")
    list(APPEND _march_flag_list "armv7ve")
    list(APPEND _available_vector_units_list "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a15.cortex-a7")
    list(APPEND _mtune_flag_list "cortex-a15.cortex-a7")
    list(APPEND _march_flag_list "armv7ve")
    list(APPEND _available_vector_units_list "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a17")
    list(APPEND _mtune_flag_list "cortex-a17")
    list(APPEND _march_flag_list "armv7ve")
    list(APPEND _available_vector_units_list "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a17.cortex-a7")
    list(APPEND _mtune_flag_list "cortex-a17.cortex-a7")
    list(APPEND _march_flag_list "armv7ve")
    list(APPEND _available_vector_units_list "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a32")
    list(APPEND _mtune_flag_list "cortex-a32")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a34")
    list(APPEND _mtune_flag_list "cortex-a34")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "crypto" "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a35")
    list(APPEND _mtune_flag_list "cortex-a35")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "crypto" "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a53")
    list(APPEND _mtune_flag_list "cortex-a53")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "crypto" "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a55")
    list(APPEND _mtune_flag_list "cortex-a55")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "fp16" "dotprod")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a57")
    list(APPEND _mtune_flag_list "cortex-a57")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a57.cortext-a53")
    list(APPEND _mtune_flag_list "cortex-a57.cortext-a53")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a72")
    list(APPEND _mtune_flag_list "cortex-a72")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "crypto" "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a72.cortext-a53")
    list(APPEND _mtune_flag_list "cortex-a72.cortext-a53")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a73")
    list(APPEND _mtune_flag_list "cortex-a73")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "crypto" "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a73.cortext-a35")
    list(APPEND _mtune_flag_list "cortex-a73.cortext-a35")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a73.cortext-a53")
    list(APPEND _mtune_flag_list "cortex-a73.cortext-a53")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "simd")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a75")
    list(APPEND _mtune_flag_list "cortex-a75")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "fp16" "dotprod")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a75.cortext-a55")
    list(APPEND _mtune_flag_list "cortex-a75.cortext-a55")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _available_vector_units_list "fp16" "dotprod")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a76")
    list(APPEND _mtune_flag_list "cortex-a76")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "fp16" "dotprod")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a76.cortext-a55")
    list(APPEND _mtune_flag_list "cortex-a76.cortext-a55")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "fp16" "dotprod")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a76ae")
    list(APPEND _mtune_flag_list "cortex-a76ae")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "fp16" "dotprod")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-a77")
    list(APPEND _mtune_flag_list "cortex-a77")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "fp16" "dotprod")

  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-r4")
    list(APPEND _mtune_flag_list "cortex-r4")
    list(APPEND _march_flag_list "armv7-r")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-r4f")
    list(APPEND _mtune_flag_list "cortex-r4f")
    list(APPEND _march_flag_list "armv7-r")
    list(APPEND _available_vector_units_list "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-r5")
    list(APPEND _mtune_flag_list "cortex-r5")
    list(APPEND _march_flag_list "armv7-r")
    list(APPEND _available_vector_units_list "idiv" "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-r7")
    list(APPEND _mtune_flag_list "cortex-r7")
    list(APPEND _march_flag_list "armv7-r")
    list(APPEND _available_vector_units_list "idiv" "vfpv3-d16-fp16")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-r8")
    list(APPEND _mtune_flag_list "cortex-r8")
    list(APPEND _march_flag_list "armv7-r")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-r52")
    list(APPEND _mtune_flag_list "cortex-r52")
    list(APPEND _march_flag_list "armv8-r")
    list(APPEND _march_flag_list "armv7-r")
    list(APPEND _available_vector_units_list "crc" "simd" "idiv" "vfpv3-d16-fp16")

  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-m0")
    list(APPEND _mtune_flag_list "cortex-m0")
    list(APPEND _march_flag_list "armv6s-m")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-m0plus")
    list(APPEND _mtune_flag_list "cortex-m0plus")
    list(APPEND _march_flag_list "armv6s-m")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-m1")
    list(APPEND _mtune_flag_list "cortex-m1")
    list(APPEND _march_flag_list "armv6s-m")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-m3")
    list(APPEND _mtune_flag_list "cortex-m3")
    list(APPEND _march_flag_list "armv7-m")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-m4")
    list(APPEND _mtune_flag_list "cortex-m4")
    list(APPEND _march_flag_list "armv7e-m")
    list(APPEND _available_vector_units_list "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-m7")
    list(APPEND _mtune_flag_list "cortex-m7")
    list(APPEND _march_flag_list "armv7e-m")
    list(APPEND _available_vector_units_list "fp.dp")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-m23")
    list(APPEND _mtune_flag_list "cortex-m23")
    list(APPEND _march_flag_list "armv8-m.base")
    list(APPEND _march_flag_list "armv7-m")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-m33")
    list(APPEND _mtune_flag_list "cortex-m33")
    list(APPEND _march_flag_list "armv8-m.main")
    list(APPEND _march_flag_list "armv7-m")
    list(APPEND _available_vector_units_list "dsp" "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-m35p")
    list(APPEND _mtune_flag_list "cortex-m35p")
    list(APPEND _march_flag_list "armv8-m.main")
    list(APPEND _march_flag_list "armv7-m")
    list(APPEND _available_vector_units_list "dsp" "fp")
  elseif(TARGET_ARCHITECTURE STREQUAL "cortex-m55")
    list(APPEND _mtune_flag_list "cortex-m55")
    list(APPEND _march_flag_list "armv8.1-m.main")
    list(APPEND _march_flag_list "armv8-m")
    list(APPEND _march_flag_list "armv7-m")
    list(APPEND _available_vector_units_list "mve.fp" "fp.dp")

  elseif(TARGET_ARCHITECTURE STREQUAL "neoverse-n1")
    list(APPEND _mtune_flag_list "neoverse-n1")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "fp16" "dotprod")
  elseif(TARGET_ARCHITECTURE STREQUAL "neoverse-e1")
    list(APPEND _mtune_flag_list "neoverse-e1")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "fp16" "dorprod")

  elseif(TARGET_ARCHITECTURE STREQUAL "brahma-b15") # Broadcom
    list(APPEND _mtune_flag_list "brahma-b15")
  elseif(TARGET_ARCHITECTURE STREQUAL "brahma-b53")
    list(APPEND _mtune_flag_list "brahma-b53")
  elseif(TARGET_ARCHITECTURE STREQUAL "thunderx2")
    list(APPEND _mtune_flag_list "thunderx2")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crypto")

  elseif(TARGET_ARCHITECTURE STREQUAL "thunderx") # Cavium
    list(APPEND _mtune_flag_list "thunderx")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "crypto")
  elseif(TARGET_ARCHITECTURE STREQUAL "thunderxt88")
    list(APPEND _mtune_flag_list "thunderxt88")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "crypto")
  elseif(TARGET_ARCHITECTURE STREQUAL "thunderxt81")
    list(APPEND _mtune_flag_list "thunderxt81")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "crypto")
  elseif(TARGET_ARCHITECTURE STREQUAL "thunderxt83")
    list(APPEND _mtune_flag_list "thunderxt83")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "crypto")
  elseif(TARGET_ARCHITECTURE STREQUAL "thunderx2t99")
    list(APPEND _mtune_flag_list "thunderx2t99")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "crypto")

  elseif(TARGET_ARCHITECTURE STREQUAL "strongarm110") # DEC
    list(APPEND _mtune_flag_list "strongarm110")
    list(APPEND _march_flag_list "armv4")
  elseif(TARGET_ARCHITECTURE STREQUAL "strongarm1100")
    list(APPEND _mtune_flag_list "strongarm1100")
    list(APPEND _march_flag_list "armv4")

  elseif(TARGET_ARCHITECTURE STREQUAL "a64fx") # FUJITSU
    list(APPEND _mtune_flag_list "a64fx")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "fp16" "sve")

  elseif(TARGET_ARCHITECTURE STREQUAL "tsv110") # HiSilicon
    list(APPEND _mtune_flag_list "tsv110")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "aes" "crypto" "fp16" "sha2")

  elseif(TARGET_ARCHITECTURE STREQUAL "denver") # Nvidia
    list(APPEND _mtune_flag_list "denver")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "crypto" "simd" "vfpv3" "vfpv4")
  elseif(TARGET_ARCHITECTURE STREQUAL "denver2")
    list(APPEND _mtune_flag_list "denver2")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "crypto" "simd" "vfpv3" "vfpv4")
  elseif(TARGET_ARCHITECTURE STREQUAL "carmel")
    list(APPEND _mtune_flag_list "denver")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "crypto" "simd" "vfpv3" "vfpv4")

  elseif(TARGET_ARCHITECTURE STREQUAL "xgene1") # APM
    list(APPEND _mtune_flag_list "xgene1")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")

  elseif(TARGET_ARCHITECTURE STREQUAL "scorpion") # Qualcomm
    list(APPEND _mtune_flag_list "scorpion")
    list(APPEND _march_flag_list "armv7-a")
  elseif(TARGET_ARCHITECTURE STREQUAL "krait")
    list(APPEND _mtune_flag_list "krait")
    list(APPEND _march_flag_list "armv7-a")
  elseif(TARGET_ARCHITECTURE STREQUAL "kryo")
    list(APPEND _mtune_flag_list "kryo")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
  elseif(TARGET_ARCHITECTURE STREQUAL "kryo2")
    list(APPEND _mtune_flag_list "kryo2")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
  elseif(TARGET_ARCHITECTURE STREQUAL "falkor")
    list(APPEND _mtune_flag_list "falkor")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
  elseif(TARGET_ARCHITECTURE STREQUAL "saphira")
    list(APPEND _mtune_flag_list "saphira")
    list(APPEND _march_flag_list "armv8.4-a")
    list(APPEND _march_flag_list "armv8.3-a")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crc" "crypto" "simd" "vfpv3" "vfpv4")

  elseif(TARGET_ARCHITECTURE STREQUAL "exynos-m1") # Samsung
    list(APPEND _mtune_flag_list "exynos-m1")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "crypto" "simd")

  elseif(TARGET_ARCHITECTURE STREQUAL "marvell-f") # Marvell
    list(APPEND _mtune_flag_list "marvell-f")
    list(APPEND _march_flag_list "armv5te")
  elseif(TARGET_ARCHITECTURE STREQUAL "marvell-pj4")
    list(APPEND _mtune_flag_list "marvell-pj4")
    list(APPEND _march_flag_list "armv7-a")
    list(APPEND _available_vector_units_list "mp" "sec" "fp")

  elseif(TARGET_ARCHITECTURE STREQUAL "i80200") # Intel
    list(APPEND _mtune_flag_list "i80200")
  elseif(TARGET_ARCHITECTURE STREQUAL "pxa250a")
    list(APPEND _mtune_flag_list "pxa250a")
  elseif(TARGET_ARCHITECTURE STREQUAL "pxa210a")
    list(APPEND _mtune_flag_list "pxa210a")
  elseif(TARGET_ARCHITECTURE STREQUAL "i80321-400")
    list(APPEND _mtune_flag_list "i80321-400")
  elseif(TARGET_ARCHITECTURE STREQUAL "i80321-600")
    list(APPEND _mtune_flag_list "i80321-600")
  elseif(TARGET_ARCHITECTURE STREQUAL "pxa250b")
    list(APPEND _mtune_flag_list "pxa250b")
  elseif(TARGET_ARCHITECTURE STREQUAL "pxa210b")
    list(APPEND _mtune_flag_list "pxa210b")
  elseif(TARGET_ARCHITECTURE STREQUAL "i80321-400-b0")
    list(APPEND _mtune_flag_list "i80321-400-b0")
  elseif(TARGET_ARCHITECTURE STREQUAL "i80321-600-b0")
    list(APPEND _mtune_flag_list "i80321-600-b0")
  elseif(TARGET_ARCHITECTURE STREQUAL "pxa250c")
    list(APPEND _mtune_flag_list "pxa250c")
  elseif(TARGET_ARCHITECTURE STREQUAL "pxa210c")
    list(APPEND _mtune_flag_list "pxa210c")
  elseif(TARGET_ARCHITECTURE STREQUAL "pxa27x")
    list(APPEND _mtune_flag_list "pxa27x")
  elseif(TARGET_ARCHITECTURE STREQUAL "ipx425-533")
    list(APPEND _mtune_flag_list "ipx425-533")
  elseif(TARGET_ARCHITECTURE STREQUAL "ipx425-400")
    list(APPEND _mtune_flag_list "ipx425-400")
  elseif(TARGET_ARCHITECTURE STREQUAL "ipx425-266")
    list(APPEND _mtune_flag_list "ipx425-266")
  elseif(TARGET_ARCHITECTURE STREQUAL "pxa32x")
    list(APPEND _mtune_flag_list "pxa32x")
  elseif(TARGET_ARCHITECTURE STREQUAL "pxa930")
    list(APPEND _mtune_flag_list "pxa930")
  elseif(TARGET_ARCHITECTURE STREQUAL "pxa30x")
    list(APPEND _mtune_flag_list "pxa30x")
  elseif(TARGET_ARCHITECTURE STREQUAL "pxa31x")
    list(APPEND _mtune_flag_list "pxa31x")
  elseif(TARGET_ARCHITECTURE STREQUAL "sa1110")
    list(APPEND _mtune_flag_list "sa1110")
  elseif(TARGET_ARCHITECTURE STREQUAL "ipx1200")
    list(APPEND _mtune_flag_list "ipx1200")

  elseif(TARGET_ARCHITECTURE STREQUAL "apple-a6") # Apple
    list(APPEND _mtune_flag_list "apple-a6")
    list(APPEND _march_flag_list "armv7-a")
  elseif(TARGET_ARCHITECTURE STREQUAL "apple-a7")
    list(APPEND _mtune_flag_list "apple-a7")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _available_vector_units_list "aes" "crypto" "fp" "neon" "sha2" "zcm" "zcz")  
  elseif(TARGET_ARCHITECTURE STREQUAL "apple-a8")
    list(APPEND _mtune_flag_list "apple-a8")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _available_vector_units_list "aes" "crypto" "fp" "neon" "sha2" "zcm" "zcz")
  elseif(TARGET_ARCHITECTURE STREQUAL "apple-a9")
    list(APPEND _mtune_flag_list "apple-a9")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _available_vector_units_list "aes" "crypto" "fp" "neon" "sha2" "zcm" "zcz")
  elseif(TARGET_ARCHITECTURE STREQUAL "apple-a10")
    list(APPEND _mtune_flag_list "apple-a10")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _available_vector_units_list "aes" "crc" "crypto" "fp" "neon" "rdm" "sha2" "zcm" "zcz")
  elseif(TARGET_ARCHITECTURE STREQUAL "apple-a11")
    list(APPEND _mtune_flag_list "apple-a11")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _available_vector_units_list "aes" "crc" "crypto" "fp" "lse" "neon" "ras" "rdm" "sha2" "zcm" "zcz")    
  elseif(TARGET_ARCHITECTURE STREQUAL "apple-a12")
    list(APPEND _mtune_flag_list "apple-a12")
    list(APPEND _march_flag_list "armv8.3-a")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _available_vector_units_list "aes" "crc" "crypto" "fp" "fp16" "lse" "neon" "ras" "rcpc" "rdm" "sha2" "zcm" "zcz")    
  elseif(TARGET_ARCHITECTURE STREQUAL "apple-a13")
    list(APPEND _mtune_flag_list "apple-a13")
    list(APPEND _march_flag_list "armv8.4-a")
    list(APPEND _march_flag_list "armv8.3-a")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _available_vector_units_list "aes" "crc" "crypto" "dotprod" "fp" "fp16" "fp16fml" "lse" "neon" "ras" "rcpc" "rdm" "sha2" "sha3" "sm4" "zcm" "zcz")        
  elseif(TARGET_ARCHITECTURE STREQUAL "apple-m1")
    list(APPEND _mtune_flag_list "vortex")
    list(APPEND _march_flag_list "armv8.3-a")
    list(APPEND _march_flag_list "armv8.2-a")
    list(APPEND _march_flag_list "armv8.1-a")
    list(APPEND _march_flag_list "armv8-a")
    list(APPEND _available_vector_units_list "aes" "crc" "crypto" "fp" "fp16" "lse" "neon" "ras" "rcpc" "rdm" "sha2" "zcm" "zcz")
    
  elseif(TARGET_ARCHITECTURE STREQUAL "native")
    list(APPEND _march_flag_list "native")
    
  elseif(TARGET_ARCHITECTURE STREQUAL "none")
    # add this clause to remove it from the else clause
    
  else()
    message(FATAL_ERROR "Unknown target architecture: \"${TARGET_ARCHITECTURE}\". Please set TARGET_ARCHITECTURE to a supported value.")
  endif()

  # Following the recommendation from
  # https://community.arm.com/developer/tools-software/tools/b/tools-software-ides-blog/posts/compiler-flags-across-architectures-march-mtune-and-mcpu
  # we first try to only use the -mcpu flag. If that fails, e.g., of
  # the compiler does not yet support the specified target, we try to
  # set the -march and -mtune flags as fallback option.

  if(TARGET_ARCHITECTURE STREQUAL "native")
    AddCompilerFlag("-mcpu=native" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
  elseif(NOT TARGET_ARCHITECTURE STREQUAL "none")
    foreach(_flag ${_mtune_flag_list})

      AddCompilerFlag("-mcpu=${_flag}" CXX_RESULT _good CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
      if(_good)
        break()
      endif(_good)
    endforeach(_flag)

    if(NOT _good)
      set(_disable_vector_unit_list)
      set(_enable_vector_unit_list)

      set(_aes_broken false)
      set(_bf16_broken false)
      set(_crc_broken false)
      set(_crypto_broken false)
      set(_dotprod_broken false)
      set(_dsp_broken false)
      set(_fp16_broken false)
      set(_fp16fml_broken false)
      set(_fp_broken false)
      set(_fp_dp_broken false)
      set(_fp_sp_broken false)
      set(_i8mm_broken false)
      set(_idiv_broken false)
      set(_lse_broken false)
      set(_mve_broken false)
      set(_mve_fp_broken false)
      set(_neon_broken false)
      set(_neon_fp16_broken false)
      set(_neon_vfpv4_broken false)
      set(_ras_broken false)
      set(_rcpc_broken false)
      set(_rdm_broken false)
      set(_rdma_broken false)
      set(_sec_broken false)
      set(_sha2_broken false)
      set(_sha3_broken false)
      set(_simd_broken false)
      set(_sm4_broken false)
      set(_sve_broken false)
      set(_vfpv3_broken false)
      set(_vfpv3_d16_broken false)
      set(_vfpv3_d16_fp16_broken false)
      set(_vfpv3_fp16_broken false)
      set(_vfpv4_broken false)
      set(_vfpv4_d16_broken false)
      set(_zcm_broken false)
      set(_zcz_broken false)

      macro(_enable_or_disable _name _flag _documentation _broken)
        if(_broken)
          set(_found false)
        else()
          _my_find(_available_vector_units_list "${_flag}" _found)
        endif()
        set(USE_${_name} ${_found} CACHE BOOL "${documentation}" ${_force})
        mark_as_advanced(USE_${_name})
        if(USE_${_name})
          list(APPEND _enable_vector_unit_list "${_flag}")
        else()
          list(APPEND _disable_vector_unit_list "${_flag}")
        endif()
      endmacro()
      
      _enable_or_disable(AES "aes" "Use AES. This will enable the aes and pmull crypto extension." _aes_broken)
      _enable_or_disable(BF16 "bf16" "Use BF16. This will enable the brain half-precision floating-point instructions." _bf16_broken)
      _enable_or_disable(CRC "crc" "Use CRC. This will enable the Cyclic Redundancy Check (CRC) instructions." _crc_broken)
      _enable_or_disable(CRYPTO "crypto" "Use CRYPTO. This will enable the cryptographic instructions." _crypto_broken)
      _enable_or_disable(DOTPROD "dotprod" "Use DOTPROD. This will enable the Dot Product extension. This also enables Advanced SIMD instructions." _dotprod_broken)
      _enable_or_disable(DSP "dsp" "Use DSP. This will enable the DSP instruction." _dsp_broken)
      _enable_or_disable(FP "fp" "Use FP. This will enable the floating-point data processing instructions." _fp_broken)
      _enable_or_disable(FP16 "fp16" "Use FP16. This will enable the half-precision floating-point data processing instructions." _fp16_broken)
      _enable_or_disable(FP16FML "fp16fml" "Use FP16FML. This will enable the FP16 fmla extension." _fp16fml_broken)
      _enable_or_disable(FP_DP "fp.dp" "Use FP.DP. This will enable the single- and double-precision floating-point instructions." _fp_dp_broken)
      _enable_or_disable(FP_SP "fp.sp" "Use FP.SP. This will enable the single-precision floating-point instructions." _fp_sp_broken)
      _enable_or_disable(I8MM "i8mm" "Use I8MM. This will enable the 8-bit Integer Matrix Multiply instructions." _i8mm_broken)
      _enable_or_disable(IDIV "idiv" "Use IDIV. This will enable the ARM-state integer division instructions." _idiv_broken)
      _enable_or_disable(LSE "lse" "Use LSE. This will enable the Large System Extension instructions." _lse_broken)
      _enable_or_disable(MVE "mve" "Use MVE. This will enable the M-Profile Vector Extension (MVE) integer instructions." _mve_broken)
      _enable_or_disable(MVE_FP "mve.fp" "Use MVE.FP. This will enable the M-Profile Vector Extension (MVE) integer and single precision floating-point instructions." _mve_fp_broken)
      _enable_or_disable(NEON "neon" "Use NEON. This will enable the Advanced SIMD (Neon) v1." _neon_broken)
      _enable_or_disable(NEON_FP16 "neon-fp16" "Use NEON-FP16. This will enable the Advanced SIMD (Neon) v1 and the VFPv3 floating-point instructions, with the half-precision floating-point conversion operations." _neon_fp16_broken)
      _enable_or_disable(NEON_VFPV4 "neon-vfpv4" "Use NEON-VFPV4. This will enable the Advanced SIMD (Neon) v2 and the VFPv4 floating-point instructions." _neon_vfpv4_broken)
      _enable_or_disable(RAS "ras" "Use RAS. This will enable the Reliability, Availability, and Serviceability extension." _ras_broken)
      _enable_or_disable(RCPC "rcpc" "Use RCPC. This will enable the RcPc extension." _rcpc_broken)
      _enable_or_disable(RDM "rdm" "Use RDM. This will enable the RDM extension." _rdm_broken)
      _enable_or_disable(RDMA "rdma" "Use RDMA. This will enable the Round Double Multiply Accumulate instructions." _rdma_broken)
      _enable_or_disable(SEC "sec" "Use SEC. This will enable the security extension." _sec_broken)
      _enable_or_disable(SHA2 "sha2" "Use SHA2. This will enable the sha2 crypto extension." _sha2_broken)
      _enable_or_disable(SHA3 "sha3" "Use SHA3. This will enable the sha512 and sha3 crypto extension." _sha3_broken)
      _enable_or_disable(SIMD "simd" "Use SIMD. This will enable the Advanced SIMD (Neon) v1 and the VFPv3 floating-point instructions." _simd_broken)
      _enable_or_disable(SM4 "sm4" "Use SM4. This will enable the the sm3 and sm4 crypto extension." _sm4_broken)
      _enable_or_disable(SVE "sve" "Use SVE. This will enable the Scalable Vector Extension instructions." _sve_broken)
      _enable_or_disable(VFPV3 "vfpv3" "Use VPFV3. This will enable the VFPv3 floating-point instructions, with 32 double-precision registers." _vfpv3_broken)
      _enable_or_disable(VFPV3_D16 "vfpv3-d16" "Use VPFV3-16. This will enable the VFPv3 floating-point instructions, with 32 double-precision registers and the half-precision floating-point conversion operations." _vfpv3_d16_broken)
      _enable_or_disable(VFPV3_D16_FP16 "vfpv3-d16-fp16" "Use VPFV3-D16-FP16. This will enable VFPv3 floating-point instructions, with 16 double-precision registers and the half-precision floating-point conversion operations." _vfpv3_d16_fp16_broken)
      _enable_or_disable(VFPV3_FP16 "vfpv3-fp16" "Use VPFV3-FP16. This will enable the VFPv3 floating-point instructions, with 32 double-precision registers and the half-precision floating-point conversion operations." _vfpv3_fp16_broken)
      _enable_or_disable(VFPV4 "vfpv4" "Use VPFV4. This will enable the VFPv4 floating-point instructions, with 32 double-precision registers." _vfpv4_broken)
      _enable_or_disable(VFPV4_D16 "vfpv4-d16" "Use VPFV4-D16. This will enable the VFPv4 floating-point instructions, with 16 double-precision registers." _vfpv4_dp16_broken)      
      _enable_or_disable(ZCM "zcm" "Use ZCM. This will enable the ZCM extension." _zcm_broken)
      _enable_or_disable(ZCZ "zcz" "Use ZCZ. This will enable the ZCZ extension." _zcz_broken)
      foreach(_march ${_march_flag_list})

        AddCompilerFlag("-march=${_march}" CXX_RESULT _good CXX_FLAGS DUMMY_FLAGS)
        if(_good)
          set(_march_plus_extensions "${_march}")
          foreach(_flag ${_enable_vector_unit_list})
            AddCompilerFlag("-march=${_march_plus_extensions}+${_flag}" CXX_RESULT _good CXX_FLAGS DUMMY_FLAGS)
            if(_good)
              set(_march_plus_extensions "${_march_plus_extensions}+${_flag}")
            endif(_good)
          endforeach(_flag)
          AddCompilerFlag("-march=${_march_plus_extensions}" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
          break()
        endif(_good)
      endforeach(_march)

      foreach(_mtune ${_mtune_flag_list})
        AddCompilerFlag("-mtune=${_mtune}" CXX_RESULT _good CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
        if(_good)
          break()
        endif(_good)
      endforeach(_mtune)
    endif(NOT _good)
  endif()

  # Compile code with profiling instrumentation
  if(TARGET_PROFILER STREQUAL "gprof")
    AddCompilerFlag("-pg" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
  endif()
endmacro(OFA_HandleArmOptions)

macro(OFA_HandlePpcOptions)
  set(_march_flag_list)
  if(TARGET_ARCHITECTURE STREQUAL "power8")
    list(APPEND _march_flag_list "power8")
    list(APPEND _march_flag_list "pwr8")
  elseif(TARGET_ARCHITECTURE STREQUAL "power9")
    list(APPEND _march_flag_list "power9")
    list(APPEND _march_flag_list "power8")
    list(APPEND _march_flag_list "pwr9")
    list(APPEND _march_flag_list "pwr8")
  elseif(TARGET_ARCHITECTURE STREQUAL "power10")
    list(APPEND _march_flag_list "power10")
    list(APPEND _march_flag_list "power9")
    list(APPEND _march_flag_list "power8")
    list(APPEND _march_flag_list "pwr10")
    list(APPEND _march_flag_list "pwr9")
    list(APPEND _march_flag_list "pwr8")
  endif()

  foreach(_flag ${_march_flag_list})
    if(CMAKE_CXX_COMPILER MATCHES "/(pgcc|pgc\\+\\+)$")
      # PGI (on Linux)
      AddCompilerFlag("-tp=${_flag}" CXX_RESULT _good CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
    else()
      AddCompilerFlag("-mcpu=${_mcpu}" CXX_RESULT _good CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
    endif()
    if(_good)
      break()
    endif(_good)
  endforeach(_flag)

  if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    AddCompilerFlag("-target powerpcle-unknown-linux-gnu" CXX_FLAGS OFA_ARCHITECTURE_FLAGS)
  endif()
endmacro(OFA_HandlePpcOptions)

macro(OptimizeForArchitecture)
  if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "i686.*|i386.*|x86.*|amd64.*|x86_64.*|AMD64.*")
    set(TARGET_ARCHITECTURE "auto" CACHE STRING "CPU architecture to optimize for. Using an incorrect setting here can result in crashes of the resulting binary because of invalid instructions used. Setting the value to \"auto\" will try to optimize for the architecture where cmake is called. Setting the value to \"native\" bypasses all checks and uses \"-march=native\" or the compiler equivalent flag. Other supported values are: \"none\", \"generic\", \"core\", \"merom\" (65nm Core2), \"penryn\" (45nm Core2), \"nehalem\", \"westmere\", \"sandybridge\", \"ivybridge\", \"haswell\", \"broadwell\", \"skylake\", \"skylake-xeon\", \"kabylake\", \"cannonlake\", \"cascadelake\", \"cooperlake\", \"icelake\", \"icelake-xeon\", \"tigerlake\", \"alderlake\", \"sapphirerapids\", \"bonnell\", \"silvermont\", \"goldmont\", \"goldmont-plus\", \"tremont\", \"knl\" (Knights Landing), \"knm\" (Knights Mill), \"atom\", \"k8\", \"k8-sse3\", \"barcelona\", \"istanbul\", \"magny-cours\", \"bulldozer\", \"interlagos\", \"piledriver\", \"steamroller\", \"excavator\", \"amd14h\", \"amd16h\", \"zen\", \"zen2\", \"zen3\"." )
  elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "^(arm.*|ARM.*|aarch64.*|AARCH64.*)")
    set(TARGET_ARCHITECTURE "auto" CACHE STRING "CPU architecture to optimize for. Using an incorrect setting here can result in crashes of the resulting binary because of invalid instructions used. Setting the value to \"auto\" will try to optimize for the architecture where cmake is called. Setting the value to \"native\" bypasses all checks and uses \"-march=native\" or the compiler equivalent flag. Other supported values are: \"none\", \"generic\", \"a64fx\", \"apple-a6\", \"apple-a7\", \"apple-a8\", \"apple-a9\", \"apple-a10\", \"apple-a11\", \"apple-a12\", \"apple-a13\", \"apple-m1\", \"arm1020e\", \"arm1020t\", \"arm1022e\", \"arm1026ej-s\", \"arm10e\", \"arm10tdmi\", \"arm1136j-s\", \"arm1136jf-s\", \"arm1156t2-s\", \"arm1156t2f-s\", \"arm1176jz-s\", \"arm1176jzf-s\", \"arm710t\", \"arm720t\", \"arm740t\", \"arm7tdmi-s\", \"arm7tdmi\", \"arm810\", \"arm8\", \"arm920\", \"arm920t\", \"arm922t\", \"arm926ej-s\", \"arm940t\", \"arm946e-s\", \"arm966e-s\", \"arm968e-s\", \"arm9\", \"arm9e\", \"arm9tdmi\", \"brahma-b15\", \"brahma-b53\", \"carmel\", \"cortex-a12\", \"cortex-a15.cortex-a7\", \"cortex-a15\", \"cortex-a17.cortex-a7\", \"cortex-a17\", \"cortex-a32\", \"cortex-a34\", \"cortex-a35\", \"cortex-a53\", \"cortex-a55\", \"cortex-a57.cortext-a53\", \"cortex-a57\", \"cortex-a5\", \"cortex-a72.cortext-a53\", \"cortex-a72\", \"cortex-a73.cortext-a35\", \"cortex-a73.cortext-a53\", \"cortex-a73\", \"cortex-a75.cortext-a55\", \"cortex-a75\", \"cortex-a76.cortext-a55\", \"cortex-a76\", \"cortex-a76ae\", \"cortex-a77\", \"cortex-a7\", \"cortex-a8\", \"cortex-a9\", \"cortex-m0\", \"cortex-m0plus\", \"cortex-m1\", \"cortex-m23\", \"cortex-m33\", \"cortex-m35p\", \"cortex-m3\", \"cortex-m4\", \"cortex-m55\", \"cortex-m7\", \"cortex-r4\", \"cortex-r4f\", \"cortex-r52\", \"cortex-r5\", \"cortex-r7\", \"cortex-r8\", \"denver2\", \"denver\", \"exynos-m1\", \"fa526\", \"fa606te\", \"fa626\", \"fa626te\", \"fa726te\", \"falkor\", \"fmp626\", \"generic-armv7-a\", \"i80200\", \"i80321-400-b0\", \"i80321-400\", \"i80321-600-b0\", \"i80321-600\", \"ipx1200\", \"ipx425-266\", \"ipx425-400\", \"ipx425-533\", \"iwmmxt2\", \"iwmmxt\", \"krait\", \"kryo2\", \"kryo\", \"marvell-f\", \"marvell-pj4\", \"mpcore\", \"neoverse-e1\", \"neoverse-n1\", \"pxa210a\", \"pxa210b\", \"pxa210c\", \"pxa250a\", \"pxa250b\", \"pxa250c\", \"pxa27x\", \"pxa30x\", \"pxa31x\", \"pxa32x\", \"pxa930\", \"sa1110\", \"saphira\", \"scorpion\", \"strongarm1100\", \"strongarm110\", \"strongarm\", \"thunderx2\", \"thunderx2t99\", \"thunderx\", \"thunderxt81\", \"thunderxt83\", \"thunderxt88\", \"tsv110\", \"xgene1\", \"xscale\".")
  elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "^(powerpc|ppc)64.*")
    set(TARGET_ARCHITECTURE "auto" CACHE STRING "CPU architecture to optimize for. Using an incorrect setting here can result in crashes of the resulting binary because of invalid instructions used. Setting the value to \"auto\" will try to optimize for the architecture where cmake is called. Other supported values are: \"none\", \"generic\", \"power8\", \"power9\", \"power10\".")
  else()
    message(WARNING "The CMAKE_SYSTEM_PROCESSOR '${CMAKE_SYSTEM_PROCESSOR}' is not supported by OptimizeForArchitecture.cmake")
  endif()
  set(_force)
  if(NOT _last_target_arch STREQUAL "${TARGET_ARCHITECTURE}")
    message(STATUS "target changed from \"${_last_target_arch}\" to \"${TARGET_ARCHITECTURE}\"")
    set(_force FORCE)
  endif()
  set(_last_target_arch "${TARGET_ARCHITECTURE}" CACHE STRING "" FORCE)
  mark_as_advanced(_last_target_arch)
  string(TOLOWER "${TARGET_ARCHITECTURE}" TARGET_ARCHITECTURE)

  if(TARGET_ARCHITECTURE STREQUAL "auto")
    OFA_AutodetectHostArchitecture()
    message(STATUS "Detected Host CPU: ${TARGET_ARCHITECTURE}")
  endif()

  if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "i686.*|i386.*|x86.*|amd64.*|x86_64.*|AMD64.*")
    OFA_HandleX86Options()
  elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "^(arm.*|ARM.*|aarch64.*|AARCH64.*)")
    OFA_HandleArmOptions()
  elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "^(powerpc|ppc)64.*")
    OFA_HandlePpcOptions()
  endif()
endmacro(OptimizeForArchitecture)
