diff options
-rw-r--r-- | src/passes/Inlining.cpp | 16 | ||||
-rw-r--r-- | test/lit/passes/inlining_splitting_basics.wast | 207 |
2 files changed, 217 insertions, 6 deletions
diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp index 229842e12..3326b7370 100644 --- a/src/passes/Inlining.cpp +++ b/src/passes/Inlining.cpp @@ -57,7 +57,7 @@ enum class InliningMode { // This function cannot be inlinined in any way. Uninlineable, // This function can be inlined fully, that is, normally: the entire function - // can be inlined. This is in contrast to partial inlining, see below. + // can be inlined. This is in contrast to split/partial inlining, see below. Full, // This function cannot be inlined normally, but we can use split inlining, // using pattern "A" or "B" (see below). @@ -611,6 +611,9 @@ struct FunctionSplitter { // split on very specific patterns we believe are worth handling in that // manner). InliningMode getSplitDrivenInliningMode(Function* func, FunctionInfo& info) { + const Index MaxIfs = options.inlining.partialInliningIfs; + assert(MaxIfs > 0); + auto* body = func->body; // If the body is a block, and we have breaks to that block, then we cannot @@ -692,7 +695,6 @@ struct FunctionSplitter { // without an else. // Find the number of ifs. - const Index MaxIfs = options.inlining.partialInliningIfs; Index numIfs = 0; while (getIf(body, numIfs) && numIfs <= MaxIfs) { numIfs++; @@ -847,6 +849,7 @@ private: Function* inlineable = copyFunction(func, "inlineable-B"); const Index MaxIfs = options.inlining.partialInliningIfs; + assert(MaxIfs > 0); // The inlineable function should only have the ifs, which will call the // outlined heavy work. @@ -1066,10 +1069,11 @@ struct Inlining : public Pass { } // When optimizing heavily for size, we may potentially split functions in - // order to inline parts of them. - if (getPassOptions().optimizeLevel >= 3 && !getPassOptions().shrinkLevel) { - functionSplitter = - std::make_unique<FunctionSplitter>(module, getPassOptions()); + // order to inline parts of them, if partialInliningIfs is enabled. + auto& options = getPassOptions(); + if (options.optimizeLevel >= 3 && !options.shrinkLevel && + options.inlining.partialInliningIfs) { + functionSplitter = std::make_unique<FunctionSplitter>(module, options); } } diff --git a/test/lit/passes/inlining_splitting_basics.wast b/test/lit/passes/inlining_splitting_basics.wast new file mode 100644 index 000000000..443686101 --- /dev/null +++ b/test/lit/passes/inlining_splitting_basics.wast @@ -0,0 +1,207 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; Test code that can be partially inlined, with and without that option. +;; +;; This is similar to inlining_splitting.wast but focuses on testing that we +;; only partially inline when the commandline flag is provided. In both of the +;; $call-* functions below, we should partially inline when that flag is set. + +;; RUN: foreach %s %t wasm-opt --inlining --optimize-level=3 --all-features -S -o - | filecheck %s --check-prefix NORMAL_ +;; RUN: foreach %s %t wasm-opt --inlining --optimize-level=3 --partial-inlining-ifs=1 --all-features -S -o - | filecheck %s --check-prefix PARTIAL + +(module + ;; NORMAL_: (type $none_=>_none (func)) + + ;; NORMAL_: (type $i32_=>_none (func (param i32))) + + ;; NORMAL_: (type $i32_=>_i32 (func (param i32) (result i32))) + + ;; NORMAL_: (import "a" "b" (func $import)) + ;; PARTIAL: (type $none_=>_none (func)) + + ;; PARTIAL: (type $i32_=>_none (func (param i32))) + + ;; PARTIAL: (type $i32_=>_i32 (func (param i32) (result i32))) + + ;; PARTIAL: (import "a" "b" (func $import)) + (import "a" "b" (func $import)) + + ;; Pattern A: functions beginning with + ;; + ;; if (simple) return; + + ;; NORMAL_: (func $pattern-A (type $i32_=>_none) (param $x i32) + ;; NORMAL_-NEXT: (if + ;; NORMAL_-NEXT: (local.get $x) + ;; NORMAL_-NEXT: (return) + ;; NORMAL_-NEXT: ) + ;; NORMAL_-NEXT: (loop $l + ;; NORMAL_-NEXT: (call $import) + ;; NORMAL_-NEXT: (br $l) + ;; NORMAL_-NEXT: ) + ;; NORMAL_-NEXT: ) + (func $pattern-A (param $x i32) + (if + (local.get $x) + (return) + ) + (loop $l + (call $import) + (br $l) + ) + ) + + ;; NORMAL_: (func $call-pattern-A (type $none_=>_none) + ;; NORMAL_-NEXT: (call $pattern-A + ;; NORMAL_-NEXT: (i32.const 1) + ;; NORMAL_-NEXT: ) + ;; NORMAL_-NEXT: (call $pattern-A + ;; NORMAL_-NEXT: (i32.const 2) + ;; NORMAL_-NEXT: ) + ;; NORMAL_-NEXT: ) + ;; PARTIAL: (func $call-pattern-A (type $none_=>_none) + ;; PARTIAL-NEXT: (local $0 i32) + ;; PARTIAL-NEXT: (local $1 i32) + ;; PARTIAL-NEXT: (block + ;; PARTIAL-NEXT: (block $__inlined_func$byn-split-inlineable-A$pattern-A + ;; PARTIAL-NEXT: (local.set $0 + ;; PARTIAL-NEXT: (i32.const 1) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: (if + ;; PARTIAL-NEXT: (i32.eqz + ;; PARTIAL-NEXT: (local.get $0) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: (call $byn-split-outlined-A$pattern-A + ;; PARTIAL-NEXT: (local.get $0) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: (block + ;; PARTIAL-NEXT: (block $__inlined_func$byn-split-inlineable-A$pattern-A$1 + ;; PARTIAL-NEXT: (local.set $1 + ;; PARTIAL-NEXT: (i32.const 2) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: (if + ;; PARTIAL-NEXT: (i32.eqz + ;; PARTIAL-NEXT: (local.get $1) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: (call $byn-split-outlined-A$pattern-A + ;; PARTIAL-NEXT: (local.get $1) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + (func $call-pattern-A + (call $pattern-A (i32.const 1)) + (call $pattern-A (i32.const 2)) + ) + + ;; Pattern B: functions containing + ;; + ;; if (simple1) heavy-work-that-is-unreachable; + ;; if (simple..) heavy-work-that-is-unreachable; + ;; simplek + + ;; NORMAL_: (func $pattern-B (type $i32_=>_i32) (param $x i32) (result i32) + ;; NORMAL_-NEXT: (if + ;; NORMAL_-NEXT: (i32.eqz + ;; NORMAL_-NEXT: (local.get $x) + ;; NORMAL_-NEXT: ) + ;; NORMAL_-NEXT: (block + ;; NORMAL_-NEXT: (call $import) + ;; NORMAL_-NEXT: (unreachable) + ;; NORMAL_-NEXT: ) + ;; NORMAL_-NEXT: ) + ;; NORMAL_-NEXT: (local.get $x) + ;; NORMAL_-NEXT: ) + (func $pattern-B (param $x i32) (result i32) + (if + (i32.eqz + (local.get $x) + ) + (block + (call $import) + (unreachable) + ) + ) + (local.get $x) + ) + + ;; NORMAL_: (func $call-pattern-B (type $none_=>_none) + ;; NORMAL_-NEXT: (drop + ;; NORMAL_-NEXT: (call $pattern-B + ;; NORMAL_-NEXT: (i32.const 1) + ;; NORMAL_-NEXT: ) + ;; NORMAL_-NEXT: ) + ;; NORMAL_-NEXT: (drop + ;; NORMAL_-NEXT: (call $pattern-B + ;; NORMAL_-NEXT: (i32.const 2) + ;; NORMAL_-NEXT: ) + ;; NORMAL_-NEXT: ) + ;; NORMAL_-NEXT: ) + ;; PARTIAL: (func $call-pattern-B (type $none_=>_none) + ;; PARTIAL-NEXT: (local $0 i32) + ;; PARTIAL-NEXT: (local $1 i32) + ;; PARTIAL-NEXT: (drop + ;; PARTIAL-NEXT: (block (result i32) + ;; PARTIAL-NEXT: (block $__inlined_func$byn-split-inlineable-B$pattern-B$2 (result i32) + ;; PARTIAL-NEXT: (local.set $0 + ;; PARTIAL-NEXT: (i32.const 1) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: (block (result i32) + ;; PARTIAL-NEXT: (if + ;; PARTIAL-NEXT: (i32.eqz + ;; PARTIAL-NEXT: (local.get $0) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: (br $__inlined_func$byn-split-inlineable-B$pattern-B$2 + ;; PARTIAL-NEXT: (call $byn-split-outlined-B$pattern-B + ;; PARTIAL-NEXT: (local.get $0) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: (local.get $0) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: (drop + ;; PARTIAL-NEXT: (block (result i32) + ;; PARTIAL-NEXT: (block $__inlined_func$byn-split-inlineable-B$pattern-B$3 (result i32) + ;; PARTIAL-NEXT: (local.set $1 + ;; PARTIAL-NEXT: (i32.const 2) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: (block (result i32) + ;; PARTIAL-NEXT: (if + ;; PARTIAL-NEXT: (i32.eqz + ;; PARTIAL-NEXT: (local.get $1) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: (br $__inlined_func$byn-split-inlineable-B$pattern-B$3 + ;; PARTIAL-NEXT: (call $byn-split-outlined-B$pattern-B + ;; PARTIAL-NEXT: (local.get $1) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: (local.get $1) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + ;; PARTIAL-NEXT: ) + (func $call-pattern-B + (drop (call $pattern-B (i32.const 1))) + (drop (call $pattern-B (i32.const 2))) + ) +) +;; PARTIAL: (func $byn-split-outlined-A$pattern-A (type $i32_=>_none) (param $x i32) +;; PARTIAL-NEXT: (loop $l +;; PARTIAL-NEXT: (call $import) +;; PARTIAL-NEXT: (br $l) +;; PARTIAL-NEXT: ) +;; PARTIAL-NEXT: ) + +;; PARTIAL: (func $byn-split-outlined-B$pattern-B (type $i32_=>_i32) (param $x i32) (result i32) +;; PARTIAL-NEXT: (call $import) +;; PARTIAL-NEXT: (unreachable) +;; PARTIAL-NEXT: ) |