Repository: compiler-explorer/compiler-explorer
Pull request #7233 (2024-12-19 21:26:18)

Add full oatdump output behind filters
This change makes full oatdump output visible behind the "Directives" filter. This does the same thing as the --full-output flag, but is more-easily used. The default code snippets have been updated to include this.

<!-- THIS COMMENT IS INVISIBLE IN THE FINAL PR, BUT FEEL FREE TO REMOVE IT
Thanks for taking the time to improve CE. We really appreciate it.
  Before opening the PR, please make sure that the tests & linter pass their checks,
  by running `make check`.
  In the best case scenario, you are also adding tests to back up your changes,
  but don't sweat it if you don't. We can discuss them at a later date.
Feel free to append your name to the CONTRIBUTORS.md file
Thanks again, we really appreciate this!
-->


kevinjeon-g: As a side note, I wasn't able to update the filter names to fit, since those are defined in separate .pug files that don't seem to have any visibility into which compiler is being used. Please let me know if that isn't correct!

Patch:
diff --git a/Makefile b/Makefile
index d21735146..e8657b854 100644
--- a/Makefile
+++ b/Makefile
@@ -37,8 +37,8 @@ info: node-installed ## print out some useful variables
 # disassemblers are needed for local deploys: #4225
 .PHONY: scripts
 scripts:
