Skip to content

Commit eedcc29

Browse files
dcodeIOkripken
authored andcommitted
Running passes on a single function in binaryen-c/.js (#1295)
* Also other function utilities in C and JS APIs
1 parent 07c5475 commit eedcc29

File tree

8 files changed

+821
-665
lines changed

8 files changed

+821
-665
lines changed

bin/binaryen.js

Lines changed: 666 additions & 663 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build-js.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ export_function "_BinaryenConstGetValueI64High"
358358
export_function "_BinaryenConstGetValueF32"
359359
export_function "_BinaryenConstGetValueF64"
360360
export_function "_BinaryenAddFunction"
361+
export_function "_BinaryenGetFunction"
362+
export_function "_BinaryenRemoveFunction"
361363
export_function "_BinaryenAddGlobal"
362364
export_function "_BinaryenAddImport"
363365
export_function "_BinaryenRemoveImport"
@@ -376,6 +378,9 @@ export_function "_BinaryenModuleAutoDrop"
376378
export_function "_BinaryenModuleWrite"
377379
export_function "_BinaryenModuleRead"
378380
export_function "_BinaryenModuleInterpret"
381+
export_function "_BinaryenFunctionGetBody"
382+
export_function "_BinaryenFunctionOptimize"
383+
export_function "_BinaryenFunctionRunPasses"
379384
export_function "_RelooperCreate"
380385
export_function "_RelooperAddBlock"
381386
export_function "_RelooperAddBranch"

docs/binaryen.js.Markdown

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ Module property operations:
2828

2929
* `addFunctionType(name, resultType, paramTypes)`: Add a function type to the module, with a specified name, result type, and param types.
3030
* `addFunction(name, functionType, varTypes, body)`: Add a function, with a name, a function type, an array of local types, and a body.
31+
* `getFunction(name)`: Gets a function reference by name.
32+
* `removeFunction(name)`: Removes a function by name.
3133
* `addImport(internalName, externalModuleName, externalBaseName, functionType)`: Add an import, with an internal name (used by other things in the module), an external module name (the module from which we import), an external base name (the name we import from that module), and a function type (for function imports).
3234
* `addExport(internalName, externalName)`: Add an export, with an internal name and an external name (the name the outside sees it exported as).
3335
* `setFunctionTable(funcs)`: Sets the function table to a array of functions.
@@ -40,7 +42,9 @@ Module operations:
4042
* `emitText()`: Returns a text representation of the module, in s-expression format.
4143
* `validate()`: Validates the module, checking it for correctness.
4244
* `optimize()`: Runs the standard optimization passes on the module.
45+
* `optimizeFunction(func)`: Runs the standard optimization passes on a function.
4346
* `runPasses(passes)`: Runs the specified passes on the module.
47+
* `runPassesOnFunction(func, passes)`: Runs the specified passes on a function.
4448
* `autoDrop()`: Automatically inserts `drop` operations. This lets you not worry about dropping when creating your code.
4549
* `interpret()`: Run the module in the Binaryen interpreter (creates the module, and calls the start method). Useful for debugging.
4650
* `dispose()`: Cleans up the module. If the Binaryen object can be garbage-collected anyhow, you don't need to do this, but if it stays around - e.g. if you create multiple `Module`s over time - then you should call this once a `Module` is no longer needed. (As binaryen.js uses compiled C++ code, we can't just rely on normal garbage collection to clean things up internally.)

src/binaryen-c.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,22 @@ BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module, const char* na
912912

913913
return ret;
914914
}
915+
BinaryenFunctionRef BinaryenGetFunction(BinaryenModuleRef module, const char* name) {
916+
if (tracing) {
917+
std::cout << " BinaryenGetFunction(the_module, \"" << name << "\");\n";
918+
}
919+
920+
auto* wasm = (Module*)module;
921+
return wasm->getFunction(name);
922+
}
923+
void BinaryenRemoveFunction(BinaryenModuleRef module, const char* name) {
924+
if (tracing) {
925+
std::cout << " BinaryenRemoveFunction(the_module, \"" << name << "\");\n";
926+
}
927+
928+
auto* wasm = (Module*)module;
929+
wasm->removeFunction(name);
930+
}
915931

