diff options
author | Kale Blankenship <kale@lemnisys.com> | 2018-11-26 21:00:24 -0800 |
---|---|---|
committer | Kale Blankenship <kale@lemnisys.com> | 2018-11-26 21:08:26 -0800 |
commit | 144503d543f1a43d5353d750da5ae253c083c5e9 (patch) | |
tree | 2d9eb71d4a528edeb06707626c6de801e1841caf /lib/compilers/golang.js | |
parent | 30969578973cf53dbabad453b1ef138ee8e342e7 (diff) | |
download | compiler-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.js | 113 |
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) { |