aboutsummaryrefslogtreecommitdiff
path: root/lib/compilers/golang.js
diff options
context:
space:
mode:
authorKale Blankenship <kale@lemnisys.com>2018-11-26 21:00:24 -0800
committerKale Blankenship <kale@lemnisys.com>2018-11-26 21:08:26 -0800
commit144503d543f1a43d5353d750da5ae253c083c5e9 (patch)
tree2d9eb71d4a528edeb06707626c6de801e1841caf /lib/compilers/golang.js
parent30969578973cf53dbabad453b1ef138ee8e342e7 (diff)
downloadcompiler-explorer-144503d543f1a43d5353d750da5ae253c083c5e9.tar.gz
compiler-explorer-144503d543f1a43d5353d750da5ae253c083c5e9.zip
go: replace PC jumps with labels
Rewrite PC jumps with labels so that it's clear where the jumps are to.
Diffstat (limited to 'lib/compilers/golang.js')
-rw-r--r--lib/compilers/golang.js113
1 files changed, 97 insertions, 16 deletions
diff --git a/lib/compilers/golang.js b/lib/compilers/golang.js
index bbf666576..f558c5eb3 100644
--- a/lib/compilers/golang.js
+++ b/lib/compilers/golang.js
@@ -26,38 +26,119 @@ const BaseCompiler = require('../base-compiler'),
_ = require('underscore'),
utils = require('../utils');
+// Each arch has a list of jump instructions in
+// Go source src/cmd/asm/internal/arch.
+const jumpPrefixes = [
+ 'j',
+ 'b',
+
+ // arm
+ 'cb',
+ 'tb',
+
+ // s390x
+ 'cmpb',
+ 'cmpub'
+];
+
class GolangCompiler extends BaseCompiler {
convertNewGoL(code) {
- const re = /^\s+(0[xX]?[0-9A-Za-z]+)?\s?[0-9]+\s*\(([^:]+):([0-9]+)\)\s*([A-Z]+)(.*)/;
- const reUnknown = /^\s+(0[xX]?[0-9A-Za-z]+)?\s?[0-9]+\s*\(<unknown line number>\)\s*([A-Z]+)(.*)/;
+ const re = /^\s+(0[xX]?[0-9A-Za-z]+)?\s?([0-9]+)\s*\(([^:]+):([0-9]+)\)\s*([A-Z]+)(.*)/;
+ const reUnknown = /^\s+(0[xX]?[0-9A-Za-z]+)?\s?([0-9]+)\s*\(<unknown line number>\)\s*([A-Z]+)(.*)/;
+ const reFunc = /TEXT\s+[".]*(\S+)\(SB\)/;
let prevLine = null;
let file = null;
let fileCount = 0;
- return _.compact(code.map(obj => {
+ let func = null;
+ let labels = {};
+ let usedLabels = {};
+ let lines = code.map(obj => {
+ let pcMatch = null;
+ let fileMatch = null;
+ let lineMatch = null;
+ let ins = null;
+ let args = null;
+
const line = obj.text;
let match = line.match(re);
if (match) {
- let res = "";
- if (file !== match[2]) {
- fileCount++;
- res += "\t.file " + fileCount + ' "' + match[2] + '"\n';
- file = match[2];
- }
- if (prevLine !== match[3]) {
- res += "\t.loc " + fileCount + " " + match[3] + " 0\n";
- prevLine = match[3];
- }
- return res + "\t" + match[4].toLowerCase() + match[5];
+ pcMatch = match[2];
+ fileMatch = match[3];
+ lineMatch = match[4];
+ ins = match[5];
+ args = match[6];
} else {
match = line.match(reUnknown);
if (match) {
- return "\t" + match[2].toLowerCase() + match[3];
+ pcMatch = match[2];
+ ins = match[3];
+ args = match[4];
} else {
return null;
}
}
- })).join("\n");
+ match = line.match(reFunc);
+ if (match) {
+ // Normalize function name.
+ func = match[1].replace(/[.()*]+/g, "_");
+ }
+
+ let res = [];
+ if (pcMatch && !labels[pcMatch]) {
+ // Create pseudo-label.
+ let label = pcMatch.replace(/^0{0,4}/, '');
+ label = `${func}_pc${label}:`;
+ if (!labels[label]) {
+ res.push(label);
+ labels[label] = true;
+ }
+ }
+
+ if (fileMatch && file !== fileMatch) {
+ fileCount++;
+ res.push(`\t.file ${fileCount} "${fileMatch}"`);
+ file = fileMatch;
+ }
+
+ if (lineMatch && prevLine !== lineMatch) {
+ res.push(`\t.loc ${fileCount} ${lineMatch} 0`);
+ prevLine = lineMatch;
+ }
+
+ ins = ins.toLowerCase();
+ args = this.replaceJump(func, ins, args, usedLabels);
+ res.push(`\t${ins}${args}`);
+ return res;
+ });
+
+ // Find unused pseudo-labels so they can be filtered out.
+ let unusedLabels = _.mapObject(labels, (val, key) => { return !usedLabels[key]; });
+
+ return _.chain(lines)
+ .flatten()
+ .compact()
+ .filter((line) => { return !unusedLabels[line]; })
+ .value()
+ .join("\n");
+ }
+
+ replaceJump(func, ins, args, usedLabels) {
+ // Check if last argument is a decimal number.
+ const re = /(\s+)([0-9]+)(\s?)$/;
+ let match = args.match(re);
+ if (!match) {
+ return args;
+ }
+
+ // Check instruction has a jump prefix
+ if (_.any(jumpPrefixes, (prefix) => { return ins.startsWith(prefix); })) {
+ let label = `${func}_pc${match[2]}`;
+ usedLabels[label + ":"] = true; // record label use for later filtering
+ return `${match[1]}${label}${match[3]}`;
+ }
+
+ return args;
}
extractLogging(stdout) {