diff options
Diffstat (limited to 'lib/compilers/racket.ts')
-rw-r--r-- | lib/compilers/racket.ts | 135 |
1 files changed, 135 insertions, 0 deletions
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, + ); + } } |