Skip to content

Commit 7b2e019

Browse files
authored
[StackIR] Run StackIR during binary writing and not as a pass (#6568)
Previously we had passes --generate-stack-ir, --optimize-stack-ir, --print-stack-ir that could be run like any other passes. After generating StackIR it was stashed on the function and invalidated if we modified BinaryenIR. If it wasn't invalidated then it was used during binary writing. This PR switches things so that we optionally generate, optimize, and print StackIR only during binary writing. It also removes all traces of StackIR from wasm.h - after this, StackIR is a feature of binary writing (and printing) logic only. This is almost NFC, but there are some minor noticeable differences: 1. We no longer print has StackIR in the text format when we see it is there. It will not be there during normal printing, as it is only present during binary writing. (but --print-stack-ir still works as before; as mentioned above it runs during writing). 2. --generate/optimize/print-stack-ir change from being passes to being flags that control that behavior instead. As passes, their order on the commandline mattered, while now it does not, and they only "globally" affect things during writing. 3. The C API changes slightly, as there is no need to pass it an option "optimize" to the StackIR APIs. Whether we optimize is handled by --optimize-stack-ir which is set like other optimization flags on the PassOptions object, so we don't need the old option to those C APIs. The main benefit here is simplifying the code, so we don't need to think about StackIR in more places than just binary writing. That may also allow future improvements to our usage of StackIR.
1 parent 006181b commit 7b2e019

File tree

78 files changed

+1007
-1017
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+1007
-1017
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@ full changeset diff at the end of each section.
1515
Current Trunk
1616
-------------
1717

18+
- StackIR is now handled entirely during binary writing. This is mostly not
19+
noticeable, except that:
20+
- Text output no longer notes `(; has Stack IR ;)` (as Stack IR only exists
21+
during binary writing).
22+
- `--generate-stack-ir`, `--optimize-stack-ir`, and `--print-stack-ir` are
23+
now flags and not passes. That means the order of operations may seem
24+
different, as they apply during binary writing (or, if no binary is written
25+
but we were still asked to print StackIR, `wasm-opt` does it at the very
26+
end).
27+
- Whether to generate, optimize, and print StackIR is now noted as part of
28+
the PassOptions. As a result `BinaryenModulePrintStackIR` and similar APIs
29+
do not receive an `optimize` flag, as they read the PassOption
30+
`optimizeStackIR` instead.
1831
- The new, standards-compliant text parser is now the default. `wasm-opt` has a
1932
`--deprecated-wat-parser` flag that will switch back to using the old text
2033
parser, but that option will go away soon.

src/binaryen-c.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5590,8 +5590,8 @@ void BinaryenModulePrint(BinaryenModuleRef module) {
55905590
std::cout << *(Module*)module;
55915591
}
55925592

5593-
void BinaryenModulePrintStackIR(BinaryenModuleRef module, bool optimize) {
5594-
wasm::printStackIR(std::cout, (Module*)module, optimize);
5593+
void BinaryenModulePrintStackIR(BinaryenModuleRef module) {
5594+
wasm::printStackIR(std::cout, (Module*)module, globalPassOptions);
55955595
}
55965596

55975597
void BinaryenModulePrintAsmjs(BinaryenModuleRef module) {
@@ -5737,7 +5737,7 @@ static BinaryenBufferSizes writeModule(BinaryenModuleRef module,
57375737
char* sourceMap,
57385738
size_t sourceMapSize) {
57395739
BufferWithRandomAccess buffer;
5740-
WasmBinaryWriter writer((Module*)module, buffer);
5740+
WasmBinaryWriter writer((Module*)module, buffer, globalPassOptions);
57415741
writer.setNamesSection(globalPassOptions.debugInfo);
57425742
std::ostringstream os;
57435743
if (sourceMapUrl) {
@@ -5778,12 +5778,11 @@ size_t BinaryenModuleWriteText(BinaryenModuleRef module,
57785778

57795779
size_t BinaryenModuleWriteStackIR(BinaryenModuleRef module,
57805780
char* output,
5781-
size_t outputSize,
5782-
bool optimize) {
5781+
size_t outputSize) {
57835782
// use a stringstream as an std::ostream. Extract the std::string
57845783
// representation, and then store in the output.
57855784
std::stringstream ss;
5786-
wasm::printStackIR(ss, (Module*)module, optimize);
5785+
wasm::printStackIR(ss, (Module*)module, globalPassOptions);
57875786

57885787
const auto temp = ss.str();
57895788
const auto ctemp = temp.c_str();
@@ -5808,7 +5807,7 @@ BinaryenModuleAllocateAndWriteResult
58085807
BinaryenModuleAllocateAndWrite(BinaryenModuleRef module,
58095808
const char* sourceMapUrl) {
58105809
BufferWithRandomAccess buffer;
5811-
WasmBinaryWriter writer((Module*)module, buffer);
5810+
WasmBinaryWriter writer((Module*)module, buffer, globalPassOptions);
58125811
writer.setNamesSection(globalPassOptions.debugInfo);
58135812
std::ostringstream os;
58145813
if (sourceMapUrl) {
@@ -5842,13 +5841,12 @@ char* BinaryenModuleAllocateAndWriteText(BinaryenModuleRef module) {
58425841
return output;
58435842
}
58445843

5845-
char* BinaryenModuleAllocateAndWriteStackIR(BinaryenModuleRef module,
5846-
bool optimize) {
5844+
char* BinaryenModuleAllocateAndWriteStackIR(BinaryenModuleRef module) {
58475845
std::ostringstream os;
58485846
bool colors = Colors::isEnabled();
58495847

58505848
Colors::setEnabled(false); // do not use colors for writing
5851-
wasm::printStackIR(os, (Module*)module, optimize);
5849+
wasm::printStackIR(os, (Module*)module, globalPassOptions);
58525850
Colors::setEnabled(colors); // restore colors state
58535851

58545852
auto str = os.str();

src/binaryen-c.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2984,8 +2984,7 @@ BINARYEN_API BinaryenModuleRef BinaryenModuleParse(const char* text);
29842984
BINARYEN_API void BinaryenModulePrint(BinaryenModuleRef module);
29852985

29862986
// Print a module to stdout in stack IR text format. Useful for debugging.
2987-
BINARYEN_API void BinaryenModulePrintStackIR(BinaryenModuleRef module,
2988-
bool optimize);
2987+
BINARYEN_API void BinaryenModulePrintStackIR(BinaryenModuleRef module);
29892988

29902989
// Print a module to stdout in asm.js syntax.
29912990
BINARYEN_API void BinaryenModulePrintAsmjs(BinaryenModuleRef module);
@@ -3126,8 +3125,7 @@ BINARYEN_API size_t BinaryenModuleWriteText(BinaryenModuleRef module,
31263125
// outputSize
31273126
BINARYEN_API size_t BinaryenModuleWriteStackIR(BinaryenModuleRef module,
31283127
char* output,
3129-
size_t outputSize,
3130-
bool optimize);
3128+
size_t outputSize);
31313129

31323130
typedef struct BinaryenBufferSizes {
31333131
size_t outputBytes;
@@ -3173,7 +3171,7 @@ BINARYEN_API char* BinaryenModuleAllocateAndWriteText(BinaryenModuleRef module);
31733171
// char* with malloc(), and expects the user to free() them manually
31743172
// once not needed anymore.
31753173
BINARYEN_API char*
3176-
BinaryenModuleAllocateAndWriteStackIR(BinaryenModuleRef module, bool optimize);
3174+
BinaryenModuleAllocateAndWriteStackIR(BinaryenModuleRef module);
31773175

31783176
// Deserialize a module from binary form, assuming the MVP feature set.
31793177
BINARYEN_API BinaryenModuleRef BinaryenModuleRead(char* input,

src/ir/module-utils.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,6 @@ Function* copyFunction(Function* func,
6969
ret->base = func->base;
7070
ret->noFullInline = func->noFullInline;
7171
ret->noPartialInline = func->noPartialInline;
72-
73-
// TODO: copy Stack IR
74-
assert(!func->stackIR);
7572
return out.addFunction(std::move(ret));
7673
}
7774

src/js/binaryen.js-post.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2688,8 +2688,8 @@ function wrapModule(module, self = {}) {
26882688
if (textPtr) _free(textPtr);
26892689
return text;
26902690
};
2691-
self['emitStackIR'] = function(optimize) {
2692-
let textPtr = Module['_BinaryenModuleAllocateAndWriteStackIR'](module, optimize);
2691+
self['emitStackIR'] = function() {
2692+
let textPtr = Module['_BinaryenModuleAllocateAndWriteStackIR'](module);
26932693
let text = UTF8ToString(textPtr);
26942694
if (textPtr) _free(textPtr);
26952695
return text;

src/pass.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,16 @@ struct PassOptions {
219219
bool closedWorld = false;
220220
// Whether to try to preserve debug info through, which are special calls.
221221
bool debugInfo = false;
222+
// Whether to generate StackIR during binary writing. This is on by default
223+
// in -O2 and above.
224+
bool generateStackIR = false;
225+
// Whether to optimize StackIR during binary writing. How we optimize depends
226+
// on other optimization flags like optimizeLevel. This is on by default in
227+
// -O2 and above.
228+
bool optimizeStackIR = false;
229+
// Whether to print StackIR during binary writing, and if so to what stream.
230+
// This is mainly useful for debugging.
231+
std::optional<std::ostream*> printStackIR;
222232
// Whether we are targeting JS. In that case we want to avoid emitting things
223233
// in the optimizer that do not translate well to JS, or that could cause us
224234
// to need extra lowering work or even a loop (where we optimize to something

src/passes/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ set(passes_SOURCES
8787
PrintFunctionMap.cpp
8888
RoundTrip.cpp
8989
SetGlobals.cpp
90-
StackIR.cpp
9190
SignaturePruning.cpp
9291
SignatureRefining.cpp
9392
SignExtLowering.cpp

src/passes/Metrics.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ struct Metrics
9494
printCounts("global");
9595
// compute binary info, so we know function sizes
9696
BufferWithRandomAccess buffer;
97-
WasmBinaryWriter writer(module, buffer);
97+
WasmBinaryWriter writer(module, buffer, getPassOptions());
9898
writer.write();
9999
// print for each function
100100
Index binaryIndex = 0;
@@ -108,14 +108,14 @@ struct Metrics
108108
});
109109
// print for each export how much code size is due to it, i.e.,
110110
// how much the module could shrink without it.
111-
auto sizeAfterGlobalCleanup = [](Module* module) {
111+
auto sizeAfterGlobalCleanup = [&](Module* module) {
112112
PassRunner runner(module,
113113
PassOptions::getWithDefaultOptimizationOptions());
114114
runner.setIsNested(true);
115115
runner.addDefaultGlobalOptimizationPostPasses(); // remove stuff
116116
runner.run();
117117
BufferWithRandomAccess buffer;
118-
WasmBinaryWriter writer(module, buffer);
118+
WasmBinaryWriter writer(module, buffer, getPassOptions());
119119
writer.write();
120120
return buffer.size();
121121
};

src/passes/Monomorphize.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,6 @@ struct Monomorphize : public Pass {
151151
// monomorphizing.
152152

153153
// Create a new function with refined parameters as a copy of the original.
154-
// (Note we must clear stack IR on the original: atm we do not have the
155-
// ability to copy stack IR, so we'd hit an internal error. But as we will
156-
// be optimizing the function anyhow, we'd be throwing away stack IR later
157-
// so this isn't a problem.)
158-
func->stackIR.reset();
159154
auto refinedTarget = Names::getValidFunctionName(*module, target);
160155
auto* refinedFunc = ModuleUtils::copyFunction(func, *module, refinedTarget);
161156
TypeUpdating::updateParamTypes(refinedFunc, refinedTypes, *module);

src/passes/Print.cpp

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,11 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> {
109109
const char* maybeSpace;
110110
const char* maybeNewLine;
111111

112-
bool full = false; // whether to not elide nodes in output when possible
113-
// (like implicit blocks) and to emit types
114-
bool stackIR = false; // whether to print stack IR if it is present
115-
// (if false, and Stack IR is there, we just
116-
// note it exists)
112+
// Whether to not elide nodes in output when possible (like implicit blocks)
113+
// and to emit types.
114+
bool full = false;
115+
// If present, it contains StackIR that we will print.
116+
std::optional<ModuleStackIR> moduleStackIR;
117117

118118
Module* currModule = nullptr;
119119
Function* currFunction = nullptr;
@@ -268,7 +268,9 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> {
268268

269269
void setFull(bool full_) { full = full_; }
270270

271-
void setStackIR(bool stackIR_) { stackIR = stackIR_; }
271+
void generateStackIR(const PassOptions& options) {
272+
moduleStackIR.emplace(*currModule, options);
273+
}
272274

273275
void setDebugInfo(bool debugInfo_) { debugInfo = debugInfo_; }
274276

@@ -2978,9 +2980,6 @@ void PrintSExpression::visitDefinedFunction(Function* curr) {
29782980
o << " (type ";
29792981
printHeapType(curr->type) << ')';
29802982
}
2981-
if (!stackIR && curr->stackIR && !minify) {
2982-
o << " (; has Stack IR ;)";
2983-
}
29842983
if (curr->getParams().size() > 0) {
29852984
Index i = 0;
29862985
for (const auto& param : curr->getParams()) {
@@ -3007,7 +3006,13 @@ void PrintSExpression::visitDefinedFunction(Function* curr) {
30073006
o << maybeNewLine;
30083007
}
30093008
// Print the body.
3010-
if (!stackIR || !curr->stackIR) {
3009+
StackIR* stackIR = nullptr;
3010+
if (moduleStackIR) {
3011+
stackIR = moduleStackIR->getStackIROrNull(curr);
3012+
}
3013+
if (stackIR) {
3014+
printStackIR(stackIR, *this);
3015+
} else {
30113016
// It is ok to emit a block here, as a function can directly contain a
30123017
// list, even if our ast avoids that for simplicity. We can just do that
30133018
// optimization here..
@@ -3021,9 +3026,6 @@ void PrintSExpression::visitDefinedFunction(Function* curr) {
30213026
printFullLine(curr->body);
30223027
}
30233028
assert(controlFlowDepth == 0);
3024-
} else {
3025-
// Print the stack IR.
3026-
printStackIR(curr->stackIR.get(), *this);
30273029
}
30283030
if (currFunction->epilogLocation.size()) {
30293031
// Print last debug location: mix of decIndent and printDebugLocation
@@ -3430,14 +3432,12 @@ class PrintStackIR : public Printer {
34303432
void run(Module* module) override {
34313433
PrintSExpression print(o);
34323434
print.setDebugInfo(getPassOptions().debugInfo);
3433-
print.setStackIR(true);
34343435
print.currModule = module;
3436+
print.generateStackIR(getPassOptions());
34353437
print.visitModule(module);
34363438
}
34373439
};
34383440

3439-
Pass* createPrintStackIRPass() { return new PrintStackIR(); }
3440-
34413441
static std::ostream& printExpression(Expression* expression,
34423442
std::ostream& o,
34433443
bool minify,
@@ -3602,12 +3602,9 @@ static std::ostream& printStackIR(StackIR* ir, PrintSExpression& printer) {
36023602
return o;
36033603
}
36043604

3605-
std::ostream& printStackIR(std::ostream& o, Module* module, bool optimize) {
3606-
wasm::PassRunner runner(module);
3607-
runner.add("generate-stack-ir");
3608-
if (optimize) {
3609-
runner.add("optimize-stack-ir");
3610-
}
3605+
std::ostream&
3606+
printStackIR(std::ostream& o, Module* module, const PassOptions& options) {
3607+
wasm::PassRunner runner(module, options);
36113608
runner.add(std::make_unique<PrintStackIR>(&o));
36123609
runner.run();
36133610
return o;
@@ -3659,9 +3656,4 @@ std::ostream& operator<<(std::ostream& o, wasm::StackInst& inst) {
36593656
return wasm::printStackInst(&inst, o);
36603657
}
36613658

3662-
std::ostream& operator<<(std::ostream& o, wasm::StackIR& ir) {
3663-
wasm::PrintSExpression printer(o);
3664-
return wasm::printStackIR(&ir, printer);
3665-
}
3666-
36673659
} // namespace std

0 commit comments

Comments
 (0)