#
#  W A R N I N G
#  -------------
#
# This file is not part of the Qt API.  It exists purely as an
# implementation detail.  It may change from version to version
# without notice, or even be removed.
#
# We mean it.
#

# Get the SIMD flags
load(qt_build_config)

# Set QT_CPU_FEATURES for convenience
QT_CPU_FEATURES = $$eval(QT_CPU_FEATURES.$$QT_ARCH)

#
# Set up compilers for SIMD (SSE/AVX, NEON etc)
#
defineTest(addSimdCompiler) {
    name = $$1
    upname = $$upper($$name)
    headers_var = $${upname}_HEADERS
    sources_var = $${upname}_SOURCES
    csources_var = $${upname}_C_SOURCES
    asm_var = $${upname}_ASM

    CONFIG($$1) {
        cflags = $$eval(QMAKE_CFLAGS_$${upname})
        ltcg: cflags += $$QMAKE_CFLAGS_DISABLE_LTCG
        contains(QT_CPU_FEATURES, $$name) {
            # Default compiler settings include this feature, so just add to SOURCES
            SOURCES += $$eval($$sources_var)
            export(SOURCES)
        } else {
            # We need special compiler flags

            # Split C and C++ sources
            $$csources_var = $$find($$sources_var, ".*\\.c$")
            $$sources_var -= $$eval($$csources_var)
            export($$csources_var)
            export($$sources_var)

            # Add C++ compiler
            $${name}_compiler.commands = $$QMAKE_CXX -c $(CXXFLAGS) $$cflags $(INCPATH) ${QMAKE_FILE_IN}
            msvc: $${name}_compiler.commands += -Fo${QMAKE_FILE_OUT}
            else: $${name}_compiler.commands += -o ${QMAKE_FILE_OUT}

            $${name}_compiler.dependency_type = TYPE_C
            $${name}_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
            $${name}_compiler.input = $$sources_var
            $${name}_compiler.variable_out = OBJECTS
            $${name}_compiler.name = compiling[$${name}] ${QMAKE_FILE_IN}
            silent: $${name}_compiler.commands = @echo compiling[$${name}] ${QMAKE_FILE_IN} && $$eval($${name}_compiler.commands)
            QMAKE_EXTRA_COMPILERS += $${name}_compiler

            export($${name}_compiler.commands)
            export($${name}_compiler.dependency_type)
            export($${name}_compiler.output)
            export($${name}_compiler.input)
            export($${name}_compiler.variable_out)
            export($${name}_compiler.name)

            # Add a C compiler
            $${name}_c_compiler.commands = $$QMAKE_CC -c $(CFLAGS) $$cflags $(INCPATH) ${QMAKE_FILE_IN}
            msvc: $${name}_c_compiler.commands += -Fo${QMAKE_FILE_OUT}
            else: $${name}_c_compiler.commands += -o ${QMAKE_FILE_OUT}

            $${name}_c_compiler.dependency_type = TYPE_C
            $${name}_c_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
            $${name}_c_compiler.input = $$csources_var
            $${name}_c_compiler.variable_out = OBJECTS
            $${name}_c_compiler.name = compiling[$${name}] ${QMAKE_FILE_IN}
            silent: $${name}_c_compiler.commands = @echo compiling[$${name}] ${QMAKE_FILE_IN} && $$eval($${name}_c_compiler.commands)
            QMAKE_EXTRA_COMPILERS += $${name}_c_compiler

            export($${name}_c_compiler.commands)
            export($${name}_c_compiler.dependency_type)
            export($${name}_c_compiler.output)
            export($${name}_c_compiler.input)
            export($${name}_c_compiler.variable_out)
            export($${name}_c_compiler.name)
        }

        # We always need an assembler (need to run the C compiler and without precompiled headers)
        msvc {
            # Don't know how to run MSVC's assembler...
            !isEmpty($$asm_var): error("Sorry, not implemented: assembling $$upname for MSVC.")
        } else: false {
            # This is just for the IDE
            SOURCES += $$eval($$asm_var)
            export(SOURCES)
        } else {
            $${name}_assembler.commands = $$QMAKE_CC -c $(CFLAGS)
            !contains(QT_CPU_FEATURES, $${name}): $${name}_assembler.commands += $$cflags
            clang:no_clang_integrated_as: $${name}_assembler.commands += -fno-integrated-as
            $${name}_assembler.commands += $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
            $${name}_assembler.dependency_type = TYPE_C
            $${name}_assembler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
            $${name}_assembler.input = $$asm_var
            $${name}_assembler.variable_out = OBJECTS
            $${name}_assembler.name = assembling[$${name}] ${QMAKE_FILE_IN}
            silent: $${name}_assembler.commands = @echo assembling[$${name}] ${QMAKE_FILE_IN} && $$eval($${name}_assembler.commands)
            QMAKE_EXTRA_COMPILERS += $${name}_assembler

            export($${name}_assembler.commands)
            export($${name}_assembler.dependency_type)
            export($${name}_assembler.output)
            export($${name}_assembler.input)
            export($${name}_assembler.variable_out)
            export($${name}_assembler.name)
        }

        HEADERS += $$eval($$headers_var)
        export(HEADERS)
        export(QMAKE_EXTRA_COMPILERS)
    }
}
addSimdCompiler(sse2)
addSimdCompiler(sse3)
addSimdCompiler(ssse3)
addSimdCompiler(sse4_1)
addSimdCompiler(sse4_2)
addSimdCompiler(aesni)
addSimdCompiler(shani)
addSimdCompiler(vaes)
addSimdCompiler(avx)
addSimdCompiler(avx2)
addSimdCompiler(avx512f)
addSimdCompiler(avx512cd)
addSimdCompiler(avx512er)
addSimdCompiler(avx512pf)
addSimdCompiler(avx512dq)
addSimdCompiler(avx512bw)
addSimdCompiler(avx512vl)
addSimdCompiler(avx512vnni)
addSimdCompiler(avx512ifma)
addSimdCompiler(avx512vbmi)
addSimdCompiler(avx512vbmi2)
addSimdCompiler(avx512bitalg)
addSimdCompiler(avx512vpopcntd)
addSimdCompiler(f16c)
addSimdCompiler(rdrnd)
addSimdCompiler(rdseed)
addSimdCompiler(neon)
addSimdCompiler(mips_dsp)
addSimdCompiler(mips_dspr2)

