Add ClangIR compilation options (#6914)

This patch adds two options to the clangir pane that affects the clangir
compilation pipeline:

* Flat CIR enables the emission of flat clangir CFG;
* -fclangir-mem2reg enables the mem2reg pass on the flat clangir CFG.
This commit is contained in:
Sirui Mu
2024-11-02 16:53:33 +08:00
committed by GitHub
parent e8b43f5744
commit a6ca0fed18
8 changed files with 117 additions and 8 deletions

View File

@@ -33,6 +33,7 @@ import _ from 'underscore';
import {unique} from '../shared/common-utils.js';
import {PPOptions} from '../static/panes/pp-view.interfaces.js';
import {ParsedAsmResultLine} from '../types/asmresult/asmresult.interfaces.js';
import {ClangirBackendOptions} from '../types/compilation/clangir.interfaces.js';
import {
ActiveTool,
BuildResult,
@@ -1411,13 +1412,23 @@ export class BaseCompiler implements ICompiler {
return utils.changeExtension(inputFilename, '.cir');
}
async generateClangir(inputFilename: string, options: string[]): Promise<ResultLine[]> {
async generateClangir(
inputFilename: string,
options: string[],
clangirOptions: ClangirBackendOptions,
): Promise<ResultLine[]> {
const outputFilename = this.getClangirOutputFilename(inputFilename);
let newOptions = [...options];
const newOptions = [...options];
if (clangirOptions.flatCFG) {
newOptions.push('-Xclang', '-emit-cir-flat');
} else {
newOptions.push('-Xclang', '-emit-cir');
}
// Replace `-o <name>.s` with `-o <name>.cir`
newOptions.splice(options.indexOf('-o'), 2);
newOptions = newOptions.concat(['-Xclang', '-emit-cir', '-o', outputFilename]);
newOptions.push('-o', outputFilename);
const execOptions = this.getDefaultExecOptions();
const output = await this.runCompiler(this.compiler.exe, newOptions, this.filename(inputFilename), execOptions);
@@ -2358,7 +2369,7 @@ export class BaseCompiler implements ICompiler {
filters,
)
: undefined,
makeClangir ? this.generateClangir(inputFilename, options) : undefined,
makeClangir ? this.generateClangir(inputFilename, options, backendOptions.produceClangir) : undefined,
makeOptPipeline
? this.generateOptPipeline(inputFilename, options, filters, backendOptions.produceOptPipeline)
: undefined,

View File

@@ -33,6 +33,7 @@ import {CompilerInfo} from '../types/compiler.interfaces.js';
import {CompilationResult} from '../types/compilation/compilation.interfaces.js';
import {OptPipelineBackendOptions} from './compilation/opt-pipeline-output.interfaces.js';
import {LLVMIrBackendOptions} from './compilation/ir.interfaces.js';
import {ClangirBackendOptions} from './compilation/clangir.interfaces.js';
import {NewToolSettings, ToolState} from './components.interfaces.js';
// This list comes from executing
@@ -117,6 +118,7 @@ export type EventMap = {
optPipelineViewOpened: (compilerId: number) => void;
optPipelineViewOptionsUpdated: (compilerId: number, options: OptPipelineBackendOptions, recompile: boolean) => void;
llvmIrViewOptionsUpdated: (compilerId: number, options: LLVMIrBackendOptions, recompile: boolean) => void;
clangirViewOptionsUpdated: (compilerId: number, options: ClangirBackendOptions, recompile: boolean) => void;
languageChange: (editorId: number | boolean, newLangId: LanguageKey, treeId?: boolean | number) => void;
modifySettings: (modifiedSettings: Partial<SiteSettings>) => void;
motd: (data: Motd) => void;

View File

@@ -35,13 +35,21 @@ import {extendConfig} from '../monaco-config.js';
import {Hub} from '../hub.js';
import {CompilationResult} from '../compilation/compilation.interfaces.js';
import {CompilerInfo} from '../compiler.interfaces.js';
import {Toggles} from '../widgets/toggles.js';
import {ClangirBackendOptions} from '../../types/compilation/clangir.interfaces.js';
export class Clangir extends MonacoPane<monaco.editor.IStandaloneCodeEditor, ClangirState> {
private options: Toggles;
private lastOptions: ClangirBackendOptions = {
flatCFG: false,
};
constructor(hub: Hub, container: Container, state: ClangirState & MonacoPaneState) {
super(hub, container, state);
if (state.clangirOutput) {
this.showClangirResults(state.clangirOutput);
}
this.onOptionsChange(true);
}
override getInitialHTML(): string {
@@ -68,6 +76,12 @@ export class Clangir extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Cla
return 'ClangIR Viewer';
}
override registerButtons(state: ClangirState): void {
super.registerButtons(state);
this.options = new Toggles(this.domRoot.find('.options'), state as unknown as Record<string, boolean>);
this.options.on('change', this.onOptionsChange.bind(this));
}
override registerCallbacks(): void {
const throttleFunction = _.throttle(
(event: monaco.editor.ICursorSelectionChangedEvent) => this.onDidChangeCursorSelection(event),
@@ -78,6 +92,31 @@ export class Clangir extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Cla
this.eventHub.emit('requestSettings');
}
override getCurrentState(): MonacoPaneState {
return {
...super.getCurrentState(),
...this.options.get(),
};
}
onOptionsChange(force = false) {
const options = this.options.get();
const newOptions: ClangirBackendOptions = {
flatCFG: options['flat-cfg'],
};
let changed = false;
for (const k in newOptions) {
if (newOptions[k] !== this.lastOptions[k]) {
changed = true;
break;
}
}
this.lastOptions = newOptions;
if (changed || force) {
this.eventHub.emit('clangirViewOptionsUpdated', this.compilerInfo.compilerId, newOptions, true);
}
}
override onCompileResult(compilerId: number, compiler: CompilerInfo, result: CompilationResult): void {
if (this.compilerInfo.compilerId !== compilerId) return;
if (result.clangirOutput) {

View File

@@ -80,6 +80,7 @@ import {LLVMIrBackendOptions} from '../compilation/ir.interfaces.js';
import {InstructionSet} from '../instructionsets.js';
import {escapeHTML} from '../../shared/common-utils.js';
import {CompilerVersionInfo, setCompilerVersionPopoverForPane} from '../widgets/compiler-version-info.js';
import {ClangirBackendOptions} from '../compilation/clangir.interfaces.js';
import {LanguageKey} from '../languages.interfaces.js';
const toolIcons = require.context('../../views/resources/logos', false, /\.(png|svg)$/);
@@ -268,6 +269,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
private haskellCmmViewOpen: boolean;
private ppOptions: PPOptions;
private llvmIrOptions: LLVMIrBackendOptions;
private clangirOptions: ClangirBackendOptions;
private optPipelineOptions: OptPipelineBackendOptions;
private isOutputOpened: boolean;
private mouseMoveThrottledFunction?: ((e: monaco.editor.IEditorMouseEvent) => void) & _.Cancelable;
@@ -1273,7 +1275,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
produceGnatDebugTree: this.gnatDebugTreeViewOpen,
produceGnatDebug: this.gnatDebugViewOpen,
produceIr: this.irViewOpen ? this.llvmIrOptions : null,
produceClangir: this.clangirViewOpen,
produceClangir: this.clangirViewOpen ? this.clangirOptions : null,
produceOptPipeline: this.optPipelineViewOpenCount > 0 ? this.optPipelineOptions : null,
produceDevice: this.deviceViewOpen,
produceRustMir: this.rustMirViewOpen,
@@ -2204,6 +2206,15 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
}
}
onClangirViewOptionsUpdated(id: number, options: ClangirBackendOptions, recompile: boolean): void {
if (this.id === id) {
this.clangirOptions = options;
if (recompile) {
this.compile();
}
}
}
onOptPipelineViewOpened(id: number): void {
if (this.id === id) {
this.optPipelineViewOpenCount++;
@@ -3001,6 +3012,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
this.eventHub.on('clangirViewOpened', this.onClangirViewOpened, this);
this.eventHub.on('clangirViewClosed', this.onClangirViewClosed, this);
this.eventHub.on('llvmIrViewOptionsUpdated', this.onLLVMIrViewOptionsUpdated, this);
this.eventHub.on('clangirViewOptionsUpdated', this.onClangirViewOptionsUpdated, this);
this.eventHub.on('optPipelineViewOpened', this.onOptPipelineViewOpened, this);
this.eventHub.on('optPipelineViewClosed', this.onOptPipelineViewClosed, this);
this.eventHub.on('optPipelineViewOptionsUpdated', this.onOptPipelineViewOptionsUpdated, this);

View File

@@ -0,0 +1,27 @@
// Copyright (c) 2023, 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.
export type ClangirBackendOptions = {
flatCFG: boolean;
};

View File

@@ -38,6 +38,7 @@ import {ResultLine} from '../resultline/resultline.interfaces.js';
import {Artifact, ToolResult} from '../tool.interfaces.js';
import {CFGResult} from './cfg.interfaces.js';
import {ClangirBackendOptions} from './clangir.interfaces.js';
import {ConfiguredOverrides} from './compiler-overrides.interfaces.js';
import {LLVMIrBackendOptions} from './ir.interfaces.js';
import {OptPipelineBackendOptions, OptPipelineOutput} from './opt-pipeline-output.interfaces.js';
@@ -103,7 +104,7 @@ export type CompilationRequestOptions = {
produceGnatDebugTree?: boolean;
produceGnatDebug?: boolean;
produceIr?: LLVMIrBackendOptions | null;
produceClangir?: boolean;
produceClangir?: ClangirBackendOptions | null;
produceOptPipeline?: OptPipelineBackendOptions | null;
produceDevice?: boolean;
produceRustMir?: boolean;

View File

@@ -0,0 +1,17 @@
mixin optionButton(bind, isActive, text, title)
.button-checkbox
button(type="button" class="dropdown-item btn btn-sm btn-light" + (isActive ? " active" : "") title=title data-bind=bind aria-pressed=isActive ? "true" : "false")
span #{text}
input.d-none(type="checkbox" checked=isActive)
#clangir
.top-bar.btn-toolbar.bg-light(role="toolbar")
include ../../font-size
.btn-group.btn-group-sm.options(role="group")
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="ClangIR Options" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output options")
span.fas.fa-anchor
span.hideable Options
.dropdown-menu
+optionButton("flat-cfg", false, "Output Flat ClangIR", "Emit flat ClangIR")
div.clangir-body
.monaco-placeholder

View File

@@ -22,6 +22,8 @@ mixin monacopane(id)
include panes/ir
include panes/clangir
include panes/opt-view
include panes/opt-pipeline
@@ -64,8 +66,6 @@ mixin monacopane(id)
+monacopane("ast")
+monacopane("clangir")
+monacopane("tool-input")
+monacopane("gnatdebugtree")