mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #11046 from ethereum/moveAndInsideOr
Move AND with constant inside OR.
This commit is contained in:
		
						commit
						4027f40495
					
				| @ -4,6 +4,7 @@ Language Features: | ||||
| 
 | ||||
| 
 | ||||
| Compiler Features: | ||||
|  * Optimizer: Try to move ``and`` with constant inside ``or`` to improve storage writes of small types. | ||||
| 
 | ||||
| 
 | ||||
| Bugfixes: | ||||
|  | ||||
| @ -507,6 +507,23 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7( | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	// Combine alternating AND/OR/AND with constant,
 | ||||
| 	// AND(OR(AND(X, A), Y), B) -> OR(AND(X, A & B), AND(Y, B))
 | ||||
| 	// Many versions due to commutativity.
 | ||||
| 	for (auto const& inner: {Builtins::AND(X, A), Builtins::AND(A, X)}) | ||||
| 		for (auto const& second: {Builtins::OR(inner, Y), Builtins::OR(Y, inner)}) | ||||
| 		{ | ||||
| 			// We might swap X and Y but this is not an issue anymore.
 | ||||
| 			rules.push_back({ | ||||
| 				Builtins::AND(second, B), | ||||
| 				[=]() -> Pattern { return Builtins::OR(Builtins::AND(X, A.d() & B.d()), Builtins::AND(Y, B)); } | ||||
| 			}); | ||||
| 			rules.push_back({ | ||||
| 				Builtins::AND(B, second), | ||||
| 				[=]() -> Pattern { return Builtins::OR(Builtins::AND(X, A.d() & B.d()), Builtins::AND(Y, B)); } | ||||
| 			}); | ||||
| 		} | ||||
| 
 | ||||
| 	rules.push_back({ | ||||
| 		// MUL(X, SHL(Y, 1)) -> SHL(Y, X)
 | ||||
| 		Builtins::MUL(X, Builtins::SHL(Y, Word(1))), | ||||
|  | ||||
							
								
								
									
										1
									
								
								test/cmdlineTests/optimize_full_storage_write/args
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/cmdlineTests/optimize_full_storage_write/args
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| --optimize --asm --metadata-hash none | ||||
							
								
								
									
										12
									
								
								test/cmdlineTests/optimize_full_storage_write/input.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								test/cmdlineTests/optimize_full_storage_write/input.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0 | ||||
| pragma solidity >=0.0; | ||||
| 
 | ||||
| contract OptimizeFullSlotWrite { | ||||
| 	uint64[4] nums; | ||||
| 	function f() public { | ||||
| 		nums[0] = 11111; | ||||
| 		nums[1] = 22222; | ||||
| 		nums[2] = 33333; | ||||
| 		nums[3] = 44444; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										64
									
								
								test/cmdlineTests/optimize_full_storage_write/output
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								test/cmdlineTests/optimize_full_storage_write/output
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| 
 | ||||
| ======= optimize_full_storage_write/input.sol:OptimizeFullSlotWrite ======= | ||||
| EVM assembly: | ||||
|     /* "optimize_full_storage_write/input.sol":60:213  contract OptimizeFullSlotWrite {... */ | ||||
|   mstore(0x40, 0x80) | ||||
|   callvalue | ||||
|   dup1 | ||||
|   iszero | ||||
|   tag_1 | ||||
|   jumpi | ||||
|   0x00 | ||||
|   dup1 | ||||
|   revert | ||||
| tag_1: | ||||
|   pop | ||||
|   dataSize(sub_0) | ||||
|   dup1 | ||||
|   dataOffset(sub_0) | ||||
|   0x00 | ||||
|   codecopy | ||||
|   0x00 | ||||
|   return | ||||
| stop | ||||
| 
 | ||||
| sub_0: assembly { | ||||
|         /* "optimize_full_storage_write/input.sol":60:213  contract OptimizeFullSlotWrite {... */ | ||||
|       mstore(0x40, 0x80) | ||||
|       callvalue | ||||
|       dup1 | ||||
|       iszero | ||||
|       tag_1 | ||||
|       jumpi | ||||
|       0x00 | ||||
|       dup1 | ||||
|       revert | ||||
|     tag_1: | ||||
|       pop | ||||
|       jumpi(tag_2, lt(calldatasize, 0x04)) | ||||
|       shr(0xe0, calldataload(0x00)) | ||||
|       dup1 | ||||
|       0x26121ff0 | ||||
|       eq | ||||
|       tag_3 | ||||
|       jumpi | ||||
|     tag_2: | ||||
|       0x00 | ||||
|       dup1 | ||||
|       revert | ||||
|         /* "optimize_full_storage_write/input.sol":111:211  function f() public {... */ | ||||
|     tag_3: | ||||
|       tag_4 | ||||
|         /* "optimize_full_storage_write/input.sol":192:207  nums[3] = 44444 */ | ||||
|       0xad9c000000000000823500000000000056ce0000000000002b67 | ||||
|         /* "optimize_full_storage_write/input.sol":135:139  nums */ | ||||
|       0x00 | ||||
|         /* "optimize_full_storage_write/input.sol":192:207  nums[3] = 44444 */ | ||||
|       sstore | ||||
|         /* "optimize_full_storage_write/input.sol":111:211  function f() public {... */ | ||||
|       jump | ||||
|     tag_4: | ||||
|       stop | ||||
| 
 | ||||
|     auxdata: <AUXDATA REMOVED> | ||||
| } | ||||
							
								
								
									
										32
									
								
								test/formal/move_and_inside_or.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								test/formal/move_and_inside_or.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | ||||
| from rule import Rule | ||||
| from opcodes import * | ||||
| 
 | ||||
| """ | ||||
| Rule: | ||||
| AND(OR(AND(X, A), Y), B) -> OR(AND(X, A & B), AND(Y, B)) | ||||
| """ | ||||
| 
 | ||||
| rule = Rule() | ||||
| 
 | ||||
| # bit width is irrelevant | ||||
| n_bits = 128 | ||||
| 
 | ||||
| # Input vars | ||||
| X = BitVec('X', n_bits) | ||||
| Y = BitVec('Y', n_bits) | ||||
| A = BitVec('A', n_bits) | ||||
| B = BitVec('B', n_bits) | ||||
| 
 | ||||
| # Non optimized result, explicit form | ||||
| nonopt = AND(OR(AND(X, A), Y), B) | ||||
| 
 | ||||
| # Optimized result | ||||
| opt = OR(AND(X, A & B), AND(Y, B)) | ||||
| 
 | ||||
| rule.check(nonopt, opt) | ||||
| 
 | ||||
| # Now the forms as they are constructod in the code. | ||||
| for inner in [AND(X, A), AND(A, X)]: | ||||
|     for second in [OR(inner, Y), OR(Y, inner)]: | ||||
|         rule.check(AND(second, B), opt) | ||||
|         rule.check(AND(B, second), opt) | ||||
| @ -0,0 +1,25 @@ | ||||
| { | ||||
|     // Tests that masks that "add" up to | ||||
|     // the full bit width are removed. | ||||
|     let a := sload(0) | ||||
|     let x := sload(a) | ||||
|     let mask := 0xffffffffffffffff | ||||
|     x := or(and(x, not(mask)), 0x2b67) | ||||
|     mask := shl(64, mask) | ||||
|     x := or(and(x, not(mask)), 0x56ce0000000000000000) | ||||
|     mask := shl(64, mask) | ||||
|     x := or(and(x, not(mask)), shl(0x80, 0x8235)) | ||||
|     mask := shl(64, mask) | ||||
|     x := or(and(x, not(mask)), shl(0xc2, 0x2b67)) | ||||
|     sstore(a, x) | ||||
| } | ||||
| // ==== | ||||
| // EVMVersion: >byzantium | ||||
| // ---- | ||||
| // step: fullSuite | ||||
| // | ||||
| // { | ||||
| //     { | ||||
| //         sstore(sload(0), 0xad9c000000000000823500000000000056ce0000000000002b67) | ||||
| //     } | ||||
| // } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user