mem-cache: Avoid write merging if there are reads in between

This CL reworks the logic in the MSHR to make sure we do not coalesce
requests unless there is a series of write requests for the whole
cache block without any other incompatible requests (e.g., read) in
between.

Change-Id: I0b3195858fb33ef85d7aae27376506057dd53ea7
Signed-off-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/23666
Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/src/mem/cache/mshr.cc b/src/mem/cache/mshr.cc
index 4241fa3..1b21546 100644
--- a/src/mem/cache/mshr.cc
+++ b/src/mem/cache/mshr.cc
@@ -111,6 +111,52 @@
     }
 }
 
+void
+MSHR::TargetList::updateWriteFlags(PacketPtr pkt)
+{
+    if (isWholeLineWrite()) {
+        // if we have already seen writes for the full block
+        // stop here, this might be a full line write followed
+        // by other compatible requests (e.g., reads)
+        return;
+    }
+
+    if (canMergeWrites) {
+        if (!pkt->isWrite()) {
+            // We won't allow further merging if this hasn't
+            // been a write
+            canMergeWrites = false;
+            return;
+        }
+
+        // Avoid merging requests with special flags (e.g.,
+        // strictly ordered)
+        const Request::FlagsType no_merge_flags =
+            Request::UNCACHEABLE | Request::STRICT_ORDER |
+            Request::MMAPPED_IPR | Request::PRIVILEGED |
+            Request::LLSC | Request::MEM_SWAP |
+            Request::MEM_SWAP_COND | Request::SECURE;
+        const auto &req_flags = pkt->req->getFlags();
+        bool compat_write = !req_flags.isSet(no_merge_flags);
+
+        // if this is the first write, it might be a whole
+        // line write and even if we can't merge any
+        // subsequent write requests, we still need to service
+        // it as a whole line write (e.g., SECURE whole line
+        // write)
+        bool first_write = empty();
+        if (first_write || compat_write) {
+            auto offset = pkt->getOffset(blkSize);
+            auto begin = writesBitmap.begin() + offset;
+            std::fill(begin, begin + pkt->getSize(), true);
+        }
+
+        // We won't allow further merging if this has been a
+        // special write
+        canMergeWrites &= compat_write;
+    }
+}
+
 inline void
 MSHR::TargetList::add(PacketPtr pkt, Tick readyTime,
                       Counter order, Target::Source source, bool markPending,
diff --git a/src/mem/cache/mshr.hh b/src/mem/cache/mshr.hh
index 40eb970..685064f 100644
--- a/src/mem/cache/mshr.hh
+++ b/src/mem/cache/mshr.hh
@@ -227,38 +227,7 @@
          *
          * @param pkt Packet considered for adding
          */
-        void
-        updateWriteFlags(PacketPtr pkt)
-        {
-            // if we have already seen writes for the full block stop
-            // here, this might be a full line write followed by
-            // other compatible requests (e.g., reads)
-            if (!isWholeLineWrite()) {
-                // Avoid merging requests with special flags (e.g.,
-                // strictly ordered)
-                const Request::FlagsType no_merge_flags =
-                    Request::UNCACHEABLE | Request::STRICT_ORDER |
-                    Request::MMAPPED_IPR | Request::PRIVILEGED |
-                    Request::LLSC | Request::MEM_SWAP |
-                    Request::MEM_SWAP_COND | Request::SECURE;
-                const auto &req_flags = pkt->req->getFlags();
-                bool compat_write = pkt->isWrite() &&
-                    !req_flags.isSet(no_merge_flags);
-                canMergeWrites &= compat_write;
-
-                // if this request is the first target in this list
-                // and additionally a whole-line write, we need to
-                // service it as a whole-line even if we won't allow
-                // any further merging (e.g., SECURE whole line
-                // write).
-                bool first_write = pkt->isWrite() && (size() == 0);
-                if (first_write || compat_write) {
-                    auto offset = pkt->getOffset(blkSize);
-                    auto begin = writesBitmap.begin() + offset;
-                    std::fill(begin, begin + pkt->getSize(), true);
-                }
-            }
-         }
+        void updateWriteFlags(PacketPtr pkt);
 
         /**
          * Tests if the flags of this TargetList have their default