Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,12 @@ test-results/*
third_party/*
yarn.lock
*.pyc

# MLIR parser artifacts (downloaded via tools/update-mlir-parser.js)
source/mlir_parser.wasm
source/mlir_parser.js
source/bindings.js
source/mlir-bindings.js

# Built web artifacts that may include wasm
dist/web/*.wasm
2 changes: 1 addition & 1 deletion package.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ const build = async (target) => {
writeLine('cp source/dir dist/dir');
const source_dir = dirname('source');
const dist_dir = dirname('dist', 'web');
const extensions = new Set(['html', 'css', 'js', 'json', 'ico', 'png']);
const extensions = new Set(['html', 'css', 'js', 'json', 'ico', 'png', 'wasm']);
await copy(source_dir, dist_dir, (file) => extensions.has(file.split('.').pop()));
await rm('dist', 'web', 'app.js');
await rm('dist', 'web', 'node.js');
Expand Down
1 change: 1 addition & 0 deletions source/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,7 @@ base.Metadata = class {
'hd5', 'hdf5', 'keras',
'tfl', 'circle', 'lite',
'mlnet', 'mar', 'maxviz', 'meta', 'nn', 'ngf', 'hn',
'mlir', 'mlirbc',
'param', 'params',
'paddle', 'pdiparams', 'pdmodel', 'pdopt', 'pdparams', 'nb',
'pkl', 'pickle', 'joblib', 'safetensors',
Expand Down
2 changes: 1 addition & 1 deletion source/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="description" content="Visualizer for neural network, deep learning and machine learning models." />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-eval' 'wasm-unsafe-eval'; object-src 'self'">
<meta name="version" content="0.0.0">
<meta name="date" content="">
<title>Netron</title>
Expand Down
277 changes: 277 additions & 0 deletions source/mlir-json-adapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
// MLIR JSON Adapter - Convert mlir-js-parser output to Netron's expected format

const mlir = {};

mlir.JsonAdapter = class {

Check failure on line 6 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

Trailing spaces not allowed

Check failure on line 6 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Trailing spaces not allowed
/**
* Convert mlir-js-parser JSON output to Netron's internal format
* @param {Object} mlirJson - Output from mlir-js-parser.parseMlirJson()
* @returns {Object} - Netron compatible object with operations and definitions
*/
static convert(mlirJson) {
if (!mlirJson || mlirJson.name !== 'builtin.module') {
throw new Error('Expected builtin.module at root');
}

Check failure on line 16 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

Trailing spaces not allowed

Check failure on line 16 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Trailing spaces not allowed
const result = {
operations: [],
definitions: []
};

Check failure on line 21 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

Trailing spaces not allowed

Check failure on line 21 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Trailing spaces not allowed
// Extract top-level operations from the module
this._convertRegions(mlirJson.regions, result.operations);

Check failure on line 24 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

Trailing spaces not allowed

Check failure on line 24 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Trailing spaces not allowed
// Extract definitions from module attributes (if any)
if (mlirJson.attributes) {
for (const [name, value] of Object.entries(mlirJson.attributes)) {
result.definitions.push({ name, value });
}
}

Check failure on line 31 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

Trailing spaces not allowed

Check failure on line 31 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Trailing spaces not allowed
return result;
}

Check failure on line 34 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

Trailing spaces not allowed

Check failure on line 34 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Trailing spaces not allowed
/**
* Convert regions to operations list
* @param {Array} regions - MLIR regions from JSON
* @param {Array} operations - Target operations array
*/
static _convertRegions(regions, operations) {
for (const region of regions) {
for (const block of region.blocks) {
for (const op of block.operations) {
const operation = this._convertOperation(op);
operations.push(operation);
}
}
}
}

Check failure on line 50 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

Trailing spaces not allowed

Check failure on line 50 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Trailing spaces not allowed
/**
* Convert single operation from mlir-js-parser JSON to Netron format
* @param {Object} jsonOp - Operation from mlir-js-parser JSON
* @returns {Object} - Netron compatible operation
*/
static _convertOperation(jsonOp) {
const operation = {
name: jsonOp.name,
kind: this._extractKind(jsonOp.name),
attributes: this._convertAttributes(jsonOp.attributes),
operands: this._convertOperands(jsonOp.operands),
results: this._convertResults(jsonOp.results),
regions: []
};

Check failure on line 65 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

Trailing spaces not allowed

Check failure on line 65 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Trailing spaces not allowed
// Convert nested regions
if (jsonOp.regions && jsonOp.regions.length > 0) {
for (const region of jsonOp.regions) {
const convertedRegion = {
blocks: []
};
for (const block of region.blocks) {
const convertedBlock = {
arguments: this._convertBlockArguments(block.arguments),
operations: []
};
for (const nestedOp of block.operations) {
convertedBlock.operations.push(this._convertOperation(nestedOp));
}
convertedRegion.blocks.push(convertedBlock);
}
operation.regions.push(convertedRegion);
}
}

Check failure on line 85 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

Trailing spaces not allowed

Check failure on line 85 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Trailing spaces not allowed
return operation;
}

Check failure on line 88 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

Trailing spaces not allowed

