mem-cache: Templatize DictionaryCompressor
authorDaniel R. Carvalho <odanrc@yahoo.com.br>
Thu, 5 Sep 2019 15:39:38 +0000 (17:39 +0200)
committerDaniel Carvalho <odanrc@yahoo.com.br>
Tue, 29 Oct 2019 21:32:02 +0000 (21:32 +0000)
Templatize DictionaryCompressor so that the dictionary entries' sizes
can be changed.

Change-Id: I3d89e3c692a721cefcd7e3c55d2ccdefa425f614
Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/21148
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu>
Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>

src/mem/cache/compressors/Compressors.py
src/mem/cache/compressors/SConscript
src/mem/cache/compressors/base_dictionary_compressor.cc [new file with mode: 0644]
src/mem/cache/compressors/cpack.cc
src/mem/cache/compressors/cpack.hh
src/mem/cache/compressors/dictionary_compressor.cc [deleted file]
src/mem/cache/compressors/dictionary_compressor.hh
src/mem/cache/compressors/dictionary_compressor_impl.hh [new file with mode: 0644]

index b6315ad8d64ae4783cb1ebeb1a75834b341717a5..4ed72190c0b6ace92c503909dda122adc3300fe5 100644 (file)
@@ -40,6 +40,14 @@ class BaseCacheCompressor(SimObject):
         "in bytes, in which a block must be compressed to. Otherwise it is "
         "stored in its uncompressed state")
 
+class BaseDictionaryCompressor(BaseCacheCompressor):
+    type = 'BaseDictionaryCompressor'
+    abstract = True
+    cxx_header = "mem/cache/compressors/dictionary_compressor.hh"
+
+    dictionary_size = Param.Int(Parent.cache_line_size,
+        "Number of dictionary entries")
+
 class BDI(BaseCacheCompressor):
     type = 'BDI'
     cxx_class = 'BDI'
@@ -49,15 +57,7 @@ class BDI(BaseCacheCompressor):
         "combinations of base and delta for the compressors. False if using" \
         "only the lowest possible delta size for each base size.");
 
-class DictionaryCompressor(BaseCacheCompressor):
-    type = 'DictionaryCompressor'
-    abstract = True
-    cxx_header = "mem/cache/compressors/dictionary_compressor.hh"
-
-    dictionary_size = Param.Int(Parent.cache_line_size,
-        "Number of dictionary entries")
-
-class CPack(DictionaryCompressor):
+class CPack(BaseDictionaryCompressor):
     type = 'CPack'
     cxx_class = 'CPack'
     cxx_header = "mem/cache/compressors/cpack.hh"
index 68cf7ef10df3209cb653ddb0164a2428adf52bbe..052dbe04fb52da55b76511ba32244744f21f9f4a 100644 (file)
@@ -33,6 +33,6 @@ Import('*')
 SimObject('Compressors.py')
 
 Source('base.cc')
+Source('base_dictionary_compressor.cc')
 Source('bdi.cc')
 Source('cpack.cc')
-Source('dictionary_compressor.cc')
diff --git a/src/mem/cache/compressors/base_dictionary_compressor.cc b/src/mem/cache/compressors/base_dictionary_compressor.cc
new file mode 100644 (file)
index 0000000..e41d875
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018-2019 Inria
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Daniel Carvalho
+ */
+
+/** @file
+ * Implementation of a base sim object for the templated dictionary-based
+ * cache compressor.
+ */
+
+#include "mem/cache/compressors/dictionary_compressor.hh"
+#include "params/BaseDictionaryCompressor.hh"
+
+BaseDictionaryCompressor::BaseDictionaryCompressor(const Params *p)
+    : BaseCacheCompressor(p), dictionarySize(p->dictionary_size), numEntries(0)
+{
+}
+
+void
+BaseDictionaryCompressor::regStats()
+{
+    BaseCacheCompressor::regStats();
+
+    // We store the frequency of each pattern
+    patternStats
+        .init(getNumPatterns())
+        .name(name() + ".pattern")
+        .desc("Number of data entries that were compressed to this pattern.")
+        ;
+
+    for (unsigned i = 0; i < getNumPatterns(); ++i) {
+        patternStats.subname(i, getName(i));
+        patternStats.subdesc(i, "Number of data entries that match pattern " +
+                                getName(i));
+    }
+}
index 9e0cc2d4203d18ca4c46351ad01debbf0c93466f..5603b0bf6d45574d3d2ac8c98b8db5c6a19b53e1 100644 (file)
 
 #include "mem/cache/compressors/cpack.hh"
 
