@@ -164,8 +164,8 @@ bool Optimizer::detect_rewrite_big_THROW() {
164164 return true ;
165165}
166166
167- // purpose 1: for one constant b.storeInt(123, 32) generate not "123 PUSHINT; SWAP; STI", but "123 PUSHINT; STIR "
168- // purpose 2: consecutive b.storeUint(ff, 16).storeUint(ff, 16) generate one "00ff00ff" STU
167+ // purpose 1: for b.storeInt(123, 32) generate not "123 PUSHINT; SWAP; STI", but "x{...} STSLICECONST "
168+ // purpose 2: consecutive b.storeUint(ff, 16).storeUint(ff, 16) generate one "x{ 00ff00ff} STSLICECONST"
169169// (since it works at IR level, it also works for const variables and auto-serialization)
170170bool Optimizer::detect_rewrite_MY_store_int () {
171171 bool first_my_store = op_[0 ]->is_custom () && op_[0 ]->op .starts_with (" MY_store_int" );
@@ -198,14 +198,38 @@ bool Optimizer::detect_rewrite_MY_store_int() {
198198 n_merged++;
199199 }
200200
201- p_ = n_merged;
202- q_ = 2 ;
203- oq_[0 ] = std::make_unique<AsmOp>(AsmOp::IntConst (op_[0 ]->loc , total_number));
204- if (total_number == 0 && total_len == 4 && first_unsigned) { // "STGRAMS" stores four 0-bits cheaper than "4 STUR"
205- oq_[1 ] = std::make_unique<AsmOp>(AsmOp::Custom (op_[0 ]->loc , " STGRAMS" , 1 , 1 ));
206- } else {
201+ // we do not want to always use STSLICECONST; for example, storing "0" 64-bit via x{00...} is more effective
202+ // for a single operation, but in practice, total bytecode becomes larger, which has a cumulative negative effect;
203+ // here is a heuristic "when to use STSLICECONST, when leave PUSHINT + STUR", based on real contracts measurements
204+ bool use_stsliceconst = total_len <= 32 || (total_len <= 48 && total_number >= 256 ) || (total_len <= 64 && total_number >= 65536 )
205+ || (total_len <= 96 && total_number >= (1ULL <<32 )) || (total_number > (1ULL <<62 ));
206+ if (!use_stsliceconst) {
207+ p_ = n_merged;
208+ q_ = 2 ;
209+ oq_[0 ] = std::make_unique<AsmOp>(AsmOp::IntConst (op_[0 ]->loc , total_number));
207210 oq_[1 ] = std::make_unique<AsmOp>(AsmOp::Custom (op_[0 ]->loc , std::to_string (total_len) + (first_unsigned ? " STUR" : " STIR" ), 1 , 1 ));
211+ return true ;
208212 }
213+
214+ p_ = n_merged;
215+ q_ = 1 ;
216+
217+ // output "x{...}" or "b{...}" (if length not divisible by 4)
218+ const td::RefInt256 base = td::make_refint (total_len % 4 == 0 ? 16 : 2 );
219+ const int s_len = base == 16 ? total_len / 4 : total_len;
220+ const char * digits = " 0123456789abcdef" ;
221+
222+ std::string result (s_len + 3 , ' 0' );
223+ result[0 ] = base == 16 ? ' x' : ' b' ;
224+ result[1 ] = ' {' ;
225+ result[s_len + 3 - 1 ] = ' }' ;
226+ for (int i = s_len - 1 ; i >= 0 && total_number != 0 ; --i) {
227+ result[2 + i] = digits[(total_number % base)->to_long ()];
228+ total_number /= base;
229+ }
230+
231+ result += " STSLICECONST" ;
232+ oq_[0 ] = std::make_unique<AsmOp>(AsmOp::Custom (op_[0 ]->loc , result, 0 , 1 ));
209233 return true ;
210234}
211235
0 commit comments