Skip to content

Commit dd490a4

Browse files
committed
VEX ir_opt: keep HashHW bindings packed instead of tombstoning
The guest-state environment used by the redundant Get/Put removal passes is a linear-scan map that only marked deleted bindings as unused, never shrinking. Since the environment is wiped wholesale very often (exits, dirty helpers, CAS, LLSC, MBE, AbiHint, precise-exception memory accesses), every later lookup, insert and overlap invalidation walked the dead slots as well. Keep the bindings packed in [0 .. used-1]: drop the inuse[] array, add deleteHHW() which fills the hole with the last binding, and turn the whole-environment wipes into 'used = 0'. Keys are unique among live bindings, so removing tombstones and reordering slots cannot change which binding a lookup finds.
1 parent ae6bf15 commit dd490a4

1 file changed

Lines changed: 48 additions & 43 deletions

File tree

VEX/priv/ir_opt.c

Lines changed: 48 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,14 @@
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+
177183
typedef
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

201218
static 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

218235
static 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

Comments
 (0)