mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2025-12-27 10:33:59 -05:00
Convert, modernize, and refactor cfg generation (#4657)
This commit is contained in:
@@ -56,7 +56,7 @@ import {Artifact, ToolResult, ToolTypeKey} from '../types/tool.interfaces';
|
||||
|
||||
import {BuildEnvSetupBase, getBuildEnvTypeByKey} from './buildenvsetup';
|
||||
import {BuildEnvDownloadInfo} from './buildenvsetup/buildenv.interfaces';
|
||||
import * as cfg from './cfg';
|
||||
import * as cfg from './cfg/cfg';
|
||||
import {CompilationEnvironment} from './compilation-env';
|
||||
import {CompilerArguments} from './compiler-arguments';
|
||||
import {ClangParser, GCCParser} from './compilers/argument-parsers';
|
||||
@@ -2379,7 +2379,7 @@ export class BaseCompiler implements ICompiler {
|
||||
// for now do not generate a cfg for llvm ir
|
||||
result.cfg = {};
|
||||
} else {
|
||||
result.cfg = cfg.generateStructure(this.compiler.compilerType, this.compiler.version, result.asm);
|
||||
result.cfg = cfg.generateStructure(this.compiler, result.asm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
352
lib/cfg.js
352
lib/cfg.js
@@ -1,352 +0,0 @@
|
||||
// Copyright (c) 2017, Najjar Chedy
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import _ from 'underscore';
|
||||
|
||||
import {logger} from './logger';
|
||||
import * as utils from './utils';
|
||||
|
||||
const InstructionType_jmp = 0;
|
||||
const InstructionType_conditionalJmpInst = 1;
|
||||
const InstructionType_notRetInst = 2;
|
||||
const InstructionType_retInst = 3;
|
||||
|
||||
// deal with typeinfo name for, typeinfo for, vtable for
|
||||
const isFunctionName = x => x.text.trim().indexOf('.') !== 0;
|
||||
|
||||
function getAsmDirective(txt) {
|
||||
const pattern = /^\s*(\.[^ L]\S*)/;
|
||||
const match = txt.match(pattern);
|
||||
if (match !== null) {
|
||||
return match[1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function filterTextSection(data) {
|
||||
let useCurrentSection = true;
|
||||
const result = [];
|
||||
for (const i in data) {
|
||||
const x = data[i];
|
||||
const directive = getAsmDirective(x.text);
|
||||
if (directive != null) {
|
||||
if (directive === '.text' || directive === '.data') {
|
||||
useCurrentSection = directive === '.text';
|
||||
} else if (directive === '.section') {
|
||||
// Only patttern match for now.
|
||||
// Extracting section name would require adjusting demangling code
|
||||
// as demangled name could contain various symbols including ','.
|
||||
useCurrentSection = /\.section\s*"?\.text/.test(x.text);
|
||||
} else if (useCurrentSection) {
|
||||
result.push(x);
|
||||
}
|
||||
} else if (useCurrentSection) {
|
||||
result.push(x);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const gcc = {
|
||||
filterData: asmArr => {
|
||||
const jmpLabelRegex = /\.L\d+:/;
|
||||
const isCode = x => x && x.text && (x.source !== null || jmpLabelRegex.test(x.text) || isFunctionName(x));
|
||||
return _.chain(filterTextSection(asmArr)).map(_.clone).filter(isCode).value();
|
||||
},
|
||||
isFunctionEnd: x => x[0] !== ' ' && x[0] !== '.' && x.includes(':'),
|
||||
|
||||
isBasicBlockEnd: (inst, prevInst) => inst[0] === '.' || prevInst.includes(' ret'),
|
||||
|
||||
isJmpInstruction: x => x.trim()[0] === 'j' || x.match(/\bb\.*(eq|ne|cs|hs|cc|lo|hi|ls|ge|lt|gt|le|rge|rlt)?\b/),
|
||||
|
||||
getInstructionType: inst => {
|
||||
if (inst.includes('jmp') || inst.includes(' b ')) return InstructionType_jmp;
|
||||
else if (gcc.isJmpInstruction(inst)) return InstructionType_conditionalJmpInst;
|
||||
else if (inst.includes(' ret')) {
|
||||
return InstructionType_retInst;
|
||||
} else {
|
||||
return InstructionType_notRetInst;
|
||||
}
|
||||
},
|
||||
|
||||
extractNodeName: inst => inst.match(/\.L\d+/) + ':',
|
||||
};
|
||||
|
||||
const clang = {
|
||||
filterData: asmArr => {
|
||||
const jmpLabelRegex = /\.LBB\d+_\d+:/;
|
||||
const isCode = x => x && x.text && (x.source !== null || jmpLabelRegex.test(x.text) || isFunctionName(x));
|
||||
|
||||
const removeComments = x => {
|
||||
const pos_x86 = x.text.indexOf('# ');
|
||||
const pos_arm = x.text.indexOf('// ');
|
||||
if (pos_x86 !== -1) x.text = utils.trimRight(x.text.substring(0, pos_x86));
|
||||
if (pos_arm !== -1) x.text = utils.trimRight(x.text.substring(0, pos_arm));
|
||||
return x;
|
||||
};
|
||||
|
||||
return _.chain(filterTextSection(asmArr)).map(_.clone).filter(isCode).map(removeComments).value();
|
||||
},
|
||||
isFunctionEnd: x => x[0] !== ' ' && x[0] !== '.' && x.includes(':'),
|
||||
|
||||
isBasicBlockEnd: (inst, prevInst) => inst[0] === '.' || prevInst.includes(' ret'),
|
||||
|
||||
isJmpInstruction: x => x.trim()[0] === 'j' || x.match(/\bb\.*(eq|ne|cs|hs|cc|lo|hi|ls|ge|lt|gt|le|rge|rlt)?\b/),
|
||||
|
||||
getInstructionType: function (inst) {
|
||||
if (inst.includes('jmp') || inst.includes(' b ')) return InstructionType_jmp;
|
||||
else if (clang.isJmpInstruction(inst)) return InstructionType_conditionalJmpInst;
|
||||
else if (inst.includes(' ret')) {
|
||||
return InstructionType_retInst;
|
||||
} else {
|
||||
return InstructionType_notRetInst;
|
||||
}
|
||||
},
|
||||
|
||||
extractNodeName: inst => inst.match(/\.LBB\d+_\d+/) + ':',
|
||||
};
|
||||
|
||||
function splitToFunctions(asmArr, isEnd) {
|
||||
if (asmArr.length === 0) return [];
|
||||
const result = [];
|
||||
let first = 1;
|
||||
const last = asmArr.length;
|
||||
const fnRange = {start: 0, end: null};
|
||||
while (first !== last) {
|
||||
if (isEnd(asmArr[first].text)) {
|
||||
fnRange.end = first;
|
||||
result.push(_.clone(fnRange));
|
||||
fnRange.start = first;
|
||||
}
|
||||
++first;
|
||||
}
|
||||
|
||||
fnRange.end = last;
|
||||
result.push(_.clone(fnRange));
|
||||
return result;
|
||||
}
|
||||
|
||||
function splitToBasicBlocks(asmArr, range, isEnd, isJmp) {
|
||||
let first = range.start;
|
||||
const last = range.end;
|
||||
if (first === last) return [];
|
||||
const functionName = asmArr[first].text;
|
||||
++first;
|
||||
|
||||
let rangeBb = {nameId: functionName, start: first, end: null, actionPos: []};
|
||||
const result = [];
|
||||
|
||||
const newRangeWith = function (oldRange, nameId, start) {
|
||||
return {nameId: nameId, start: start, actionPos: [], end: oldRange.end};
|
||||
};
|
||||
|
||||
while (first < last) {
|
||||
const inst = asmArr[first].text;
|
||||
if (isEnd(inst, asmArr[first - 1] ? asmArr[first - 1].text : '')) {
|
||||
rangeBb.end = first;
|
||||
result.push(_.clone(rangeBb));
|
||||
//inst is expected to be .L*: where * in 1,2,...
|
||||
rangeBb = newRangeWith(rangeBb, inst, first + 1);
|
||||
} else if (isJmp(inst)) {
|
||||
rangeBb.actionPos.push(first);
|
||||
}
|
||||
++first;
|
||||
}
|
||||
|
||||
rangeBb.end = last;
|
||||
result.push(_.clone(rangeBb));
|
||||
return result;
|
||||
}
|
||||
|
||||
function splitToCanonicalBasicBlock(basicBlock) {
|
||||
const actionPos = basicBlock.actionPos;
|
||||
let actPosSz = actionPos.length;
|
||||
if (actionPos[actPosSz - 1] + 1 === basicBlock.end) {
|
||||
--actPosSz;
|
||||
}
|
||||
|
||||
if (actPosSz === 0)
|
||||
return [
|
||||
{
|
||||
nameId: basicBlock.nameId,
|
||||
start: basicBlock.start,
|
||||
end: basicBlock.end,
|
||||
},
|
||||
];
|
||||
else if (actPosSz === 1)
|
||||
return [
|
||||
{nameId: basicBlock.nameId, start: basicBlock.start, end: actionPos[0] + 1},
|
||||
{nameId: basicBlock.nameId + '@' + (actionPos[0] + 1), start: actionPos[0] + 1, end: basicBlock.end},
|
||||
];
|
||||
else {
|
||||
let first = 0;
|
||||
const last = actPosSz;
|
||||
const blockName = basicBlock.nameId;
|
||||
let tmp = {nameId: blockName, start: basicBlock.start, end: actionPos[first] + 1};
|
||||
const result = [];
|
||||
result.push(_.clone(tmp));
|
||||
while (first !== last - 1) {
|
||||
tmp.nameId = blockName + '@' + (actionPos[first] + 1);
|
||||
tmp.start = actionPos[first] + 1;
|
||||
++first;
|
||||
tmp.end = actionPos[first] + 1;
|
||||
result.push(_.clone(tmp));
|
||||
}
|
||||
|
||||
tmp = {nameId: blockName + '@' + (actionPos[first] + 1), start: actionPos[first] + 1, end: basicBlock.end};
|
||||
result.push(_.clone(tmp));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function concatInstructions(asmArr, first, last) {
|
||||
return _.chain(asmArr.slice(first, last))
|
||||
.map(x => x.text)
|
||||
.value()
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
function makeNodes(asms, arrOfCanonicalBasicBlock) {
|
||||
return _.map(arrOfCanonicalBasicBlock, e => {
|
||||
return {
|
||||
id: e.nameId,
|
||||
label: `${e.nameId}${e.nameId.includes(':') ? '' : ':'}\n${concatInstructions(asms, e.start, e.end)}`,
|
||||
color: '#99ccff',
|
||||
shape: 'box',
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function makeEdges(asmArr, arrOfCanonicalBasicBlock, rules) {
|
||||
const edge = {};
|
||||
const edges = [];
|
||||
|
||||
const setEdge = function (edge, sourceNode, targetNode, color) {
|
||||
edge.from = sourceNode;
|
||||
edge.to = targetNode;
|
||||
edge.arrows = 'to';
|
||||
edge.color = color;
|
||||
};
|
||||
const isBasicBlockEnd = rules.isBasicBlockEnd;
|
||||
|
||||
const hasName = function (asmArr, cbb) {
|
||||
const asm = asmArr[cbb.end];
|
||||
return asm ? isBasicBlockEnd(asm.text, '') : false;
|
||||
};
|
||||
|
||||
const generateName = function (name, suffix) {
|
||||
const pos = name.indexOf('@');
|
||||
if (pos === -1) return name + '@' + suffix;
|
||||
|
||||
return name.substring(0, pos + 1) + suffix;
|
||||
};
|
||||
/* note: x.end-1 possible values:
|
||||
jmp .L*, {jne,je,jg,...} .L*, ret/rep ret, call and any other instruction that doesn't change control flow
|
||||
*/
|
||||
|
||||
_.each(arrOfCanonicalBasicBlock, function (x) {
|
||||
let targetNode;
|
||||
const lastInst = asmArr[x.end - 1].text;
|
||||
switch (rules.getInstructionType(lastInst)) {
|
||||
case InstructionType_jmp: {
|
||||
//we have to deal only with jmp destination, jmp instruction are always taken.
|
||||
//edge from jump inst
|
||||
targetNode = rules.extractNodeName(lastInst);
|
||||
setEdge(edge, x.nameId, targetNode, 'blue');
|
||||
edges.push(_.clone(edge));
|
||||
break;
|
||||
}
|
||||
case InstructionType_conditionalJmpInst: {
|
||||
//deal with : branch taken, branch not taken
|
||||
targetNode = rules.extractNodeName(lastInst);
|
||||
setEdge(edge, x.nameId, targetNode, 'green');
|
||||
edges.push(_.clone(edge));
|
||||
targetNode = hasName(asmArr, x) ? asmArr[x.end].text : generateName(x.nameId, x.end);
|
||||
setEdge(edge, x.nameId, targetNode, 'red');
|
||||
edges.push(_.clone(edge));
|
||||
logger.debug(edge);
|
||||
break;
|
||||
}
|
||||
case InstructionType_notRetInst: {
|
||||
//precondition: lastInst is not last instruction in asmArr (but it is in canonical basic block)
|
||||
//note : asmArr[x.end] expected to be .L*:(name of a basic block)
|
||||
// this .L*: has to be exactly after the last instruction in the current canonical basic block
|
||||
if (asmArr[x.end]) {
|
||||
targetNode = asmArr[x.end].text;
|
||||
setEdge(edge, x.nameId, targetNode, 'grey');
|
||||
edges.push(_.clone(edge));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InstructionType_retInst: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
logger.debug(edges);
|
||||
return edges;
|
||||
}
|
||||
|
||||
function isLLVMBased(compilerType, version) {
|
||||
return (
|
||||
version.includes('clang') ||
|
||||
version.includes('LLVM') ||
|
||||
version.includes('rustc') ||
|
||||
compilerType === 'swift' ||
|
||||
compilerType === 'zig' ||
|
||||
compilerType === 'ispc'
|
||||
);
|
||||
}
|
||||
|
||||
export function generateStructure(compilerType, version, asmArr) {
|
||||
const rules = isLLVMBased(compilerType, version) ? clang : gcc;
|
||||
const code = rules.filterData(asmArr);
|
||||
const funcs = splitToFunctions(code, rules.isFunctionEnd);
|
||||
if (funcs.length === 0) {
|
||||
return funcs;
|
||||
}
|
||||
const result = {};
|
||||
_.each(
|
||||
funcs,
|
||||
_.bind(function (rng) {
|
||||
const basicBlocks = splitToBasicBlocks(code, rng, rules.isBasicBlockEnd, rules.isJmpInstruction);
|
||||
let arrOfCanonicalBasicBlock = [];
|
||||
_.each(
|
||||
basicBlocks,
|
||||
_.bind(function (elm) {
|
||||
const tmp = splitToCanonicalBasicBlock(elm);
|
||||
arrOfCanonicalBasicBlock = arrOfCanonicalBasicBlock.concat(tmp);
|
||||
}, this),
|
||||
);
|
||||
|
||||
result[code[rng.start].text] = {
|
||||
nodes: makeNodes(code, arrOfCanonicalBasicBlock),
|
||||
edges: makeEdges(code, arrOfCanonicalBasicBlock, rules),
|
||||
};
|
||||
}, this),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
91
lib/cfg/cfg-parsers/base.ts
Normal file
91
lib/cfg/cfg-parsers/base.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) 2023, Compiler Explorer Authors
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import _ from 'underscore';
|
||||
|
||||
import {ResultLine} from '../../../types/resultline/resultline.interfaces';
|
||||
import {BaseInstructionSetInfo} from '../instruction-sets/base';
|
||||
|
||||
export class BaseCFGParser {
|
||||
static get key() {
|
||||
return 'base';
|
||||
}
|
||||
|
||||
constructor(public readonly instructionSetInfo: BaseInstructionSetInfo) {}
|
||||
|
||||
isFunctionName(line: ResultLine) {
|
||||
return line.text.trim().indexOf('.') !== 0;
|
||||
}
|
||||
|
||||
getAsmDirective(txt: string) {
|
||||
const pattern = /^\s*(\.[^ L]\S*)/;
|
||||
const match = txt.match(pattern);
|
||||
if (match !== null) {
|
||||
return match[1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
filterTextSection(data: ResultLine[]) {
|
||||
let useCurrentSection = true;
|
||||
const result: ResultLine[] = [];
|
||||
for (const i in data) {
|
||||
const x = data[i];
|
||||
const directive = this.getAsmDirective(x.text);
|
||||
if (directive != null) {
|
||||
if (directive === '.text' || directive === '.data') {
|
||||
useCurrentSection = directive === '.text';
|
||||
} else if (directive === '.section') {
|
||||
// Only patttern match for now.
|
||||
// Extracting section name would require adjusting demangling code
|
||||
// as demangled name could contain various symbols including ','.
|
||||
useCurrentSection = /\.section\s*"?\.text/.test(x.text);
|
||||
} else if (useCurrentSection) {
|
||||
result.push(x);
|
||||
}
|
||||
} else if (useCurrentSection) {
|
||||
result.push(x);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
filterData(assembly: ResultLine[]) {
|
||||
const jmpLabelRegex = /\.L\d+:/;
|
||||
const isCode = x => x && x.text && (x.source !== null || jmpLabelRegex.test(x.text) || this.isFunctionName(x));
|
||||
return this.filterTextSection(assembly).map(_.clone).filter(isCode);
|
||||
}
|
||||
|
||||
isFunctionEnd(x: string) {
|
||||
return x[0] !== ' ' && x[0] !== '.' && x.includes(':');
|
||||
}
|
||||
|
||||
isBasicBlockEnd(inst: string, prevInst: string) {
|
||||
return inst[0] === '.' || prevInst.includes(' ret');
|
||||
}
|
||||
|
||||
extractNodeName(inst: string) {
|
||||
return inst.match(/\.L\d+/) + ':';
|
||||
}
|
||||
}
|
||||
55
lib/cfg/cfg-parsers/clang.ts
Normal file
55
lib/cfg/cfg-parsers/clang.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2023, Compiler Explorer Authors
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import _ from 'underscore';
|
||||
|
||||
import {ResultLine} from '../../../types/resultline/resultline.interfaces';
|
||||
import * as utils from '../../utils';
|
||||
|
||||
import {BaseCFGParser} from './base';
|
||||
|
||||
export class ClangCFGParser extends BaseCFGParser {
|
||||
static override get key() {
|
||||
return 'clang';
|
||||
}
|
||||
|
||||
override filterData(assembly: ResultLine[]) {
|
||||
const jmpLabelRegex = /\.LBB\d+_\d+:/;
|
||||
const isCode = x => x && x.text && (x.source !== null || jmpLabelRegex.test(x.text) || this.isFunctionName(x));
|
||||
|
||||
const removeComments = (x: ResultLine) => {
|
||||
const pos_x86 = x.text.indexOf('# ');
|
||||
const pos_arm = x.text.indexOf('// ');
|
||||
if (pos_x86 !== -1) x.text = utils.trimRight(x.text.substring(0, pos_x86));
|
||||
if (pos_arm !== -1) x.text = utils.trimRight(x.text.substring(0, pos_arm));
|
||||
return x;
|
||||
};
|
||||
|
||||
return this.filterTextSection(assembly).map(_.clone).filter(isCode).map(removeComments);
|
||||
}
|
||||
|
||||
override extractNodeName(inst: string) {
|
||||
return inst.match(/\.LBB\d+_\d+/) + ':';
|
||||
}
|
||||
}
|
||||
45
lib/cfg/cfg-parsers/gcc.ts
Normal file
45
lib/cfg/cfg-parsers/gcc.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2023, Compiler Explorer Authors
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import _ from 'underscore';
|
||||
|
||||
import {ResultLine} from '../../../types/resultline/resultline.interfaces';
|
||||
|
||||
import {BaseCFGParser} from './base';
|
||||
|
||||
export class GccCFGParser extends BaseCFGParser {
|
||||
static override get key() {
|
||||
return 'gcc';
|
||||
}
|
||||
|
||||
override filterData(assembly: ResultLine[]) {
|
||||
const jmpLabelRegex = /\.L\d+:/;
|
||||
const isCode = x => x && x.text && (x.source !== null || jmpLabelRegex.test(x.text) || this.isFunctionName(x));
|
||||
return this.filterTextSection(assembly).map(_.clone).filter(isCode);
|
||||
}
|
||||
|
||||
override extractNodeName(inst: string) {
|
||||
return inst.match(/\.L\d+/) + ':';
|
||||
}
|
||||
}
|
||||
297
lib/cfg/cfg.ts
Normal file
297
lib/cfg/cfg.ts
Normal file
@@ -0,0 +1,297 @@
|
||||
// Copyright (c) 2023, Compiler Explorer Authors
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import _ from 'underscore';
|
||||
|
||||
import {CompilerInfo} from '../../types/compiler.interfaces';
|
||||
import {ResultLine} from '../../types/resultline/resultline.interfaces';
|
||||
import {BaseCompiler} from '../base-compiler';
|
||||
import {makeDefaultedKeyedTypeGetter} from '../keyed-type';
|
||||
import {logger} from '../logger';
|
||||
|
||||
import {BaseCFGParser} from './cfg-parsers/base';
|
||||
import {ClangCFGParser} from './cfg-parsers/clang';
|
||||
import {GccCFGParser} from './cfg-parsers/gcc';
|
||||
import {BaseInstructionSetInfo, InstructionType} from './instruction-sets/base';
|
||||
|
||||
// TODO(jeremy-rifkin):
|
||||
// I've done some work to split out the compiler / instruction set logic
|
||||
// We'll want to do some work to fill in information for instruction sets and other compilers
|
||||
// A good comparison https://godbolt.org/z/8EvqoWhYo
|
||||
// MSVC especially is a little weird, LLVM is also a much different structure than normal asm
|
||||
|
||||
const parsers = makeDefaultedKeyedTypeGetter(
|
||||
'cfg parser provider',
|
||||
{
|
||||
ClangCFGParser,
|
||||
GccCFGParser,
|
||||
},
|
||||
BaseCFGParser,
|
||||
);
|
||||
const instructionSets = makeDefaultedKeyedTypeGetter('instruction set info provider', {}, BaseInstructionSetInfo);
|
||||
|
||||
type Range = {
|
||||
start: number;
|
||||
end: number;
|
||||
};
|
||||
|
||||
function splitToFunctions(asmArr: ResultLine[], parser: BaseCFGParser) {
|
||||
if (asmArr.length === 0) return [];
|
||||
const result: Range[] = [];
|
||||
let first = 1;
|
||||
const last = asmArr.length;
|
||||
const fnRange: Range = {start: 0, end: 0};
|
||||
while (first !== last) {
|
||||
if (parser.isFunctionEnd(asmArr[first].text)) {
|
||||
fnRange.end = first;
|
||||
result.push(_.clone(fnRange));
|
||||
fnRange.start = first;
|
||||
}
|
||||
++first;
|
||||
}
|
||||
|
||||
fnRange.end = last;
|
||||
result.push(_.clone(fnRange));
|
||||
return result;
|
||||
}
|
||||
|
||||
type BBRange = {
|
||||
nameId: string;
|
||||
start: number;
|
||||
end: number;
|
||||
actionPos: number[];
|
||||
};
|
||||
|
||||
function splitToBasicBlocks(asmArr: ResultLine[], range: Range, parser: BaseCFGParser) {
|
||||
let first = range.start;
|
||||
const last = range.end;
|
||||
if (first === last) return [];
|
||||
const functionName = asmArr[first].text;
|
||||
++first;
|
||||
|
||||
let rangeBb: BBRange = {nameId: functionName, start: first, end: 0, actionPos: []};
|
||||
const result: BBRange[] = [];
|
||||
|
||||
const newRangeWith = function (oldRange, nameId, start) {
|
||||
return {nameId: nameId, start: start, actionPos: [], end: oldRange.end};
|
||||
};
|
||||
|
||||
while (first < last) {
|
||||
const inst = asmArr[first].text;
|
||||
if (parser.isBasicBlockEnd(inst, asmArr[first - 1] ? asmArr[first - 1].text : '')) {
|
||||
rangeBb.end = first;
|
||||
result.push(_.clone(rangeBb));
|
||||
//inst is expected to be .L*: where * in 1,2,...
|
||||
rangeBb = newRangeWith(rangeBb, inst, first + 1);
|
||||
} else if (parser.instructionSetInfo.isJmpInstruction(inst)) {
|
||||
rangeBb.actionPos.push(first);
|
||||
}
|
||||
++first;
|
||||
}
|
||||
|
||||
rangeBb.end = last;
|
||||
result.push(_.clone(rangeBb));
|
||||
return result;
|
||||
}
|
||||
|
||||
type CanonicalBB = {
|
||||
nameId: string;
|
||||
start: number;
|
||||
end: number;
|
||||
};
|
||||
|
||||
function splitToCanonicalBasicBlock(basicBlock: BBRange): CanonicalBB[] {
|
||||
const actionPos = basicBlock.actionPos;
|
||||
let actPosSz = actionPos.length;
|
||||
if (actionPos[actPosSz - 1] + 1 === basicBlock.end) {
|
||||
--actPosSz;
|
||||
}
|
||||
|
||||
if (actPosSz === 0)
|
||||
return [
|
||||
{
|
||||
nameId: basicBlock.nameId,
|
||||
start: basicBlock.start,
|
||||
end: basicBlock.end,
|
||||
},
|
||||
];
|
||||
else if (actPosSz === 1)
|
||||
return [
|
||||
{nameId: basicBlock.nameId, start: basicBlock.start, end: actionPos[0] + 1},
|
||||
{nameId: basicBlock.nameId + '@' + (actionPos[0] + 1), start: actionPos[0] + 1, end: basicBlock.end},
|
||||
];
|
||||
else {
|
||||
let first = 0;
|
||||
const last = actPosSz;
|
||||
const blockName = basicBlock.nameId;
|
||||
let tmp: CanonicalBB = {nameId: blockName, start: basicBlock.start, end: actionPos[first] + 1};
|
||||
const result: CanonicalBB[] = [];
|
||||
result.push(_.clone(tmp));
|
||||
while (first !== last - 1) {
|
||||
tmp.nameId = blockName + '@' + (actionPos[first] + 1);
|
||||
tmp.start = actionPos[first] + 1;
|
||||
++first;
|
||||
tmp.end = actionPos[first] + 1;
|
||||
result.push(_.clone(tmp));
|
||||
}
|
||||
|
||||
tmp = {nameId: blockName + '@' + (actionPos[first] + 1), start: actionPos[first] + 1, end: basicBlock.end};
|
||||
result.push(_.clone(tmp));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function concatInstructions(asmArr: ResultLine[], first: number, last: number) {
|
||||
return asmArr
|
||||
.slice(first, last)
|
||||
.map(x => x.text)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
type Node = {
|
||||
id: string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
function makeNodes(asms: ResultLine[], arrOfCanonicalBasicBlock: CanonicalBB[]): Node[] {
|
||||
return arrOfCanonicalBasicBlock.map(e => ({
|
||||
id: e.nameId,
|
||||
label: `${e.nameId}${e.nameId.includes(':') ? '' : ':'}\n${concatInstructions(asms, e.start, e.end)}`,
|
||||
}));
|
||||
}
|
||||
|
||||
type Edge = {
|
||||
from: string;
|
||||
to: string;
|
||||
arrows: string;
|
||||
color: string;
|
||||
};
|
||||
|
||||
function makeEdges(asmArr: ResultLine[], arrOfCanonicalBasicBlock: CanonicalBB[], parser: BaseCFGParser) {
|
||||
const edges: Edge[] = [];
|
||||
|
||||
const setEdge = (sourceNode: string, targetNode: string, color: string) => ({
|
||||
from: sourceNode,
|
||||
to: targetNode,
|
||||
arrows: 'to',
|
||||
color: color,
|
||||
});
|
||||
const isBasicBlockEnd = parser.isBasicBlockEnd;
|
||||
|
||||
const hasName = (asmArr: ResultLine[], cbb: CanonicalBB) => {
|
||||
const asm = asmArr[cbb.end];
|
||||
return asm ? isBasicBlockEnd(asm.text, '') : false;
|
||||
};
|
||||
|
||||
const generateName = function (name: string, suffix: number) {
|
||||
const pos = name.indexOf('@');
|
||||
if (pos === -1) return `${name}@${suffix}`;
|
||||
|
||||
return name.substring(0, pos + 1) + suffix;
|
||||
};
|
||||
/* note: x.end-1 possible values:
|
||||
jmp .L*, {jne,je,jg,...} .L*, ret/rep ret, call and any other instruction that doesn't change control flow
|
||||
*/
|
||||
|
||||
for (const x of arrOfCanonicalBasicBlock) {
|
||||
let targetNode;
|
||||
const lastInst = asmArr[x.end - 1].text;
|
||||
switch (parser.instructionSetInfo.getInstructionType(lastInst)) {
|
||||
case InstructionType.jmp: {
|
||||
//we have to deal only with jmp destination, jmp instruction are always taken.
|
||||
//edge from jump inst
|
||||
targetNode = parser.extractNodeName(lastInst);
|
||||
edges.push(setEdge(x.nameId, targetNode, 'blue'));
|
||||
break;
|
||||
}
|
||||
case InstructionType.conditionalJmpInst: {
|
||||
//deal with : branch taken, branch not taken
|
||||
targetNode = parser.extractNodeName(lastInst);
|
||||
edges.push(setEdge(x.nameId, targetNode, 'green'));
|
||||
targetNode = hasName(asmArr, x) ? asmArr[x.end].text : generateName(x.nameId, x.end);
|
||||
edges.push(setEdge(x.nameId, targetNode, 'red'));
|
||||
break;
|
||||
}
|
||||
case InstructionType.notRetInst: {
|
||||
//precondition: lastInst is not last instruction in asmArr (but it is in canonical basic block)
|
||||
//note : asmArr[x.end] expected to be .L*:(name of a basic block)
|
||||
// this .L*: has to be exactly after the last instruction in the current canonical basic block
|
||||
if (asmArr[x.end]) {
|
||||
targetNode = asmArr[x.end].text;
|
||||
edges.push(setEdge(x.nameId, targetNode, 'grey'));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InstructionType.retInst: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.debug(edges);
|
||||
return edges;
|
||||
}
|
||||
|
||||
function isLLVMBased({compilerType, version}: CompilerInfo) {
|
||||
return (
|
||||
version.includes('clang') ||
|
||||
version.includes('LLVM') ||
|
||||
version.includes('rustc') ||
|
||||
compilerType === 'swift' ||
|
||||
compilerType === 'zig' ||
|
||||
compilerType === 'ispc'
|
||||
);
|
||||
}
|
||||
|
||||
type CFG = {
|
||||
nodes: Node[];
|
||||
edges: Edge[];
|
||||
};
|
||||
|
||||
export function generateStructure(compilerInfo: CompilerInfo, asmArr: ResultLine[]) {
|
||||
const compilerGroup = isLLVMBased(compilerInfo) ? 'clang' : compilerInfo.group;
|
||||
const instructionSet = new (instructionSets(compilerInfo.instructionSet))();
|
||||
const parser = new (parsers(compilerGroup))(instructionSet);
|
||||
const code = parser.filterData(asmArr);
|
||||
const functions = splitToFunctions(code, parser);
|
||||
if (functions.length === 0) {
|
||||
return functions;
|
||||
}
|
||||
const result: Record<string, CFG> = {};
|
||||
for (const fn of functions) {
|
||||
const basicBlocks = splitToBasicBlocks(code, fn, parser);
|
||||
let arrOfCanonicalBasicBlock: CanonicalBB[] = [];
|
||||
for (const bb of basicBlocks) {
|
||||
const tmp = splitToCanonicalBasicBlock(bb);
|
||||
arrOfCanonicalBasicBlock = arrOfCanonicalBasicBlock.concat(tmp);
|
||||
}
|
||||
|
||||
result[code[fn.start].text] = {
|
||||
nodes: makeNodes(code, arrOfCanonicalBasicBlock),
|
||||
edges: makeEdges(code, arrOfCanonicalBasicBlock, parser),
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
50
lib/cfg/instruction-sets/base.ts
Normal file
50
lib/cfg/instruction-sets/base.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2023, Compiler Explorer Authors
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
export enum InstructionType {
|
||||
jmp,
|
||||
conditionalJmpInst,
|
||||
notRetInst,
|
||||
retInst,
|
||||
}
|
||||
|
||||
export class BaseInstructionSetInfo {
|
||||
static get key() {
|
||||
return 'base';
|
||||
}
|
||||
|
||||
isJmpInstruction(x: string) {
|
||||
return x.trim()[0] === 'j' || x.match(/\bb\.*(eq|ne|cs|hs|cc|lo|hi|ls|ge|lt|gt|le|rge|rlt)?\b/);
|
||||
}
|
||||
|
||||
getInstructionType(inst: string) {
|
||||
if (inst.includes('jmp') || inst.includes(' b ')) return InstructionType.jmp;
|
||||
else if (this.isJmpInstruction(inst)) return InstructionType.conditionalJmpInst;
|
||||
else if (inst.includes(' ret')) {
|
||||
return InstructionType.retInst;
|
||||
} else {
|
||||
return InstructionType.notRetInst;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -580,13 +580,13 @@ export class CompileHandler {
|
||||
},
|
||||
error => {
|
||||
if (typeof error === 'string') {
|
||||
logger.error('Error during compilation: ', {error});
|
||||
logger.error('Error during compilation 1: ', {error});
|
||||
} else {
|
||||
if (error.stack) {
|
||||
logger.error('Error during compilation: ', error);
|
||||
logger.error('Error during compilation 2: ', error);
|
||||
Sentry.captureException(error);
|
||||
} else if (error.code) {
|
||||
logger.error('Error during compilation: ', error.code);
|
||||
logger.error('Error during compilation 3: ', error.code);
|
||||
if (typeof error.stderr === 'string') {
|
||||
error.stdout = utils.parseOutput(error.stdout);
|
||||
error.stderr = utils.parseOutput(error.stderr);
|
||||
@@ -594,7 +594,7 @@ export class CompileHandler {
|
||||
res.end(JSON.stringify(error));
|
||||
return;
|
||||
} else {
|
||||
logger.error('Error during compilation: ', error);
|
||||
logger.error('Error during compilation 4: ', error);
|
||||
}
|
||||
|
||||
error = `Internal Compiler Explorer error: ${error.stack || error}`;
|
||||
|
||||
@@ -63,11 +63,26 @@ export function makeKeyedTypeGetter<T extends Keyable>(
|
||||
const keyMap = makeKeyMap(typeName, objects);
|
||||
|
||||
return function getFromKey(key) {
|
||||
const obj = keyMap[key];
|
||||
if (obj === undefined) {
|
||||
if (key in keyMap) {
|
||||
return keyMap[key];
|
||||
} else {
|
||||
throw new Error(`No ${typeName} named '${key}' found`);
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
export function makeDefaultedKeyedTypeGetter<T extends Keyable>(
|
||||
typeName: string,
|
||||
objects: Record<string, T>,
|
||||
defaultObject: T,
|
||||
): (key: string) => T {
|
||||
const keyMap = makeKeyMap(typeName, objects);
|
||||
|
||||
return function getFromKey(key) {
|
||||
if (key in keyMap) {
|
||||
return keyMap[key];
|
||||
} else {
|
||||
return defaultObject;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
20
test/cfg-cases/cfg-clang.if-else.json
generated
20
test/cfg-cases/cfg-clang.if-else.json
generated
@@ -204,9 +204,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "__cxx_global_var_init:",
|
||||
"label": "__cxx_global_var_init:\n pushq %rax\n movl std::__ioinit, %edi\n callq std::ios_base::Init::Init()\n movl std::ios_base::Init::~Init(), %edi\n movl std::__ioinit, %esi\n movl $__dso_handle, %edx\n popq %rax\n jmp __cxa_atexit",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "__cxx_global_var_init:\n pushq %rax\n movl std::__ioinit, %edi\n callq std::ios_base::Init::Init()\n movl std::ios_base::Init::~Init(), %edi\n movl std::__ioinit, %esi\n movl $__dso_handle, %edx\n popq %rax\n jmp __cxa_atexit"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
@@ -222,21 +220,15 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "foo(int, double, float):",
|
||||
"label": "foo(int, double, float):\n movl $583, %eax\n movsd .LCPI1_0(%rip), %xmm2\n ucomisd %xmm0, %xmm2\n jbe .LBB1_2",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "foo(int, double, float):\n movl $583, %eax\n movsd .LCPI1_0(%rip), %xmm2\n ucomisd %xmm0, %xmm2\n jbe .LBB1_2"
|
||||
},
|
||||
{
|
||||
"id": "foo(int, double, float):@14",
|
||||
"label": "foo(int, double, float):@14\n leal (%rdi,%rdi,4), %ecx\n xorps %xmm2, %xmm2\n cvtss2sd %xmm1, %xmm2\n cvtsi2sdl %ecx, %xmm3\n mulsd %xmm0, %xmm3\n ucomisd %xmm3, %xmm2\n cvttss2si %xmm1, %eax\n cmoval %ecx, %eax",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "foo(int, double, float):@14\n leal (%rdi,%rdi,4), %ecx\n xorps %xmm2, %xmm2\n cvtss2sd %xmm1, %xmm2\n cvtsi2sdl %ecx, %xmm3\n mulsd %xmm0, %xmm3\n ucomisd %xmm3, %xmm2\n cvttss2si %xmm1, %eax\n cmoval %ecx, %eax"
|
||||
},
|
||||
{
|
||||
"id": ".LBB1_2:",
|
||||
"label": ".LBB1_2:\n retq",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".LBB1_2:\n retq"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
@@ -264,9 +256,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "_GLOBAL__sub_I_example.cpp:",
|
||||
"label": "_GLOBAL__sub_I_example.cpp:\n jmp __cxx_global_var_init",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "_GLOBAL__sub_I_example.cpp:\n jmp __cxx_global_var_init"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
|
||||
40
test/cfg-cases/cfg-clang.loop.json
generated
40
test/cfg-cases/cfg-clang.loop.json
generated
@@ -338,9 +338,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "__cxx_global_var_init:",
|
||||
"label": "__cxx_global_var_init:\n pushq %rax\n movl std::__ioinit, %edi\n callq std::ios_base::Init::Init()\n movl std::ios_base::Init::~Init(), %edi\n movl std::__ioinit, %esi\n movl $__dso_handle, %edx\n popq %rax\n jmp __cxa_atexit",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "__cxx_global_var_init:\n pushq %rax\n movl std::__ioinit, %edi\n callq std::ios_base::Init::Init()\n movl std::ios_base::Init::~Init(), %edi\n movl std::__ioinit, %esi\n movl $__dso_handle, %edx\n popq %rax\n jmp __cxa_atexit"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
@@ -356,51 +354,35 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "foo(int, double, float):",
|
||||
"label": "foo(int, double, float):\n movl $583, %eax\n movsd .LCPI1_0(%rip), %xmm2\n ucomisd %xmm0, %xmm2\n jbe .LBB1_6",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "foo(int, double, float):\n movl $583, %eax\n movsd .LCPI1_0(%rip), %xmm2\n ucomisd %xmm0, %xmm2\n jbe .LBB1_6"
|
||||
},
|
||||
{
|
||||
"id": "foo(int, double, float):@14",
|
||||
"label": "foo(int, double, float):@14\n leal (%rdi,%rdi,4), %eax\n xorps %xmm2, %xmm2\n cvtss2sd %xmm1, %xmm2\n cvtsi2sdl %eax, %xmm3\n mulsd %xmm0, %xmm3\n ucomisd %xmm3, %xmm2\n jbe .LBB1_5",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "foo(int, double, float):@14\n leal (%rdi,%rdi,4), %eax\n xorps %xmm2, %xmm2\n cvtss2sd %xmm1, %xmm2\n cvtsi2sdl %eax, %xmm3\n mulsd %xmm0, %xmm3\n ucomisd %xmm3, %xmm2\n jbe .LBB1_5"
|
||||
},
|
||||
{
|
||||
"id": "foo(int, double, float):@21",
|
||||
"label": "foo(int, double, float):@21\n movl %eax, %ecx\n imull %edi, %ecx\n testl %ecx, %ecx\n jle .LBB1_6",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "foo(int, double, float):@21\n movl %eax, %ecx\n imull %edi, %ecx\n testl %ecx, %ecx\n jle .LBB1_6"
|
||||
},
|
||||
{
|
||||
"id": "foo(int, double, float):@25",
|
||||
"label": "foo(int, double, float):@25\n xorl %ecx, %ecx",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "foo(int, double, float):@25\n xorl %ecx, %ecx"
|
||||
},
|
||||
{
|
||||
"id": ".LBB1_4:",
|
||||
"label": ".LBB1_4:\n addl %eax, %eax\n xorps %xmm0, %xmm0\n cvtsi2ssl %eax, %xmm0\n movaps %xmm0, %xmm2\n subss %xmm1, %xmm2\n mulss %xmm0, %xmm2\n cvttss2si %xmm2, %eax\n incl %ecx\n movl %eax, %edx\n imull %edi, %edx\n cmpl %edx, %ecx\n jl .LBB1_4",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".LBB1_4:\n addl %eax, %eax\n xorps %xmm0, %xmm0\n cvtsi2ssl %eax, %xmm0\n movaps %xmm0, %xmm2\n subss %xmm1, %xmm2\n mulss %xmm0, %xmm2\n cvttss2si %xmm2, %eax\n incl %ecx\n movl %eax, %edx\n imull %edi, %edx\n cmpl %edx, %ecx\n jl .LBB1_4"
|
||||
},
|
||||
{
|
||||
"id": ".LBB1_4:@39",
|
||||
"label": ".LBB1_4:@39\n jmp .LBB1_6",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".LBB1_4:@39\n jmp .LBB1_6"
|
||||
},
|
||||
{
|
||||
"id": ".LBB1_5:",
|
||||
"label": ".LBB1_5:\n cvttss2si %xmm1, %eax",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".LBB1_5:\n cvttss2si %xmm1, %eax"
|
||||
},
|
||||
{
|
||||
"id": ".LBB1_6:",
|
||||
"label": ".LBB1_6:\n retq",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".LBB1_6:\n retq"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
@@ -476,9 +458,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "_GLOBAL__sub_I_example.cpp:",
|
||||
"label": "_GLOBAL__sub_I_example.cpp:\n jmp __cxx_global_var_init",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "_GLOBAL__sub_I_example.cpp:\n jmp __cxx_global_var_init"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
|
||||
8
test/cfg-cases/cfg-clang.single-block.json
generated
8
test/cfg-cases/cfg-clang.single-block.json
generated
@@ -100,9 +100,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "main:",
|
||||
"label": "main:\n xorl %eax, %eax\n retq",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "main:\n xorl %eax, %eax\n retq"
|
||||
}
|
||||
],
|
||||
"edges": []
|
||||
@@ -111,9 +109,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "_GLOBAL__sub_I_example.cpp:",
|
||||
"label": "_GLOBAL__sub_I_example.cpp:\n pushq %rax\n movl std::__ioinit, %edi\n callq std::ios_base::Init::Init()\n movl std::ios_base::Init::~Init(), %edi\n movl std::__ioinit, %esi\n movl $__dso_handle, %edx\n popq %rax\n jmp __cxa_atexit",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "_GLOBAL__sub_I_example.cpp:\n pushq %rax\n movl std::__ioinit, %edi\n callq std::ios_base::Init::Init()\n movl std::ios_base::Init::~Init(), %edi\n movl std::__ioinit, %esi\n movl $__dso_handle, %edx\n popq %rax\n jmp __cxa_atexit"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
|
||||
48
test/cfg-cases/cfg-clang.split.json
generated
48
test/cfg-cases/cfg-clang.split.json
generated
@@ -82,45 +82,31 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "remove_space(char const*, char*, unsigned long):",
|
||||
"label": "remove_space(char const*, char*, unsigned long):\n testq %rdx, %rdx\n je .LBB0_6",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "remove_space(char const*, char*, unsigned long):\n testq %rdx, %rdx\n je .LBB0_6"
|
||||
},
|
||||
{
|
||||
"id": "remove_space(char const*, char*, unsigned long):@3",
|
||||
"label": "remove_space(char const*, char*, unsigned long):@3\n xorl %eax, %eax",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "remove_space(char const*, char*, unsigned long):@3\n xorl %eax, %eax"
|
||||
},
|
||||
{
|
||||
"color": "#99ccff",
|
||||
"id": ".LBB0_2:",
|
||||
"label": ".LBB0_2:\n movzbl (%rdi,%rax), %ecx\n cmpb $97, %cl\n je .LBB0_5",
|
||||
"shape": "box"
|
||||
{ "id": ".LBB0_2:",
|
||||
"label": ".LBB0_2:\n movzbl (%rdi,%rax), %ecx\n cmpb $97, %cl\n je .LBB0_5"
|
||||
|
||||
},
|
||||
{
|
||||
"color": "#99ccff",
|
||||
"id": ".LBB0_2:@8",
|
||||
"label": ".LBB0_2:@8\n cmpb $122, %cl\n je .LBB0_5",
|
||||
"shape": "box"
|
||||
{ "id": ".LBB0_2:@8",
|
||||
"label": ".LBB0_2:@8\n cmpb $122, %cl\n je .LBB0_5"
|
||||
|
||||
},
|
||||
{
|
||||
"color": "#99ccff",
|
||||
"id": ".LBB0_2:@10",
|
||||
"label": ".LBB0_2:@10\n movb %cl, (%rsi)\n addq $1, %rsi",
|
||||
"shape": "box"
|
||||
{ "id": ".LBB0_2:@10",
|
||||
"label": ".LBB0_2:@10\n movb %cl, (%rsi)\n addq $1, %rsi"
|
||||
|
||||
},
|
||||
{
|
||||
"color": "#99ccff",
|
||||
"id": ".LBB0_5:",
|
||||
"label": ".LBB0_5:\n addq $1, %rax\n cmpq %rax, %rdx\n jne .LBB0_2",
|
||||
"shape": "box"
|
||||
{ "id": ".LBB0_5:",
|
||||
"label": ".LBB0_5:\n addq $1, %rax\n cmpq %rax, %rdx\n jne .LBB0_2"
|
||||
|
||||
},
|
||||
{
|
||||
"color": "#99ccff",
|
||||
"id": ".LBB0_6:",
|
||||
"label": ".LBB0_6:\n movq %rsi, %rax\n retq",
|
||||
"shape": "box"
|
||||
{ "id": ".LBB0_6:",
|
||||
"label": ".LBB0_6:\n movq %rsi, %rax\n retq"
|
||||
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
|
||||
20
test/cfg-cases/cfg-clang.symbol-filter.json
generated
20
test/cfg-cases/cfg-clang.symbol-filter.json
generated
@@ -86,9 +86,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "foo(int, int):",
|
||||
"label": "foo(int, int):\n retq",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "foo(int, int):\n retq"
|
||||
}
|
||||
],
|
||||
"edges": []
|
||||
@@ -97,9 +95,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "foo3(int, int):",
|
||||
"label": "foo3(int, int):\n retq",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "foo3(int, int):\n retq"
|
||||
}
|
||||
],
|
||||
"edges": []
|
||||
@@ -108,9 +104,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "foo5(int, int):",
|
||||
"label": "foo5(int, int):\n retq",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "foo5(int, int):\n retq"
|
||||
}
|
||||
],
|
||||
"edges": []
|
||||
@@ -119,9 +113,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "foo6::<impl something for rust>::foo:",
|
||||
"label": "foo6::<impl something for rust>::foo:\n retq",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "foo6::<impl something for rust>::foo:\n retq"
|
||||
}
|
||||
],
|
||||
"edges": []
|
||||
@@ -130,9 +122,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "type metadata accessor for [Swift.Int]:",
|
||||
"label": "type metadata accessor for [Swift.Int]:\n retq",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "type metadata accessor for [Swift.Int]:\n retq"
|
||||
}
|
||||
],
|
||||
"edges": []
|
||||
|
||||
40
test/cfg-cases/cfg-gcc.binary.json
generated
40
test/cfg-cases/cfg-gcc.binary.json
generated
@@ -144,35 +144,25 @@
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"color": "#99ccff",
|
||||
"id": "main:",
|
||||
"label": "main:\n test edi,edi\n js 4003ea <main+0x1a>",
|
||||
"shape": "box"
|
||||
{ "id": "main:",
|
||||
"label": "main:\n test edi,edi\n js 4003ea <main+0x1a>"
|
||||
|
||||
},
|
||||
{
|
||||
"color": "#99ccff",
|
||||
"id": "main:@3",
|
||||
"label": "main:@3\n add edi,0x1\n xor eax,eax\n xor edx,edx\n nop DWORD PTR [rax+rax*1+0x0]\n add eax,edx\n add edx,0x1\n cmp edx,edi\n jne 4003e0 <main+0x10>",
|
||||
"shape": "box"
|
||||
{ "id": "main:@3",
|
||||
"label": "main:@3\n add edi,0x1\n xor eax,eax\n xor edx,edx\n nop DWORD PTR [rax+rax*1+0x0]\n add eax,edx\n add edx,0x1\n cmp edx,edi\n jne 4003e0 <main+0x10>"
|
||||
|
||||
},
|
||||
{
|
||||
"color": "#99ccff",
|
||||
"id": "main:@11",
|
||||
"label": "main:@11\n ret ",
|
||||
"shape": "box"
|
||||
{ "id": "main:@11",
|
||||
"label": "main:@11\n ret "
|
||||
|
||||
},
|
||||
{
|
||||
"color": "#99ccff",
|
||||
"id": " xor eax,eax",
|
||||
"label": " xor eax,eax:\n ret ",
|
||||
"shape": "box"
|
||||
{ "id": " xor eax,eax",
|
||||
"label": " xor eax,eax:\n ret "
|
||||
|
||||
},
|
||||
{
|
||||
"color": "#99ccff",
|
||||
"id": " nop DWORD PTR [rax]",
|
||||
"label": " nop DWORD PTR [rax]:\n",
|
||||
"shape": "box"
|
||||
{ "id": " nop DWORD PTR [rax]",
|
||||
"label": " nop DWORD PTR [rax]:\n"
|
||||
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
84
test/cfg-cases/cfg-gcc.if-else.json
generated
84
test/cfg-cases/cfg-gcc.if-else.json
generated
@@ -797,123 +797,83 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "main:",
|
||||
"label": "main:\n lea edx, [0+rdi*8]\n test edx, edx\n je .L8",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "main:\n lea edx, [0+rdi*8]\n test edx, edx\n je .L8"
|
||||
},
|
||||
{
|
||||
"id": "main:@4",
|
||||
"label": "main:@4\n add edx, edi\n je .L13",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "main:@4\n add edx, edi\n je .L13"
|
||||
},
|
||||
{
|
||||
"id": "main:@6",
|
||||
"label": "main:@6\n imul eax, edi, 223\n cmp eax, 1\n je .L14",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "main:@6\n imul eax, edi, 223\n cmp eax, 1\n je .L14"
|
||||
},
|
||||
{
|
||||
"id": "main:@9",
|
||||
"label": "main:@9\n xor eax, eax",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "main:@9\n xor eax, eax"
|
||||
},
|
||||
{
|
||||
"id": ".L1:",
|
||||
"label": ".L1:\n rep ret",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L1:\n rep ret"
|
||||
},
|
||||
{
|
||||
"id": ".L14:",
|
||||
"label": ".L14:\n test edi, edi\n jle .L1",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L14:\n test edi, edi\n jle .L1"
|
||||
},
|
||||
{
|
||||
"id": ".L14:@15",
|
||||
"label": ".L14:@15\n lea edx, [rdi-1]\n mov esi, edx\n shr esi\n add esi, 1\n cmp edx, 11\n jbe .L10",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L14:@15\n lea edx, [rdi-1]\n mov esi, edx\n shr esi\n add esi, 1\n cmp edx, 11\n jbe .L10"
|
||||
},
|
||||
{
|
||||
"id": ".L14:@21",
|
||||
"label": ".L14:@21\n mov DWORD PTR [rsp-12], edi\n pxor xmm3, xmm3\n movd xmm7, DWORD PTR [rsp-12]\n mov ecx, esi\n xor edx, edx\n movdqa xmm2, XMMWORD PTR .LC0[rip]\n shr ecx, 2\n pshufd xmm4, xmm7, 0\n movdqa xmm6, XMMWORD PTR .LC1[rip]\n movdqa xmm5, xmm4\n psrlq xmm5, 32",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L14:@21\n mov DWORD PTR [rsp-12], edi\n pxor xmm3, xmm3\n movd xmm7, DWORD PTR [rsp-12]\n mov ecx, esi\n xor edx, edx\n movdqa xmm2, XMMWORD PTR .LC0[rip]\n shr ecx, 2\n pshufd xmm4, xmm7, 0\n movdqa xmm6, XMMWORD PTR .LC1[rip]\n movdqa xmm5, xmm4\n psrlq xmm5, 32"
|
||||
},
|
||||
{
|
||||
"id": ".L5:",
|
||||
"label": ".L5:\n movdqa xmm0, xmm2\n add edx, 1\n movdqa xmm1, xmm2\n cmp ecx, edx\n paddd xmm2, xmm6\n pmuludq xmm0, xmm4\n pshufd xmm0, xmm0, 8\n psrlq xmm1, 32\n pmuludq xmm1, xmm5\n pshufd xmm1, xmm1, 8\n punpckldq xmm0, xmm1\n paddd xmm3, xmm0\n ja .L5",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L5:\n movdqa xmm0, xmm2\n add edx, 1\n movdqa xmm1, xmm2\n cmp ecx, edx\n paddd xmm2, xmm6\n pmuludq xmm0, xmm4\n pshufd xmm0, xmm0, 8\n psrlq xmm1, 32\n pmuludq xmm1, xmm5\n pshufd xmm1, xmm1, 8\n punpckldq xmm0, xmm1\n paddd xmm3, xmm0\n ja .L5"
|
||||
},
|
||||
{
|
||||
"id": ".L5:@46",
|
||||
"label": ".L5:@46\n movdqa xmm0, xmm3\n mov r8d, esi\n and r8d, -4\n psrldq xmm0, 8\n paddd xmm3, xmm0\n movdqa xmm0, xmm3\n psrldq xmm0, 4\n paddd xmm3, xmm0\n movd edx, xmm3\n add eax, edx\n lea edx, [r8+r8]\n cmp esi, r8d\n lea ecx, [rdx+1]\n je .L15",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L5:@46\n movdqa xmm0, xmm3\n mov r8d, esi\n and r8d, -4\n psrldq xmm0, 8\n paddd xmm3, xmm0\n movdqa xmm0, xmm3\n psrldq xmm0, 4\n paddd xmm3, xmm0\n movd edx, xmm3\n add eax, edx\n lea edx, [r8+r8]\n cmp esi, r8d\n lea ecx, [rdx+1]\n je .L15"
|
||||
},
|
||||
{
|
||||
"id": ".L4:",
|
||||
"label": ".L4:\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+3]\n cmp edi, ecx\n jl .L1",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L4:\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+3]\n cmp edi, ecx\n jl .L1"
|
||||
},
|
||||
{
|
||||
"id": ".L4:@66",
|
||||
"label": ".L4:@66\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+5]\n cmp edi, ecx\n jl .L1",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L4:@66\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+5]\n cmp edi, ecx\n jl .L1"
|
||||
},
|
||||
{
|
||||
"id": ".L4:@71",
|
||||
"label": ".L4:@71\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+7]\n cmp edi, ecx\n jl .L1",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L4:@71\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+7]\n cmp edi, ecx\n jl .L1"
|
||||
},
|
||||
{
|
||||
"id": ".L4:@76",
|
||||
"label": ".L4:@76\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+9]\n cmp edi, ecx\n jl .L1",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L4:@76\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+9]\n cmp edi, ecx\n jl .L1"
|
||||
},
|
||||
{
|
||||
"id": ".L4:@81",
|
||||
"label": ".L4:@81\n imul ecx, edi\n add edx, 11\n add eax, ecx\n cmp edi, edx\n jl .L1",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L4:@81\n imul ecx, edi\n add edx, 11\n add eax, ecx\n cmp edi, edx\n jl .L1"
|
||||
},
|
||||
{
|
||||
"id": ".L4:@86",
|
||||
"label": ".L4:@86\n imul edi, edx\n add eax, edi\n ret",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L4:@86\n imul edi, edx\n add eax, edi\n ret"
|
||||
},
|
||||
{
|
||||
"id": ".L13:",
|
||||
"label": ".L13:\n imul edx, edi\n imul eax, edx, 78\n ret",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L13:\n imul edx, edi\n imul eax, edx, 78\n ret"
|
||||
},
|
||||
{
|
||||
"id": ".L8:",
|
||||
"label": ".L8:\n mov eax, 78\n ret",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L8:\n mov eax, 78\n ret"
|
||||
},
|
||||
{
|
||||
"id": ".L15:",
|
||||
"label": ".L15:\n ret",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L15:\n ret"
|
||||
},
|
||||
{
|
||||
"id": ".L10:",
|
||||
"label": ".L10:\n mov ecx, 1\n xor edx, edx\n jmp .L4",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L10:\n mov ecx, 1\n xor edx, edx\n jmp .L4"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
@@ -1085,9 +1045,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "_GLOBAL__sub_I_main:",
|
||||
"label": "_GLOBAL__sub_I_main:\n sub rsp, 8\n mov edi, OFFSET FLAT:std::__ioinit\n call std::ios_base::Init::Init()\n mov edx, OFFSET FLAT:__dso_handle\n mov esi, OFFSET FLAT:std::__ioinit\n mov edi, OFFSET FLAT:std::ios_base::Init::~Init()\n add rsp, 8\n jmp __cxa_atexit",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "_GLOBAL__sub_I_main:\n sub rsp, 8\n mov edi, OFFSET FLAT:std::__ioinit\n call std::ios_base::Init::Init()\n mov edx, OFFSET FLAT:__dso_handle\n mov esi, OFFSET FLAT:std::__ioinit\n mov edi, OFFSET FLAT:std::ios_base::Init::~Init()\n add rsp, 8\n jmp __cxa_atexit"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
|
||||
92
test/cfg-cases/cfg-gcc.loop.json
generated
92
test/cfg-cases/cfg-gcc.loop.json
generated
@@ -857,135 +857,91 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "main:",
|
||||
"label": "main:\n lea edx, [0+rdi*8]\n test edx, edx\n je .L10",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "main:\n lea edx, [0+rdi*8]\n test edx, edx\n je .L10"
|
||||
},
|
||||
{
|
||||
"id": "main:@4",
|
||||
"label": "main:@4\n add edx, edi\n je .L14",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "main:@4\n add edx, edi\n je .L14"
|
||||
},
|
||||
{
|
||||
"id": "main:@6",
|
||||
"label": "main:@6\n imul edx, edi, 223\n mov eax, 1\n cmp edx, eax\n je .L15",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "main:@6\n imul edx, edi, 223\n mov eax, 1\n cmp edx, eax\n je .L15"
|
||||
},
|
||||
{
|
||||
"id": "main:@10",
|
||||
"label": "main:@10\n lea edx, [rdi+rax]\n cmp edi, edx\n jl .L16",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "main:@10\n lea edx, [rdi+rax]\n cmp edi, edx\n jl .L16"
|
||||
},
|
||||
{
|
||||
"id": "main:@13",
|
||||
"label": "main:@13\n imul edi, edx\n imul eax, edi\n ret",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "main:@13\n imul edi, edx\n imul eax, edi\n ret"
|
||||
},
|
||||
{
|
||||
"id": ".L14:",
|
||||
"label": ".L14:\n imul edx, edi\n imul eax, edx, 78\n ret",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L14:\n imul edx, edi\n imul eax, edx, 78\n ret"
|
||||
},
|
||||
{
|
||||
"id": ".L15:",
|
||||
"label": ".L15:\n test edi, edi\n jle .L1",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L15:\n test edi, edi\n jle .L1"
|
||||
},
|
||||
{
|
||||
"id": ".L15:@23",
|
||||
"label": ".L15:@23\n lea edx, [rdi-1]\n mov esi, edx\n shr esi\n add esi, 1\n cmp edx, 11\n jbe .L11",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L15:@23\n lea edx, [rdi-1]\n mov esi, edx\n shr esi\n add esi, 1\n cmp edx, 11\n jbe .L11"
|
||||
},
|
||||
{
|
||||
"id": ".L15:@29",
|
||||
"label": ".L15:@29\n mov DWORD PTR [rsp-12], edi\n pxor xmm3, xmm3\n movd xmm7, DWORD PTR [rsp-12]\n mov ecx, esi\n xor edx, edx\n movdqa xmm2, XMMWORD PTR .LC0[rip]\n shr ecx, 2\n pshufd xmm4, xmm7, 0\n movdqa xmm6, XMMWORD PTR .LC1[rip]\n movdqa xmm5, xmm4\n psrlq xmm5, 32",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L15:@29\n mov DWORD PTR [rsp-12], edi\n pxor xmm3, xmm3\n movd xmm7, DWORD PTR [rsp-12]\n mov ecx, esi\n xor edx, edx\n movdqa xmm2, XMMWORD PTR .LC0[rip]\n shr ecx, 2\n pshufd xmm4, xmm7, 0\n movdqa xmm6, XMMWORD PTR .LC1[rip]\n movdqa xmm5, xmm4\n psrlq xmm5, 32"
|
||||
},
|
||||
{
|
||||
"id": ".L6:",
|
||||
"label": ".L6:\n movdqa xmm0, xmm2\n add edx, 1\n movdqa xmm1, xmm2\n cmp ecx, edx\n paddd xmm2, xmm6\n pmuludq xmm0, xmm4\n pshufd xmm0, xmm0, 8\n psrlq xmm1, 32\n pmuludq xmm1, xmm5\n pshufd xmm1, xmm1, 8\n punpckldq xmm0, xmm1\n paddd xmm3, xmm0\n ja .L6",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L6:\n movdqa xmm0, xmm2\n add edx, 1\n movdqa xmm1, xmm2\n cmp ecx, edx\n paddd xmm2, xmm6\n pmuludq xmm0, xmm4\n pshufd xmm0, xmm0, 8\n psrlq xmm1, 32\n pmuludq xmm1, xmm5\n pshufd xmm1, xmm1, 8\n punpckldq xmm0, xmm1\n paddd xmm3, xmm0\n ja .L6"
|
||||
},
|
||||
{
|
||||
"id": ".L6:@54",
|
||||
"label": ".L6:@54\n movdqa xmm0, xmm3\n mov r8d, esi\n and r8d, -4\n psrldq xmm0, 8\n paddd xmm3, xmm0\n movdqa xmm0, xmm3\n psrldq xmm0, 4\n paddd xmm3, xmm0\n movd edx, xmm3\n add eax, edx\n lea edx, [r8+r8]\n cmp esi, r8d\n lea ecx, [rdx+1]\n je .L17",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L6:@54\n movdqa xmm0, xmm3\n mov r8d, esi\n and r8d, -4\n psrldq xmm0, 8\n paddd xmm3, xmm0\n movdqa xmm0, xmm3\n psrldq xmm0, 4\n paddd xmm3, xmm0\n movd edx, xmm3\n add eax, edx\n lea edx, [r8+r8]\n cmp esi, r8d\n lea ecx, [rdx+1]\n je .L17"
|
||||
},
|
||||
{
|
||||
"id": ".L5:",
|
||||
"label": ".L5:\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+3]\n cmp edi, ecx\n jl .L1",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L5:\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+3]\n cmp edi, ecx\n jl .L1"
|
||||
},
|
||||
{
|
||||
"id": ".L5:@74",
|
||||
"label": ".L5:@74\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+5]\n cmp edi, ecx\n jl .L1",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L5:@74\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+5]\n cmp edi, ecx\n jl .L1"
|
||||
},
|
||||
{
|
||||
"id": ".L5:@79",
|
||||
"label": ".L5:@79\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+7]\n cmp edi, ecx\n jl .L1",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L5:@79\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+7]\n cmp edi, ecx\n jl .L1"
|
||||
},
|
||||
{
|
||||
"id": ".L5:@84",
|
||||
"label": ".L5:@84\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+9]\n cmp edi, ecx\n jl .L1",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L5:@84\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+9]\n cmp edi, ecx\n jl .L1"
|
||||
},
|
||||
{
|
||||
"id": ".L5:@89",
|
||||
"label": ".L5:@89\n imul ecx, edi\n add edx, 11\n add eax, ecx\n cmp edi, edx\n jl .L1",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L5:@89\n imul ecx, edi\n add edx, 11\n add eax, ecx\n cmp edi, edx\n jl .L1"
|
||||
},
|
||||
{
|
||||
"id": ".L5:@94",
|
||||
"label": ".L5:@94\n imul edx, edi\n add eax, edx\n ret",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L5:@94\n imul edx, edi\n add eax, edx\n ret"
|
||||
},
|
||||
{
|
||||
"id": ".L10:",
|
||||
"label": ".L10:\n mov eax, 78",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L10:\n mov eax, 78"
|
||||
},
|
||||
{
|
||||
"id": ".L1:",
|
||||
"label": ".L1:\n rep ret",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L1:\n rep ret"
|
||||
},
|
||||
{
|
||||
"id": ".L16:",
|
||||
"label": ".L16:\n mov rax, QWORD PTR [rsi]\n movsx eax, BYTE PTR [rax]\n ret",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L16:\n mov rax, QWORD PTR [rsi]\n movsx eax, BYTE PTR [rax]\n ret"
|
||||
},
|
||||
{
|
||||
"id": ".L17:",
|
||||
"label": ".L17:\n ret",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L17:\n ret"
|
||||
},
|
||||
{
|
||||
"id": ".L11:",
|
||||
"label": ".L11:\n mov ecx, 1\n xor edx, edx\n jmp .L5",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": ".L11:\n mov ecx, 1\n xor edx, edx\n jmp .L5"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
@@ -1169,9 +1125,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "_GLOBAL__sub_I_main:",
|
||||
"label": "_GLOBAL__sub_I_main:\n sub rsp, 8\n mov edi, OFFSET FLAT:std::__ioinit\n call std::ios_base::Init::Init()\n mov edx, OFFSET FLAT:__dso_handle\n mov esi, OFFSET FLAT:std::__ioinit\n mov edi, OFFSET FLAT:std::ios_base::Init::~Init()\n add rsp, 8\n jmp __cxa_atexit",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "_GLOBAL__sub_I_main:\n sub rsp, 8\n mov edi, OFFSET FLAT:std::__ioinit\n call std::ios_base::Init::Init()\n mov edx, OFFSET FLAT:__dso_handle\n mov esi, OFFSET FLAT:std::__ioinit\n mov edi, OFFSET FLAT:std::ios_base::Init::~Init()\n add rsp, 8\n jmp __cxa_atexit"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
|
||||
8
test/cfg-cases/cfg-gcc.single-block.json
generated
8
test/cfg-cases/cfg-gcc.single-block.json
generated
@@ -88,9 +88,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "main:",
|
||||
"label": "main:\n xor eax, eax\n ret",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "main:\n xor eax, eax\n ret"
|
||||
}
|
||||
],
|
||||
"edges": []
|
||||
@@ -99,9 +97,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "_GLOBAL__sub_I_main:",
|
||||
"label": "_GLOBAL__sub_I_main:\n sub rsp, 8\n mov edi, OFFSET FLAT:std::__ioinit\n call std::ios_base::Init::Init()\n mov edx, OFFSET FLAT:__dso_handle\n mov esi, OFFSET FLAT:std::__ioinit\n mov edi, OFFSET FLAT:std::ios_base::Init::~Init()\n add rsp, 8\n jmp __cxa_atexit",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "_GLOBAL__sub_I_main:\n sub rsp, 8\n mov edi, OFFSET FLAT:std::__ioinit\n call std::ios_base::Init::Init()\n mov edx, OFFSET FLAT:__dso_handle\n mov esi, OFFSET FLAT:std::__ioinit\n mov edi, OFFSET FLAT:std::ios_base::Init::~Init()\n add rsp, 8\n jmp __cxa_atexit"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
|
||||
20
test/cfg-cases/cfg-gcc.symbol-filter.json
generated
20
test/cfg-cases/cfg-gcc.symbol-filter.json
generated
@@ -86,9 +86,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "foo(int, int):",
|
||||
"label": "foo(int, int):\n retq",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "foo(int, int):\n retq"
|
||||
}
|
||||
],
|
||||
"edges": []
|
||||
@@ -97,9 +95,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "foo3(int, int):",
|
||||
"label": "foo3(int, int):\n retq",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "foo3(int, int):\n retq"
|
||||
}
|
||||
],
|
||||
"edges": []
|
||||
@@ -108,9 +104,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "foo5(int, int):",
|
||||
"label": "foo5(int, int):\n retq",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "foo5(int, int):\n retq"
|
||||
}
|
||||
],
|
||||
"edges": []
|
||||
@@ -119,9 +113,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "foo6::<impl something for rust>::foo:",
|
||||
"label": "foo6::<impl something for rust>::foo:\n retq",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "foo6::<impl something for rust>::foo:\n retq"
|
||||
}
|
||||
],
|
||||
"edges": []
|
||||
@@ -130,9 +122,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"id": "type metadata accessor for [Swift.Int]:",
|
||||
"label": "type metadata accessor for [Swift.Int]:\n retq",
|
||||
"color": "#99ccff",
|
||||
"shape": "box"
|
||||
"label": "type metadata accessor for [Swift.Int]:\n retq"
|
||||
}
|
||||
],
|
||||
"edges": []
|
||||
|
||||
@@ -22,13 +22,19 @@
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import * as cfg from '../lib/cfg';
|
||||
import * as cfg from '../lib/cfg/cfg';
|
||||
|
||||
import {fs, path, resolvePathFromTestRoot} from './utils';
|
||||
|
||||
async function DoCfgTest(cfgArg, filename) {
|
||||
const contents = await fs.readJson(filename, 'utf8');
|
||||
const structure = cfg.generateStructure('', cfgArg, contents.asm);
|
||||
const structure = cfg.generateStructure(
|
||||
{
|
||||
compilerType: '',
|
||||
version: cfgArg,
|
||||
},
|
||||
contents.asm,
|
||||
);
|
||||
structure.should.deep.equal(contents.cfg);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user