aboutsummaryrefslogtreecommitdiff
path: root/lib/compilers
diff options
context:
space:
mode:
authorJ. Ryan Stinnett <jryans@gmail.com>2023-12-12 01:35:45 +0000
committerGitHub <noreply@github.com>2023-12-11 19:35:45 -0600
commitf0e1d5d26490b4a62aaee35b4cfc700d6e3f8a1c (patch)
treeb238d2e81495603183d34adb65b6b33a715f1c25 /lib/compilers
parent7d3156ae5ffe62a9f8b9188ea7f8c92276f526a1 (diff)
downloadcompiler-explorer-f0e1d5d26490b4a62aaee35b4cfc700d6e3f8a1c.tar.gz
compiler-explorer-f0e1d5d26490b4a62aaee35b4cfc700d6e3f8a1c.zip
Add Racket optimisation pipeline (#5836)gh-9905
This adds a Racket optimisation pipeline view by reusing the existing LLVM-focused optimisation pipeline UI. A Racket-specific pass parser translates its output into passes for the UI to present. This new Racket optimisation pipeline view is currently only enabled for Racket nightly, as it depends on [recent changes](https://github.com/racket/racket/pull/4842) to Racket's compiler output to function. This also extends the opt pipeline view to allow customising the function selector label as well as the options and filters for each compiler where needed. ![image](https://github.com/compiler-explorer/compiler-explorer/assets/279572/f540b41e-fd55-4375-bb2d-a0bb977530b3) --------- Co-authored-by: Matt Godbolt <matt@godbolt.org>
Diffstat (limited to 'lib/compilers')
-rw-r--r--lib/compilers/argument-parsers.ts26
-rw-r--r--lib/compilers/hlsl.ts8
-rw-r--r--lib/compilers/llc.ts9
-rw-r--r--lib/compilers/opt.ts9
-rw-r--r--lib/compilers/racket.ts135
-rw-r--r--lib/compilers/rust.ts9
-rw-r--r--lib/compilers/snowball.ts6
-rw-r--r--lib/compilers/swift.ts9
8 files changed, 179 insertions, 32 deletions
diff --git a/lib/compilers/argument-parsers.ts b/lib/compilers/argument-parsers.ts
index cd89e9783..026c61c3c 100644
--- a/lib/compilers/argument-parsers.ts
+++ b/lib/compilers/argument-parsers.ts
@@ -275,15 +275,16 @@ export class ClangParser extends BaseParser {
this.mllvmOptions.has('--print-before-all') &&
this.mllvmOptions.has('--print-after-all')
) {
- compiler.compiler.supportsOptPipelineView = true;
- compiler.compiler.optPipelineArg = ['-mllvm', '--print-before-all', '-mllvm', '--print-after-all'];
- compiler.compiler.optPipelineModuleScopeArg = [];
- compiler.compiler.optPipelineNoDiscardValueNamesArg = [];
+ compiler.compiler.optPipeline = {
+ arg: ['-mllvm', '--print-before-all', '-mllvm', '--print-after-all'],
+ moduleScopeArg: [],
+ noDiscardValueNamesArg: [],
+ };
if (this.mllvmOptions.has('--print-module-scope')) {
- compiler.compiler.optPipelineModuleScopeArg = ['-mllvm', '-print-module-scope'];
+ compiler.compiler.optPipeline.moduleScopeArg = ['-mllvm', '-print-module-scope'];
}
if (this.hasSupport(options, '-fno-discard-value-names')) {
- compiler.compiler.optPipelineNoDiscardValueNamesArg = ['-fno-discard-value-names'];
+ compiler.compiler.optPipeline.noDiscardValueNamesArg = ['-fno-discard-value-names'];
}
}
@@ -496,15 +497,16 @@ export class LDCParser extends BaseParser {
}
if (this.hasSupport(options, '--print-before-all') && this.hasSupport(options, '--print-after-all')) {
- compiler.compiler.supportsOptPipelineView = true;
- compiler.compiler.optPipelineArg = ['--print-before-all', '--print-after-all'];
- compiler.compiler.optPipelineModuleScopeArg = [];
- compiler.compiler.optPipelineNoDiscardValueNamesArg = [];
+ compiler.compiler.optPipeline = {
+ arg: ['--print-before-all', '--print-after-all'],
+ moduleScopeArg: [],
+ noDiscardValueNamesArg: [],
+ };
if (this.hasSupport(options, '--print-module-scope')) {
- compiler.compiler.optPipelineModuleScopeArg = ['--print-module-scope'];
+ compiler.compiler.optPipeline.moduleScopeArg = ['--print-module-scope'];
}
if (this.hasSupport(options, '--fno-discard-value-names')) {
- compiler.compiler.optPipelineNoDiscardValueNamesArg = ['--fno-discard-value-names'];
+ compiler.compiler.optPipeline.noDiscardValueNamesArg = ['--fno-discard-value-names'];
}
}
diff --git a/lib/compilers/hlsl.ts b/lib/compilers/hlsl.ts
index c4d2f8e48..c4b8f727a 100644
--- a/lib/compilers/hlsl.ts
+++ b/lib/compilers/hlsl.ts
@@ -41,9 +41,11 @@ export class HLSLCompiler extends BaseCompiler {
this.compiler.supportsIntel = false;
this.spirvAsm = new SPIRVAsmParser(this.compilerProps);
- this.compiler.supportsOptPipelineView = true;
- this.compiler.optPipelineArg = ['-print-before-all', '-print-after-all'];
- this.compiler.optPipelineNoDiscardValueNamesArg = [];
+ this.compiler.optPipeline = {
+ arg: ['-print-before-all', '-print-after-all'],
+ moduleScopeArg: [],
+ noDiscardValueNamesArg: [],
+ };
}
override async generateAST(inputFilename, options): Promise<ResultLine[]> {
diff --git a/lib/compilers/llc.ts b/lib/compilers/llc.ts
index dc7144817..b236e0c39 100644
--- a/lib/compilers/llc.ts
+++ b/lib/compilers/llc.ts
@@ -36,10 +36,11 @@ export class LLCCompiler extends BaseCompiler {
constructor(info: PreliminaryCompilerInfo, env) {
super(info, env);
this.compiler.supportsIntel = true;
- this.compiler.supportsOptPipelineView = true;
- this.compiler.optPipelineArg = ['-print-after-all', '-print-before-all'];
- this.compiler.optPipelineModuleScopeArg = ['-print-module-scope'];
- this.compiler.optPipelineNoDiscardValueNamesArg = [];
+ this.compiler.optPipeline = {
+ arg: ['-print-after-all', '-print-before-all'],
+ moduleScopeArg: ['-print-module-scope'],
+ noDiscardValueNamesArg: [],
+ };
}
override getSharedLibraryPathsAsArguments() {
diff --git a/lib/compilers/opt.ts b/lib/compilers/opt.ts
index 418230f31..753fc2b26 100644
--- a/lib/compilers/opt.ts
+++ b/lib/compilers/opt.ts
@@ -35,10 +35,11 @@ export class OptCompiler extends BaseCompiler {
constructor(info: PreliminaryCompilerInfo, env) {
super(info, env);
- this.compiler.supportsOptPipelineView = true;
- this.compiler.optPipelineArg = ['-print-after-all', '-print-before-all'];
- this.compiler.optPipelineModuleScopeArg = ['-print-module-scope'];
- this.compiler.optPipelineNoDiscardValueNamesArg = [];
+ this.compiler.optPipeline = {
+ arg: ['-print-after-all', '-print-before-all'],
+ moduleScopeArg: ['-print-module-scope'],
+ noDiscardValueNamesArg: [],
+ };
}
override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: string) {
diff --git a/lib/compilers/racket.ts b/lib/compilers/racket.ts
index 0811058d1..57a4fb0bf 100644
--- a/lib/compilers/racket.ts
+++ b/lib/compilers/racket.ts
@@ -24,14 +24,22 @@
import path from 'path';
+import fs from 'fs-extra';
+
import type {CompilationResult, ExecutionOptions} from '../../types/compilation/compilation.interfaces.js';
import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
+import type {
+ OptPipelineBackendOptions,
+ OptPipelineOutput,
+} from '../../types/compilation/opt-pipeline-output.interfaces.js';
import {BaseCompiler} from '../base-compiler.js';
import {logger} from '../logger.js';
+import {RacketPassDumpParser} from '../parsers/racket-pass-dump-parser.js';
export class RacketCompiler extends BaseCompiler {
private raco: string;
+ private passDumpParser: RacketPassDumpParser;
static get key() {
return 'racket';
@@ -46,7 +54,17 @@ export class RacketCompiler extends BaseCompiler {
},
env,
);
+ // Revise this if we add released versions of Racket 8.12 or later
+ if (this.compiler.isNightly) {
+ this.compiler.optPipeline = {
+ groupName: 'Linklet',
+ // Disable all options and filters, currently unsupported
+ supportedOptions: [],
+ supportedFilters: [],
+ };
+ }
this.raco = this.compilerProps<string>(`compiler.${this.compiler.id}.raco`);
+ this.passDumpParser = new RacketPassDumpParser(this.compilerProps);
}
override optionsForFilter(
@@ -62,6 +80,10 @@ export class RacketCompiler extends BaseCompiler {
return [];
}
+ override isCfgCompiler(/*compilerVersion*/) {
+ return false;
+ }
+
override supportsObjdump(): boolean {
return true;
}
@@ -70,6 +92,28 @@ export class RacketCompiler extends BaseCompiler {
return [];
}
+ override orderArguments(
+ options: string[],
+ inputFilename: string,
+ libIncludes: string[],
+ libOptions: string[],
+ libPaths: string[],
+ libLinks: string[],
+ userOptions: string[],
+ staticLibLinks: string[],
+ ) {
+ // Move input file to end of options
+ return options.concat(
+ userOptions,
+ libIncludes,
+ libOptions,
+ libPaths,
+ libLinks,
+ staticLibLinks,
+ [this.filename(inputFilename)],
+ );
+ }
+
override async runCompiler(
compiler: string,
options: string[],
@@ -85,7 +129,14 @@ export class RacketCompiler extends BaseCompiler {
}
// Compile to bytecode via `raco make`
+ options = [...options];
options.unshift('make');
+
+ // Replace input filename (which may be different than the default)
+ // as in pipeline mode below
+ options.pop();
+ options.push(inputFilename);
+
const makeResult = await this.exec(this.raco, options, execOptions);
return this.transformToCompilationResult(makeResult, inputFilename);
@@ -129,4 +180,88 @@ export class RacketCompiler extends BaseCompiler {
asm: [{text: result.asm}],
};
}
+
+ override async generateOptPipeline(
+ inputFilename: string,
+ options: string[],
+ filters: ParseFiltersAndOutputOptions,
+ optPipelineOptions: OptPipelineBackendOptions,
+ ): Promise<OptPipelineOutput | undefined> {
+ // Use a separate directory so this is not affected by the main
+ // compilation (which races in parallel)
+ const pipelineDir = await this.newTempDir();
+ const inputFile = this.filename(inputFilename);
+ const pipelineFile = path.join(pipelineDir, path.basename(inputFile));
+ await fs.copyFile(inputFile, pipelineFile);
+
+ const execOptions = this.getDefaultExecOptions();
+ execOptions.maxOutput = 1024 * 1024 * 1024;
+
+ // Dump various optimisation passes during compilation
+ execOptions.env['PLT_LINKLET_SHOW_CP0'] = '1';
+ execOptions.env['PLT_LINKLET_SHOW_PASSES'] = 'all';
+ execOptions.env['PLT_LINKLET_SHOW_ASSEMBLY'] = '1';
+
+ const compileStart = performance.now();
+ const output = await this.runCompiler(
+ this.compiler.exe,
+ options,
+ pipelineFile,
+ execOptions,
+ );
+ const compileEnd = performance.now();
+
+ if (output.timedOut) {
+ return {
+ error: 'Racket invocation timed out',
+ results: {},
+ compileTime: output.execTime || compileEnd - compileStart,
+ };
+ }
+
+ if (output.code !== 0) {
+ return;
+ }
+
+ // Useful for local debugging
+ // const passesFile = path.join(pipelineDir, 'passes.scm');
+ // console.log('Passes:', passesFile);
+ // await fs.writeFile(passesFile, output.stderr.map(l => l.text).join('\n'));
+
+ try {
+ const parseStart = performance.now();
+ const llvmOptPipeline = await this.processOptPipeline(
+ output,
+ filters,
+ optPipelineOptions,
+ /* debugPatched = */ false,
+ );
+ const parseEnd = performance.now();
+
+ return {
+ results: llvmOptPipeline,
+ compileTime: compileEnd - compileStart,
+ parseTime: parseEnd - parseStart,
+ };
+ } catch (e: any) {
+ return {
+ error: e.toString(),
+ results: {},
+ compileTime: compileEnd - compileStart,
+ };
+ }
+ }
+
+ override async processOptPipeline(
+ output,
+ filters: ParseFiltersAndOutputOptions,
+ optPipelineOptions: OptPipelineBackendOptions,
+ debugPatched?: boolean,
+ ) {
+ return this.passDumpParser.process(
+ output.stderr,
+ filters,
+ optPipelineOptions,
+ );
+ }
}
diff --git a/lib/compilers/rust.ts b/lib/compilers/rust.ts
index e57a86840..be3448db8 100644
--- a/lib/compilers/rust.ts
+++ b/lib/compilers/rust.ts
@@ -49,7 +49,6 @@ export class RustCompiler extends BaseCompiler {
super(info, env);
this.compiler.supportsIntel = true;
this.compiler.supportsIrView = true;
- this.compiler.supportsOptPipelineView = true;
this.compiler.supportsRustMirView = true;
const isNightly = this.isNightly();
@@ -60,9 +59,11 @@ export class RustCompiler extends BaseCompiler {
this.compiler.irArg = ['--emit', 'llvm-ir'];
this.compiler.minIrArgs = ['--emit=llvm-ir'];
- this.compiler.optPipelineArg = ['-C', 'llvm-args=-print-after-all -print-before-all'];
- this.compiler.optPipelineModuleScopeArg = ['-C', 'llvm-args=-print-module-scope'];
- this.compiler.optPipelineNoDiscardValueNamesArg = isNightly ? ['-Z', 'fewer-names=no'] : [];
+ this.compiler.optPipeline = {
+ arg: ['-C', 'llvm-args=-print-after-all -print-before-all'],
+ moduleScopeArg: ['-C', 'llvm-args=-print-module-scope'],
+ noDiscardValueNamesArg: isNightly ? ['-Z', 'fewer-names=no'] : [],
+ };
this.linker = this.compilerProps<string>('linker');
}
diff --git a/lib/compilers/snowball.ts b/lib/compilers/snowball.ts
index 2e3a3d1e2..7698b682e 100644
--- a/lib/compilers/snowball.ts
+++ b/lib/compilers/snowball.ts
@@ -40,7 +40,11 @@ export class SnowballCompiler extends BaseCompiler {
super(info, env);
this.compiler.supportsIntel = true;
this.compiler.supportsIrView = true;
- this.compiler.supportsOptPipelineView = true;
+ this.compiler.optPipeline = {
+ arg: [],
+ moduleScopeArg: [],
+ noDiscardValueNamesArg: [],
+ };
this.compiler.supportsCfg = true;
this.compiler.irArg = ['--emit', 'llvm-ir'];
diff --git a/lib/compilers/swift.ts b/lib/compilers/swift.ts
index 7d943752f..2844be29c 100644
--- a/lib/compilers/swift.ts
+++ b/lib/compilers/swift.ts
@@ -35,10 +35,11 @@ export class SwiftCompiler extends BaseCompiler {
constructor(info: PreliminaryCompilerInfo, env) {
super(info, env);
- this.compiler.supportsOptPipelineView = true;
- this.compiler.optPipelineArg = ['-Xllvm', '-print-after-all', '-Xllvm', '-print-before-all'];
- this.compiler.optPipelineModuleScopeArg = ['-Xllvm', '-print-module-scope'];
- this.compiler.optPipelineNoDiscardValueNamesArg = [];
+ this.compiler.optPipeline = {
+ arg: ['-Xllvm', '-print-after-all', '-Xllvm', '-print-before-all'],
+ moduleScopeArg: ['-Xllvm', '-print-module-scope'],
+ noDiscardValueNamesArg: [],
+ };
}
override getSharedLibraryPathsAsArguments() {