# Haswell sub-architecture
defineTest(addSimdArch) {
    name = arch_$$1
    dependencies = $$2
    upname = $$upper($$name)

    cpu_features_missing =
    for(part, dependencies) {
        !contains(QT_CPU_FEATURES, $$part): cpu_features_missing = 1
    }

    CONFIG += $$name
    isEmpty(cpu_features_missing): QT_CPU_FEATURES += $$name

    export(QT_CPU_FEATURES)
    export(CONFIG)
    addSimdCompiler($$name)
}

isEmpty(QMAKE_CFLAGS_ARCH_HASWELL): QMAKE_CFLAGS_ARCH_HASWELL = $$QMAKE_CFLAGS_AVX2
avx2: addSimdArch(haswell, avx2 bmi bmi2 f16c fma lzcnt popcnt)

# Follow the Intel compiler's lead and define profiles of AVX512 instructions
defineTest(addAvx512Profile) {
    name = $$1
    dependencies = $$2
    upname = $$upper($$name)
    varname = QMAKE_CFLAGS_$$upname

    cpu_features_missing =
    cflags = $$QMAKE_CFLAGS_ARCH_HASWELL $$QMAKE_CFLAGS_AVX512F
    for(part, dependencies) {
        !CONFIG($$part): return()           # Profile isn't supported by the compiler

        uppart = $$upper($$part)
        cflags *= $$eval(QMAKE_CFLAGS_$${uppart})
        !contains(QT_CPU_FEATURES, $$uppart): cpu_features_missing += $$uppart
    }

    CONFIG += $$name
    isEmpty(cpu_features_missing): QT_CPU_FEATURES += $$name
    $$varname = $$cflags

    export(QT_CPU_FEATURES)
    export(CONFIG)
    export($$varname)
    addSimdCompiler($$name)
}
addAvx512Profile(avx512common, avx512cd)
addAvx512Profile(avx512core, avx512cd avx512bw avx512dq avx512vl)
