# Copyright 2025-2026, Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause

name: Reusable ISPC test workflow

permissions: read-all

on:
  workflow_call:
    inputs:
      platform:
        description: 'Platform to test on (linux, macos, windows)'
        required: true
        type: string
      architecture:
        description: 'Architecture to test (x86, x86-64, aarch64)'
        required: true
        type: string
      artifact_name:
        description: 'Name of the artifact to test'
        required: true
        type: string
      targets:
        description: 'JSON array of targets to test'
        required: false
        type: string
        default: '["avx2-i32x8"]'
      optsets:
        description: 'Optimization sets to test'
        required: false
        type: string
        default: '-O2'
      enable_lto:
        description: 'Was the build using LTO'
        required: false
        type: boolean
        default: false
      enable_xe:
        description: 'Was the build with XE support'
        required: false
        type: boolean
        default: false
      enable_debug:
        description: 'Enable debug mode for tests'
        required: false
        type: boolean
        default: false
      calling_conv:
        description: 'Optional calling convention to test (Windows only)'
        required: false
        type: string
        default: ''
      ispc_extra_flags:
        description: 'Additional ISPC flags to pass'
        required: false
        type: string
        default: ''

env:
  LLVM_HOME: ${{ inputs.platform == 'windows' && 'C:\\projects\\llvm' || github.workspace }}
  ISPC_HOME: ${{ github.workspace }}
  INSTALL_COMPUTE_RUNTIME: ${{ inputs.enable_xe && '1' || '' }}
  COMPUTE_RUNTIME_GITHUB_RELEASE: ${{ inputs.enable_xe && '1' || '' }}

