aboutsummaryrefslogtreecommitdiff
path: root/lib/base-compiler.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/base-compiler.js')
-rw-r--r--lib/base-compiler.js148
1 files changed, 108 insertions, 40 deletions
diff --git a/lib/base-compiler.js b/lib/base-compiler.js
index 461e842ee..a2c7e0eac 100644
--- a/lib/base-compiler.js
+++ b/lib/base-compiler.js
@@ -753,11 +753,33 @@ export class BaseCompiler {
return [{text: 'Internal error; unable to open output path'}];
}
- async generateGccDump(inputFilename, options, gccDumpOptions) {
- // Maybe we should not force any RTL dump and let user hand-pick what he needs
- const addOpts = [];
- /* if not defined, consider it true */
+ /**
+ * @returns {{filename_suffix: string, name: string, command_prefix: string}}
+ * `filename_suffix`: dump file name suffix if GCC default dump names is used
+ *
+ * `name`: the name to be displayed in the UI
+ *
+ * `command_prefix`: command prefix to be used in case this dump is to be
+ * created using a targeted option (eg. -fdump-rtl-expand)
+ */
+ fromInternalGccDumpName(internalDumpName, selectedPasses) {
+ if (!selectedPasses)
+ selectedPasses = ['ipa', 'tree', 'rtl'];
+
+ const internalNameRe = new RegExp('^\\s*(' + selectedPasses.join('|') +')-([\\w_-]+).*ON$');
+ const match = internalDumpName.match(internalNameRe);
+ if (match)
+ return {
+ filename_suffix: `${match[1][0]}.${match[2]}`,
+ name: match[2] + ' (' + match[1] + ')',
+ command_prefix: `-fdump-${match[1]}-${match[2]}`,
+ };
+ else
+ return null;
+ }
+ getGccDumpOptions(gccDumpOptions, removeEmptyPasses) {
+ const addOpts = ['-fdump-passes'];
// Build dump options to append to the end of the -fdump command-line flag.
// GCC accepts these options as a list of '-' separated names that may
// appear in any order.
@@ -793,17 +815,35 @@ export class BaseCompiler {
flags += '-all';
}
- if (gccDumpOptions.treeDump !== false) {
- addOpts.push('-fdump-tree-all' + flags);
- }
- if (gccDumpOptions.rtlDump !== false) {
- addOpts.push('-fdump-rtl-all' + flags);
- }
- if (gccDumpOptions.ipaDump !== false) {
- addOpts.push('-fdump-ipa-all' + flags);
+ // If we want to remove the passes that won't produce anything from the
+ // drop down menu, we need to ask for all dump files and see what's
+ // really created. This is currently only possible with regular GCC, not
+ // for compilers that us libgccjit. The later can't easily move dump
+ // files outside of the tempdir created on the fly.
+ if (removeEmptyPasses){
+ if (gccDumpOptions.treeDump !== false) {
+ addOpts.push('-fdump-tree-all' + flags);
+ }
+ if (gccDumpOptions.rtlDump !== false) {
+ addOpts.push('-fdump-rtl-all' + flags);
+ }
+ if (gccDumpOptions.ipaDump !== false) {
+ addOpts.push('-fdump-ipa-all' + flags);
+ }
+ } else {
+ // If not dumping everything, create a specific command like
+ // -fdump-tree-fixup_cfg1-some-flags=stdout
+ if (gccDumpOptions.pass) {
+ const dumpCmd = gccDumpOptions.pass.command_prefix + flags + '=stdout';
+ addOpts.push(dumpCmd);
+ }
}
- const newOptions = options.concat(addOpts);
+ return addOpts;
+ }
+
+ async generateGccDump(inputFilename, options, gccDumpOptions, removeEmptyPasses) {
+ const newOptions = options.concat(this.getGccDumpOptions(gccDumpOptions, removeEmptyPasses));
const execOptions = this.getDefaultExecOptions();
// A higher max output is needed for when the user includes headers
@@ -811,7 +851,8 @@ export class BaseCompiler {
return this.processGccDumpOutput(
gccDumpOptions,
- await this.runCompiler(this.compiler.exe, newOptions, this.filename(inputFilename), execOptions));
+ await this.runCompiler(this.compiler.exe, newOptions, this.filename(inputFilename), execOptions),
+ removeEmptyPasses);
}
async checkOutputFileAndDoPostProcess(asmResult, outputFilename, filters) {
@@ -1170,7 +1211,9 @@ export class BaseCompiler {
] = await Promise.all([
this.runCompiler(this.compiler.exe, options, inputFilenameSafe, execOptions),
(makeAst ? this.generateAST(inputFilename, options) : ''),
- (makeGccDump ? this.generateGccDump(inputFilename, options, backendOptions.produceGccDump) : ''),
+ (makeGccDump ? this.generateGccDump(inputFilename, options,
+ backendOptions.produceGccDump,
+ this.compiler.removeEmptyGccDump) : ''),
(makeGnatDebug ? this.generateGnatDebug(inputFilename, options) : ''),
(makeIr ? this.generateIR(inputFilename, options, filters) : ''),
(makeRustMir ? this.generateRustMir(inputFilename, options) : ''),
@@ -1624,15 +1667,14 @@ export class BaseCompiler {
}
- async processGccDumpOutput(opts, result) {
+ async processGccDumpOutput(opts, result, removeEmptyPasses) {
const rootDir = path.dirname(result.inputFilename);
- const allFiles = await fs.readdir(rootDir);
if (opts.treeDump === false && opts.rtlDump === false && opts.ipaDump === false) {
return {
all: [],
- selectedPass: '',
- currentPassOutput: 'Nothing selected for dump:\nselect at least one of Tree/RTL filter',
+ selectedPass: null,
+ currentPassOutput: 'Nothing selected for dump:\nselect at least one of Tree/IPA/RTL filter',
syntaxHighlight: false,
};
}
@@ -1643,34 +1685,60 @@ export class BaseCompiler {
currentPassOutput: '<No pass selected>',
syntaxHighlight: false,
};
+ const selectedPasses = [];
+
+ if (opts.treeDump) selectedPasses.push('tree');
+ if (opts.ipaDump) selectedPasses.push('ipa');
+ if (opts.rtlDump) selectedPasses.push('rtl');
+
+ let dumpFileName;
let passFound = false;
- // Phase letter is one of {i, l, r, t}
- // {outpufilename}.{extension}.{passNumber}{phaseLetter}.{phaseName}
- const dumpFilenameRegex = /^.+?\..+?\.(\d+?[ilrt]\..+)$/;
- for (let filename of allFiles) {
- const match = dumpFilenameRegex.exec(filename);
- if (match) {
- const pass = match[1];
- output.all.push(pass);
- const filePath = path.join(rootDir, filename);
- if (opts.pass === pass && (await fs.stat(filePath)).isFile()) {
+
+ for (const obj of Object.values(result.stderr)) {
+ const selectizeObject = this.fromInternalGccDumpName(obj.text, selectedPasses);
+ if (selectizeObject){
+ if (opts.pass && opts.pass.name === selectizeObject.name)
passFound = true;
- output.currentPassOutput = await fs.readFile(filePath, 'utf-8');
- if (/^\s*$/.test(output.currentPassOutput)) {
- output.currentPassOutput = 'File for selected pass is empty.';
- } else {
- output.syntaxHighlight = true;
- }
+
+ if (removeEmptyPasses){
+ const f = fs.readdirSync(rootDir).filter(fn => fn.endsWith(selectizeObject.filename_suffix));
+
+ // pass is enabled, but the dump hasn't produced anything:
+ // don't add it to the drop down menu
+ if (f.length === 0)
+ continue;
+
+ if (opts.pass && opts.pass.name === selectizeObject.name)
+ dumpFileName = path.join(rootDir, f[0]);
}
+
+ output.all.push(selectizeObject);
}
}
- if (opts.pass && !passFound) {
- output.currentPassOutput = `Pass '${opts.pass}' was requested
-but is not valid anymore with current filters.
-Please select another pass or change filters.`;
- }
+ if (opts.pass && passFound){
+ output.currentPassOutput = '';
+ if (removeEmptyPasses) {
+ if (dumpFileName)
+ output.currentPassOutput = await fs.readFile(dumpFileName, 'utf-8');
+ // else leave the currentPassOutput empty. Can happen when some
+ // UI options are changed and a now disabled pass is still
+ // requested.
+ } else {
+ for (const obj of Object.values(result.stdout)) {
+ output.currentPassOutput += obj.text + '\n';
+ }
+ }
+ if (/^\s*$/.test(output.currentPassOutput)) {
+ output.currentPassOutput = `Pass '${opts.pass.name}' was requested
+but nothing was dumped. Possible causes are:
+ - pass is not valid in this (maybe you changed the compiler options);
+ - pass is valid but did not emit anything (eg. it was not executed).`;
+ } else {
+ output.syntaxHighlight = true;
+ }
+ }
return output;
}