mem-cache: Add encoding bits to the data of multi compressors

When compressing using a multi-compressor, one must be able to
identify which sub-compressor should be used to decompress data.
This can be achieved by either adding encoding bits to block's
tag or data entry.

It was previously assumed that these encoding bits would be added
to the tag, but now make it a parameter that defaults to the data
entry.

Change-Id: Id322425e7a6ad59cb2ec7a4167a43de4c55c482c
Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/33380
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/src/mem/cache/compressors/Compressors.py b/src/mem/cache/compressors/Compressors.py
index 1c47ac1..f7e8a7d 100644
--- a/src/mem/cache/compressors/Compressors.py
+++ b/src/mem/cache/compressors/Compressors.py
@@ -113,6 +113,9 @@
     # since these compressors have many overlapping patterns
     compressors = VectorParam.BaseCacheCompressor([CPack(), FPCD()],
         "Array of compressors")
+    encoding_in_tags = Param.Bool(False, "If set the bits to inform which "
+        "sub-compressor compressed some data are added to its corresponding "
+        "tag entry.")
 
 class PerfectCompressor(BaseCacheCompressor):
     type = 'PerfectCompressor'
diff --git a/src/mem/cache/compressors/multi.cc b/src/mem/cache/compressors/multi.cc
index 51dbc2b..bb98dcd 100644
--- a/src/mem/cache/compressors/multi.cc
+++ b/src/mem/cache/compressors/multi.cc
@@ -59,6 +59,8 @@
 
 Multi::Multi(const Params *p)
   : Base(p), compressors(p->compressors),
+    numEncodingBits(p->encoding_in_tags ? 0 :
+        std::log2(alignToPowerOfTwo(compressors.size()))),
     multiStats(stats, *this)
 {
     fatal_if(compressors.size() == 0, "There must be at least one compressor");
@@ -128,6 +130,8 @@
         Cycles temp_decomp_lat;
         auto temp_comp_data =
             compressors[i]->compress(data, comp_lat, temp_decomp_lat);
+        temp_comp_data->setSizeBits(temp_comp_data->getSizeBits() +
+            numEncodingBits);
         results.push(std::make_shared<Results>(i, std::move(temp_comp_data),
             temp_decomp_lat, blkSize));
         max_comp_lat = std::max(max_comp_lat, comp_lat);
diff --git a/src/mem/cache/compressors/multi.hh b/src/mem/cache/compressors/multi.hh
index 095dd03..868682f 100644
--- a/src/mem/cache/compressors/multi.hh
+++ b/src/mem/cache/compressors/multi.hh
@@ -58,6 +58,23 @@
     /** List of sub-compressors. */
     std::vector<Base*> compressors;
 
+    /**
+     * An encoding is associated to each sub-compressor to inform which
+     * sub-compressor to use when decompressing data. This information can
+     * be added either to the tag entry, in which case no extra bits are
+     * added to the compressed data (numEncodingBits = 0), or to the
+     * compressed data itself.
+     *
+     * There is no encoding reserved for the uncompressed case; it is assumed
+     * that an "is compressed" bit is stored in the tags. Therefore, even if
+     * storing the encoding within the compressed data, these extra bits are
+     * not added when the data is uncompressible.
+     *
+     * These extra bits are taken into account when thresholding the
+     * compressed data's size.
+     */
+    const std::size_t numEncodingBits;
+
     struct MultiStats : public Stats::Group
     {
         const Multi& compressor;