+#include "mem/cache/compressors/dictionary_compressor_impl.hh"
 #include "params/CPack.hh"
 
 CPack::CPack(const Params *p)
-    : DictionaryCompressor(p)
+    : DictionaryCompressor<uint32_t>(p)
 {
 }
 
 void
-CPack::addToDictionary(std::array<uint8_t, 4> data)
+CPack::addToDictionary(DictionaryEntry data)
 {
     assert(numEntries < dictionarySize);
     dictionary[numEntries++] = data;
@@ -52,7 +53,7 @@ std::unique_ptr<BaseCacheCompressor::CompressionData>
 CPack::compress(const uint64_t* data, Cycles& comp_lat, Cycles& decomp_lat)
 {
     std::unique_ptr<BaseCacheCompressor::CompressionData> comp_data =
-        DictionaryCompressor::compress(data);
+        DictionaryCompressor<uint32_t>::compress(data);
 
     // Set compression latency (Accounts for pattern matching, length
     // generation, packaging and shifting)
index bd258b3727b741a946efd3572b1223d1ff0bbfe4..75a091c276f8a667bcf6006fede1c24df4961b53 100644 (file)
@@ -36,7 +36,6 @@
 #ifndef __MEM_CACHE_COMPRESSORS_CPACK_HH__
 #define __MEM_CACHE_COMPRESSORS_CPACK_HH__
 
-#include <array>
 #include <cstdint>
 #include <map>
 #include <memory>
 
 struct CPackParams;
 
-class CPack : public DictionaryCompressor
+class CPack : public DictionaryCompressor<uint32_t>
 {
   private:
+    using DictionaryEntry = DictionaryCompressor<uint32_t>::DictionaryEntry;
+
     // Forward declaration of all possible patterns
     class PatternZZZZ;
     class PatternXXXX;
@@ -88,14 +89,14 @@ class CPack : public DictionaryCompressor
     };
 
     std::unique_ptr<Pattern> getPattern(
-        const std::array<uint8_t, 4>& bytes,
-        const std::array<uint8_t, 4>& dict_bytes,
+        const DictionaryEntry& bytes,
+        const DictionaryEntry& dict_bytes,
         const int match_location) const override
     {
         return PatternFactory::getPattern(bytes, dict_bytes, match_location);
     }
 
-    void addToDictionary(std::array<uint8_t, 4> data) override;
+    void addToDictionary(DictionaryEntry data) override;
 
     /**
      * Apply compression.
@@ -126,19 +127,19 @@ class CPack : public DictionaryCompressor
 class CPack::PatternZZZZ : public DictionaryCompressor::Pattern
 {
   public:
-    PatternZZZZ(const std::array<uint8_t, 4> bytes, const int match_location)
+    PatternZZZZ(const DictionaryEntry bytes, const int match_location)
         : Pattern(ZZZZ, 0x0, 2, 0, 0, false) {}
 
-    static bool isPattern(const std::array<uint8_t, 4>& bytes,
-                          const std::array<uint8_t, 4>& dict_bytes,
-                          const int match_location)
+    static bool isPattern(const DictionaryEntry& bytes,
+        const DictionaryEntry& dict_bytes,
+        const int match_location)
     {
         return (bytes[3] == 0) && (bytes[2] == 0) && (bytes[1] == 0) &&
                (bytes[0] == 0);
     }
 
-    std::array<uint8_t, 4>
-    decompress(const std::array<uint8_t, 4> dict_bytes) const override
+    DictionaryEntry
+    decompress(const DictionaryEntry dict_bytes) const override
     {
         return {0, 0, 0, 0};
     }
@@ -150,23 +151,23 @@ class CPack::PatternXXXX : public DictionaryCompressor::Pattern
     /**
      * A copy of the word.
      */
-    const std::array<uint8_t, 4> bytes;
+    const DictionaryEntry bytes;
 
   public:
-    PatternXXXX(const std::array<uint8_t, 4> bytes, const int match_location)
+    PatternXXXX(const DictionaryEntry bytes, const int match_location)
         : Pattern(XXXX, 0x1, 2, 4, 0, true), bytes(bytes) {}
 
-    static bool isPattern(const std::array<uint8_t, 4>& bytes,
-                          const std::array<uint8_t, 4>& dict_bytes,
-                          const int match_location)
+    static bool isPattern(const DictionaryEntry& bytes,
+        const DictionaryEntry& dict_bytes,
+        const int match_location)
     {
         // It can always be an unmatch, as it is set to this class when other
         // patterns fail
         return true;
     }
 
-    std::array<uint8_t, 4>
-    decompress(const std::array<uint8_t, 4> dict_bytes) const override
+    DictionaryEntry
+    decompress(const DictionaryEntry dict_bytes) const override
     {
         return bytes;
     }
@@ -175,18 +176,18 @@ class CPack::PatternXXXX : public DictionaryCompressor::Pattern
 class CPack::PatternMMMM : public DictionaryCompressor::Pattern
 {
   public:
-    PatternMMMM(const std::array<uint8_t, 4> bytes, const int match_location)
+    PatternMMMM(const DictionaryEntry bytes, const int match_location)
         : Pattern(MMMM, 0x2, 6, 0, match_location, true) {}
 
-    static bool isPattern(const std::array<uint8_t, 4>& bytes,
-                          const std::array<uint8_t, 4>& dict_bytes,
-                          const int match_location)
+    static bool isPattern(const DictionaryEntry& bytes,
+        const DictionaryEntry& dict_bytes,
+        const int match_location)
     {
         return (bytes == dict_bytes) && (match_location >= 0);
     }
 
-    std::array<uint8_t, 4>
-    decompress(const std::array<uint8_t, 4> dict_bytes) const override
+    DictionaryEntry
+    decompress(const DictionaryEntry dict_bytes) const override
     {
         return dict_bytes;
     }
@@ -202,13 +203,13 @@ class CPack::PatternMMXX : public DictionaryCompressor::Pattern
     const uint8_t byte1;
 
   public:
-    PatternMMXX(const std::array<uint8_t, 4> bytes, const int match_location)
+    PatternMMXX(const DictionaryEntry bytes, const int match_location)
         : Pattern(MMXX, 0xC, 8, 2, match_location, true),
                   byte0(bytes[0]), byte1(bytes[1]) {}
 
-    static bool isPattern(const std::array<uint8_t, 4>& bytes,
-                          const std::array<uint8_t, 4>& dict_bytes,
-                          const int match_location)
+    static bool isPattern(const DictionaryEntry& bytes,
+        const DictionaryEntry& dict_bytes,
+        const int match_location)
     {
         // Notice we don't compare bytes[0], as otherwise we'd be unnecessarily
         // discarding MMXM. If that pattern is added this should be modified
@@ -217,8 +218,8 @@ class CPack::PatternMMXX : public DictionaryCompressor::Pattern
 
     }
 
-    std::array<uint8_t, 4>
-    decompress(const std::array<uint8_t, 4> dict_bytes) const override
+    DictionaryEntry
+    decompress(const DictionaryEntry dict_bytes) const override
     {
         return {byte0, byte1, dict_bytes[2], dict_bytes[3]};
     }
@@ -233,19 +234,19 @@ class CPack::PatternZZZX : public DictionaryCompressor::Pattern
     const uint8_t byte;
 
   public:
-    PatternZZZX(const std::array<uint8_t, 4> bytes, const int match_location)
+    PatternZZZX(const DictionaryEntry bytes, const int match_location)
         : Pattern(ZZZX, 0xD, 4, 1, 0, false), byte(bytes[0]) {}
 
-    static bool isPattern(const std::array<uint8_t, 4>& bytes,
-                          const std::array<uint8_t, 4>& dict_bytes,
-                          const int match_location)
+    static bool isPattern(const DictionaryEntry& bytes,
+        const DictionaryEntry& dict_bytes,
+        const int match_location)
     {
         return (bytes[3] == 0) && (bytes[2] == 0) && (bytes[1] == 0) &&
                (bytes[0] != 0);
     }
 
-    std::array<uint8_t, 4>
-    decompress(const std::array<uint8_t, 4> dict_bytes) const override
+    DictionaryEntry
+    decompress(const DictionaryEntry dict_bytes) const override
     {
         return {byte, 0, 0, 0};
     }
@@ -260,21 +261,21 @@ class CPack::PatternMMMX : public DictionaryCompressor::Pattern
     const uint8_t byte;
 
   public:
-    PatternMMMX(const std::array<uint8_t, 4> bytes, const int match_location)
+    PatternMMMX(const DictionaryEntry bytes, const int match_location)
         : Pattern(MMMX, 0xE, 8, 1, match_location, true),
                   byte(bytes[0]) {}
 
-    static bool isPattern(const std::array<uint8_t, 4>& bytes,
-                          const std::array<uint8_t, 4>& dict_bytes,
-                          const int match_location)
+    static bool isPattern(const DictionaryEntry& bytes,
+        const DictionaryEntry& dict_bytes,
+        const int match_location)
     {
         return (bytes[3] == dict_bytes[3]) && (bytes[2] == dict_bytes[2]) &&
                (bytes[1] == dict_bytes[1]) && (bytes[0] != dict_bytes[0]) &&
                (match_location >= 0);
     }
 
-    std::array<uint8_t, 4>
-    decompress(const std::array<uint8_t, 4> dict_bytes) const override
+    DictionaryEntry
+    decompress(const DictionaryEntry dict_bytes) const override
     {
         return {byte, dict_bytes[1], dict_bytes[2], dict_bytes[3]};
     }
diff --git a/src/mem/cache/compressors/dictionary_compressor.cc b/src/mem/cache/compressors/dictionary_compressor.cc
deleted file mode 100644 (file)
index c53d14a..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (c) 2018-2019 Inria
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Daniel Carvalho
- */
-
-/** @file
- * Implementation of a dictionary based cache compressor.
- */
-
-#include "mem/cache/compressors/dictionary_compressor.hh"
-
-#include <algorithm>
-
-#include "debug/CacheComp.hh"
-#include "params/DictionaryCompressor.hh"
-
-DictionaryCompressor::CompData::CompData(const std::size_t dictionary_size)
-    : CompressionData()
-{
-}
-
-DictionaryCompressor::CompData::~CompData()
-{
-}
-
-DictionaryCompressor::DictionaryCompressor(const Params *p)
-    : BaseCacheCompressor(p), dictionarySize(p->dictionary_size)
-{
-    dictionary.resize(dictionarySize);
-
-    resetDictionary();
-}
-
-void
-DictionaryCompressor::resetDictionary()
-{
-    // Reset number of valid entries
-    numEntries = 0;
-
-    // Set all entries as 0
-    std::array<uint8_t, 4> zero_word = {0, 0, 0, 0};
-    std::fill(dictionary.begin(), dictionary.end(), zero_word);
-}
-
-std::unique_ptr<DictionaryCompressor::Pattern>
-DictionaryCompressor::compressWord(const uint32_t data)
-{
-    // Split data in bytes
-    const std::array<uint8_t, 4> bytes = {
-        static_cast<uint8_t>(data & 0xFF),
-        static_cast<uint8_t>((data >> 8) & 0xFF),
-        static_cast<uint8_t>((data >> 16) & 0xFF),
-        static_cast<uint8_t>((data >> 24) & 0xFF)
-    };
-
-    // Start as a no-match pattern. A negative match location is used so that
-    // patterns that depend on the dictionary entry don't match
-    std::unique_ptr<Pattern> pattern = getPattern(bytes, {0, 0, 0, 0}, -1);
-
-    // Search for word on dictionary
-    for (std::size_t i = 0; i < numEntries; i++) {
-        // Try matching input with possible patterns
-        std::unique_ptr<Pattern> temp_pattern =
-            getPattern(bytes, dictionary[i], i);
-
-        // Check if found pattern is better than previous
-        if (temp_pattern->getSizeBits() < pattern->getSizeBits()) {
-            pattern = std::move(temp_pattern);
-        }
-    }
-
-    // Update stats
-    patternStats[pattern->getPatternNumber()]++;
-
-    // Push into dictionary
-    if (pattern->shouldAllocate()) {
-        addToDictionary(bytes);
-    }
-
-    return pattern;
-}
-
-std::unique_ptr<BaseCacheCompressor::CompressionData>
-DictionaryCompressor::compress(const uint64_t* data)
-{
-    std::unique_ptr<CompData> comp_data =
-        std::unique_ptr<CompData>(new CompData(dictionarySize));
-
-    // Compression size
-    std::size_t size = 0;
-
-    // Reset dictionary
-    resetDictionary();
-
-    // Compress every word sequentially
-    for (std::size_t i = 0; i < blkSize/8; i++) {
-        const uint32_t first_word = ((data[i])&0xFFFFFFFF00000000) >> 32;
-        const uint32_t second_word = (data[i])&0x00000000FFFFFFFF;
-
-        // Compress both words
-        std::unique_ptr<Pattern> first_pattern = compressWord(first_word);
-        std::unique_ptr<Pattern> second_pattern = compressWord(second_word);
-
-        // Update total line compression size
-        size += first_pattern->getSizeBits() + second_pattern->getSizeBits();
-
-        // Print debug information
-        DPRINTF(CacheComp, "Compressed %08x to %s\n", first_word,
-                first_pattern->print());
-        DPRINTF(CacheComp, "Compressed %08x to %s\n", second_word,
-                second_pattern->print());
-
-        // Append to pattern list
-        comp_data->entries.push_back(std::move(first_pattern));
-        comp_data->entries.push_back(std::move(second_pattern));
-    }
-
-    // Set final compression size
-    comp_data->setSizeBits(size);
-
-    // Return compressed line
-    return std::move(comp_data);
-}
-
-uint32_t
-DictionaryCompressor::decompressWord(const Pattern* pattern)
-{
-    // Search for matching entry
-    std::vector<std::array<uint8_t, 4>>::iterator entry_it =
-        dictionary.begin();
-    std::advance(entry_it, pattern->getMatchLocation());
-
-    // Decompress the match. If the decompressed value must be added to
-    // the dictionary, do it
-    const std::array<uint8_t, 4> data = pattern->decompress(*entry_it);
-    if (pattern->shouldAllocate()) {
-        addToDictionary(data);
-    }
-
-    // Return word
-    return (((((data[3] << 8) | data[2]) << 8) | data[1]) << 8) | data[0];
-}
-
-void
-DictionaryCompressor::decompress(const CompressionData* comp_data,
-    uint64_t* data)
-{
-    const CompData* casted_comp_data = static_cast<const CompData*>(comp_data);
-
-    // Reset dictionary
-    resetDictionary();
-
-    // Decompress every entry sequentially
-    std::vector<uint32_t> decomp_words;
-    for (const auto& entry : casted_comp_data->entries) {
-        const uint32_t word = decompressWord(&*entry);
-        decomp_words.push_back(word);
-
-        // Print debug information
-        DPRINTF(CacheComp, "Decompressed %s to %x\n", entry->print(), word);
-    }
-
-    // Concatenate the decompressed words to generate the cache lines
-    for (std::size_t i = 0; i < blkSize/8; i++) {
-        data[i] = (static_cast<uint64_t>(decomp_words[2*i]) << 32) |
-                        decomp_words[2*i+1];
-    }
-}
-
-void
-DictionaryCompressor::regStats()
-{
-    BaseCacheCompressor::regStats();
-
-    // We store the frequency of each pattern
-    patternStats
-        .init(getNumPatterns())
-        .name(name() + ".pattern")
-        .desc("Number of data entries that were compressed to this pattern.")
-        ;
-
-    for (unsigned i = 0; i < getNumPatterns(); ++i) {
-        patternStats.subname(i, getName(i));
-        patternStats.subdesc(i, "Number of data entries that match pattern " +
-                                getName(i));
-    }
-}
index 87e69ccc890441fcca3009d1ac189f14eeeca053..7467d5a175d9d6c68bd66f8d782051358c1f3446 100644 (file)
 #include "base/types.hh"
 #include "mem/cache/compressors/base.hh"
 
-struct DictionaryCompressorParams;
+struct BaseDictionaryCompressorParams;
 
-class DictionaryCompressor : public BaseCacheCompressor
+class BaseDictionaryCompressor : public BaseCacheCompressor
+{
+  protected:
+    /** Dictionary size. */
+    const std::size_t dictionarySize;
+
+    /** Number of valid entries in the dictionary. */
+    std::size_t numEntries;
+
+    /**
+     * @defgroup CompressionStats Compression specific statistics.
+     * @{
+     */
+
+    /** Number of data entries that were compressed to each pattern. */
+    Stats::Vector patternStats;
+
+    /**
+     * @}
+     */
+
+    /**
+     * Trick function to get the number of patterns.
+     *
+     * @return The number of defined patterns.
+     */
+    virtual uint64_t getNumPatterns() const = 0;
+
+    /**
+     * Get meta-name assigned to the given pattern.
+     *
+     * @param number The number of the pattern.
+     * @return The meta-name of the pattern.
+     */
+    virtual std::string getName(int number) const = 0;
+
+  public:
+    typedef BaseDictionaryCompressorParams Params;
+    BaseDictionaryCompressor(const Params *p);
+    ~BaseDictionaryCompressor() = default;
+
+    void regStats() override;
+};
+
+/**
+ * A template version of the dictionary compressor that allows to choose the
+ * dictionary size.
+ *
+ * @tparam The type of a dictionary entry (e.g., uint16_t, uint32_t, etc).
+ */
+template <class T>
+class DictionaryCompressor : public BaseDictionaryCompressor
 {
   protected:
     /**
@@ -69,6 +120,9 @@ class DictionaryCompressor : public BaseCacheCompressor
     // Forward declaration of a pattern
     class Pattern;
 
+    /** Convenience typedef for a dictionary entry. */
+    typedef std::array<uint8_t, sizeof(T)> DictionaryEntry;
+
     /**
      * Create a factory to determine if input matches a pattern. The if else
      * chains are constructed by recursion. The patterns should be explored
@@ -78,8 +132,8 @@ class DictionaryCompressor : public BaseCacheCompressor
     struct Factory
     {
         static std::unique_ptr<Pattern> getPattern(
-            const std::array<uint8_t, 4>& bytes,
-            const std::array<uint8_t, 4>& dict_bytes, const int match_location)
+            const DictionaryEntry& bytes, const DictionaryEntry& dict_bytes,
+            const int match_location)
         {
             // If match this pattern, instantiate it. If a negative match
             // location is used, the patterns that use the dictionary bytes
@@ -100,9 +154,9 @@ class DictionaryCompressor : public BaseCacheCompressor
     template <class Head>
     struct Factory<Head>
     {
-        static std::unique_ptr<Pattern> getPattern(
-            const std::array<uint8_t, 4>& bytes,
-            const std::array<uint8_t, 4>& dict_bytes, const int match_location)
+        static std::unique_ptr<Pattern>
+        getPattern(const DictionaryEntry& bytes,
+            const DictionaryEntry& dict_bytes, const int match_location)
         {
             // Instantiate last pattern. Should be the XXXX pattern.
             return std::unique_ptr<Pattern>(new Head(bytes, match_location));
@@ -110,51 +164,15 @@ class DictionaryCompressor : public BaseCacheCompressor
     };
 
     /** The dictionary. */
-    std::vector<std::array<uint8_t, 4>> dictionary;
-
-    /** Dictionary size. */
-    const std::size_t dictionarySize;
-
-    /** Number of valid entries in the dictionary. */
-    std::size_t numEntries;
-
-    /**
-     * @defgroup CompressionStats Compression specific statistics.
-     * @{
-     */
-
-    /**
-     * Number of data entries that were compressed to each pattern.
-     */
-    Stats::Vector patternStats;
-
-    /**
-     * @}
-     */
-
-    /**
-     * Trick function to get the number of patterns.
-     *
-     * @return The number of defined patterns.
-     */
-    virtual uint64_t getNumPatterns() const = 0;
-
-    /**
-     * Get meta-name assigned to the given pattern.
-     *
-     * @param number The number of the pattern.
-     * @return The meta-name of the pattern.
-     */
-    virtual std::string getName(int number) const = 0;
+    std::vector<DictionaryEntry> dictionary;
 
     /**
      * Since the factory cannot be instantiated here, classes that inherit
      * from this base class have to implement the call to their factory's
      * getPattern.
      */
-    virtual std::unique_ptr<Pattern> getPattern(
-        const std::array<uint8_t, 4>& bytes,
-        const std::array<uint8_t, 4>& dict_bytes,
+    virtual std::unique_ptr<Pattern>
+    getPattern(const DictionaryEntry& bytes, const DictionaryEntry& dict_bytes,
         const int match_location) const = 0;
 
     /**
@@ -163,15 +181,15 @@ class DictionaryCompressor : public BaseCacheCompressor
      * @param data Data to be compressed.
      * @return The pattern this data matches.
      */
-    std::unique_ptr<Pattern> compressWord(const uint32_t data);
+    std::unique_ptr<Pattern> compressValue(const T data);
 
     /**
-     * Decompress a word.
+     * Decompress a pattern into a value that fits in a dictionary entry.
      *
      * @param pattern The pattern to be decompressed.
      * @return The decompressed word.
      */
-    uint32_t decompressWord(const Pattern* pattern);
+    T decompressValue(const Pattern* pattern);
 
     /** Clear all dictionary entries. */
     void resetDictionary();
@@ -181,7 +199,7 @@ class DictionaryCompressor : public BaseCacheCompressor
      *
      * @param data The new entry.
      */
-    virtual void addToDictionary(std::array<uint8_t, 4> data) = 0;
+    virtual void addToDictionary(const DictionaryEntry data) = 0;
 
     /**
      * Apply compression.
@@ -200,18 +218,26 @@ class DictionaryCompressor : public BaseCacheCompressor
      */
     void decompress(const CompressionData* comp_data, uint64_t* data) override;
 
-  public:
-    /** Convenience typedef. */
-    typedef DictionaryCompressorParams Params;
-
-    /** Default constructor. */
-    DictionaryCompressor(const Params *p);
+    /**
+     * Turn a value into a dictionary entry.
+     *
+     * @param value The value to turn.
+     * @return A dictionary entry containing the value.
+     */
+    static DictionaryEntry toDictionaryEntry(T value);
 
-    /** Default destructor. */
-    ~DictionaryCompressor() {};
+    /**
+     * Turn a dictionary entry into a value.
+     *
+     * @param The dictionary entry to turn.
+     * @return The value that the dictionary entry contained.
+     */
+    static T fromDictionaryEntry(const DictionaryEntry& entry);
 
-    /** Register local statistics. */
-    void regStats() override;
+  public:
+    typedef BaseDictionaryCompressorParams Params;
+    DictionaryCompressor(const Params *p);
+    ~DictionaryCompressor() = default;
 };
 
 /**
@@ -220,7 +246,8 @@ class DictionaryCompressor : public BaseCacheCompressor
  * decompress(). Then the new pattern must be added to the PatternFactory
  * declaration in crescent order of size (in the DictionaryCompressor class).
  */
-class DictionaryCompressor::Pattern
+template <class T>
+class DictionaryCompressor<T>::Pattern
 {
   protected:
     /** Pattern enum number. */
@@ -322,25 +349,26 @@ class DictionaryCompressor::Pattern
      * @param dict_bytes The bytes in the corresponding matching entry.
      * @return The decompressed pattern.
      */
-    virtual std::array<uint8_t, 4> decompress(
-        const std::array<uint8_t, 4> dict_bytes) const = 0;
+    virtual DictionaryEntry decompress(
+        const DictionaryEntry dict_bytes) const = 0;
 };
 
-class DictionaryCompressor::CompData : public CompressionData
+template <class T>
+class DictionaryCompressor<T>::CompData : public CompressionData
 {
   public:
     /** The patterns matched in the original line. */
     std::vector<std::unique_ptr<Pattern>> entries;
 
+    CompData();
+    ~CompData() = default;
+
     /**
-     * Default constructor.
+     * Add a pattern entry to the list of patterns.
      *
-     * @param dictionary_size Number of entries in the dictionary.
+     * @param entry The new pattern entry.
      */
-    CompData(const std::size_t dictionary_size);
-
-    /** Default destructor. */
-    ~CompData();
+    virtual void addEntry(std::unique_ptr<Pattern>);
 };
 
 #endif //__MEM_CACHE_COMPRESSORS_DICTIONARY_COMPRESSOR_HH__
diff --git a/src/mem/cache/compressors/dictionary_compressor_impl.hh b/src/mem/cache/compressors/dictionary_compressor_impl.hh
new file mode 100644 (file)
index 0000000..66827d7
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2018-2019 Inria
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Daniel Carvalho
+ */
+
+/** @file
+ * Implementation of a dictionary based cache compressor.
+ */
+
+#ifndef __MEM_CACHE_COMPRESSORS_DICTIONARY_COMPRESSOR_IMPL_HH__
+#define __MEM_CACHE_COMPRESSORS_DICTIONARY_COMPRESSOR_IMPL_HH__
+
+#include <algorithm>
+
+#include "debug/CacheComp.hh"
+#include "mem/cache/compressors/dictionary_compressor.hh"
+#include "params/BaseDictionaryCompressor.hh"
+
+template <class T>
+DictionaryCompressor<T>::CompData::CompData()
+    : CompressionData()
+{
+}
+
+template <class T>
+void
+DictionaryCompressor<T>::CompData::addEntry(std::unique_ptr<Pattern> pattern)
+{
+    // Increase size
+    setSizeBits(getSizeBits() + pattern->getSizeBits());
+
+    // Push new entry to list
+    entries.push_back(std::move(pattern));
+}
+
+template <class T>
+DictionaryCompressor<T>::DictionaryCompressor(const Params *p)
+    : BaseDictionaryCompressor(p)
+{
+    dictionary.resize(dictionarySize);
+
+    resetDictionary();
+}
+
+template <class T>
+void
+DictionaryCompressor<T>::resetDictionary()
+{
+    // Reset number of valid entries
+    numEntries = 0;
+
+    // Set all entries as 0
+    std::fill(dictionary.begin(), dictionary.end(), toDictionaryEntry(0));
+}
+
+template <typename T>
+std::unique_ptr<typename DictionaryCompressor<T>::Pattern>
+DictionaryCompressor<T>::compressValue(const T data)
+{
+    // Split data in bytes
+    const DictionaryEntry bytes = toDictionaryEntry(data);
+
+    // Start as a no-match pattern. A negative match location is used so that
+    // patterns that depend on the dictionary entry don't match
+    std::unique_ptr<Pattern> pattern =
+        getPattern(bytes, toDictionaryEntry(0), -1);
+
+    // Search for word on dictionary
+    for (std::size_t i = 0; i < numEntries; i++) {
+        // Try matching input with possible patterns
+        std::unique_ptr<Pattern> temp_pattern =
+            getPattern(bytes, dictionary[i], i);
+
+        // Check if found pattern is better than previous
+        if (temp_pattern->getSizeBits() < pattern->getSizeBits()) {
+            pattern = std::move(temp_pattern);
+        }
+    }
+
+    // Update stats
+    patternStats[pattern->getPatternNumber()]++;
+
+    // Push into dictionary
+    if (pattern->shouldAllocate()) {
+        addToDictionary(bytes);
+    }
+
+    return pattern;
+}
+
+template <class T>
+std::unique_ptr<BaseCacheCompressor::CompressionData>
+DictionaryCompressor<T>::compress(const uint64_t* data)
+{
+    std::unique_ptr<CompData> comp_data =
+        std::unique_ptr<CompData>(new CompData());
+
+    // Reset dictionary
+    resetDictionary();
+
+    // Compress every value sequentially
+    const std::vector<T> values((T*)data, (T*)data + blkSize / sizeof(T));
+    for (const auto& value : values) {
+        std::unique_ptr<Pattern> pattern = compressValue(value);
+        DPRINTF(CacheComp, "Compressed %016x to %s\n", value,
+            pattern->print());
+        comp_data->addEntry(std::move(pattern));
+    }
+
+    // Return compressed line
+    return std::move(comp_data);
+}
+
+template <class T>
+T
+DictionaryCompressor<T>::decompressValue(const Pattern* pattern)
+{
+    // Search for matching entry
+    auto entry_it = dictionary.begin();
+    std::advance(entry_it, pattern->getMatchLocation());
+
+    // Decompress the match. If the decompressed value must be added to
+    // the dictionary, do it
+    const DictionaryEntry data = pattern->decompress(*entry_it);
+    if (pattern->shouldAllocate()) {
+        addToDictionary(data);
+    }
+
+    // Return value
+    return fromDictionaryEntry(data);
+}
+
+template <class T>
+void
+DictionaryCompressor<T>::decompress(const CompressionData* comp_data,
+    uint64_t* data)
+{
+    const CompData* casted_comp_data = static_cast<const CompData*>(comp_data);
+
+    // Reset dictionary
+    resetDictionary();
+
+    // Decompress every entry sequentially
+    std::vector<T> decomp_values;
+    for (const auto& entry : casted_comp_data->entries) {
+        const T value = decompressValue(&*entry);
+        decomp_values.push_back(value);
+        DPRINTF(CacheComp, "Decompressed %s to %x\n", entry->print(), value);
+    }
+
+    // Concatenate the decompressed values to generate the original data
+    for (std::size_t i = 0; i < blkSize/8; i++) {
+        data[i] = 0;
+        const std::size_t values_per_entry = sizeof(uint64_t)/sizeof(T);
+        for (int j = values_per_entry - 1; j >= 0; j--) {
+            data[i] |=
+                static_cast<uint64_t>(decomp_values[values_per_entry*i+j]) <<
+                (j*8*sizeof(T));
+        }
+    }
+}
+
+template <class T>
+typename DictionaryCompressor<T>::DictionaryEntry
+DictionaryCompressor<T>::toDictionaryEntry(T value)
+{
+    DictionaryEntry entry;
+    for (int i = 0; i < sizeof(T); i++) {
+        entry[i] = value & 0xFF;
+        value >>= 8;
+    }
+    return entry;
+}
+
+template <class T>
+T
+DictionaryCompressor<T>::fromDictionaryEntry(const DictionaryEntry& entry)
+{
+    T value = 0;
+    for (int i = sizeof(T) - 1; i >= 0; i--) {
+        value <<= 8;
+        value |= entry[i];
+    }
+    return value;
+}
+
+#endif //__MEM_CACHE_COMPRESSORS_DICTIONARY_COMPRESSOR_IMPL_HH__