Skip to content

Commit 882eafe

Browse files
authored
[NFC] Add tests for missing exact CFP optimizations (#7890)
CFP takes advantage of exact type information, but it currently does so only for immutable fields. It is also unnecessarily conservative about how it propagates type information so that sets to a type inhibit optimizations of its sibling types, even though those sets cannot possibly affect the siblings. Add tests for these cases to demonstrate the benefit of follow-on PRs that will fix these issues.
1 parent 3221690 commit 882eafe

File tree

1 file changed

+365
-0
lines changed

1 file changed

+365
-0
lines changed

test/lit/passes/cfp.wast

Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2499,6 +2499,371 @@
24992499
)
25002500
)
25012501

2502+
(module
2503+
;; Same as above but now the fields are mutable.
2504+
(rec
2505+
;; CHECK: (rec
2506+
;; CHECK-NEXT: (type $A (sub (struct (field (mut i32)))))
2507+
(type $A (sub (struct (field (mut i32)))))
2508+
;; CHECK: (type $B (sub $A (struct (field (mut i32)))))
2509+
(type $B (sub $A (struct (field (mut i32)))))
2510+
)
2511+
2512+
;; CHECK: (type $2 (func (param i32)))
2513+
2514+
;; CHECK: (func $test (type $2) (param $0 i32)
2515+
;; CHECK-NEXT: (local $A (ref $A))
2516+
;; CHECK-NEXT: (local $B (ref $B))
2517+
;; CHECK-NEXT: (local $A-exact (ref (exact $A)))
2518+
;; CHECK-NEXT: (local $B-exact (ref (exact $B)))
2519+
;; CHECK-NEXT: (local.set $A
2520+
;; CHECK-NEXT: (local.tee $A-exact
2521+
;; CHECK-NEXT: (struct.new $A
2522+
;; CHECK-NEXT: (i32.const 10)
2523+
;; CHECK-NEXT: )
2524+
;; CHECK-NEXT: )
2525+
;; CHECK-NEXT: )
2526+
;; CHECK-NEXT: (local.set $B
2527+
;; CHECK-NEXT: (local.tee $B-exact
2528+
;; CHECK-NEXT: (struct.new $B
2529+
;; CHECK-NEXT: (i32.const 20)
2530+
;; CHECK-NEXT: )
2531+
;; CHECK-NEXT: )
2532+
;; CHECK-NEXT: )
2533+
;; CHECK-NEXT: (drop
2534+
;; CHECK-NEXT: (struct.get $A 0
2535+
;; CHECK-NEXT: (local.get $A)
2536+
;; CHECK-NEXT: )
2537+
;; CHECK-NEXT: )
2538+
;; CHECK-NEXT: (drop
2539+
;; CHECK-NEXT: (block (result i32)
2540+
;; CHECK-NEXT: (drop
2541+
;; CHECK-NEXT: (ref.as_non_null
2542+
;; CHECK-NEXT: (local.get $B)
2543+
;; CHECK-NEXT: )
2544+
;; CHECK-NEXT: )
2545+
;; CHECK-NEXT: (i32.const 20)
2546+
;; CHECK-NEXT: )
2547+
;; CHECK-NEXT: )
2548+
;; CHECK-NEXT: (drop
2549+
;; CHECK-NEXT: (struct.get $A 0
2550+
;; CHECK-NEXT: (local.get $A-exact)
2551+
;; CHECK-NEXT: )
2552+
;; CHECK-NEXT: )
2553+
;; CHECK-NEXT: (drop
2554+
;; CHECK-NEXT: (block (result i32)
2555+
;; CHECK-NEXT: (drop
2556+
;; CHECK-NEXT: (ref.as_non_null
2557+
;; CHECK-NEXT: (local.get $B-exact)
2558+
;; CHECK-NEXT: )
2559+
;; CHECK-NEXT: )
2560+
;; CHECK-NEXT: (i32.const 20)
2561+
;; CHECK-NEXT: )
2562+
;; CHECK-NEXT: )
2563+
;; CHECK-NEXT: )
2564+
(func $test (param $0 i32)
2565+
(local $A (ref $A))
2566+
(local $B (ref $B))
2567+
(local $A-exact (ref (exact $A)))
2568+
(local $B-exact (ref (exact $B)))
2569+
(local.set $A
2570+
(local.tee $A-exact
2571+
(struct.new $A
2572+
(i32.const 10)
2573+
)
2574+
)
2575+
)
2576+
(local.set $B
2577+
(local.tee $B-exact
2578+
(struct.new $B
2579+
(i32.const 20)
2580+
)
2581+
)
2582+
)
2583+
;; We can optimize an inexact $B, but not $A.
2584+
(drop
2585+
(struct.get $A 0
2586+
(local.get $A)
2587+
)
2588+
)
2589+
(drop
2590+
(struct.get $B 0
2591+
(local.get $B)
2592+
)
2593+
)
2594+
;; We should be able to optimize both exact references TODO.
2595+
(drop
2596+
(struct.get $A 0
2597+
(local.get $A-exact)
2598+
)
2599+
)
2600+
(drop
2601+
(struct.get $B 0
2602+
(local.get $B-exact)
2603+
)
2604+
)
2605+
)
2606+
)
2607+
2608+
(module
2609+
;; Same as above but now we add no-op sets.
2610+
(rec
2611+
;; CHECK: (rec
2612+
;; CHECK-NEXT: (type $A (sub (struct (field (mut i32)))))
2613+
(type $A (sub (struct (field (mut i32)))))
2614+
;; CHECK: (type $B (sub $A (struct (field (mut i32)))))
2615+
(type $B (sub $A (struct (field (mut i32)))))
2616+
)
2617+
2618+
;; CHECK: (type $2 (func (param i32)))
2619+
2620+
;; CHECK: (func $test (type $2) (param $0 i32)
2621+
;; CHECK-NEXT: (local $A (ref $A))
2622+
;; CHECK-NEXT: (local $B (ref $B))
2623+
;; CHECK-NEXT: (local $A-exact (ref (exact $A)))
2624+
;; CHECK-NEXT: (local $B-exact (ref (exact $B)))
2625+
;; CHECK-NEXT: (local.set $A
2626+
;; CHECK-NEXT: (local.tee $A-exact
2627+
;; CHECK-NEXT: (struct.new $A
2628+
;; CHECK-NEXT: (i32.const 10)
2629+
;; CHECK-NEXT: )
2630+
;; CHECK-NEXT: )
2631+
;; CHECK-NEXT: )
2632+
;; CHECK-NEXT: (local.set $B
2633+
;; CHECK-NEXT: (local.tee $B-exact
2634+
;; CHECK-NEXT: (struct.new $B
2635+
;; CHECK-NEXT: (i32.const 20)
2636+
;; CHECK-NEXT: )
2637+
;; CHECK-NEXT: )
2638+
;; CHECK-NEXT: )
2639+
;; CHECK-NEXT: (struct.set $A 0
2640+
;; CHECK-NEXT: (local.get $A-exact)
2641+
;; CHECK-NEXT: (i32.const 10)
2642+
;; CHECK-NEXT: )
2643+
;; CHECK-NEXT: (struct.set $B 0
2644+
;; CHECK-NEXT: (local.get $B-exact)
2645+
;; CHECK-NEXT: (i32.const 20)
2646+
;; CHECK-NEXT: )
2647+
;; CHECK-NEXT: (drop
2648+
;; CHECK-NEXT: (struct.get $A 0
2649+
;; CHECK-NEXT: (local.get $A)
2650+
;; CHECK-NEXT: )
2651+
;; CHECK-NEXT: )
2652+
;; CHECK-NEXT: (drop
2653+
;; CHECK-NEXT: (struct.get $B 0
2654+
;; CHECK-NEXT: (local.get $B)
2655+
;; CHECK-NEXT: )
2656+
;; CHECK-NEXT: )
2657+
;; CHECK-NEXT: (drop
2658+
;; CHECK-NEXT: (struct.get $A 0
2659+
;; CHECK-NEXT: (local.get $A-exact)
2660+
;; CHECK-NEXT: )
2661+
;; CHECK-NEXT: )
2662+
;; CHECK-NEXT: (drop
2663+
;; CHECK-NEXT: (struct.get $B 0
2664+
;; CHECK-NEXT: (local.get $B-exact)
2665+
;; CHECK-NEXT: )
2666+
;; CHECK-NEXT: )
2667+
;; CHECK-NEXT: )
2668+
(func $test (param $0 i32)
2669+
(local $A (ref $A))
2670+
(local $B (ref $B))
2671+
(local $A-exact (ref (exact $A)))
2672+
(local $B-exact (ref (exact $B)))
2673+
(local.set $A
2674+
(local.tee $A-exact
2675+
(struct.new $A
2676+
(i32.const 10)
2677+
)
2678+
)
2679+
)
2680+
(local.set $B
2681+
(local.tee $B-exact
2682+
(struct.new $B
2683+
(i32.const 20)
2684+
)
2685+
)
2686+
)
2687+
;; No-op exact sets should not inhibit optimization.
2688+
(struct.set $A 0
2689+
(local.get $A-exact)
2690+
(i32.const 10)
2691+
)
2692+
(struct.set $B 0
2693+
(local.get $B-exact)
2694+
(i32.const 20)
2695+
)
2696+
;; We should be able to optimize an inexact $B, but not $A TODO.
2697+
(drop
2698+
(struct.get $A 0
2699+
(local.get $A)
2700+
)
2701+
)
2702+
(drop
2703+
(struct.get $B 0
2704+
(local.get $B)
2705+
)
2706+
)
2707+
;; We should be able to optimize both exact references TODO.
2708+
(drop
2709+
(struct.get $A 0
2710+
(local.get $A-exact)
2711+
)
2712+
)
2713+
(drop
2714+
(struct.get $B 0
2715+
(local.get $B-exact)
2716+
)
2717+
)
2718+
)
2719+
)
2720+
2721+
(module
2722+
;; Sets to a subtype should not affect exact gets of a supertype or sibling.
2723+
(rec
2724+
;; CHECK: (rec
2725+
;; CHECK-NEXT: (type $A (sub (struct (field (mut i32)))))
2726+
(type $A (sub (struct (field (mut i32)))))
2727+
;; CHECK: (type $B (sub $A (struct (field (mut i32)))))
2728+
(type $B (sub $A (struct (field (mut i32)))))
2729+
;; CHECK: (type $C (sub $A (struct (field (mut i32)))))
2730+
(type $C (sub $A (struct (field (mut i32)))))
2731+
)
2732+
2733+
;; CHECK: (type $3 (func))
2734+
2735+
;; CHECK: (type $4 (func (param (ref $B))))
2736+
2737+
;; CHECK: (type $5 (func (param (ref $A) (ref $B) (ref $C))))
2738+
2739+
;; CHECK: (type $6 (func (param (ref (exact $A)) (ref (exact $B)) (ref (exact $C)))))
2740+
2741+
;; CHECK: (func $news (type $3)
2742+
;; CHECK-NEXT: (drop
2743+
;; CHECK-NEXT: (struct.new $A
2744+
;; CHECK-NEXT: (i32.const 10)
2745+
;; CHECK-NEXT: )
2746+
;; CHECK-NEXT: )
2747+
;; CHECK-NEXT: (drop
2748+
;; CHECK-NEXT: (struct.new $B
2749+
;; CHECK-NEXT: (i32.const 20)
2750+
;; CHECK-NEXT: )
2751+
;; CHECK-NEXT: )
2752+
;; CHECK-NEXT: (drop
2753+
;; CHECK-NEXT: (struct.new $C
2754+
;; CHECK-NEXT: (i32.const 30)
2755+
;; CHECK-NEXT: )
2756+
;; CHECK-NEXT: )
2757+
;; CHECK-NEXT: )
2758+
(func $news
2759+
(drop
2760+
(struct.new $A
2761+
(i32.const 10)
2762+
)
2763+
)
2764+
(drop
2765+
(struct.new $B
2766+
(i32.const 20)
2767+
)
2768+
)
2769+
(drop
2770+
(struct.new $C
2771+
(i32.const 30)
2772+
)
2773+
)
2774+
)
2775+
2776+
;; CHECK: (func $set-B (type $4) (param $B (ref $B))
2777+
;; CHECK-NEXT: (struct.set $B 0
2778+
;; CHECK-NEXT: (local.get $B)
2779+
;; CHECK-NEXT: (i32.const 666)
2780+
;; CHECK-NEXT: )
2781+
;; CHECK-NEXT: )
2782+
(func $set-B (param $B (ref $B))
2783+
;; Inhibits optimizations on B and inexact A only.
2784+
(struct.set $B 0
2785+
(local.get $B)
2786+
(i32.const 666)
2787+
)
2788+
)
2789+
2790+
;; CHECK: (func $inexact-gets (type $5) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
2791+
;; CHECK-NEXT: (drop
2792+
;; CHECK-NEXT: (struct.get $A 0
2793+
;; CHECK-NEXT: (local.get $A)
2794+
;; CHECK-NEXT: )
2795+
;; CHECK-NEXT: )
2796+
;; CHECK-NEXT: (drop
2797+
;; CHECK-NEXT: (struct.get $B 0
2798+
;; CHECK-NEXT: (local.get $B)
2799+
;; CHECK-NEXT: )
2800+
;; CHECK-NEXT: )
2801+
;; CHECK-NEXT: (drop
2802+
;; CHECK-NEXT: (struct.get $C 0
2803+
;; CHECK-NEXT: (local.get $C)
2804+
;; CHECK-NEXT: )
2805+
;; CHECK-NEXT: )
2806+
;; CHECK-NEXT: )
2807+
(func $inexact-gets (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
2808+
(drop
2809+
(struct.get $A 0
2810+
(local.get $A)
2811+
)
2812+
)
2813+
(drop
2814+
(struct.get $B 0
2815+
(local.get $B)
2816+
)
2817+
)
2818+
;; This should be optimizable TODO.
2819+
(drop
2820+
(struct.get $C 0
2821+
(local.get $C)
2822+
)
2823+
)
2824+
)
2825+
2826+
;; CHECK: (func $exact-gets (type $6) (param $A-exact (ref (exact $A))) (param $B-exact (ref (exact $B))) (param $C-exact (ref (exact $C)))
2827+
;; CHECK-NEXT: (drop
2828+
;; CHECK-NEXT: (struct.get $A 0
2829+
;; CHECK-NEXT: (local.get $A-exact)
2830+
;; CHECK-NEXT: )
2831+
;; CHECK-NEXT: )
2832+
;; CHECK-NEXT: (drop
2833+
;; CHECK-NEXT: (struct.get $B 0
2834+
;; CHECK-NEXT: (local.get $B-exact)
2835+
;; CHECK-NEXT: )
2836+
;; CHECK-NEXT: )
2837+
;; CHECK-NEXT: (drop
2838+
;; CHECK-NEXT: (struct.get $C 0
2839+
;; CHECK-NEXT: (local.get $C-exact)
2840+
;; CHECK-NEXT: )
2841+
;; CHECK-NEXT: )
2842+
;; CHECK-NEXT: )
2843+
(func $exact-gets (param $A-exact (ref (exact $A)))
2844+
(param $B-exact (ref (exact $B)))
2845+
(param $C-exact (ref (exact $C)))
2846+
(drop
2847+
;; This should be optimizable TODO.
2848+
(struct.get $A 0
2849+
(local.get $A-exact)
2850+
)
2851+
)
2852+
;; Not optimizable.
2853+
(drop
2854+
(struct.get $B 0
2855+
(local.get $B-exact)
2856+
)
2857+
)
2858+
;; This should be optimizable TODO.
2859+
(drop
2860+
(struct.get $C 0
2861+
(local.get $C-exact)
2862+
)
2863+
)
2864+
)
2865+
)
2866+
25022867
;; A type with two subtypes. A copy on the parent can affect either child.
25032868
(module
25042869
(rec

0 commit comments

Comments
 (0)