Fix unused label issues

Treat labels which are used only by directives in other labels as used
if the other label itself is used by an opcode: that is, propagate the
transitive usage of labels.

Fixes #35
This commit is contained in:
Matt Godbolt 2016-09-20 09:09:47 -05:00
parent 69bfef015f
commit 461e6110ef
5 changed files with 145 additions and 24 deletions

View File

@ -23,6 +23,7 @@
// POSSIBILITY OF SUCH DAMAGE.
(function () {
var _ = require('underscore-node');
var tabsRe = /\t/g;
function expandTabs(line) {
@ -35,35 +36,91 @@
});
}
var labelFind = /[.a-zA-Z_][a-zA-Z0-9$_.]*/g;
var dataDefn = /\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)/;
var fileFind = /^\s*\.file\s+(\d+)\s+"([^"]+)".*/;
var hasOpcode = /^\s*([a-zA-Z$_][a-zA-Z0-9$_.]*:\s*)?[a-zA-Z].*/;
var labelDef = /^([.a-zA-Z_][a-zA-Z0-9$_.]+):/;
var hasOpcode = /^\s*([a-zA-Z$_][a-zA-Z0-9$_.]*:\s*)?[a-zA-Z].*/;
function findUsedLabels(asmLines, filterDirectives) {
var labelsUsed = {};
var weakUsages = {};
var currentLabel = "";
// Scan through looking for definite label usages (ones used by opcodes),
// and ones that are weakly used: that is, their use is conditional on another label.
// For example:
// .foo: .string "moo"
// .baz: .quad .foo
// mov eax, .baz
// In this case, the '.baz' is used by an opcode, and so is strongly used.
// The '.foo' is weakly used by .baz.
asmLines.forEach(function (line) {
var match = line.match(labelDef);
if (match)
currentLabel = match[1];
if (!line || line[0] === '.') return;
match = line.match(labelFind);
if (!match) return;
if (!filterDirectives || line.match(hasOpcode)) {
// Only count a label as used if it's used by an opcode, or else we're not filtering directives.
match.forEach(function (label) {
labelsUsed[label] = true;
});
} else if (currentLabel) {
// Note any "weak" usages by this label; that is, usages that are only
// interesting if the currentLabel is used by an opcode.
if (!weakUsages[currentLabel]) weakUsages[currentLabel] = [];
match.forEach(function (label) {
weakUsages[currentLabel].push(label);
});
}
});
// Now follow the chains of used labels, marking any weak references they refer
// to as also used. We iteratively do this until either no new labels are found,
// or we hit a limit (only here to prevent a pathological case from hanging).
var MaxLabelIterations = 10;
for (var iter = 0; iter < MaxLabelIterations; ++iter) {
var toAdd = [];
_.each(labelsUsed, function (t, label) {
_.each(weakUsages[label], function (nowused) {
if (labelsUsed[nowused]) return;
toAdd.push(nowused);
});
});
if (!toAdd) break;
_.each(toAdd, function (label) {
labelsUsed[label] = true;
});
}
return labelsUsed;
}
function parseFiles(asmLines) {
var files = {};
asmLines.forEach(function (line) {
var match = line.match(fileFind);
if (match) {
files[parseInt(match[1])] = match[2];
}
});
return files;
}
function processAsm(asm, filters) {
if (filters.binary) return processBinaryAsm(asm, filters);
var result = [];
var asmLines = asm.split("\n");
var labelsUsed = {};
var labelFind = /[.a-zA-Z0-9_][a-zA-Z0-9$_.]*/g;
var files = {};
var labelsUsed = findUsedLabels(asmLines, filters.directives);
var files = parseFiles(asmLines);
var prevLabel = "";
var dataDefn = /\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)/;
var fileFind = /^\s*\.file\s+(\d+)\s+"([^"]+)".*/;
var hasOpcode = /^\s*([a-zA-Z0-9$_][a-zA-Z0-9$_.]*:\s*)?[a-zA-Z].*/;
asmLines.forEach(function (line) {
if (line === "" || line[0] === ".") return;
var match = line.match(labelFind);
if (match && (!filters.directives || line.match(hasOpcode))) {
// Only count a label as used if it's used by an opcode, or else we're not filtering directives.
match.forEach(function (label) {
labelsUsed[label] = true;
});
}
match = line.match(fileFind);
if (match) {
files[parseInt(match[1])] = match[2];
}
});
var directive = /^\s*\..*$/;
var labelDefinition = /^([a-zA-Z0-9$_.]+):/;
var commentOnly = /^\s*(#|@|\/\/).*/;
var sourceTag = /^\s*\.loc\s+(\d+)\s+(\d+).*/;
var stdInLooking = /.*<stdin>|-/;
@ -89,7 +146,7 @@
if (filters.commentOnly && line.match(commentOnly)) return;
match = line.match(labelDefinition);
match = line.match(labelDef);
if (match) {
// It's a label definition.
if (labelsUsed[match[1]] === undefined) {

View File

@ -28,7 +28,8 @@
"nopt": "3.0.x",
"serve-favicon": "2.3.x",
"serve-static": "1.10.x",
"temp": "0.8.x"
"temp": "0.8.x",
"underscore-node": "*"
},
"devDependencies": {
"supervisor": "0.3.1",

View File

@ -0,0 +1,46 @@
.file "example.cpp"
.intel_syntax noprefix
.text
.Ltext0:
.globl s_sA
.section .rodata
.LC0:
.string "hello world!"
.data
.align 8
.type s_sA, @object
.size s_sA, 8
s_sA:
.quad .LC0
.section .rodata
.align 8
.type s_sB, @object
.size s_sB, 10
s_sB:
.string "hey there"
.text
.globl main
.type main, @function
main:
.LFB0:
.file 1 "/tmp/gcc-explorer-compiler116820-58-ewfj5u/example.cpp"
.loc 1 6 0
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
.loc 1 7 0
mov rax, QWORD PTR s_sA[rip]
mov rdi, rax
call puts
.loc 1 8 0
mov edi, OFFSET FLAT:s_sB
call puts
.loc 1 9 0
mov eax, 0
pop rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc

View File

@ -0,0 +1,17 @@
.LC0:
.string "hello world!"
s_sA:
.quad .LC0
s_sB:
.string "hey there"
main:
push rbp
mov rbp, rsp
mov rax, QWORD PTR s_sA[rip]
mov rdi, rax
call puts
mov edi, OFFSET FLAT:s_sB
call puts
mov eax, 0
pop rbp
ret

View File

@ -68,7 +68,6 @@ function testFilter(filename, suffix, filters, withSource) {
assertEq(file[i], lineExpected, expected + ":" + (i + 1));
}
}
cases.forEach(function (x) {
testFilter(x, "", {})
});
@ -91,4 +90,5 @@ cases.forEach(function (x) {
if (failures) {
console.log(failures + " failures");
process.exit(1);
}