-	mkdir --parents out/dist/etc/scripts/disasms
-	cp --recursive --update etc/scripts/disasms/* out/dist/etc/scripts/disasms
+	mkdir -p out/dist/etc/scripts/disasms
+	cp -R --update etc/scripts/disasms/* out/dist/etc/scripts/disasms
 
 .PHONY: prereqs
 prereqs: $(NODE_MODULES)
diff --git a/etc/config/c++.amazon.properties b/etc/config/c++.amazon.properties
index 81943a473..704315f15 100644
--- a/etc/config/c++.amazon.properties
+++ b/etc/config/c++.amazon.properties
@@ -1,4 +1,4 @@
-compilers=&gcc86:&icc:&icx:&clang:&clangx86trunk:&clang-rocm:&mosclang-trunk:&rvclang:&wasmclang:&loongarch-clang:&cl:&cross:&ellcc:&zapcc:&djggp:&armclang32:&armclang64:&zigcxx:&cxx6502:&nvcxx_arm_cxx:godbolt.org@443/gpu:godbolt.org@443/winprod:&hexagon-clang:&edg:&vast
+compilers=&gcc86:&icc:&icx:&clang:&clangx86trunk:&clang-rocm:&mosclang-trunk:&rvclang:&wasmclang:&loongarch-clang:&cl:&cross:&ellcc:&zapcc:&djggp:&armclang32:&armclang64:&zigcxx:&cxx6502:&nvcxx_arm_cxx:godbolt.org@443/gpu:godbolt.org@443/winprod:&hexagon-clang:&edg:&vast:&qnx
 # Disabled: nvcxx_x86_cxx
 # The disabled groups are actually used in the c++.gpu.properties. One day these might exist on both servers, so I want
 # to keep them in the same place.
@@ -277,7 +277,7 @@ compiler.g142assert.semver=14.2 (assertions)
 
 ################################
 # Clang for x86
-group.clang.compilers=&clangx86assert:clang30:clang31:clang32:clang33:clang341:clang350:clang351:clang352:clang37x:clang36x:clang371:clang380:clang381:clang390:clang391:clang400:clang401:clang500:clang501:clang502:clang600:clang601:clang700:clang701:clang710:clang800:clang801:clang900:clang901:clang1000:clang1001:clang1100:clang1101:clang1200:clang1201:clang1300:clang1301:clang1400:clang1500:clang1600:clang1701:clang1810:clang1910
+group.clang.compilers=&clangx86assert:clang30:clang31:clang32:clang33:clang341:clang350:clang351:clang352:clang37x:clang36x:clang371:clang380:clang381:clang390:clang391:clang400:clang401:clang500:clang501:clang502:clang600:clang601:clang700:clang701:clang710:clang800:clang801:clang900:clang901:clang1000:clang1001:clang1100:clang1101:clang1200:clang1201:clang1300:clang1301:clang1400:clang1500:clang1600:clang1701:clang1810:clang1810_clad180:clang1910
 group.clang.intelAsm=-mllvm --x86-asm-syntax=intel
 group.clang.options=--gcc-toolchain=/opt/compiler-explorer/gcc-7.2.0
 group.clang.groupName=Clang x86-64
@@ -453,6 +453,11 @@ compiler.clang1810.semver=18.1.0
 compiler.clang1810.options=--gcc-toolchain=/opt/compiler-explorer/gcc-13.2.0
 compiler.clang1810.ldPath=${exePath}/../lib|${exePath}/../lib/x86_64-unknown-linux-gnu
 compiler.clang1810.debugPatched=true
+compiler.clang1810_clad180.exe=/opt/compiler-explorer/clang-18.1.0/bin/clang++
+compiler.clang1810_clad180.semver=18.1.0 (clad 1.8)
+compiler.clang1810_clad180.options=--gcc-toolchain=/opt/compiler-explorer/gcc-13.2.0 -fplugin=/opt/compiler-explorer/clang-plugins/clad-1.8-clang-18.1.0/lib/clad.so -I/opt/compiler-explorer/clang-plugins/clad-1.8-clang-18.1.0/include
+compiler.clang1810_clad180.ldPath=${exePath}/../lib|${exePath}/../lib/x86_64-unknown-linux-gnu
+compiler.clang1810_clad180.debugPatched=true
 compiler.clang1910.exe=/opt/compiler-explorer/clang-19.1.0/bin/clang++
 compiler.clang1910.semver=19.1.0
 compiler.clang1910.options=--gcc-toolchain=/opt/compiler-explorer/gcc-14.2.0
@@ -3882,6 +3887,26 @@ compiler.vast-trunk.exe=/opt/compiler-explorer/vast-trunk/bin/vast-front
 compiler.vast-trunk.isNightly=true
 compiler.vast-trunk.options=-resource-dir /opt/compiler-explorer/clang-17.0.1/lib/clang/17/ --gcc-toolchain=/opt/compiler-explorer/gcc-13.2.0
 
+#################################
+# QNX
+group.qnx.compilers=qnx800
+group.qnx.groupName=QNX
+group.qnx.compilerType=qnx
+group.qnx.isSemVer=true
+group.qnx.baseName=qnx
+group.qnx.licenseLink=https://blackberry.qnx.com/en/products/qnx-everywhere/licensing
+group.qnx.licenseName=QNX Everywhere (Non-Commercial)
+group.qnx.licensePreamble=QNX Everywhere / Non-Commercial only. Proprietary for commercial applications.
+
+# Don't be tempted to put group.qnx.qnxLicense here - it needs to be on each individually
+# See https://github.com/compiler-explorer/compiler-explorer/issues/7150
+
+compiler.qnx800.exe=/opt/compiler-explorer/qnx-800/host/linux/x86_64/usr/bin/q++
+compiler.qnx800.semver=8.0.0
+compiler.qnx800.qnxHost=/opt/compiler-explorer/qnx-800/host/linux/x86_64
+compiler.qnx800.qnxTarget=/opt/compiler-explorer/qnx-800/target/qnx
+compiler.qnx800.qnxLicense=/opt/qnx/licenses
+
 #################################
 #################################
 # Installed libs
diff --git a/etc/config/compiler-explorer.amazon.properties b/etc/config/compiler-explorer.amazon.properties
index 5a4d98906..1b11ad343 100644
--- a/etc/config/compiler-explorer.amazon.properties
+++ b/etc/config/compiler-explorer.amazon.properties
@@ -11,7 +11,6 @@ cacheConfig=InMemory(25);S3(storage.godbolt.org,cache,us-east-1)
 executableCacheConfig=S3(storage.godbolt.org,cache,us-east-1)
 # Anything outside will not expire
 compilerCacheConfig=S3(storage.godbolt.org,compiler-info-cache,us-east-1)
-clientGoogleAnalyticsEnabled=true
 # Do not get too stuck on failed proxies or the instances might not be able to wake up
 proxyRetries=10
 proxyRetryMs=500
diff --git a/etc/config/compiler-explorer.amazonwin.properties b/etc/config/compiler-explorer.amazonwin.properties
index 96b96b9f6..a5021a587 100644
--- a/etc/config/compiler-explorer.amazonwin.properties
+++ b/etc/config/compiler-explorer.amazonwin.properties
@@ -24,7 +24,6 @@ eventLoopLagThresholdErr=1000
 compileTimeoutMs=25000
 binaryExecTimeoutMs=15000
 
-clientGoogleAnalyticsEnabled=false
 thirdPartyIntegrationEnabled=false
 statusTrackingEnabled=false
 
diff --git a/etc/nsjail/compilers-and-tools.cfg b/etc/nsjail/compilers-and-tools.cfg
index 7230f33eb..a3690d4ad 100644
--- a/etc/nsjail/compilers-and-tools.cfg
+++ b/etc/nsjail/compilers-and-tools.cfg
@@ -209,6 +209,14 @@ mount {
     mandatory: false
 }
 
+# Needed for QNX non-free compilers
+mount {
+    src: "/opt/qnx"
+    dst: "/opt/qnx"
+    is_bind: true
+    mandatory: false
+}
+
 # Needed for things with shim scripts e.g. Python
 mount {
     src: "/infra/.deploy/etc/scripts"
diff --git a/examples/android-java/default.java b/examples/android-java/default.java
index 8fdbfb493..b3049143c 100644
--- a/examples/android-java/default.java
+++ b/examples/android-java/default.java
@@ -3,6 +3,9 @@
 // For R8, please load R8Example for an example with a keep annotation,
 // which will prevent unused code from being removed from the final output.
 //
+// For dex2oat, 'Filter...' > 'Directives' can be unchecked for full
+// oatdump output.
+//
 // (For advanced use only) Click "Templates > Android Java IDE" for
 // profile-guided compilation.
 
diff --git a/examples/android-kotlin/default.kt b/examples/android-kotlin/default.kt
index a41ad43dd..66c00b1f7 100644
--- a/examples/android-kotlin/default.kt
+++ b/examples/android-kotlin/default.kt
@@ -3,6 +3,9 @@
 // For R8, please load R8Example for an example with a keep annotation,
 // which will prevent unused code from being removed from the final output.
 //
+// For dex2oat, 'Filter...' > 'Directives' can be unchecked for full
+// oatdump output.
+//
 // (For advanced use only) Click "Templates > Android Kotlin IDE" for
 // profile-guided compilation.
 
diff --git a/lib/base-compiler.ts b/lib/base-compiler.ts
index 4381c6f77..67c3aeb34 100644
--- a/lib/base-compiler.ts
+++ b/lib/base-compiler.ts
@@ -123,6 +123,7 @@ import type {PropertyGetter} from './properties.interfaces.js';
 import {propsFor} from './properties.js';
 import {HeaptrackWrapper} from './runtime-tools/heaptrack-wrapper.js';
 import {LibSegFaultHelper} from './runtime-tools/libsegfault-helper.js';
+import {SentryCapture} from './sentry.js';
 import * as StackUsage from './stack-usage-transformer.js';
 import {
     clang_style_sysroot_flag,
@@ -3025,8 +3026,8 @@ export class BaseCompiler {
 
         if (result.optPath) {
             delete result.optPath;
-            result.optOutput = optOutput;
         }
+        result.optOutput = optOutput;
 
         if (result.stackUsagePath) {
             delete result.stackUsagePath;
@@ -3136,12 +3137,77 @@ export class BaseCompiler {
         return await demangler.process(result);
     }
 
-    async processOptOutput(optPath: string) {
-        const optRemarksRaw = await fs.readFile(optPath, 'utf8');
-        const output: OptRemark[] = processRawOptRemarks(optRemarksRaw, this.compileFilename);
+    processGccOptInfo(stderr: ResultLine[], compileFileName: string): {remarks: OptRemark[]; newStdErr: ResultLine[]} {
+        const remarks: OptRemark[] = [];
+        const nonRemarkStderr: ResultLine[] = [];
 
-        if (this.compiler.demangler) {
-            const result = JSON.stringify(output, null, 4);
+        // example stderr lines:
+        // <source>:3:20: optimized: loop vectorized using 8 byte vectors
+        // <source>: 2: 6: note: vectorized 1 loops in function.
+        // <source>:11:13: missed: statement clobbers memory: somefunc (&i);
+        const remarkRegex = /^(.*?):\s*(\d+):\s*(\d+): (.*?): (.*)$/;
+
+        const mapOptType = (type: string, line: ResultLine): 'Missed' | 'Passed' | 'Analysis' => {
+            if (type === 'missed') return 'Missed';
+            if (type === 'optimized') return 'Passed';
+            if (type === 'note') return 'Analysis';
+
+            // Did we miss any types?
+            SentryCapture(line, `Unexpected opt type: ${type}`);
+            return 'Analysis';
+        };
+
+        for (const line of stderr) {
+            const match = line.text.match(remarkRegex);
+            if (match) {
+                const [_, file, lineNum, colNum, type, message] = match;
+                if (!file || (file !== '<source>' && !file.includes(compileFileName))) continue;
+
+                // convert to llvm-emitted OptRemark format, just because it was here first
+                remarks.push({
+                    DebugLoc: {
+                        File: file,
+                        // Could use line.tag for these too:
+                        Line: parseInt(lineNum, 10),
+                        Column: parseInt(colNum, 10),
+                    },
+                    optType: mapOptType(type, line),
+                    displayString: message,
+                    // TODO: make these optional?
+                    Function: '',
+                    Pass: '',
+                    Name: '',
+                    Args: [],
+                });
+            } else {
+                nonRemarkStderr.push(line);
+            }
+        }
+        // We omit remark lines from stderr to avoid it causing red squigglies in the source pane
+        return {remarks: remarks, newStdErr: nonRemarkStderr};
+    }
+
+    async processOptOutput(compilationRes: CompilationResult) {
+        // The distinction between clang and gcc opt remarks is a bit ad-hoc. A cleaner way might have been
+        // to override processOptOutput in ClangCompiler and GCCCompiler, but that would have required having
+        // all llvm-based compilers inherit ClangCompiler and all gcc-based ones inherit GCCCompiler.
+        // Might be a good idea to refactor this some day.
+
+        let remarks: OptRemark[] = [];
+        if (this.compiler.optArg && this.compiler.optArg === '-fopt-info-all') {
+            // gcc-like
+            ({remarks, newStdErr: compilationRes.stderr} = this.processGccOptInfo(
+                compilationRes.stderr,
+                this.compileFilename,
+            ));
+        } else if (compilationRes.optPath) {
+            // clang-like
+            const optRemarksRaw = await fs.readFile(compilationRes.optPath, 'utf8');
+            remarks = processRawOptRemarks(optRemarksRaw, this.compileFilename);
+        }
+
+        if (remarks.length > 0 && this.compiler.demangler) {
+            const result = JSON.stringify(remarks, null, 4);
             const demangleResult: UnprocessedExecResult = await this.exec(
                 this.compiler.demangler,
                 [...this.compiler.demanglerArgs, '-n'],
@@ -3156,8 +3222,7 @@ export class BaseCompiler {
                 }
             }
         }
-
-        return output;
+        return remarks;
     }
 
     async processStackUsageOutput(suPath: string): Promise<StackUsage.StackUsageInfo[]> {
@@ -3342,7 +3407,7 @@ but nothing was dumped. Possible causes are:
     async postProcess(result: CompilationResult, outputFilename: string, filters: ParseFiltersAndOutputOptions) {
         const postProcess = _.compact(this.compiler.postProcess);
         const maxSize = this.env.ceProps('max-asm-size', 64 * 1024 * 1024);
-        const optPromise = result.optPath ? this.processOptOutput(unwrap(result.optPath)) : ([] as OptRemark[]);
+        const optPromise = this.processOptOutput(result);
         const stackUsagePromise = result.stackUsagePath
             ? this.processStackUsageOutput(result.stackUsagePath)
             : ([] as StackUsage.StackUsageInfo[]);
diff --git a/lib/compilers/_all.ts b/lib/compilers/_all.ts
index 90d2ff31d..5e10b9f3c 100644
--- a/lib/compilers/_all.ts
+++ b/lib/compilers/_all.ts
@@ -117,6 +117,7 @@ export {PPCICompiler} from './ppci.js';
 export {PtxAssembler} from './ptxas.js';
 export {PythonCompiler} from './python.js';
 export {PythranCompiler} from './pythran.js';
+export {QNXCompiler} from './qnx.js';
 export {R8Compiler} from './r8.js';
 export {RacketCompiler} from './racket.js';
 export {RGACompiler} from './rga.js';
diff --git a/lib/compilers/argument-parsers.ts b/lib/compilers/argument-parsers.ts
index 016a8ce38..ac240a140 100644
--- a/lib/compilers/argument-parsers.ts
+++ b/lib/compilers/argument-parsers.ts
@@ -180,6 +180,10 @@ export class GCCParser extends BaseParser {
         if (this.hasSupport(options, '-fverbose-asm')) {
             compiler.compiler.supportsVerboseAsm = true;
         }
+        if (this.hasSupport(options, '-fopt-info')) {
+            compiler.compiler.optArg = '-fopt-info-all';
+            compiler.compiler.supportsOptOutput = true;
+        }
         // This check is not infallible, but takes care of Rust and Swift being picked up :)
         if (_.find(keys, key => key.startsWith('-fdump-'))) {
             compiler.compiler.supportsGccDump = true;
diff --git a/lib/compilers/dex2oat.ts b/lib/compilers/dex2oat.ts
index 5d60080f1..a49a5ed21 100644
--- a/lib/compilers/dex2oat.ts
+++ b/lib/compilers/dex2oat.ts
@@ -361,7 +361,7 @@ export class Dex2OatCompiler extends BaseCompiler {
         };
     }
 
-    override async processAsm(result) {
+    override async processAsm(result, filters: ParseFiltersAndOutputOptions) {
         let asm: string = '';
 
         if (typeof result.asm === 'string') {
@@ -381,7 +381,7 @@ export class Dex2OatCompiler extends BaseCompiler {
         }
 
         const segments: ParsedAsmResultLine[] = [];
-        if (this.fullOutput) {
+        if (this.fullOutput || !filters.directives) {
             // Returns entire dex2oat output.
             segments.push({text: asm, source: null});
         } else {
diff --git a/lib/compilers/qnx.ts b/lib/compilers/qnx.ts
new file mode 100644
index 000000000..33602337e
--- /dev/null
+++ b/lib/compilers/qnx.ts
@@ -0,0 +1,56 @@
+// Copyright (c) 2024, Compiler Explorer Authors
+// All rights reserved.
+//
+// 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.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+
+import {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
+import {BaseCompiler} from '../base-compiler.js';
+import {CompilationEnvironment} from '../compilation-env.js';
+
+export class QNXCompiler extends BaseCompiler {
+    qnxHost: string;
+    qnxTarget: string;
+    qnxLicense: string;
+
+    static get key() {
+        return 'qnx';
+    }
+
+    constructor(info: PreliminaryCompilerInfo, env: CompilationEnvironment) {
+        super(info, env);
+        this.qnxHost = this.compilerProps<string>(`compiler.${this.compiler.id}.qnxHost`);
+        this.qnxTarget = this.compilerProps<string>(`compiler.${this.compiler.id}.qnxTarget`);
+        this.qnxLicense = this.compilerProps<string>(`compiler.${this.compiler.id}.qnxLicense`);
+    }
+
+    override getDefaultExecOptions() {
+        const execOptions = super.getDefaultExecOptions();
+        execOptions.env = {
+            ...execOptions.env,
+            QNX_HOST: this.qnxHost,
+            QNX_TARGET: this.qnxTarget,
+            QNX_SHARED_LICENSE_FILE: this.qnxLicense,
+        };
+
+        return execOptions;
+    }
+}
diff --git a/static/modes/glsl-mode.ts b/static/modes/glsl-mode.ts
index 7a6533bb8..1384d547a 100644
--- a/static/modes/glsl-mode.ts
+++ b/static/modes/glsl-mode.ts
@@ -737,5 +737,6 @@ function definition(): monaco.languages.IMonarchLanguage {
 
 monaco.languages.register({id: 'glsl'});
 monaco.languages.setMonarchTokensProvider('glsl', definition());
+monaco.languages.setLanguageConfiguration('glsl', cpp.conf);
 
 export {};
diff --git a/static/modes/hlsl-mode.ts b/static/modes/hlsl-mode.ts
index 7d78f30c1..e265858f9 100644
--- a/static/modes/hlsl-mode.ts
+++ b/static/modes/hlsl-mode.ts
@@ -321,5 +321,6 @@ function definition(): monaco.languages.IMonarchLanguage {
 
 monaco.languages.register({id: 'hlsl'});
 monaco.languages.setMonarchTokensProvider('hlsl', definition());
+monaco.languages.setLanguageConfiguration('hlsl', cpp.conf);
 
 export {};
diff --git a/static/modes/slang-mode.ts b/static/modes/slang-mode.ts
index 02b607af5..7b0784e2c 100644
--- a/static/modes/slang-mode.ts
+++ b/static/modes/slang-mode.ts
@@ -268,5 +268,6 @@ function definition(): monaco.languages.IMonarchLanguage {
 
 monaco.languages.register({id: 'slang'});
 monaco.languages.setMonarchTokensProvider('slang', definition());
+monaco.languages.setLanguageConfiguration('slang', cpp.conf);
 
 export {};
diff --git a/static/modes/spirv-mode.ts b/static/modes/spirv-mode.ts
index 34fd2fd84..cdfc1bb8d 100644
--- a/static/modes/spirv-mode.ts
+++ b/static/modes/spirv-mode.ts
@@ -47,7 +47,16 @@ export function definition(): monaco.languages.IMonarchLanguage {
     };
 }
 
+function configuration(): monaco.languages.LanguageConfiguration {
+    return {
+        comments: {
+            lineComment: ';',
+        },
+    };
+}
+
 monaco.languages.register({id: 'spirv'});
 monaco.languages.setMonarchTokensProvider('spirv', definition());
+monaco.languages.setLanguageConfiguration('spirv', configuration());
 
 export {};
diff --git a/static/panes/opt-view.interfaces.ts b/static/panes/opt-view.interfaces.ts
index b3fa0741e..3a271c8d2 100644
--- a/static/panes/opt-view.interfaces.ts
+++ b/static/panes/opt-view.interfaces.ts
@@ -39,12 +39,12 @@ type SourceLocation = {
     Column: number;
 };
 
+// TODO: move from static to interfaces
 export type OptRemark = {
     DebugLoc: SourceLocation;
     Function: string;
     Pass: string;
     Name: string;
-    text: string;
     optType: 'Missed' | 'Passed' | 'Analysis';
     displayString: string;
     Args: Array<object>;
diff --git a/static/panes/pp-view.interfaces.ts b/static/panes/pp-view.interfaces.ts
index 10bcba83f..0c94e5a61 100644
--- a/static/panes/pp-view.interfaces.ts
+++ b/static/panes/pp-view.interfaces.ts
@@ -26,6 +26,7 @@ export interface PPViewState {
     ppOutput: any;
 }
 
+// TODO: move to interfaces
 export type PPOptions = {
     'filter-headers': boolean;
     'clang-format': boolean;


Test patch:
diff --git a/test/android-tests.ts b/test/android-tests.ts
index 969f71d08..39ecfe2ec 100644
--- a/test/android-tests.ts
+++ b/test/android-tests.ts
@@ -97,7 +97,7 @@ describe('dex2oat', () => {
         const objdumpResult = {
             asm,
         };
-        const processed = await compiler.processAsm(objdumpResult);
+        const processed = await compiler.processAsm(objdumpResult, compiler.getDefaultFilters());
         expect(processed).toHaveProperty('asm');
         const actualSegments = (processed as {asm: ParsedAsmResultLine[]}).asm;
 
diff --git a/test/base-compiler-tests.ts b/test/base-compiler-tests.ts
index 39aa320f2..6da95af7e 100644
--- a/test/base-compiler-tests.ts
+++ b/test/base-compiler-tests.ts
@@ -32,6 +32,7 @@ import {RustCompiler} from '../lib/compilers/rust.js';
 import {Win32Compiler} from '../lib/compilers/win32.js';
 import * as props from '../lib/properties.js';
 import {splitArguments} from '../shared/common-utils.js';
+import {CompilationResult} from '../types/compilation/compilation.interfaces.js';
 import {CompilerOverrideType, ConfiguredOverrides} from '../types/compilation/compiler-overrides.interfaces.js';
 import {CompilerInfo} from '../types/compiler.interfaces.js';
 
@@ -626,7 +627,7 @@ describe('Compiler execution', () => {
     //     return objdumpTest('llvm', ['-d', 'output', '-l', '-C', '--x86-asm-syntax=intel']);
     // });
 
-    it('should run process opt output', async () => {
+    it('should run process llvm opt output', async () => {
         const test = `--- !Missed
 Pass: inline
 Name: NeverInline
@@ -638,7 +639,8 @@ Args: []
         const dirPath = await compiler.newTempDir();
         const optPath = path.join(dirPath, 'temp.out');
         await fs.writeFile(optPath, test);
-        expect(await compiler.processOptOutput(optPath)).toEqual([
+        const dummyResult: CompilationResult = {optPath: optPath, code: 0, stdout: [], stderr: [], timedOut: false};
+        expect(await compiler.processOptOutput(dummyResult)).toEqual([
             {
                 Args: [],
                 DebugLoc: {Column: 21, File: 'example.cpp', Line: 4},
@@ -651,6 +653,59 @@ Args: []
         ]);
     });
 
+    it('should run process gcc opt output', async () => {
+        const test = [
+            {
+                text: '<source>:5:9: optimized: loop with 1 iterations completely unrolled (header execution count 78082503)',
+            },
+            {text: '<source>:3:6: note: ***** Analysis failed with vector mode V4SI'},
+            {
+                text: '<source>:11:6: missed: splitting region at control altering definition _44 = std::basic_filebuf<char>::open (&fs._M_filebuf, "myfile", 16);',
+            },
+            {
+                text: '/opt/compiler-explorer/gcc-14.1.0/include/c++/14.1.0/bits/basic_ios.h:466:59: missed: statement clobbers memory: std::ios_base::ios_base (&MEM[(struct basic_ios *)&fs + 248B].D.46591);',
+            },
+        ];
+        const dummyResult: CompilationResult = {
+            code: 0,
+            stdout: [],
+            stderr: test,
+            timedOut: false,
+        };
+        const tmpCompiler = compiler;
+        tmpCompiler.compiler.optArg = '-fopt-info-all';
+        expect(await tmpCompiler.processOptOutput(dummyResult)).toEqual([
+            {
+                Args: [],
+                DebugLoc: {File: '<source>', Line: 5, Column: 9},
+                Function: '',
+                Name: '',
+                Pass: '',
+                displayString: 'loop with 1 iterations completely unrolled (header execution count 78082503)',
+                optType: 'Passed',
+            },
+            {
+                Args: [],
+                DebugLoc: {File: '<source>', Line: 3, Column: 6},
+                Function: '',
+                Name: '',
+                Pass: '',
+                displayString: '***** Analysis failed with vector mode V4SI',
+                optType: 'Analysis',
+            },
+            {
+                Args: [],
+                DebugLoc: {File: '<source>', Line: 11, Column: 6},
+                Function: '',
+                Name: '',
+                Pass: '',
+                displayString:
+                    'splitting region at control altering definition _44 = std::basic_filebuf<char>::open (&fs._M_filebuf, "myfile", 16);',
+                optType: 'Missed',
+            },
+        ]);
+    });
+
     it('should normalize extra file path', () => {
         const withDemangler = {...noExecuteSupportCompilerInfo, demangler: 'demangler-exe', demanglerType: 'cpp'};
         const compiler = new BaseCompiler(withDemangler, ce) as any; // to get to the protected...