summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/SignatureRefining.cpp26
-rw-r--r--test/lit/passes/signature-refining.wast57
2 files changed, 83 insertions, 0 deletions
diff --git a/src/passes/SignatureRefining.cpp b/src/passes/SignatureRefining.cpp
index 24d120dda..ae124dc79 100644
--- a/src/passes/SignatureRefining.cpp
+++ b/src/passes/SignatureRefining.cpp
@@ -73,6 +73,15 @@ struct SignatureRefining : public Pass {
std::vector<Call*> calls;
std::vector<CallRef*> callRefs;
+ // Additional calls to take into account. We store intrinsic calls here,
+ // as they must appear twice: call.without.effects is both a normal call
+ // and also takes a final parameter that is a function reference that is
+ // called, and so two signatures are relevant for it. For the latter, we
+ // add the call as an "extra call" (which is an unusual call, as it has an
+ // extra parameter at the end, the function reference, compared to what we
+ // expect for the signature being called).
+ std::vector<Call*> extraCalls;
+
// A possibly improved LUB for the results.
LUBFinder resultsLUB;
@@ -107,6 +116,17 @@ struct SignatureRefining : public Pass {
// called.
for (auto* call : info.calls) {
allInfo[module->getFunction(call->target)->type].calls.push_back(call);
+
+ // For call.without.effects, we also add the effective function being
+ // called as well. The final operand is the function reference being
+ // called, which defines that type.
+ if (Intrinsics(*module).isCallWithoutEffects(call)) {
+ auto targetType = call->operands.back()->type;
+ if (!targetType.isRef()) {
+ continue;
+ }
+ allInfo[targetType.getHeapType()].extraCalls.push_back(call);
+ }
}
// For indirect calls, add each call_ref to the type the call_ref uses.
@@ -187,6 +207,12 @@ struct SignatureRefining : public Pass {
for (auto* callRef : info.callRefs) {
updateLUBs(callRef->operands);
}
+ for (auto* call : info.extraCalls) {
+ // Note that these intrinsic calls have an extra function reference
+ // param at the end, but updateLUBs looks at |numParams| only, so it
+ // considers just the relevant parameters.
+ updateLUBs(call->operands);
+ }
// Find the final LUBs, and see if we found an improvement.
std::vector<Type> newParamsTypes;
diff --git a/test/lit/passes/signature-refining.wast b/test/lit/passes/signature-refining.wast
index c2a505e51..95007b1c4 100644
--- a/test/lit/passes/signature-refining.wast
+++ b/test/lit/passes/signature-refining.wast
@@ -985,3 +985,60 @@
(struct.new $C) ;; this will allow this function's result to be refined to $C
)
)
+
+;; Test we consider call.without.effects when deciding what to refine. $A has
+;; two subtypes, B1 and B2, and a call.without.effects sends in one while a
+;; normal call sends in the other. As a result, we cannot refine to either.
+(module
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $A (sub (struct )))
+ (type $A (sub (struct)))
+
+ ;; CHECK: (type $B1 (sub $A (struct )))
+ (type $B1 (sub $A (struct)))
+
+ ;; CHECK: (type $B2 (sub $A (struct )))
+ (type $B2 (sub $A (struct)))
+ )
+
+ ;; CHECK: (type $3 (func (param (ref $A) funcref)))
+
+ ;; CHECK: (type $4 (func))
+
+ ;; CHECK: (type $5 (func (param (ref $A))))
+
+ ;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $no.side.effects (type $3) (param (ref $A) funcref)))
+ (import "binaryen-intrinsics" "call.without.effects" (func $no.side.effects
+ (param (ref $A))
+ (param funcref)
+ ))
+
+ ;; CHECK: (elem declare func $target)
+
+ ;; CHECK: (func $calls (type $4)
+ ;; CHECK-NEXT: (call $no.side.effects
+ ;; CHECK-NEXT: (struct.new_default $B1)
+ ;; CHECK-NEXT: (ref.func $target)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $target
+ ;; CHECK-NEXT: (struct.new_default $B2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $calls
+ (call $no.side.effects
+ (struct.new $B1)
+ (ref.func $target)
+ )
+ (call $target
+ (struct.new $B2)
+ )
+ )
+
+ ;; CHECK: (func $target (type $5) (param $x (ref $A))
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $target (param $x (ref $A))
+ ;; Because of the two calls above, this cannot be refined.
+ )
+)