@@ -310,40 +310,205 @@ class DismantleExpression : public Transform {
310
310
const IR::Node* preorder (IR::LAnd* expression) override { return shortCircuit (expression); }
311
311
const IR::Node* preorder (IR::LOr* expression) override { return shortCircuit (expression); }
312
312
313
- // We don't want to compute the full read/write set here so we
314
- // overapproximate it as follows: all declarations that occur in
315
- // an expression.
316
- // TODO: this could be made more precise, perhaps using LocationSets.
317
- class ReadsWrites : public Inspector {
313
+ // / This class represents the path to a location.
314
+ // / Given a struct S { bit a; bit b; } and a variable S x;
315
+ // / a path can be x.a, or just x. An array index is represented as a
316
+ // / number (encoded as a string) or as "*", denoting an unknown index.
317
+ struct LocationPath : public IHasDbPrint {
318
+ const IR::IDeclaration* root;
319
+ std::vector<cstring> path;
320
+
321
+ explicit LocationPath (const IR::IDeclaration* root): root(root) { CHECK_NULL (root); }
322
+
323
+ const LocationPath* append (cstring suffix) const {
324
+ auto result = new LocationPath (root);
325
+ result->path = path;
326
+ result->path .push_back (suffix);
327
+ return result;
328
+ }
329
+
330
+ // / True if this path is a prefix of other or the other way around
331
+ bool isPrefix (const LocationPath* other) const {
332
+ // Due to the structure of the P4 language, two distinct
333
+ // declarations can never alias.
334
+ if (root != other->root )
335
+ return false ;
336
+ size_t len = std::min (path.size (), other->path .size ());
337
+ for (size_t i = 0 ; i < len; i++) {
338
+ if (path.at (i) == " *" || other->path .at (i) == " *" )
339
+ continue ;
340
+ if (path.at (i) != other->path .at (i))
341
+ return false ;
342
+ }
343
+ return true ;
344
+ }
345
+
346
+ void dbprint (std::ostream& out) const override {
347
+ out << root->getName ();
348
+ for (auto p : path)
349
+ out << " ." << p;
350
+ }
351
+ };
352
+
353
+ // / We represent a set of location set as a set of LocationPath
354
+ // / objects.
355
+ class SetOfLocations : public IHasDbPrint {
318
356
public:
319
- std::set<const IR::IDeclaration*> decls;
320
- ReferenceMap* refMap;
357
+ std::set<const LocationPath*> paths;
358
+
359
+ SetOfLocations () = default ;
360
+ explicit SetOfLocations (const LocationPath* path) {
361
+ add (path);
362
+ }
363
+ explicit SetOfLocations (const SetOfLocations* set): paths(set->paths) {}
364
+
365
+ void add (const LocationPath* path) { paths.emplace (path); }
366
+ bool overlaps (const SetOfLocations* other) const {
367
+ // Normally one of these sets has only one element, because
368
+ // one of the two is a left-value, so this should be fast.
369
+ for (auto s : paths) {
370
+ for (auto so : other->paths ) {
371
+ if (s->isPrefix (so))
372
+ return true ;
373
+ }
374
+ }
375
+ return false ;
376
+ }
377
+
378
+ const SetOfLocations* join (const SetOfLocations* other) const {
379
+ auto result = new SetOfLocations (this );
380
+ for (auto p : other->paths )
381
+ result->add (p);
382
+ return result;
383
+ }
384
+
385
+ // / Append suffix to each location in the set
386
+ const SetOfLocations* append (cstring suffix) const {
387
+ auto result = new SetOfLocations ();
388
+ for (auto p : paths) {
389
+ auto append = p->append (suffix);
390
+ result->add (append);
391
+ }
392
+ return result;
393
+ }
321
394
322
- explicit ReadsWrites (ReferenceMap* refMap) : refMap(refMap)
395
+ void dbprint (std::ostream& out) const override {
396
+ for (auto p : paths)
397
+ out << p << std::endl;
398
+ }
399
+ };
400
+
401
+ // / Computes the SetOfLocations read and written by an expression.
402
+ // / This is invoked only for expressions that appear as arguments
403
+ // / to method calls.
404
+ class ReadsWrites : public Inspector {
405
+ const ReferenceMap* refMap;
406
+ std::map<const IR::Expression*, const SetOfLocations*> rw;
407
+
408
+ public:
409
+ explicit ReadsWrites (const ReferenceMap* refMap) : refMap(refMap)
323
410
{ setName (" ReadsWrites" ); }
324
411
412
+ void postorder (const IR::Operation_Binary* expression) override {
413
+ auto left = ::get (rw, expression->left );
414
+ auto right = ::get (rw, expression->right );
415
+ rw.emplace (expression, left->join (right));
416
+ }
417
+
325
418
void postorder (const IR::PathExpression* expression) override {
326
419
auto decl = refMap->getDeclaration (expression->path );
327
- decls.emplace (decl);
420
+ auto path = new LocationPath (decl);
421
+ auto locs = new SetOfLocations (path);
422
+ rw.emplace (expression, locs);
423
+ }
424
+
425
+ void postorder (const IR::Operation_Unary* expression) override {
426
+ auto e = ::get (rw, expression->expr );
427
+ rw.emplace (expression, e);
428
+ }
429
+
430
+ void postorder (const IR::Member* expression) override {
431
+ auto e = ::get (rw, expression->expr );
432
+ auto result = e->append (expression->member );
433
+ rw.emplace (expression, result);
434
+ }
435
+
436
+ void postorder (const IR::ArrayIndex* expression) override {
437
+ auto e = ::get (rw, expression->left );
438
+ const SetOfLocations* result;
439
+ if (expression->right ->is <IR::Constant>()) {
440
+ int index = expression->right ->to <IR::Constant>()->asInt ();
441
+ result = e->append (Util::toString (index ));
442
+ } else {
443
+ result = e->append (" *" );
444
+ }
445
+ rw.emplace (expression, result);
446
+ }
447
+
448
+ void postorder (const IR::Literal* expression) override {
449
+ rw.emplace (expression, new SetOfLocations ());
450
+ }
451
+
452
+ void postorder (const IR::TypeNameExpression* expression) override {
453
+ rw.emplace (expression, new SetOfLocations ());
454
+ }
455
+
456
+ void postorder (const IR::Operation_Ternary* expression) override {
457
+ auto e0 = ::get (rw, expression->e0 );
458
+ auto e1 = ::get (rw, expression->e1 );
459
+ auto e2 = ::get (rw, expression->e2 );
460
+ rw.emplace (expression, e0 ->join (e1 )->join (e2 ));
461
+ }
462
+
463
+ void postorder (const IR::MethodCallExpression* expression) override {
464
+ // The only expression that can appear here is h.isValid();
465
+ // The ReadsWrites analysis is not called for other methods that
466
+ // have side-effects -- these are always copied into temporaries.
467
+ BUG_CHECK (expression->method ->is <IR::Member>(),
468
+ " %1%: expected isValid()" , expression);
469
+ auto member = expression->method ->to <IR::Member>();
470
+ BUG_CHECK (member->member == " isValid" , " %1%: expected isValid()" , expression);
471
+ auto obj = member->expr ;
472
+ auto e = ::get (rw, obj);
473
+ rw.emplace (expression, e->append (" $valid" ));
474
+ }
475
+
476
+ void postorder (const IR::ConstructorCallExpression* expression) override {
477
+ const SetOfLocations* result = new SetOfLocations ();
478
+ for (auto e : *expression->arguments ) {
479
+ auto s = ::get (rw, e);
480
+ result = result->join (s);
481
+ }
482
+ rw.emplace (expression, result);
483
+ }
484
+
485
+ void postorder (const IR::ListExpression* expression) override {
486
+ const SetOfLocations* result = new SetOfLocations ();
487
+ for (auto e : expression->components ) {
488
+ auto s = ::get (rw, e);
489
+ result = result->join (s);
490
+ }
491
+ rw.emplace (expression, result);
492
+ }
493
+
494
+ const SetOfLocations* get (const IR::Expression* expression) {
495
+ expression->apply (*this );
496
+ auto result = ::get (rw, expression);
497
+ CHECK_NULL (result);
498
+ LOG3 (" SetOfLocations(" << expression << " )=" << result);
499
+ return result;
328
500
}
329
501
};
330
502
331
503
// Conservative alias analysis. We implement this here because this pass
332
504
// runs early in the front end, before enough information is present (eg.
333
505
// def-use information) to do a precise alias analysis.
334
506
bool mayAlias (const IR::Expression* left, const IR::Expression* right) const {
335
- ReadsWrites rwleft (refMap);
336
- (void )left->apply (rwleft);
337
- ReadsWrites rwright (refMap);
338
- (void )right->apply (rwright);
339
-
340
- for (auto d : rwleft.decls ) {
341
- if (rwright.decls .count (d) > 0 ) {
342
- LOG3 (dbp (d) << " accessed by both " << dbp (left) << " and " << dbp (right));
343
- return true ;
344
- }
345
- }
346
- return false ;
507
+ ReadsWrites rw (refMap);
508
+ auto llocs = rw.get (left);
509
+ auto rlocs = rw.get (right);
510
+ LOG3 (" Checking overlap between " << llocs << " and " << rlocs);
511
+ return llocs->overlaps (rlocs);
347
512
}
348
513
349
514
// / Returns true if type is a header or a struct containing a header.
@@ -430,6 +595,10 @@ class DismantleExpression : public Transform {
430
595
break ;
431
596
if (!p1->hasOut () && !p2->hasOut ())
432
597
continue ;
598
+ if (useTemporary.find (p1) != useTemporary.end ())
599
+ continue ;
600
+ if (useTemporary.find (p2) != useTemporary.end ())
601
+ continue ;
433
602
auto arg2 = desc.substitution .lookup (p2);
434
603
if (mayAlias (arg1, arg2)) {
435
604
LOG3 (" Using temporary for " << dbp (mce) <<
0 commit comments