Skip to content

Commit 551d875

Browse files
authored
[SIMD] Fix relaxed SIMD in wasm-ctor-eval (#7495)
Relaxed SIMD is a new class of "nonconstant" (too variable to execute at compile time) code. Throw a non-constant exception in the right place in the interpreter. This requires moving the NonconstantException class to a higher place.
1 parent e6f1c53 commit 551d875

5 files changed

Lines changed: 68 additions & 5 deletions

File tree

src/binaryen-c.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6144,7 +6144,7 @@ ExpressionRunnerRunAndDispose(ExpressionRunnerRef runner,
61446144
if (!flow.breaking() && !flow.values.empty()) {
61456145
ret = flow.getConstExpression(*R->getModule());
61466146
}
6147-
} catch (CExpressionRunner::NonconstantException&) {
6147+
} catch (NonconstantException&) {
61486148
}
61496149
delete R;
61506150
return ret;

src/passes/Precompute.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ struct Precompute
728728
flow = PrecomputingExpressionRunner(
729729
getModule(), getValues, heapValues, replaceExpression)
730730
.visit(curr);
731-
} catch (PrecomputingExpressionRunner::NonconstantException&) {
731+
} catch (NonconstantException&) {
732732
return Flow(NONCONSTANT_FLOW);
733733
}
734734
// If we are replacing the expression, then the resulting value must be of

src/tools/wasm-ctor-eval.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,11 @@ EvalCtorOutcome evalCtor(EvallingModuleRunner& instance,
11131113
}
11141114
}
11151115
break;
1116+
} catch (NonconstantException& fail) {
1117+
if (!quiet) {
1118+
std::cout << " ...stopping due to non-constant code\n";
1119+
}
1120+
break;
11161121
}
11171122

11181123
if (flow.breakTo == RETURN_CALL_FLOW) {

src/wasm-interpreter.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ struct WasmException {
5151
};
5252
std::ostream& operator<<(std::ostream& o, const WasmException& exn);
5353

54+
// An exception thrown when we try to execute non-constant code, that is, code
55+
// that we cannot properly evaluate at compile time (e.g. if it refers to an
56+
// import, or we are optimizing and it uses relaxed SIMD).
57+
// TODO: use a flow with a special name, as this is likely very slow
58+
struct NonconstantException {};
59+
5460
// Utilities
5561

5662
extern Name WASM, RETURN_FLOW, RETURN_CALL_FLOW, NONCONSTANT_FLOW;
@@ -2457,9 +2463,6 @@ class ConstantExpressionRunner : public ExpressionRunner<SubType> {
24572463
std::unordered_map<Name, Literals> globalValues;
24582464

24592465
public:
2460-
struct NonconstantException {
2461-
}; // TODO: use a flow with a special name, as this is likely very slow
2462-
24632466
ConstantExpressionRunner(Module* module,
24642467
Flags flags,
24652468
Index maxDepth,
@@ -4540,6 +4543,10 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
45404543
arguments = flow.values;
45414544
}
45424545

4546+
if (flow.breaking() && flow.breakTo == NONCONSTANT_FLOW) {
4547+
throw NonconstantException();
4548+
}
4549+
45434550
// cannot still be breaking, it means we missed our stop
45444551
assert(!flow.breaking() || flow.breakTo == RETURN_FLOW);
45454552
auto type = flow.getType();

test/lit/ctor-eval/relaxed.wast

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
2+
;; RUN: wasm-ctor-eval %s --ctors=return,drop,passthrough --quiet -all -S -o - | filecheck %s
3+
4+
;; The relaxed SIMD operation here cannot be optimized by wasm-ctor-eval, as we
5+
;; do not know how the VM that the code will run on should execute it. We can
6+
;; optimize nothing here, and should not error.
7+
8+
(module
9+
;; CHECK: (type $0 (func (result v128)))
10+
11+
;; CHECK: (type $1 (func))
12+
13+
;; CHECK: (export "drop" (func $drop))
14+
15+
;; CHECK: (export "passthrough" (func $passthrough))
16+
17+
;; CHECK: (func $return (type $0) (result v128)
18+
;; CHECK-NEXT: (f32x4.relaxed_max
19+
;; CHECK-NEXT: (v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
20+
;; CHECK-NEXT: (v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
21+
;; CHECK-NEXT: )
22+
;; CHECK-NEXT: )
23+
(func $return (export "return") (result v128)
24+
;; This function returns a nonconstant value directly.
25+
(f32x4.relaxed_max
26+
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
27+
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
28+
)
29+
)
30+
31+
;; CHECK: (func $drop (type $1)
32+
;; CHECK-NEXT: (drop
33+
;; CHECK-NEXT: (call $return)
34+
;; CHECK-NEXT: )
35+
;; CHECK-NEXT: )
36+
(func $drop (export "drop")
37+
;; This function swallows a nonconstant value.
38+
(drop
39+
(call $return)
40+
)
41+
)
42+
43+
;; CHECK: (func $passthrough (type $0) (result v128)
44+
;; CHECK-NEXT: (call $return)
45+
;; CHECK-NEXT: )
46+
(func $passthrough (export "passthrough") (result v128)
47+
;; This function passes through a nonconstant value.
48+
(call $return)
49+
)
50+
)
51+

0 commit comments

Comments
 (0)