Skip to content

Commit e7b2c9d

Browse files
authored
[compiler] Add a simplifier rule to replace match with is (#18070)
If looking at `match (e) { V => true, _ => false }`, we reduce this to `e is V`, which is more efficient.
1 parent c531ae8 commit e7b2c9d

File tree

12 files changed

+148
-89
lines changed

12 files changed

+148
-89
lines changed

third_party/move/move-compiler-v2/src/env_pipeline/ast_simplifier.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use itertools::Itertools;
5252
use log::{debug, log_enabled, trace, Level};
5353
use move_core_types::ability::Ability;
5454
use move_model::{
55-
ast::{Exp, ExpData, Operation, Pattern, Value, VisitorPosition},
55+
ast::{Exp, ExpData, MatchArm, Operation, Pattern, Value, VisitorPosition},
5656
constant_folder::ConstantFolder,
5757
exp_rewriter::ExpRewriterFunctions,
5858
model::{FunctionEnv, GlobalEnv, NodeId, Parameter},
@@ -870,6 +870,41 @@ impl ExpRewriterFunctions for SimplifierRewriter<'_> {
870870
})
871871
}
872872

873+
fn rewrite_match(&mut self, id: NodeId, disc: &Exp, arms: &[MatchArm]) -> Option<Exp> {
874+
// match (e) { V(_) => true, _ => false } ==> e is V
875+
let is_bool = |e: &Exp, test: bool| -> bool {
876+
matches!(e.as_ref(), ExpData::Value(_, Value::Bool(v)) if test == *v)
877+
};
878+
if arms.len() == 2
879+
&& let MatchArm {
880+
loc: _,
881+
pattern: Pattern::Struct(_, qid, Some(variant), args),
882+
condition: None,
883+
body,
884+
} = &arms[0]
885+
&& args.iter().all(|p| matches!(p, Pattern::Wildcard(_)))
886+
&& is_bool(body, true)
887+
&& let MatchArm {
888+
loc: _,
889+
pattern: Pattern::Wildcard(_),
890+
condition: None,
891+
body,
892+
} = &arms[1]
893+
&& is_bool(body, false)
894+
{
895+
Some(
896+
ExpData::Call(
897+
id,
898+
Operation::TestVariants(qid.module_id, qid.id, vec![*variant]),
899+
vec![disc.clone()],
900+
)
901+
.into_exp(),
902+
)
903+
} else {
904+
None
905+
}
906+
}
907+
873908
fn rewrite_enter_block_scope(
874909
&mut self,
875910
id: NodeId,

third_party/move/move-compiler-v2/tests/file-format-generator/struct_variants.exp

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -87,29 +87,8 @@ l1: move_loc l2
8787

8888
// Function definition at index 1
8989
#[persistent] public fun is_inner1(l0: &Inner): bool
90-
local l1: bool
91-
local l2: &Inner
92-
copy_loc l0
93-
test_variant Inner, Inner1
94-
br_false l0
9590
move_loc l0
96-
pop
97-
// @5
98-
ld_true
99-
st_loc l1
100-
branch l1
101-
l0: move_loc l0
102-
st_loc l2
103-
// @10
104-
move_loc l2
105-
pop
106-
ld_false
107-
st_loc l1
108-
branch l1
109-
// @15
110-
ld_u64 14566554180833181697
111-
abort
112-
l1: move_loc l1
91+
test_variant Inner, Inner1
11392
ret
11493

11594
// Function definition at index 2

third_party/move/move-compiler-v2/tests/file-format-generator/struct_variants.opt.exp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,8 @@ l1: ld_u64 14566554180833181697
7676

7777
// Function definition at index 1
7878
#[persistent] public fun is_inner1(l0: &Inner): bool
79-
copy_loc l0
80-
test_variant Inner, Inner1
81-
br_false l0
8279
move_loc l0
83-
pop
84-
// @5
85-
ld_true
86-
ret
87-
l0: move_loc l0
88-
pop
89-
ld_false
90-
// @10
80+
test_variant Inner, Inner1
9181
ret
9282

9383
// Function definition at index 2

third_party/move/move-compiler-v2/tests/file-format-generator/variants_match_reduces_to_is.exp

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,8 @@ enum Color
1212

1313
// Function definition at index 0
1414
fun test_red(l0: &Color): bool
15-
local l1: bool
16-
local l2: &Color
17-
copy_loc l0
18-
test_variant Color, Red
19-
br_false l0
2015
move_loc l0
21-
pop
22-
// @5
23-
ld_true
24-
st_loc l1
25-
branch l1
26-
l0: move_loc l0
27-
st_loc l2
28-
// @10
29-
move_loc l2
30-
pop
31-
ld_false
32-
st_loc l1
33-
branch l1
34-
// @15
35-
ld_u64 14566554180833181697
36-
abort
37-
l1: move_loc l1
16+
test_variant Color, Red
3817
ret
3918

4019
// Function definition at index 1

third_party/move/move-compiler-v2/tests/file-format-generator/variants_match_reduces_to_is.opt.exp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,8 @@ enum Color
1212

1313
// Function definition at index 0
1414
fun test_red(l0: &Color): bool
15-
copy_loc l0
16-
test_variant Color, Red
17-
br_false l0
1815
move_loc l0
19-
pop
20-
// @5
21-
ld_true
22-
ret
23-
l0: move_loc l0
24-
pop
25-
ld_false
26-
// @10
16+
test_variant Color, Red
2717
ret
2818

2919
// Function definition at index 1
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// -- Model dump before first bytecode pipeline
2+
module 0x66::m {
3+
enum E {
4+
A {
5+
0: u64,
6+
}
7+
B,
8+
C {
9+
0: bool,
10+
}
11+
}
12+
private fun variant_test(e: &E): bool {
13+
match (e) {
14+
m::E::A{ 0: _ } => {
15+
true
16+
}
17+
_: &E => {
18+
false
19+
}
20+
}
21+
22+
}
23+
} // end 0x66::m
24+
25+
// -- Sourcified model before first bytecode pipeline
26+
module 0x66::m {
27+
enum E {
28+
A {
29+
0: u64,
30+
}
31+
B,
32+
C {
33+
0: bool,
34+
}
35+
}
36+
fun variant_test(e: &E): bool {
37+
match (e) {
38+
E::A(_) => true,
39+
_ => false,
40+
}
41+
}
42+
}
43+
44+
// -- Model dump before second bytecode pipeline
45+
module 0x66::m {
46+
enum E {
47+
A {
48+
0: u64,
49+
}
50+
B,
51+
C {
52+
0: bool,
53+
}
54+
}
55+
private fun variant_test(e: &E): bool {
56+
test_variants m::E::A(e)
57+
}
58+
} // end 0x66::m
59+
60+
61+
============ bytecode verification succeeded ========
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module 0x66::m {
2+
3+
enum E {
4+
A(u64),
5+
B,
6+
C(bool)
7+
}
8+
9+
fun variant_test(e: &E): bool {
10+
match (e) {
11+
A(_) => true,
12+
_ => false
13+
}
14+
}
15+
}

third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/enum/round-trip/enum_matching.decompiled

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,7 @@ module 0x42::m {
5454
_v2 + _v3
5555
}
5656
public fun is_inner1(p0: &Inner): bool {
57-
if (p0 is Inner1) return true;
58-
false
57+
p0 is Inner1
5958
}
6059
public fun is_some<T0>(p0: &Option<T0>): bool {
6160
loop {
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
processed 15 tasks
2-
task 0 lines 3-257: publish [module 0x42::m {]
3-
task 1 lines 260-260: run 0x42::m::t1_is_inner1
2+
task 0 lines 3-256: publish [module 0x42::m {]
3+
task 1 lines 259-259: run 0x42::m::t1_is_inner1
44
return values: true
5-
task 2 lines 262-262: run 0x42::m::t2_is_inner1
5+
task 2 lines 261-261: run 0x42::m::t2_is_inner1
66
return values: false
7-
task 3 lines 264-264: run 0x42::m::t1_inner_value
7+
task 3 lines 263-263: run 0x42::m::t1_inner_value
88
return values: 7
9-
task 4 lines 266-266: run 0x42::m::t1_outer_value
9+
task 4 lines 265-265: run 0x42::m::t1_outer_value
1010
return values: 0
11-
task 5 lines 268-268: run 0x42::m::t2_outer_value
11+
task 5 lines 267-267: run 0x42::m::t2_outer_value
1212
return values: 3
13-
task 6 lines 270-270: run 0x42::m::t3_outer_value
13+
task 6 lines 269-269: run 0x42::m::t3_outer_value
1414
return values: 8
15-
task 7 lines 272-272: run 0x42::m::t1_outer_value_nested
15+
task 7 lines 271-271: run 0x42::m::t1_outer_value_nested
1616
return values: 27
17-
task 8 lines 274-274: run 0x42::m::t2_outer_value_nested
17+
task 8 lines 273-273: run 0x42::m::t2_outer_value_nested
1818
return values: 12
19-
task 9 lines 276-276: run 0x42::m::t1_outer_value_with_cond
19+
task 9 lines 275-275: run 0x42::m::t1_outer_value_with_cond
2020
return values: 1
21-
task 10 lines 278-278: run 0x42::m::t1_outer_value_with_cond_ref
21+
task 10 lines 277-277: run 0x42::m::t1_outer_value_with_cond_ref
2222
return values: true
23-
task 11 lines 280-280: run 0x42::m::t1_is_some
23+
task 11 lines 279-279: run 0x42::m::t1_is_some
2424
return values: false
25-
task 12 lines 282-282: run 0x42::m::t2_is_some
25+
task 12 lines 281-281: run 0x42::m::t2_is_some
2626
return values: true
27-
task 13 lines 284-284: run 0x42::m::t1_is_some_specialized
27+
task 13 lines 283-283: run 0x42::m::t1_is_some_specialized
2828
return values: false
29-
task 14 lines 286-286: run 0x42::m::t2_is_some_specialized
29+
task 14 lines 285-285: run 0x42::m::t2_is_some_specialized
3030
return values: true

third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/enum/round-trip/enum_scoping.decompiled

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ module 0x42::m {
2525
}
2626
}
2727
public fun check_scoping(p0: &Inner): u64 {
28-
if (p0 is Inner1) ();
2928
3
3029
}
3130
fun t1_check_scoping(): u64 {

0 commit comments

Comments
 (0)