Skip to content

Commit bcc6205

Browse files
authored
De-morgan's "and" law (#1297)
(eqz X) and (eqz Y) === eqz (X or Y) Normally de-morgan's laws apply only to boolean vars, but for the and (but not or or xor) version, it works in all cases (both sides are true iff X and Y have all zero bits).
1 parent 290b875 commit bcc6205

12 files changed

+292
-267
lines changed

src/passes/OptimizeInstructions.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,32 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
562562
}
563563
}
564564
}
565+
// bitwise operations
566+
if (binary->op == AndInt32) {
567+
// try de-morgan's AND law,
568+
// (eqz X) and (eqz Y) === eqz (X or Y)
569+
// Note that the OR and XOR laws do not work here, as these
570+
// are not booleans (we could check if they are, but a boolean
571+
// would already optimize with the eqz anyhow, unless propagating).
572+
// But for AND, the left is true iff X and Y are each all zero bits,
573+
// and the right is true if the union of their bits is zero; same.
574+
if (auto* left = binary->left->dynCast<Unary>()) {
575+
if (left->op == EqZInt32) {
576+
if (auto* right = binary->right->dynCast<Unary>()) {
577+
if (right->op == EqZInt32) {
578+
// reuse one unary, drop the other
579+
auto* leftValue = left->value;
580+
left->value = binary;
581+
binary->left = leftValue;
582+
binary->right = right->value;
583+
binary->op = OrInt32;
584+
return left;
585+
}
586+
}
587+
}
588+
}
589+
}
590+
// for and and or, we can potentially conditionalize
565591
if (binary->op == AndInt32 || binary->op == OrInt32) {
566592
return conditionalizeExpensiveOnBitwise(binary);
567593
}

