-
Notifications
You must be signed in to change notification settings - Fork 860
Use indirect call effects in LinearExecutionWalker #8738
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,10 +56,11 @@ | |
| ) | ||
|
|
||
| (module | ||
| ;; CHECK: (type $throw-type (func (result f64))) | ||
|
|
||
| ;; CHECK: (type $const-type (func (result f32))) | ||
| (type $const-type (func (result f32))) | ||
|
|
||
| ;; CHECK: (type $throw-type (func (result f64))) | ||
| (type $throw-type (func (result f64))) | ||
|
|
||
| ;; CHECK: (global $g (mut i32) (i32.const 0)) | ||
|
|
@@ -68,7 +69,7 @@ | |
| ;; CHECK: (table $t 2 2 funcref) | ||
| (table $t 2 2 funcref) | ||
|
|
||
| ;; CHECK: (tag $t (type $2)) | ||
| ;; CHECK: (tag $t (type $4)) | ||
| (tag $t) | ||
|
|
||
| ;; CHECK: (func $const (type $const-type) (result f32) | ||
|
|
@@ -90,32 +91,48 @@ | |
| ) | ||
| (elem declare $throws) | ||
|
|
||
| ;; CHECK: (func $read-g (type $3) (param $ref (ref null $const-type)) (result i32) | ||
| ;; CHECK: (func $read-g-with-nop-call-ref (type $5) (param $ref (ref null $const-type)) (result i32) | ||
| ;; CHECK-NEXT: (local $x i32) | ||
| ;; CHECK-NEXT: (local.set $x | ||
| ;; CHECK-NEXT: (global.get $g) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: (nop) | ||
| ;; CHECK-NEXT: (drop | ||
| ;; CHECK-NEXT: (call_ref $const-type | ||
| ;; CHECK-NEXT: (local.get $ref) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: (local.get $x) | ||
| ;; CHECK-NEXT: (global.get $g) | ||
| ;; CHECK-NEXT: ) | ||
| (func $read-g (param $ref (ref null $const-type)) (result i32) | ||
| (func $read-g-with-nop-call-ref (param $ref (ref null $const-type)) (result i32) | ||
| (local $x i32) | ||
| (local.set $x (global.get $g)) | ||
|
|
||
| ;; With more precise effect analysis for indirect calls, we can determine | ||
| ;; that the only possible target for this ref is $const in a closed world, | ||
| ;; which wouldn't block our optimizations. | ||
| ;; TODO: Add effects analysis for indirect calls. | ||
| ;; With --closed-world enabled, we can tell that this can only possibly call | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think --closed-world isn't even necessary for this, since this module has no imports or exports. There's no way for an outside function reference to sneak in.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, is it worth doing any indirect call analysis in the open world case? We could aggregate type effects unconditionally, and if we see a function ref that's imported or exported then invalidate the effects for that type and all subtypes. But any exported table of funcref would be enough to stop all analysis, and I know that many users use --closed-world anyway? In practice, we only do indirect call analysis if --closed-world is enabled, so I think the comment is appropriate. It's still true that --closed-world is enough to determine that $const is the only possible callee here.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should do indirect call analysis in open world, too. It just needs to respect the public/private type classification it gets from
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll leave this alone since I think the comment is still accurate for now based on #8754. In the future we can change GlobalEffects to look at public/private for types instead of --closed-world at which point we can change this. |
||
| ;; $const, which doesn't block our optimizations. | ||
| (drop (call_ref $const-type (local.get $ref))) | ||
|
|
||
| (local.get $x) | ||
| ) | ||
|
|
||
| ;; CHECK: (func $read-g-with-throw-in-between (type $4) (param $ref (ref $throw-type)) (result i32) | ||
| ;; CHECK: (func $read-g-with-nop-call-indirect (type $2) (result i32) | ||
| ;; CHECK-NEXT: (local $x i32) | ||
| ;; CHECK-NEXT: (nop) | ||
| ;; CHECK-NEXT: (drop | ||
| ;; CHECK-NEXT: (call_indirect $t (type $const-type) | ||
| ;; CHECK-NEXT: (i32.const 0) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: (global.get $g) | ||
| ;; CHECK-NEXT: ) | ||
| (func $read-g-with-nop-call-indirect (result i32) | ||
| (local $x i32) | ||
| (local.set $x (global.get $g)) | ||
|
|
||
| ;; Similar to above with call_indirect instead of call_ref. | ||
| (drop (call_indirect (type $const-type) (i32.const 0))) | ||
|
|
||
| (local.get $x) | ||
| ) | ||
|
|
||
| ;; CHECK: (func $read-g-with-effectful-call-ref (type $3) (param $ref (ref $throw-type)) (result i32) | ||
| ;; CHECK-NEXT: (local $x i32) | ||
| ;; CHECK-NEXT: (local.set $x | ||
| ;; CHECK-NEXT: (global.get $g) | ||
|
|
@@ -127,7 +144,7 @@ | |
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: (local.get $x) | ||
| ;; CHECK-NEXT: ) | ||
| (func $read-g-with-throw-in-between (param $ref (ref $throw-type)) (result i32) | ||
| (func $read-g-with-effectful-call-ref (param $ref (ref $throw-type)) (result i32) | ||
| (local $x i32) | ||
| (local.set $x (global.get $g)) | ||
|
|
||
|
|
@@ -138,25 +155,52 @@ | |
| (local.get $x) | ||
| ) | ||
|
|
||
| ;; CHECK: (func $read-g-with-call-indirect-in-between (type $5) (result i32) | ||
| ;; CHECK: (func $read-g-with-effectful-call-indirect (type $3) (param $ref (ref $throw-type)) (result i32) | ||
| ;; CHECK-NEXT: (local $x i32) | ||
| ;; CHECK-NEXT: (local.set $x | ||
| ;; CHECK-NEXT: (global.get $g) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: (drop | ||
| ;; CHECK-NEXT: (call_indirect $t (type $const-type) | ||
| ;; CHECK-NEXT: (call_indirect $t (type $throw-type) | ||
| ;; CHECK-NEXT: (i32.const 0) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: (local.get $x) | ||
| ;; CHECK-NEXT: ) | ||
| (func $read-g-with-call-indirect-in-between (result i32) | ||
| (func $read-g-with-effectful-call-indirect (param $ref (ref $throw-type)) (result i32) | ||
| (local $x i32) | ||
| (local.set $x (global.get $g)) | ||
|
|
||
| ;; Similar to above with call_indirect instead of call_ref. | ||
| ;; TODO: Add effects analysis for indirect calls. | ||
| (drop (call_indirect (type $const-type) (i32.const 0))) | ||
| ;; Similar to above, except here we can tell that the indirect call may | ||
| ;; throw so optimization is halted. | ||
| (drop (call_indirect (type $throw-type) (i32.const 0))) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess SimplifyLocals could be improved to optimize here despite the throws effect, but that's unrelated to this PR. |
||
|
|
||
| (local.get $x) | ||
| ) | ||
|
|
||
| ;; CHECK: (func $read-g-with-unreachable-call-ref (type $2) (result i32) | ||
| ;; CHECK-NEXT: (local $x i32) | ||
| ;; CHECK-NEXT: (local.set $x | ||
| ;; CHECK-NEXT: (global.get $g) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: (drop | ||
| ;; CHECK-NEXT: (block ;; (replaces unreachable CallRef we can't emit) | ||
| ;; CHECK-NEXT: (drop | ||
| ;; CHECK-NEXT: (unreachable) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: (unreachable) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: (local.get $x) | ||
| ;; CHECK-NEXT: ) | ||
| (func $read-g-with-unreachable-call-ref (result i32) | ||
| (local $x i32) | ||
| (local.set $x (global.get $g)) | ||
|
|
||
| ;; This is guaranteed to trap, and the type immediate doesn't matter. | ||
| ;; TODO: we should be able to optimize this, but something is likely missing | ||
| ;; in SimplifyGlobals (LinearExecutionWalker handles this case correctly). | ||
| (drop (call_ref $throw-type (unreachable))) | ||
|
|
||
| (local.get $x) | ||
| ) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.