aboutsummaryrefslogtreecommitdiff
path: root/lib/compilers/golang.js
diff options
context:
space:
mode:
authorMatt Godbolt <matt@godbolt.org>2019-03-21 20:31:42 -0500
committerGitHub <noreply@github.com>2019-03-21 20:31:42 -0500
commitb87322568ed7f73a8583cdce707f68f07a0995dd (patch)
tree387ffc9ba2487bea8c6ab9eb7c40d03cd1e74dc6 /lib/compilers/golang.js
parentb8815fbdb20261634919d976310c13e945249250 (diff)
parenta47efe6d65f86024f46be5ef96139bb2f67dca73 (diff)
downloadcompiler-explorer-b87322568ed7f73a8583cdce707f68f07a0995dd.tar.gz
compiler-explorer-b87322568ed7f73a8583cdce707f68f07a0995dd.zip
Merge branch 'master' into llvm
Diffstat (limited to 'lib/compilers/golang.js')
-rw-r--r--lib/compilers/golang.js139
1 files changed, 123 insertions, 16 deletions
diff --git a/lib/compilers/golang.js b/lib/compilers/golang.js
index bbf666576..8c298ad38 100644
--- a/lib/compilers/golang.js
+++ b/lib/compilers/golang.js
@@ -23,41 +23,144 @@
// POSSIBILITY OF SUCH DAMAGE.
const BaseCompiler = require('../base-compiler'),
+ argumentParsers = require("./argument-parsers"),
_ = 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 funcCollisions = {};
+ 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, "_");
+
+ // It's possible for normalized function names to collide.
+ // Keep a count of collisions per function name. Labels get
+ // suffixed with _[collisions] when collisions > 0.
+ let collisions = funcCollisions[func];
+ if (collisions == null) {
+ collisions = 0;
+ } else {
+ collisions++;
+ }
+
+ funcCollisions[func] = collisions;
+ }
+
+ let res = [];
+ if (pcMatch && !labels[pcMatch]) {
+ // Create pseudo-label.
+ let label = pcMatch.replace(/^0{0,4}/, '');
+ let suffix = '';
+ if (funcCollisions[func] > 0) {
+ suffix = `_${funcCollisions[func]}`;
+ }
+
+ label = `${func}_pc${label}${suffix}:`;
+ 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, funcCollisions[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, collisions, 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]}`;
+ if (collisions > 0) {
+ label += `_${collisions}`;
+ }
+ usedLabels[label + ":"] = true; // record label use for later filtering
+ return `${match[1]}${label}${match[3]}`;
+ }
+
+ return args;
}
extractLogging(stdout) {
@@ -90,6 +193,10 @@ class GolangCompiler extends BaseCompiler {
}
return execOptions;
}
+
+ getArgumentParser() {
+ return argumentParsers.Clang;
+ }
}
module.exports = GolangCompiler;