test/emcc_O2_hello_world.fromasm

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,11 +1674,9 @@
16741674
)
16751675
(block
16761676
(if
1677-
(i32.and
1678-
(i32.eqz
1677+
(i32.eqz
1678+
(i32.or
16791679
(get_local $6)
1680-
)
1681-
(i32.eqz
16821680
(get_local $30)
16831681
)
16841682
)

test/emcc_O2_hello_world.fromasm.clamp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,11 +1674,9 @@
16741674
)
16751675
(block
16761676
(if
1677-
(i32.and
1678-
(i32.eqz
1677+
(i32.eqz
1678+
(i32.or
16791679
(get_local $6)
1680-
)
1681-
(i32.eqz
16821680
(get_local $30)
16831681
)
16841682
)

test/emcc_O2_hello_world.fromasm.imprecise

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,11 +1673,9 @@
16731673
)
16741674
(block
16751675
(if
1676-
(i32.and
1677-
(i32.eqz
1676+
(i32.eqz
1677+
(i32.or
16781678
(get_local $6)
1679-
)
1680-
(i32.eqz
16811679
(get_local $30)
16821680
)
16831681
)

test/emcc_hello_world.fromasm

Lines changed: 53 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3659,27 +3659,20 @@
36593659
(br $__rjti$3)
36603660
)
36613661
(if
3662-
(i32.and
3663-
(i32.eqz
3664-
(tee_local $7
3665-
(i32.load
3666-
(tee_local $5
3667-
(get_local $19)
3668-
)
3662+
(i32.or
3663+
(tee_local $7
3664+
(i32.load
3665+
(tee_local $5
3666+
(get_local $19)
36693667
)
36703668
)
36713669
)
3672-
(i32.eqz
3673-
(tee_local $8
3674-
(i32.load offset=4
3675-
(get_local $5)
3676-
)
3670+
(tee_local $8
3671+
(i32.load offset=4
3672+
(get_local $5)
36773673
)
36783674
)
36793675
)
3680-
(set_local $8
3681-
(get_local $26)
3682-
)
36833676
(block
36843677
(set_local $5
36853678
(get_local $7)
@@ -3707,27 +3700,24 @@
37073700
)
37083701
)
37093702
(br_if $while-in32
3710-
(i32.eqz
3711-
(i32.and
3712-
(i32.eqz
3713-
(tee_local $5
3714-
(call $_bitshift64Lshr
3715-
(get_local $5)
3716-
(get_local $7)
3717-
(i32.const 3)
3718-
)
3719-
)
3720-
)
3721-
(i32.eqz
3722-
(tee_local $7
3723-
(get_global $tempRet0)
3724-
)
3703+
(i32.or
3704+
(tee_local $5
3705+
(call $_bitshift64Lshr
3706+
(get_local $5)
3707+
(get_local $7)
3708+
(i32.const 3)
37253709
)
37263710
)
3711+
(tee_local $7
3712+
(get_global $tempRet0)
3713+
)
37273714
)
37283715
)
37293716
)
37303717
)
3718+
(set_local $8
3719+
(get_local $26)
3720+
)
37313721
)
37323722
(set_local $5
37333723
(if (result i32)
@@ -6478,36 +6468,20 @@
64786468
)
64796469
)
64806470
(if
6481-
(i32.and
6482-
(i32.eqz
6483-
(tee_local $8
6484-
(i32.load
6485-
(tee_local $5
6486-
(get_local $19)
6487-
)
6471+
(i32.or
6472+
(tee_local $8
6473+
(i32.load
6474+
(tee_local $5
6475+
(get_local $19)
64886476
)
64896477
)
64906478
)
6491-
(i32.eqz
6492-
(tee_local $11
6493-
(i32.load offset=4
6494-
(get_local $5)
6495-
)
6479+
(tee_local $11
6480+
(i32.load offset=4
6481+
(get_local $5)
64966482
)
64976483
)
64986484
)
6499-
(block
6500-
(set_local $5
6501-
(get_local $26)
6502-
)
6503-
(set_local $8
6504-
(i32.const 0)
6505-
)
6506-
(set_local $9
6507-
(i32.const 4091)
6508-
)
6509-
(br $__rjti$8)
6510-
)
65116485
(block
65126486
(set_local $5
65136487
(get_local $8)
@@ -6537,23 +6511,17 @@
65376511
)
65386512
)
65396513
(br_if $while-in123
6540-
(i32.eqz
6541-
(i32.and
6542-
(i32.eqz
6543-
(tee_local $5
6544-
(call $_bitshift64Lshr
6545-
(get_local $5)
6546-
(get_local $11)
6547-
(i32.const 4)
6548-
)
6549-
)
6550-
)
6551-
(i32.eqz
6552-
(tee_local $11
6553-
(get_global $tempRet0)
6554-
)
6514+
(i32.or
6515+
(tee_local $5
6516+
(call $_bitshift64Lshr
6517+
(get_local $5)
6518+
(get_local $11)
6519+
(i32.const 4)
65556520
)
65566521
)
6522+
(tee_local $11
6523+
(get_global $tempRet0)
6524+
)
65576525
)
65586526
)
65596527
(set_local $5
@@ -6569,15 +6537,13 @@
65696537
(i32.const 8)
65706538
)
65716539
)
6572-
(i32.and
6573-
(i32.eqz
6540+
(i32.eqz
6541+
(i32.or
65746542
(i32.load
65756543
(tee_local $11
65766544
(get_local $19)
65776545
)
65786546
)
6579-
)
6580-
(i32.eqz
65816547
(i32.load offset=4
65826548
(get_local $11)
65836549
)
@@ -6606,6 +6572,18 @@
66066572
)
66076573
(br $__rjti$8)
66086574
)
6575+
(block
6576+
(set_local $5
6577+
(get_local $26)
6578+
)
6579+
(set_local $8
6580+
(i32.const 0)
6581+
)
6582+
(set_local $9
6583+
(i32.const 4091)
6584+
)
6585+
(br $__rjti$8)
6586+
)
66096587
)
66106588
)
66116589
(set_local $5
@@ -9378,11 +9356,9 @@
93789356
)
93799357
)
93809358
(if
9381-
(i32.and
9382-
(i32.eqz
9359+
(i32.eqz
9360+
(i32.or
93839361
(get_local $4)
9384-
)
9385-
(i32.eqz
93869362
(get_local $0)
93879363
)
93889364
)

0 commit comments

Comments
 (0)