916932
BinaryenGlobalRef BinaryenAddGlobal(BinaryenModuleRef module, const char* name, BinaryenType type, int8_t mutable_, BinaryenExpressionRef init) {
917933
if (tracing) {
@@ -1213,6 +1229,50 @@ void BinaryenModuleInterpret(BinaryenModuleRef module) {
12131229
ModuleInstance instance(*wasm, &interface);
12141230
}
12151231

1232+
//
1233+
// ========== Function Operations ==========
1234+
//
1235+
1236+
BinaryenExpressionRef BinaryenFunctionGetBody(BinaryenFunctionRef func) {
1237+
if (tracing) {
1238+
std::cout << " BinaryenFunctionGetBody(functions[" << functions[func] << "]);\n";
1239+
}
1240+
1241+
return ((Function*)func)->body;
1242+
}
1243+
1244+
void BinaryenFunctionOptimize(BinaryenFunctionRef func, BinaryenModuleRef module) {
1245+
if (tracing) {
1246+
std::cout << " BinaryenFunctionOptimize(functions[" << functions[func] << "], the_module);\n";
1247+
}
1248+
1249+
Module* wasm = (Module*)module;
1250+
PassRunner passRunner(wasm);
1251+
passRunner.addDefaultOptimizationPasses();
1252+
passRunner.runFunction((Function*)func);
1253+
}
1254+
1255+
void BinaryenFunctionRunPasses(BinaryenFunctionRef func, BinaryenModuleRef module, const char **passes, BinaryenIndex numPasses) {
1256+
if (tracing) {
1257+
std::cout << " {\n";
1258+
std::cout << " const char* passes[] = { ";
1259+
for (BinaryenIndex i = 0; i < numPasses; i++) {
1260+
if (i > 0) std::cout << ", ";
1261+
std::cout << "\"" << passes[i] << "\"";
1262+
}
1263+
std::cout << " };\n";
1264+
std::cout << " BinaryenFunctionRunPasses(functions[" << functions[func] << ", the_module, passes, " << numPasses << ");\n";
1265+
std::cout << " }\n";
1266+
}
1267+
1268+
Module* wasm = (Module*)module;
1269+
PassRunner passRunner(wasm);
1270+
for (BinaryenIndex i = 0; i < numPasses; i++) {
1271+
passRunner.add(passes[i]);
1272+
}
1273+
passRunner.runFunction((Function*)func);
1274+
}
1275+
12161276
//
12171277
// ========== CFG / Relooper ==========
12181278
//

src/binaryen-c.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,12 @@ typedef void* BinaryenFunctionRef;
400400
// at indexes 1 and 2, etc., that is, they share an index space.
401401
BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module, const char* name, BinaryenFunctionTypeRef type, BinaryenType* varTypes, BinaryenIndex numVarTypes, BinaryenExpressionRef body);
402402

403+
// Gets a function reference by name.
404+
BinaryenFunctionRef BinaryenGetFunction(BinaryenModuleRef module, const char* name);
405+
406+
// Removes a function by name.
407+
void BinaryenRemoveFunction(BinaryenModuleRef module, const char* name);
408+
403409
// Imports
404410

405411
typedef void* BinaryenImportRef;
@@ -451,7 +457,7 @@ void BinaryenModulePrintAsmjs(BinaryenModuleRef module);
451457
// @return 0 if an error occurred, 1 if validated succesfully
452458
int BinaryenModuleValidate(BinaryenModuleRef module);
453459

454-
// Run the standard optimization passes on the module.
460+
// Runs the standard optimization passes on the module.
455461
void BinaryenModuleOptimize(BinaryenModuleRef module);
456462

457463
// Runs the specified passes on the module.
@@ -474,6 +480,19 @@ BinaryenModuleRef BinaryenModuleRead(char* input, size_t inputSize);
474480
// and then destroying the instance.
475481
void BinaryenModuleInterpret(BinaryenModuleRef module);
476482

483+
//
484+
// ========== Function Operations ==========
485+
//
486+
487+
// Gets the body of the function.
488+
BinaryenExpressionRef BinaryenFunctionGetBody(BinaryenFunctionRef func);
489+
490+
// Runs the standard optimization passes on the function.
491+
void BinaryenFunctionOptimize(BinaryenFunctionRef func, BinaryenModuleRef module);
492+
493+
// Runs the specified passes on the function.
494+
void BinaryenFunctionRunPasses(BinaryenFunctionRef func, BinaryenModuleRef module, const char **passes, BinaryenIndex numPasses);
495+
477496
//
478497
// ========== CFG / Relooper ==========
479498
//

src/js/binaryen.js-post.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,16 @@
10191019
return Module['_BinaryenAddFunction'](module, strToStack(name), functionType, i32sToStack(varTypes), varTypes.length, body);
10201020
});
10211021
};
1022+
this['getFunction'] = function(name) {
1023+
return preserveStack(function() {
1024+
return Module['_BinaryenGetFunction'](module, strToStack(name));
1025+
});
1026+
};
1027+
this['removeFunction'] = function(name) {
1028+
return preserveStack(function() {
1029+
return Module['_BinaryenRemoveFunction'](module, strToStack(name));
1030+
});
1031+
};
10221032
this['addGlobal'] = function(name, type, mutable, init) {
10231033
return preserveStack(function() {
10241034
return Module['_BinaryenAddGlobal'](module, strToStack(name), type, mutable, init);
@@ -1098,13 +1108,25 @@
10981108
this['optimize'] = function() {
10991109
return Module['_BinaryenModuleOptimize'](module);
11001110
};
1111+
this['optimizeFunction'] = function(func) {
1112+
if (typeof func === "string") func = this['getFunction'](func);
1113+
return Module['_BinaryenFunctionOptimize'](func, module);
1114+
};
11011115
this['runPasses'] = function(passes) {
11021116
return preserveStack(function() {
11031117
return Module['_BinaryenModuleRunPasses'](module, i32sToStack(
11041118
passes.map(strToStack)
11051119
), passes.length);
11061120
});
1107-
}
1121+
};
1122+
this['runPassesOnFunction'] = function(func, passes) {
1123+
if (typeof func === "string") func = this['getFunction'](func);
1124+
return preserveStack(function() {
1125+
return Module['_BinaryenFunctionRunPasses'](func, module, i32sToStack(
1126+
passes.map(strToStack)
1127+
), passes.length);
1128+
});
1129+
};
11081130
this['autoDrop'] = function() {
11091131
return Module['_BinaryenModuleAutoDrop'](module);
11101132
};
@@ -1172,6 +1194,10 @@
11721194
return Module['_BinaryenConstGetValueF64'](expr);
11731195
};
11741196

1197+
Module['getFunctionBody'] = function(func) {
1198+
return Module['_BinaryenFunctionGetBody'](func);
1199+
};
1200+
11751201
// emit text of an expression or a module
11761202
Module['emitText'] = function(expr) {
11771203
if (typeof expr === 'object') {

test/binaryen.js/functions.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
var module = new Binaryen.Module();
2+
3+
var signature = module.addFunctionType("i", Binaryen.i32, []);
4+
5+
var func = module.addFunction("a-function", signature, [],
6+
module.i32.add(
7+
module.i32.const(1),
8+
module.i32.const(2)
9+
)
10+
);
11+
12+
console.log("GetFunction is equal: " + (func === module.getFunction("a-function")));
13+
14+
module.runPassesOnFunction(func, ["precompute"]);
15+
16+
var body = Binaryen.getFunctionBody(func);
17+
18+
console.log("ExpressionId=" + Binaryen.getExpressionId(body));
19+
console.log("ExpressionType=" + Binaryen.getExpressionType(body));
20+
console.log(Binaryen.emitText(body));
21+
22+
module.removeFunction("a-function");
23+
24+
module.addGlobal("a-global", Binaryen.i32, false, body);
25+
26+
module.validate();
27+
28+
console.log(module.emitText());

test/binaryen.js/functions.js.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
GetFunction is equal: true
2+
ExpressionId=15
3+
ExpressionType=1
4+
(i32.const 3)
5+
6+
(module
7+
(type $i (func (result i32)))
8+
(global $a-global i32 (i32.const 3))
9+
(memory $0 0)
10+
)
11+

0 commit comments

Comments
 (0)