diff options
author | Matt Godbolt <matt@godbolt.org> | 2019-03-21 20:31:42 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-21 20:31:42 -0500 |
commit | b87322568ed7f73a8583cdce707f68f07a0995dd (patch) | |
tree | 387ffc9ba2487bea8c6ab9eb7c40d03cd1e74dc6 /lib/compilers/golang.js | |
parent | b8815fbdb20261634919d976310c13e945249250 (diff) | |
parent | a47efe6d65f86024f46be5ef96139bb2f67dca73 (diff) | |
download | compiler-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.js | 139 |
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; |