summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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: )