diff options
author | J. Ryan Stinnett <jryans@gmail.com> | 2023-12-12 01:35:45 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-11 19:35:45 -0600 |
commit | f0e1d5d26490b4a62aaee35b4cfc700d6e3f8a1c (patch) | |
tree | b238d2e81495603183d34adb65b6b33a715f1c25 /lib/compilers | |
parent | 7d3156ae5ffe62a9f8b9188ea7f8c92276f526a1 (diff) | |
download | compiler-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.

---------
Co-authored-by: Matt Godbolt <matt@godbolt.org>
Diffstat (limited to 'lib/compilers')
-rw-r--r-- | lib/compilers/argument-parsers.ts | 26 | ||||
-rw-r--r-- | lib/compilers/hlsl.ts | 8 | ||||
-rw-r--r-- | lib/compilers/llc.ts | 9 | ||||
-rw-r--r-- | lib/compilers/opt.ts | 9 | ||||
-rw-r--r-- | lib/compilers/racket.ts | 135 | ||||
-rw-r--r-- | lib/compilers/rust.ts | 9 | ||||
-rw-r--r-- | lib/compilers/snowball.ts | 6 | ||||
-rw-r--r-- | lib/compilers/swift.ts | 9 |
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() { |