jobs:
  test:
    name: ${{ inputs.platform }} (${{ inputs.architecture }}, ${{ matrix.target }}, ${{ inputs.optsets }})
    runs-on: ${{ inputs.platform == 'macos' && (inputs.architecture == 'aarch64' && 'macos-14' || 'macos-15-intel') || (inputs.platform == 'windows' && (inputs.architecture == 'aarch64' && 'windows-11-arm' || 'windows-2022')) || (inputs.architecture == 'aarch64' && 'ubuntu-22.04-arm') || 'ubuntu-22.04' }}
    continue-on-error: false
    strategy:
      fail-fast: false
      matrix:
        target: ${{ fromJson(inputs.targets) }}

    steps:
    - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0

    - name: Download package
      uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
      with:
        name: ${{ inputs.artifact_name }}

    - name: Install dependencies and unpack artifacts
      shell: bash
      run: |
        if [ "${INPUTS_PLATFORM}" == "linux" ]; then
          bash .github/workflows/scripts/install-test-deps.sh
        elif [ "${INPUTS_PLATFORM}" == "macos" ]; then
          if [[ "${{ inputs.enable_lto }}" == "true" ]]; then
            ISPC_TAR=$(ls ispc-*-macOS.universal.tar.gz)
            tar xf "$ISPC_TAR"
            ISPC_DIR=$(basename "$ISPC_TAR" .tar.gz)
            echo "$GITHUB_WORKSPACE/$ISPC_DIR/bin" >> "$GITHUB_PATH"
          else
            ISPC_TAR=$(ls ispc-*-macos.tar.gz)
            tar xf "$ISPC_TAR"
            ISPC_DIR=$(basename "$ISPC_TAR" .tar.gz)
            echo "$GITHUB_WORKSPACE/$ISPC_DIR/bin" >> "$GITHUB_PATH"
          fi
          echo "ISPC_HOME=$GITHUB_WORKSPACE" >> "$GITHUB_ENV"
          echo "LLVM_HOME=$GITHUB_WORKSPACE" >> "$GITHUB_ENV"
        else
          pwsh .github/workflows/scripts/install-test-deps.ps1
        fi
      env:
        INPUTS_PLATFORM: ${{ inputs.platform }}

    - name: Check environment
      run: |
        if [ "$INPUTS_PLATFORM" == "windows" ]; then
          pwsh -Command "Get-CimInstance -ClassName Win32_Processor | Select-Object Caption, DeviceID, Name, NumberOfCores, MaxClockSpeed, Status | Format-Table -AutoSize"
        elif [ "$INPUTS_PLATFORM" == "linux" ]; then
          cat /proc/cpuinfo
        elif [ "$INPUTS_PLATFORM" == "macos" ]; then
          sysctl -n machdep.cpu.brand_string
        fi
      shell: bash
      env:
        INPUTS_PLATFORM: ${{ inputs.platform }}

    - name: Running tests on Linux/macOS (alloy mode)
      # See issue #2818 for more details about skipping avx512, avx10 and avx2vnni targets. It's SDE problem running on AMD runner.
      # Unfortunately it's not possible to do this on job level, so we need to do it on step level.
      if: (inputs.platform == 'linux' || inputs.platform == 'macos') && inputs.architecture != 'aarch64' && inputs.architecture != 'wasm32' && inputs.architecture != 'wasm64' && !(inputs.architecture == 'x86' && (contains(matrix.target, 'avx2vnni') || contains(matrix.target, 'avx512') || contains(matrix.target, 'avx10')))
      uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
      with:
        timeout_minutes: 120
        max_attempts: 2
        shell: bash
        command: |
          # Reset fail_db.txt to clean state before each attempt
          git checkout -- tests/fail_db.txt
          echo "PATH=${PATH}"
          if [ "${{ inputs.enable_debug }}" = "true" ]; then
            ./scripts/alloy.py -r --only="stability ${INPUTS_ARCHITECTURE} current debug ${INPUTS_OPTSETS}" --only-targets="${MATRIX_TARGET}" --time --update-errors=FP --ispc-flags="${INPUTS_ISPC_EXTRA_FLAGS}"
          else
            ./scripts/alloy.py -r --only="stability ${INPUTS_ARCHITECTURE} current ${INPUTS_OPTSETS}" --only-targets="${MATRIX_TARGET}" --time --update-errors=FP --ispc-flags="${INPUTS_ISPC_EXTRA_FLAGS}"
          fi
          # Check for test failures - retry if flaky
          git diff --exit-code
      env:
        INPUTS_ARCHITECTURE: ${{ inputs.architecture }}
        INPUTS_OPTSETS: ${{ inputs.optsets }}
        MATRIX_TARGET: ${{ matrix.target }}
        INPUTS_ISPC_EXTRA_FLAGS: ${{ inputs.ispc_extra_flags }}

    - name: Running tests on Linux/macOS (run_tests mode)
      if: (inputs.platform == 'linux' || inputs.platform == 'macos') && (inputs.architecture == 'aarch64' || inputs.architecture == 'wasm32' || inputs.architecture == 'wasm64')
      uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
      with:
        timeout_minutes: 240
        max_attempts: 2
        shell: bash
        command: |
          if [ "${INPUTS_ARCHITECTURE}" == "wasm32" ] || [ "${INPUTS_ARCHITECTURE}" == "wasm64" ]; then
            source scripts/install_emscripten.sh && emcc --version
          fi

          echo "PATH=${PATH}"
          IFS=' ' read -ra OPT_LEVELS <<< "${INPUTS_OPTSETS}"

          for opt in "${OPT_LEVELS[@]}"; do
            # Remove dashes from each option
            opt_no_dash="${opt//-/}"
            echo "About to execute run_tests.py with opt: $opt_no_dash"
            ./scripts/run_tests.py -t "${MATRIX_TARGET}" -a "${INPUTS_ARCHITECTURE}" -o "$opt_no_dash" --time --update-errors=FP --ispc-flags="${INPUTS_ISPC_EXTRA_FLAGS}"
            echo "Finished executing run_tests.py with opt: $opt_no_dash"
          done
      env:
        INPUTS_ARCHITECTURE: ${{ inputs.architecture }}
        INPUTS_OPTSETS: ${{ inputs.optsets }}
        MATRIX_TARGET: ${{ matrix.target }}
        INPUTS_ISPC_EXTRA_FLAGS: ${{ inputs.ispc_extra_flags }}

    - name: Running tests on Windows (alloy mode)
      if: inputs.platform == 'windows' && inputs.calling_conv == '' && inputs.architecture != 'aarch64'
      uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
      with:
        timeout_minutes: 240
        max_attempts: 2
        shell: pwsh
        command: |
          # Reset fail_db.txt to clean state before each attempt
          git checkout -- tests/fail_db.txt
          $env:ISPC_HOME = "$pwd"
          .github/workflows/scripts/load-vs-env.ps1 "$env:INPUTS_ARCHITECTURE"
          if ("${{ inputs.enable_debug }}" -eq "true") {
            python .\scripts\alloy.py -r --only="stability $env:INPUTS_ARCHITECTURE current debug $env:INPUTS_OPTSETS" --only-targets="$env:MATRIX_TARGET" --time --update-errors=FP --ispc-flags="$env:INPUTS_ISPC_EXTRA_FLAGS"
          } else {
            python .\scripts\alloy.py -r --only="stability $env:INPUTS_ARCHITECTURE current $env:INPUTS_OPTSETS" --only-targets="$env:MATRIX_TARGET" --time --update-errors=FP --ispc-flags="$env:INPUTS_ISPC_EXTRA_FLAGS"
          }
          Write-Host "Finished executing alloy.py"
          # Check for test failures - retry if flaky
          git diff --exit-code
      env:
        INPUTS_ARCHITECTURE: ${{ inputs.architecture }}
        INPUTS_OPTSETS: ${{ inputs.optsets }}
        MATRIX_TARGET: ${{ matrix.target }}
        INPUTS_ISPC_EXTRA_FLAGS: ${{ inputs.ispc_extra_flags }}

    - name: Running tests on Windows (run_tests mode)
      if: inputs.platform == 'windows' && (inputs.calling_conv != '' || inputs.architecture == 'aarch64')
      uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
      with:
        timeout_minutes: 240
        max_attempts: 2
        shell: pwsh
        command: |
          $env:ISPC_HOME = "$pwd"
          .github/workflows/scripts/load-vs-env.ps1 "$env:INPUTS_ARCHITECTURE"

          # Split optsets and run tests for each optimization level
          $optLevels = "$env:INPUTS_OPTSETS".Split(" ", [System.StringSplitOptions]::RemoveEmptyEntries)
          Write-Host "optLevels array created: $($optLevels -join ', ')"

          foreach ($opt in $optLevels) {
            $optNoDash = $opt -replace "-", ""
            Write-Host "About to execute run_tests.py with opt: $optNoDash"
            if ("$env:INPUTS_CALLING_CONV" -ne "" -and "$env:INPUTS_ARCHITECTURE" -ne "aarch64") {
              python .\scripts\run_tests.py --calling_conv=$env:INPUTS_CALLING_CONV --target=$env:MATRIX_TARGET --arch=$env:INPUTS_ARCHITECTURE --opt=$optNoDash --ispc-flags="$env:INPUTS_ISPC_EXTRA_FLAGS"
            } else {
              python .\scripts\run_tests.py --target=$env:MATRIX_TARGET --arch=$env:INPUTS_ARCHITECTURE --opt=$optNoDash --ispc-flags="$env:INPUTS_ISPC_EXTRA_FLAGS"
            }
            Write-Host "Finished executing run_tests.py with opt: $optNoDash"
          }
      env:
        INPUTS_ARCHITECTURE: ${{ inputs.architecture }}
        INPUTS_OPTSETS: ${{ inputs.optsets }}
        INPUTS_CALLING_CONV: ${{ inputs.calling_conv }}
        MATRIX_TARGET: ${{ matrix.target }}
        INPUTS_ISPC_EXTRA_FLAGS: ${{ inputs.ispc_extra_flags }}

    - name: Set artifact name prefix
      if: always()
      id: set-artifact-name
      shell: bash
      run: |
        TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
        if [ "${{ inputs.enable_debug }}" == "true" ]; then
          echo "name_prefix=${INPUTS_ARTIFACT_NAME}.debug.${INPUTS_ARCHITECTURE}.${MATRIX_TARGET}.${TIMESTAMP}" >> "$GITHUB_OUTPUT"
        else
          echo "name_prefix=${INPUTS_ARTIFACT_NAME}.${INPUTS_ARCHITECTURE}.${MATRIX_TARGET}.${TIMESTAMP}" >> "$GITHUB_OUTPUT"
        fi
      env:
        INPUTS_ARTIFACT_NAME: ${{ inputs.artifact_name }}
        INPUTS_ARCHITECTURE: ${{ inputs.architecture }}
        MATRIX_TARGET: ${{ matrix.target }}
    - name: Check
      run: |
        # Print fails to the log.
        git diff --exit-code
    - name: Upload fail_db.txt
      uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
      if: failure()
      with:
        name: fail_db.${{ steps.set-artifact-name.outputs.name_prefix }}.txt
        path: tests/fail_db.txt

    - name: Upload alloy logs
      uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
      if: failure() && inputs.architecture != 'aarch64'
      with:
        name: alloy_results.${{ steps.set-artifact-name.outputs.name_prefix }}
        path: alloy_results_*