Check failure on line 88 in source/mlir-json-adapter.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Trailing spaces not allowed
/**
* Extract operation kind from full name (e.g., "func.func" -> "func")
* @param {string} name - Full operation name
* @returns {string} - Operation kind
*/
static _extractKind(name) {
if (name.startsWith('torch.')) {
const parts = name.split('.');
if (parts[1] === 'aten' || parts[1] === 'prim') {
return parts[2] || parts[1];
}
return parts[1] || name;
}

const lastDot = name.lastIndexOf('.');
return lastDot !== -1 ? name.substring(lastDot + 1) : name;
}

/**
* Convert attributes from mlir-js-parser format to Netron format
* @param {Object} jsonAttributes - Attributes from JSON
* @returns {Array} - Array of attribute objects
*/
static _convertAttributes(jsonAttributes) {
const attributes = [];
for (const [name, value] of Object.entries(jsonAttributes)) {
let convertedValue = value;
let type = this._inferAttributeType(value);

// Special handling for function_type attribute
if (name === 'function_type' && typeof value === 'string') {
convertedValue = this._parseFunctionType(value);
type = 'function_type';
}

attributes.push({
name,
value: convertedValue,
type
});
}
return attributes;
}

/**
* Convert operands from mlir-js-parser format
* @param {Array} jsonOperands - Operands from JSON
* @returns {Array} - Array of operand objects
*/
static _convertOperands(jsonOperands) {
return jsonOperands.map((operand, index) => ({
name: operand.name || index.toString(),
value: operand.value || `%${index}`, // SSA value name
type: operand.type
}));
}

/**
* Convert results from mlir-js-parser format
* @param {Array} jsonResults - Results from JSON
* @returns {Array} - Array of result objects
*/
static _convertResults(jsonResults) {
return jsonResults.map((result, index) => ({
name: result.name || index.toString(),
value: result.value || `%${index}`, // SSA value name
type: result.type
}));
}

/**
* Convert block arguments
* @param {Array} jsonArguments - Block arguments from JSON
* @returns {Array} - Array of argument objects
*/
static _convertBlockArguments(jsonArguments) {
return jsonArguments.map((arg, index) => ({
name: arg.name || index.toString(),
type: arg.type,
value: arg.value || `%arg${index}`
}));
}

/**
* Infer attribute type from value
* @param {*} value - Attribute value
* @returns {string} - Inferred type
*/
static _inferAttributeType(value) {
if (typeof value === 'string') {
// Check if it looks like a number
if (/^\d+$/.test(value)) return 'int64';
if (/^\d*\.\d*$/.test(value)) return 'float32';
return 'string';
}
if (typeof value === 'boolean') return 'boolean';
if (Array.isArray(value)) return 'array';
if (typeof value === 'object') return 'dictionary';
return 'attribute';
}

/**
* Extract function type information for compatibility with existing Netron code
* This is needed for functions that have special handling in mlir.Graph constructor
* @param {Object} funcOp - Function operation from JSON
* @returns {Object} - Function type information
*/
static extractFunctionType(funcOp) {
// Look for function_type attribute
const functionTypeAttr = funcOp.attributes.function_type;

if (functionTypeAttr) {
return functionTypeAttr;
}

// Fallback: try to infer from operation structure
return {
inputs: funcOp.operands || [],
results: funcOp.results || []
};
}

/**
* Parse MLIR function type string into inputs/results format
* Converts "(i32, f32) -> (tensor<4xf32>)" to {inputs: [...], results: [...]}
* @param {string} functionTypeStr - Function type string from MLIR
* @returns {Object} - Object with inputs and results arrays
*/
static _parseFunctionType(functionTypeStr) {
try {
// Basic parsing for function type string like "(i32) -> i32" or "(i32, f32) -> (tensor<4xf32>)"
const match = functionTypeStr.match(/^\(([^)]*)\)\s*->\s*(.+)$/);

if (!match) {
// Fallback for malformed strings
return { inputs: [], results: [] };
}

const inputsStr = match[1].trim();
const resultsStr = match[2].trim();

// Parse inputs
const inputs = [];
if (inputsStr) {
const inputTypes = inputsStr.split(',').map(s => s.trim()).filter(s => s);
for (let i = 0; i < inputTypes.length; i++) {
inputs.push({
name: i.toString(),
type: inputTypes[i],
value: `%arg${i}`
});
}
}

// Parse results
const results = [];
let resultTypes = [];

if (resultsStr.startsWith('(') && resultsStr.endsWith(')')) {
// Multiple results: "(type1, type2)"
const innerResults = resultsStr.slice(1, -1).trim();
if (innerResults) {
resultTypes = innerResults.split(',').map(s => s.trim()).filter(s => s);
}
} else {
// Single result: "type"
resultTypes = [resultsStr];
}

for (let i = 0; i < resultTypes.length; i++) {
results.push({
name: i.toString(),
type: resultTypes[i],
value: `%${i}`
});
}

return { inputs, results };

} catch (error) {
// Fallback on parsing error
console.warn('Failed to parse function type:', functionTypeStr, error);
return { inputs: [], results: [] };
}
}
};

// Export for use in mlir.js
export { mlir };
Loading
Loading