param( [Parameter(Mandatory = $true)] [ValidateSet('scalar', 'baseline', 'avx2')] [string]$Profile ) $ErrorActionPreference = 'Stop' $build = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot "..\out\build\msvc-$Profile")) $targets = @('uc_demo', 'uc_tests', 'uc_bench') function Require-Flag( [string]$Command, [string]$Pattern, [string]$Description, [string]$Context ) { if ($Command -notmatch $Pattern) { throw "${Profile}/${Context}: missing $Description" } } function Reject-Flag( [string]$Command, [string]$Pattern, [string]$Description, [string]$Context ) { if ($Command -match $Pattern) { throw "${Profile}/${Context}: unexpected $Description" } } function Assert-ProfileCommand( [string]$Command, [string]$Context ) { $optimizationFlags = @([regex]::Matches( $Command, '(?i)(?:^|\s)/(?:O1|O2|Od|Ox)(?=\s|$)' ) | ForEach-Object { $_.Value.Trim() }) if ($optimizationFlags.Count -ne 1 -or $optimizationFlags[0] -ine '/O2') { $actual = if ($optimizationFlags.Count -eq 0) { 'none' } else { $optimizationFlags -join ', ' } throw "${Profile}/${Context}: expected exactly /O2, found $actual" } $runtimeFlags = @([regex]::Matches( $Command, '(?i)(?:^|\s)/(?:MDd?|MTd?)(?=\s|$)' ) | ForEach-Object { $_.Value.Trim() }) if ($runtimeFlags.Count -ne 1 -or $runtimeFlags[0] -ine '/MT') { $actual = if ($runtimeFlags.Count -eq 0) { 'none' } else { $runtimeFlags -join ', ' } throw "${Profile}/${Context}: expected exactly /MT, found $actual" } Reject-Flag $Command '(?i)(?:^|\s)/GL(?=\s|$)' '/GL (IPO/LTO must be off)' $Context switch ($Profile) { 'scalar' { Require-Flag $Command '(?i)(?:^|\s)/d2Qvec-(?=\s|$)' '/d2Qvec-' $Context Require-Flag $Command '(?i)(?:^|\s)/Qvec-report:1(?=\s|$)' '/Qvec-report:1' $Context Require-Flag $Command '(?i)(?:^|\s)/Oi-(?=\s|$)' '/Oi-' $Context Require-Flag $Command '(?i)UC_SIMD_PROFILE_SCALAR=1' 'UC_SIMD_PROFILE_SCALAR=1' $Context Require-Flag $Command '(?i)_USE_STD_VECTOR_ALGORITHMS=0' '_USE_STD_VECTOR_ALGORITHMS=0' $Context Reject-Flag $Command '(?i)(?:^|\s)/arch:AVX\S*' '/arch:AVX*' $Context Reject-Flag $Command '(?i)UC_SIMD_PROFILE_(?:BASELINE|AVX2)=1' 'a foreign SIMD profile definition' $Context } 'baseline' { Require-Flag $Command '(?i)UC_SIMD_PROFILE_BASELINE=1' 'UC_SIMD_PROFILE_BASELINE=1' $Context Reject-Flag $Command '(?i)(?:^|\s)/(?:d2Qvec-|Qvec-)(?=\s|$)' 'vectorizer-disable flag' $Context Reject-Flag $Command '(?i)(?:^|\s)/Oi-(?=\s|$)' '/Oi-' $Context Reject-Flag $Command '(?i)(?:^|\s)/arch:AVX\S*' '/arch:AVX*' $Context Reject-Flag $Command '(?i)_USE_STD_VECTOR_ALGORITHMS=0|UC_SIMD_PROFILE_(?:SCALAR|AVX2)=1' 'a foreign SIMD profile definition' $Context } 'avx2' { Require-Flag $Command '(?i)UC_SIMD_PROFILE_AVX2=1' 'UC_SIMD_PROFILE_AVX2=1' $Context Reject-Flag $Command '(?i)(?:^|\s)/(?:d2Qvec-|Qvec-)(?=\s|$)' 'vectorizer-disable flag' $Context Reject-Flag $Command '(?i)(?:^|\s)/Oi-(?=\s|$)' '/Oi-' $Context Reject-Flag $Command '(?i)_USE_STD_VECTOR_ALGORITHMS=0|UC_SIMD_PROFILE_(?:SCALAR|BASELINE)=1' 'a foreign SIMD profile definition' $Context $architectureFlags = @([regex]::Matches( $Command, '(?i)(?:^|\s)/arch:\S+' ) | ForEach-Object { $_.Value.Trim() }) if ($architectureFlags.Count -ne 1 -or $architectureFlags[0] -ine '/arch:AVX2') { $actual = if ($architectureFlags.Count -eq 0) { 'none' } else { $architectureFlags -join ', ' } throw "${Profile}/${Context}: expected exactly /arch:AVX2, found $actual" } } } } $validatedCommands = 0 foreach ($target in $targets) { $releaseDirectory = Join-Path $build "$target.dir\Release" if (-not (Test-Path -LiteralPath $releaseDirectory -PathType Container)) { throw "${Profile}/${target}: missing Release build directory $releaseDirectory" } $logs = @(Get-ChildItem -LiteralPath $releaseDirectory -Recurse ` -Filter 'CL.command.1.tlog' -File) if ($logs.Count -ne 1) { throw "${Profile}/${target}: expected one compiler command log, found $($logs.Count)" } # MSBuild writes command tlogs as UTF-16LE without a reliable BOM. $commandLines = @(Get-Content -LiteralPath $logs[0].FullName -Encoding Unicode | Where-Object { $_ -and -not $_.StartsWith('^') }) if ($commandLines.Count -eq 0) { throw "${Profile}/${target}: compiler command log contains no commands" } for ($index = 0; $index -lt $commandLines.Count; ++$index) { $context = if ($commandLines.Count -eq 1) { $target } else { "$target command $($index + 1)" } Assert-ProfileCommand $commandLines[$index] $context ++$validatedCommands } } Write-Host "Build flag audit passed for ${Profile}: $validatedCommands Release compiler command(s) across $($targets.Count) targets."