33use super :: cfg:: { BasicBlock , ControlFlowGraph , Instr } ;
44use crate :: codegen:: Expression ;
55use crate :: sema:: ast:: { Namespace , RetrieveType , Type } ;
6- use solang_parser:: pt:: Loc ;
6+ use solang_parser:: pt:: { Loc , StorageType } ;
77use std:: collections:: { HashMap , HashSet } ;
88use std:: fmt;
99
@@ -51,6 +51,7 @@ enum Transfer {
5151 Store {
5252 def : Definition ,
5353 expr : Option < Expression > ,
54+ storage_type : Option < StorageType > ,
5455 } ,
5556}
5657
@@ -66,8 +67,12 @@ impl fmt::Display for Transfer {
6667 Transfer :: Kill { var_no } => {
6768 write ! ( f, "Kill %{var_no}" )
6869 }
69- Transfer :: Store { def, expr } => {
70- write ! ( f, "Storage: {expr:?} at {def}" )
70+ Transfer :: Store {
71+ def,
72+ expr,
73+ storage_type,
74+ } => {
75+ write ! ( f, "Storage: {expr:?} at {def} (type: {storage_type:?})" )
7176 }
7277 }
7378 }
@@ -76,7 +81,7 @@ impl fmt::Display for Transfer {
7681#[ derive( Clone , PartialEq , Eq ) ]
7782struct ReachingDefs {
7883 vars : HashMap < usize , HashMap < Definition , Option < Expression > > > ,
79- stores : Vec < ( Definition , Expression ) > ,
84+ stores : Vec < ( Definition , Expression , Option < StorageType > ) > ,
8085}
8186
8287type BlockVars = HashMap < usize , Vec < ReachingDefs > > ;
@@ -165,7 +170,11 @@ fn reaching_definitions(cfg: &mut ControlFlowGraph) -> (Vec<Vec<Vec<Transfer>>>,
165170
166171 // merge storage stores
167172 for store in & vars. stores {
168- if !block_vars[ 0 ] . stores . iter ( ) . any ( |( def, _) | * def == store. 0 ) {
173+ if !block_vars[ 0 ]
174+ . stores
175+ . iter ( )
176+ . any ( |( def, _, _) | * def == store. 0 )
177+ {
169178 block_vars[ 0 ] . stores . push ( store. clone ( ) ) ;
170179 changed = true ;
171180 }
@@ -230,7 +239,11 @@ fn instr_transfers(block_no: usize, block: &BasicBlock) -> Vec<Vec<Transfer>> {
230239 // possibly we should check if the function is pure/view and not clear storage references
231240 let mut v = set_var ( res) ;
232241
233- v. push ( Transfer :: Store { def, expr : None } ) ;
242+ v. push ( Transfer :: Store {
243+ def,
244+ expr : None ,
245+ storage_type : None ,
246+ } ) ;
234247
235248 v
236249 }
@@ -256,7 +269,11 @@ fn instr_transfers(block_no: usize, block: &BasicBlock) -> Vec<Vec<Transfer>> {
256269 // A constructor/external call can call us back and modify storage
257270 vec ! [
258271 Transfer :: Kill { var_no: * res } ,
259- Transfer :: Store { def, expr: None } ,
272+ Transfer :: Store {
273+ def,
274+ expr: None ,
275+ storage_type: None ,
276+ } ,
260277 ]
261278 }
262279 Instr :: Store { dest, .. } => {
@@ -277,15 +294,29 @@ fn instr_transfers(block_no: usize, block: &BasicBlock) -> Vec<Vec<Transfer>> {
277294 vec ! [
278295 Transfer :: Kill { var_no: * res } ,
279296 Transfer :: Kill { var_no: * success } ,
280- Transfer :: Store { def, expr: None } ,
297+ Transfer :: Store {
298+ def,
299+ expr: None ,
300+ storage_type: None ,
301+ } ,
281302 ]
282303 }
283- Instr :: SetStorageBytes { storage, .. }
284- | Instr :: ClearStorage { storage, .. }
285- | Instr :: SetStorage { storage, .. } => {
304+ Instr :: SetStorageBytes { storage, .. } | Instr :: ClearStorage { storage, .. } => {
286305 vec ! [ Transfer :: Store {
287306 def,
288307 expr: Some ( storage. clone( ) ) ,
308+ storage_type: None ,
309+ } ]
310+ }
311+ Instr :: SetStorage {
312+ storage,
313+ storage_type,
314+ ..
315+ } => {
316+ vec ! [ Transfer :: Store {
317+ def,
318+ expr: Some ( storage. clone( ) ) ,
319+ storage_type: storage_type. clone( ) ,
289320 } ]
290321 }
291322 Instr :: PopStorage {
@@ -300,11 +331,16 @@ fn instr_transfers(block_no: usize, block: &BasicBlock) -> Vec<Vec<Transfer>> {
300331 Transfer :: Store {
301332 def,
302333 expr: Some ( storage. clone( ) ) ,
334+ storage_type: None ,
303335 } ,
304336 ]
305337 }
306338 Instr :: Return { .. } => {
307- vec ! [ Transfer :: Store { def, expr: None } ]
339+ vec ! [ Transfer :: Store {
340+ def,
341+ expr: None ,
342+ storage_type: None ,
343+ } ]
308344 }
309345 _ => Vec :: new ( ) ,
310346 } ) ;
@@ -402,7 +438,11 @@ fn apply_transfers(
402438 vars. vars . insert ( * var_no, v) ;
403439 }
404440 }
405- Transfer :: Store { def, expr } => {
441+ Transfer :: Store {
442+ def,
443+ expr,
444+ storage_type,
445+ } => {
406446 // store to contract storage. This should kill any equal
407447 let mut eliminated_vars = Vec :: new ( ) ;
408448
@@ -440,7 +480,9 @@ fn apply_transfers(
440480 // all stores should are no longer reaching if they are clobbered by this store
441481 let mut eliminated_stores = Vec :: new ( ) ;
442482
443- for ( no, ( def, storage) ) in vars. stores . iter ( ) . enumerate ( ) {
483+ for ( no, ( def, storage, store_storage_type) ) in
484+ vars. stores . iter ( ) . enumerate ( )
485+ {
444486 let storage_vars = get_vars_at ( def, block_vars) ;
445487
446488 if expression_compare (
@@ -451,6 +493,7 @@ fn apply_transfers(
451493 cfg,
452494 block_vars,
453495 ) == ExpressionCmp :: Equal
496+ && storage_type == store_storage_type
454497 {
455498 eliminated_stores. push ( no) ;
456499 }
@@ -460,7 +503,7 @@ fn apply_transfers(
460503 vars. stores . remove ( no) ;
461504 }
462505
463- vars. stores . push ( ( * def, expr. clone ( ) ) ) ;
506+ vars. stores . push ( ( * def, expr. clone ( ) , storage_type . clone ( ) ) ) ;
464507 } else {
465508 // flush all reaching stores
466509 vars. stores . truncate ( 0 ) ;
@@ -495,7 +538,11 @@ pub fn dead_storage(cfg: &mut ControlFlowGraph, _ns: &mut Namespace) {
495538
496539 match & cfg. blocks [ block_no] . instr [ instr_no] {
497540 Instr :: LoadStorage {
498- res, ty, storage, ..
541+ res,
542+ ty,
543+ storage,
544+ storage_type,
545+ ..
499546 } => {
500547 // is there a definition which has the same storage expression
501548 let mut found = None ;
@@ -519,6 +566,7 @@ pub fn dead_storage(cfg: &mut ControlFlowGraph, _ns: &mut Namespace) {
519566 ) == ExpressionCmp :: Equal
520567 && storage_def. var_no != * res
521568 && ty == storage_def. ty
569+ && storage_type. as_ref ( ) == storage_def. storage_type
522570 {
523571 found = Some ( var_no) ;
524572 break ;
@@ -538,11 +586,12 @@ pub fn dead_storage(cfg: &mut ControlFlowGraph, _ns: &mut Namespace) {
538586 } ,
539587 } ;
540588 } else {
541- for ( def, expr) in & vars. stores {
589+ for ( def, expr, store_storage_type ) in & vars. stores {
542590 let def_vars = get_vars_at ( def, & block_vars) ;
543591
544592 if expression_compare ( storage, vars, expr, & def_vars, cfg, & block_vars)
545593 != ExpressionCmp :: NotEqual
594+ && storage_type == store_storage_type
546595 {
547596 if let Some ( entry) = redundant_stores. get_mut ( def) {
548597 * entry = false ;
@@ -552,7 +601,7 @@ pub fn dead_storage(cfg: &mut ControlFlowGraph, _ns: &mut Namespace) {
552601 }
553602 }
554603 Instr :: PushStorage { storage, .. } | Instr :: PopStorage { storage, .. } => {
555- for ( def, expr) in & vars. stores {
604+ for ( def, expr, _store_storage_type ) in & vars. stores {
556605 let def_vars = get_vars_at ( def, & block_vars) ;
557606
558607 if expression_compare ( storage, vars, expr, & def_vars, cfg, & block_vars)
@@ -585,7 +634,7 @@ pub fn dead_storage(cfg: &mut ControlFlowGraph, _ns: &mut Namespace) {
585634 . iter ( )
586635 . any ( |t| matches ! ( t, Transfer :: Store { expr: None , .. } ) )
587636 {
588- for ( def, _) in & vars. stores {
637+ for ( def, _, _ ) in & vars. stores {
589638 // insert new entry or override existing one
590639 redundant_stores. insert ( * def, false ) ;
591640 }
@@ -613,6 +662,7 @@ struct StorageDef<'a> {
613662 var_no : usize ,
614663 slot : & ' a Expression ,
615664 ty : & ' a Type ,
665+ storage_type : Option < & ' a StorageType > ,
616666}
617667
618668fn get_storage_definition < ' a > (
@@ -625,11 +675,16 @@ fn get_storage_definition<'a>(
625675 {
626676 match & cfg. blocks [ * block_no] . instr [ * instr_no] {
627677 Instr :: LoadStorage {
628- storage, res, ty, ..
678+ storage,
679+ res,
680+ ty,
681+ storage_type,
682+ ..
629683 } => Some ( StorageDef {
630684 var_no : * res,
631685 slot : storage,
632686 ty,
687+ storage_type : storage_type. as_ref ( ) ,
633688 } ) ,
634689 _ => None ,
635690 }
0 commit comments