174174 hashing, but it's not clear whether or not this would really be any
175175 faster. */
176176
177+ /* The bindings are kept packed in [0 .. used-1]: deleting a binding
178+ moves the last one into the hole rather than leaving a tombstone
179+ behind. That keeps every scan proportional to the number of live
180+ bindings, which matters because the environments are wiped wholesale
181+ (see the |used = 0| sites below) far more often than they are read. */
182+
177183typedef
178184 struct {
179- Bool * inuse ;
180185 HWord * key ;
181186 HWord * val ;
182187 Int size ;
@@ -189,21 +194,33 @@ static HashHW* newHHW ( void )
189194 HashHW * h = LibVEX_Alloc_inline (sizeof (HashHW ));
190195 h -> size = 8 ;
191196 h -> used = 0 ;
192- h -> inuse = LibVEX_Alloc_inline (h -> size * sizeof (Bool ));
193197 h -> key = LibVEX_Alloc_inline (h -> size * sizeof (HWord ));
194198 h -> val = LibVEX_Alloc_inline (h -> size * sizeof (HWord ));
195199 return h ;
196200}
197201
198202
203+ /* Delete the binding at index i. The map is unordered, so the hole is
204+ filled with the last binding. Callers iterating over the map must
205+ therefore re-examine index i afterwards. */
206+
207+ static inline void deleteHHW ( HashHW * h , Int i )
208+ {
209+ vassert (i >= 0 && i < h -> used );
210+ h -> used -- ;
211+ h -> key [i ] = h -> key [h -> used ];
212+ h -> val [i ] = h -> val [h -> used ];
213+ }
214+
215+
199216/* Look up key in the map. */
200217
201218static Bool lookupHHW ( const HashHW * h , /*OUT*/ HWord * val , HWord key )
202219{
203220 Int i ;
204221 /* vex_printf("lookupHHW(%llx)\n", key ); */
205222 for (i = 0 ; i < h -> used ; i ++ ) {
206- if (h -> inuse [ i ] && h -> key [i ] == key ) {
223+ if (h -> key [i ] == key ) {
207224 if (val )
208225 * val = h -> val [i ];
209226 return True ;
@@ -217,12 +234,12 @@ static Bool lookupHHW ( const HashHW* h, /*OUT*/HWord* val, HWord key )
217234
218235static void addToHHW ( HashHW * h , HWord key , HWord val )
219236{
220- Int i , j ;
237+ Int i ;
221238 /* vex_printf("addToHHW(%llx, %llx)\n", key, val); */
222239
223240 /* Find and replace existing binding, if any. */
224241 for (i = 0 ; i < h -> used ; i ++ ) {
225- if (h -> inuse [ i ] && h -> key [i ] == key ) {
242+ if (h -> key [i ] == key ) {
226243 h -> val [i ] = val ;
227244 return ;
228245 }
@@ -231,26 +248,19 @@ static void addToHHW ( HashHW* h, HWord key, HWord val )
231248 /* Ensure a space is available. */
232249 if (h -> used == h -> size ) {
233250 /* Copy into arrays twice the size. */
234- Bool * inuse2 = LibVEX_Alloc_inline (2 * h -> size * sizeof (Bool ));
235251 HWord * key2 = LibVEX_Alloc_inline (2 * h -> size * sizeof (HWord ));
236252 HWord * val2 = LibVEX_Alloc_inline (2 * h -> size * sizeof (HWord ));
237- for (i = j = 0 ; i < h -> size ; i ++ ) {
238- if (!h -> inuse [i ]) continue ;
239- inuse2 [j ] = True ;
240- key2 [j ] = h -> key [i ];
241- val2 [j ] = h -> val [i ];
242- j ++ ;
253+ for (i = 0 ; i < h -> used ; i ++ ) {
254+ key2 [i ] = h -> key [i ];
255+ val2 [i ] = h -> val [i ];
243256 }
244- h -> used = j ;
245257 h -> size *= 2 ;
246- h -> inuse = inuse2 ;
247258 h -> key = key2 ;
248259 h -> val = val2 ;
249260 }
250261
251262 /* Finally, add it. */
252263 vassert (h -> used < h -> size );
253- h -> inuse [h -> used ] = True ;
254264 h -> key [h -> used ] = key ;
255265 h -> val [h -> used ] = val ;
256266 h -> used ++ ;
@@ -594,17 +604,16 @@ static void invalidateOverlaps ( HashHW* h, UInt k_lo, UInt k_hi )
594604 .. k_hi) */
595605 /* vex_printf("invalidate %d .. %d\n", k_lo, k_hi ); */
596606
597- for (j = 0 ; j < h -> used ; j ++ ) {
598- if (!h -> inuse [j ])
599- continue ;
607+ for (j = 0 ; j < h -> used ; /* see below */ ) {
600608 e_lo = (((UInt )h -> key [j ]) >> 16 ) & 0xFFFF ;
601609 e_hi = ((UInt )h -> key [j ]) & 0xFFFF ;
602610 vassert (e_lo <= e_hi );
603611 if (e_hi < k_lo || k_hi < e_lo )
604- continue ; /* no overlap possible */
612+ j ++ ; /* no overlap possible */
605613 else
606- /* overlap; invalidate */
607- h -> inuse [j ] = False ;
614+ /* overlap; invalidate. The last binding is moved into slot j,
615+ so re-examine j rather than advancing. */
616+ deleteHHW (h , j );
608617 }
609618}
610619
@@ -686,8 +695,7 @@ static void redundant_get_removal_BB ( IRSB* bb )
686695 }
687696 if (writes ) {
688697 /* dump the entire env (not clever, but correct ...) */
689- for (j = 0 ; j < env -> used ; j ++ )
690- env -> inuse [j ] = False ;
698+ env -> used = 0 ;
691699 if (0 ) vex_printf ("rGET: trash env due to dirty helper\n" );
692700 }
693701 }
@@ -772,8 +780,7 @@ static void handle_gets_Stmt (
772780 case Ist_Dirty :
773781 case Ist_CAS :
774782 case Ist_LLSC :
775- for (j = 0 ; j < env -> used ; j ++ )
776- env -> inuse [j ] = False ;
783+ env -> used = 0 ;
777784 break ;
778785
779786 /* all other cases are boring. */
@@ -831,8 +838,7 @@ static void handle_gets_Stmt (
831838 case VexRegUpdAllregsAtMemAccess :
832839 /* Precise exceptions required at mem access.
833840 Flush all guest state. */
834- for (j = 0 ; j < env -> used ; j ++ )
835- env -> inuse [j ] = False ;
841+ env -> used = 0 ;
836842 break ;
837843 case VexRegUpdSpAtMemAccess :
838844 /* We need to dump the stack pointer
@@ -841,15 +847,15 @@ static void handle_gets_Stmt (
841847 to verify only the sp is to be checked. */
842848 /* fallthrough */
843849 case VexRegUpdUnwindregsAtMemAccess :
844- for (j = 0 ; j < env -> used ; j ++ ) {
845- if (!env -> inuse [j ])
846- continue ;
850+ for (j = 0 ; j < env -> used ; /* see below */ ) {
847851 /* Just flush the minimal amount required, as computed by
848852 preciseMemExnsFn. */
849853 HWord k_lo = (env -> key [j ] >> 16 ) & 0xFFFF ;
850854 HWord k_hi = env -> key [j ] & 0xFFFF ;
851855 if (preciseMemExnsFn ( k_lo , k_hi , pxControl ))
852- env -> inuse [j ] = False ;
856+ deleteHHW (env , j ); /* re-examine slot j */
857+ else
858+ j ++ ;
853859 }
854860 break ;
855861 case VexRegUpdAllregsAtEachInsn :
@@ -886,7 +892,7 @@ static void redundant_put_removal_BB (
886892 VexRegisterUpdates pxControl
887893 )
888894{
889- Int i , j ;
895+ Int i ;
890896 Bool isPut ;
891897 IRStmt * st ;
892898 UInt key = 0 ; /* keep gcc -O happy */
@@ -931,8 +937,7 @@ static void redundant_put_removal_BB (
931937 // typeOfIRConst(st->Ist.Exit.dst));
932938 //re_add = lookupHHW(env, NULL, key);
933939 /* (2) */
934- for (j = 0 ; j < env -> used ; j ++ )
935- env -> inuse [j ] = False ;
940+ env -> used = 0 ;
936941 /* (3) */
937942 //if (0 && re_add)
938943 // addToHHW(env, (HWord)key, 0);
@@ -4578,12 +4583,12 @@ static Bool do_cse_BB ( IRSB* bb, Bool allowLoadsToBeCSEd )
45784583 }
45794584
45804585 if (paranoia > 0 ) {
4581- for (j = 0 ; j < aenv -> used ; j ++ ) {
4582- if (!aenv -> inuse [j ])
4583- continue ;
4586+ for (j = 0 ; j < aenv -> used ; /* see below */ ) {
45844587 ae = (AvailExpr * )aenv -> key [j ];
4585- if (ae -> tag != GetIt && ae -> tag != Load )
4588+ if (ae -> tag != GetIt && ae -> tag != Load ) {
4589+ j ++ ;
45864590 continue ;
4591+ }
45874592 invalidate = False ;
45884593 if (paranoia >= 2 ) {
45894594 invalidate = True ;
@@ -4623,10 +4628,10 @@ static Bool do_cse_BB ( IRSB* bb, Bool allowLoadsToBeCSEd )
46234628 vpanic ("do_cse_BB(2)" );
46244629 }
46254630
4626- if (invalidate ) {
4627- aenv -> inuse [ j ] = False ;
4628- aenv -> key [ j ] = ( HWord ) NULL ; /* be sure */
4629- }
4631+ if (invalidate )
4632+ deleteHHW ( aenv , j ); /* re-examine slot j */
4633+ else
4634+ j ++ ;
46304635 } /* for j */
46314636 } /* paranoia > 0 */
46324637
@@ -4649,7 +4654,7 @@ static Bool do_cse_BB ( IRSB* bb, Bool allowLoadsToBeCSEd )
46494654
46504655 /* search aenv for eprime, unfortunately the hard way */
46514656 for (j = 0 ; j < aenv -> used ; j ++ )
4652- if (aenv -> inuse [ j ] && eq_AvailExpr (eprime , (AvailExpr * )aenv -> key [j ]))
4657+ if (eq_AvailExpr (eprime , (AvailExpr * )aenv -> key [j ]))
46534658 break ;
46544659
46554660 if (j < aenv -> used ) {
0 commit comments