| /* |
| * Copyright (c) 2018-2020 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. |
| */ |
| |
| /** @file |
| * Definition of the Frequent Pattern Compression cache compressor, as |
| * described in "Frequent Pattern Compression: A Significance-Based |
| * Compression Scheme for L2 Caches". |
| */ |
| |
| #ifndef __MEM_CACHE_COMPRESSORS_FPC_HH__ |
| #define __MEM_CACHE_COMPRESSORS_FPC_HH__ |
| |
| #include <cstdint> |
| #include <map> |
| #include <memory> |
| #include <string> |
| #include <type_traits> |
| #include <vector> |
| |
| #include "base/bitfield.hh" |
| #include "base/types.hh" |
| #include "mem/cache/compressors/dictionary_compressor.hh" |
| |
| namespace gem5 |
| { |
| |
| struct FPCParams; |
| |
| GEM5_DEPRECATED_NAMESPACE(Compressor, compression); |
| namespace compression |
| { |
| |
| class FPC : public DictionaryCompressor<uint32_t> |
| { |
| private: |
| using DictionaryEntry = DictionaryCompressor<uint32_t>::DictionaryEntry; |
| |
| /** |
| * Compression data for FPC. It contains a list of the patterns |
| * encountered while parsing the cache line. |
| */ |
| class FPCCompData; |
| |
| // Declaration of all possible patterns |
| class ZeroRun; |
| class SignExtended4Bits; |
| class SignExtended1Byte; |
| class SignExtendedHalfword; |
| class ZeroPaddedHalfword; |
| class SignExtendedTwoHalfwords; |
| class RepBytes; |
| class Uncompressed; |
| |
| /** |
| * The possible patterns. If a new pattern is added, it must be done |
| * before NUM_PATTERNS. |
| */ |
| enum PatternNumber |
| { |
| ZERO_RUN, SIGN_EXTENDED_4_BITS, SIGN_EXTENDED_1_BYTE, |
| SIGN_EXTENDED_HALFWORD, ZERO_PADDED_HALFWORD, |
| SIGN_EXTENDED_TWO_HALFWORDS, REP_BYTES, UNCOMPRESSED, |
| NUM_PATTERNS |
| }; |
| |
| /** |
| * Number of bits of the zero run size bitfield. If the size of the |
| * zero run reaches the maximum value, it is split into ZERO_RUN entries. |
| */ |
| const int zeroRunSizeBits; |
| |
| uint64_t getNumPatterns() const override { return NUM_PATTERNS; } |
| |
| std::string |
| getName(int number) const override |
| { |
| static std::map<int, std::string> patternNames = { |
| {ZERO_RUN, "ZERO_RUN"}, |
| {SIGN_EXTENDED_4_BITS, "SignExtended4Bits"}, |
| {SIGN_EXTENDED_1_BYTE, "SignExtended1Byte"}, |
| {SIGN_EXTENDED_HALFWORD, "SignExtendedHalfword"}, |
| {ZERO_PADDED_HALFWORD, "ZeroPaddedHalfword"}, |
| {SIGN_EXTENDED_TWO_HALFWORDS, "SignExtendedTwoHalfwords"}, |
| {REP_BYTES, "RepBytes"}, |
| {UNCOMPRESSED, "Uncompressed"} |
| }; |
| |
| return patternNames[number]; |
| }; |
| |
| std::unique_ptr<Pattern> getPattern( |
| const DictionaryEntry& bytes, |
| const DictionaryEntry& dict_bytes, |
| const int match_location) const override |
| { |
| using PatternFactory = Factory<ZeroRun, SignExtended4Bits, |
| SignExtended1Byte, SignExtendedHalfword, ZeroPaddedHalfword, |
| SignExtendedTwoHalfwords, RepBytes, Uncompressed>; |
| return PatternFactory::getPattern(bytes, dict_bytes, match_location); |
| } |
| |
| void addToDictionary(const DictionaryEntry data) override; |
| |
| std::unique_ptr<DictionaryCompressor::CompData> |
| instantiateDictionaryCompData() const override; |
| |
| public: |
| typedef FPCParams Params; |
| FPC(const Params &p); |
| ~FPC() = default; |
| }; |
| |
| class FPC::FPCCompData : public DictionaryCompressor<uint32_t>::CompData |
| { |
| protected: |
| /** |
| * Number of bits of the zero run size bitfield. If the size of the |
| * zero run reaches the maximum value, it is split into ZERO_RUN entries. |
| */ |
| const int zeroRunSizeBits; |
| |
| public: |
| FPCCompData(int zeroRunSizeBits); |
| ~FPCCompData() = default; |
| |
| void addEntry(std::unique_ptr<Pattern> pattern) override; |
| }; |
| |
| // Pattern implementations |
| |
| class FPC::ZeroRun : public MaskedValuePattern<0, 0xFFFFFFFF> |
| { |
| private: |
| /** Run length so far. */ |
| int _runLength; |
| |
| /** |
| * A zero run consists of a main ZeroRun pattern, which has a meaningful |
| * real size (i.e., different from zero), and X-1 fake (i.e., they are |
| * zero-sized, and don't exist in a real implementation) patterns, with X |
| * being the size of the zero run. |
| */ |
| int _realSize; |
| |
| public: |
| ZeroRun(const DictionaryEntry bytes, const int match_location) |
| : MaskedValuePattern<0, 0xFFFFFFFF>(ZERO_RUN, ZERO_RUN, 3, -1, bytes, |
| false), |
| _runLength(0), _realSize(0) |
| { |
| } |
| |
| std::size_t |
| getSizeBits() const override |
| { |
| return _realSize; |
| } |
| |
| /** |
| * Get the number of zeros in the run so far. |
| * |
| * @return The number of zeros in this run. |
| */ |
| int getRunLength() const { return _runLength; } |
| |
| /** |
| * Set the number of zeros in the run so far. |
| * |
| * @param The number of zeros in this run. |
| */ |
| void setRunLength(int length) { _runLength = length; } |
| |
| /** |
| * When the real size is set it means that we are adding the main zero |
| * run pattern. When that happens, the metadata length must also be taken |
| * into account for the size calculation. |
| * |
| * @param size Number of bits used to represent the number of zeros in the |
| * run. |
| */ |
| void setRealSize(int size) { _realSize = length + size; } |
| }; |
| |
| class FPC::SignExtended4Bits : public SignExtendedPattern<4> |
| { |
| public: |
| SignExtended4Bits(const DictionaryEntry bytes, const int match_location) |
| : SignExtendedPattern<4>(SIGN_EXTENDED_4_BITS, SIGN_EXTENDED_4_BITS, 3, |
| bytes) |
| { |
| } |
| }; |
| |
| class FPC::SignExtended1Byte : public SignExtendedPattern<8> |
| { |
| public: |
| SignExtended1Byte(const DictionaryEntry bytes, const int match_location) |
| : SignExtendedPattern<8>(SIGN_EXTENDED_1_BYTE, SIGN_EXTENDED_1_BYTE, 3, |
| bytes) |
| { |
| } |
| }; |
| |
| class FPC::SignExtendedHalfword : public SignExtendedPattern<16> |
| { |
| public: |
| SignExtendedHalfword(const DictionaryEntry bytes, const int match_location) |
| : SignExtendedPattern<16>(SIGN_EXTENDED_HALFWORD, SIGN_EXTENDED_HALFWORD, |
| 3, bytes) |
| { |
| } |
| }; |
| |
| class FPC::ZeroPaddedHalfword : public MaskedValuePattern<0, 0x0000FFFF> |
| { |
| public: |
| ZeroPaddedHalfword(const DictionaryEntry bytes, const int match_location) |
| : MaskedValuePattern<0, 0x0000FFFF>(ZERO_PADDED_HALFWORD, |
| ZERO_PADDED_HALFWORD, 3, -1, bytes, false) |
| { |
| } |
| }; |
| |
| class FPC::SignExtendedTwoHalfwords : public Pattern |
| { |
| private: |
| /** These are the bytes that are extended to form the two halfwords. */ |
| const int8_t extendedBytes[2]; |
| |
| public: |
| SignExtendedTwoHalfwords(const DictionaryEntry bytes, |
| const int match_location) |
| : Pattern(SIGN_EXTENDED_TWO_HALFWORDS, SIGN_EXTENDED_TWO_HALFWORDS, 3, |
| 16, -1, false), |
| extendedBytes{int8_t(fromDictionaryEntry(bytes) & mask(8)), |
| int8_t((fromDictionaryEntry(bytes) >> 16) & mask(8))} |
| { |
| } |
| |
| static bool |
| isPattern(const DictionaryEntry& bytes, |
| const DictionaryEntry& dict_bytes, const int match_location) |
| { |
| const uint32_t data = fromDictionaryEntry(bytes); |
| const int16_t halfwords[2] = { |
| int16_t(data & mask(16)), |
| int16_t((data >> 16) & mask(16)) |
| }; |
| return (halfwords[0] == (uint16_t)szext<8>(halfwords[0])) && |
| (halfwords[1] == (uint16_t)szext<8>(halfwords[1])); |
| } |
| |
| DictionaryEntry |
| decompress(const DictionaryEntry dict_bytes) const override |
| { |
| uint16_t halfwords[2] = { |
| (uint16_t)szext<8>(extendedBytes[0]), |
| (uint16_t)szext<8>(extendedBytes[1]) |
| }; |
| return toDictionaryEntry((halfwords[1] << 16) | halfwords[0]); |
| } |
| }; |
| |
| class FPC::RepBytes : public RepeatedValuePattern<uint8_t> |
| { |
| public: |
| RepBytes(const DictionaryEntry bytes, const int match_location) |
| : RepeatedValuePattern<uint8_t>(REP_BYTES, REP_BYTES, 3, -1, bytes, |
| false) |
| { |
| } |
| }; |
| |
| class FPC::Uncompressed : public UncompressedPattern |
| { |
| public: |
| Uncompressed(const DictionaryEntry bytes, const int match_location) |
| : UncompressedPattern(UNCOMPRESSED, UNCOMPRESSED, 3, -1, bytes) |
| { |
| } |
| }; |
| |
| } // namespace compression |
| } // namespace gem5 |
| |
| #endif //__MEM_CACHE_COMPRESSORS_FPC_HH__ |