summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-05-10 13:33:50 -0700
committerGitHub <noreply@github.com>2023-05-10 13:33:50 -0700
commitb1dba91a6bf881b5bfa68da7bb56bbb3bbf90a0a (patch)
treef3dc4097e70742aa09c2965b99529f95f3a08876
parentc5c223943770412b2ebd7d9f23fce8c11cf5982e (diff)
downloadbinaryen-b1dba91a6bf881b5bfa68da7bb56bbb3bbf90a0a.tar.gz
binaryen-b1dba91a6bf881b5bfa68da7bb56bbb3bbf90a0a.tar.bz2
binaryen-b1dba91a6bf881b5bfa68da7bb56bbb3bbf90a0a.zip
Gate all partial inlining behind the partial-inlining-ifs flag (#5710)
#4191 meant to do that, I think, but only did so for "pattern B". This does it for all patterns, and adds assertions. In theory this could regress code that benefits from partial inlining of "pattern A" (since this PR stops doing it by default), but I did not see a significant difference on any benchmarks, and it is easy to re-enable that behavior by doing --partial-inlining-ifs=1.
-rw-r--r--src/passes/Inlining.cpp16
-rw-r--r--test/lit/passes/inlining_splitting_basics.wast207
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: )