]> git.ipfire.org Git - thirdparty/xz.git/commitdiff
liblzma: LZMA decoder: Get rid of next_state[].
authorLasse Collin <lasse.collin@tukaani.org>
Mon, 12 Feb 2024 15:09:10 +0000 (17:09 +0200)
committerLasse Collin <lasse.collin@tukaani.org>
Wed, 14 Feb 2024 16:31:16 +0000 (18:31 +0200)
It's not completely obvious if this is better in the decoder.
It should be good if compiler can avoid creating a branch
(like using CMOV on x86).

This also makes lzma_encoder.c use the new macros.

src/liblzma/lzma/lzma_common.h
src/liblzma/lzma/lzma_decoder.c
src/liblzma/lzma/lzma_encoder.c

index 77b629552b6e12a4bb1ba7b41b53d05f482b50f6..d46b8502b2d1e7376596bb9c84d3e5189b3ac2b5 100644 (file)
@@ -83,6 +83,20 @@ typedef enum {
                                ? (state) - 3 \
                                : (state) - 6))
 
+/// Like update_literal(state) but when it is already known that
+/// is_literal_state(state) is true.
+#define update_literal_normal(state) \
+       state = ((state) <= STATE_SHORTREP_LIT_LIT \
+                       ? STATE_LIT_LIT \
+                       : (state) - 3);
+
+/// Like update_literal(state) but when it is already known that
+/// is_literal_state(state) is false.
+#define update_literal_matched(state) \
+       state = ((state) <= STATE_LIT_SHORTREP \
+                       ? (state) - 3 \
+                       : (state) - 6);
+
 /// Indicate that the latest state was a match.
 #define update_match(state) \
        state = ((state) < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH)
index 0788558f78d77f8c304b9affd39962665cc2fe6f..c5049a48d772615cc4d227f0ce19c38c7f36954c 100644 (file)
@@ -307,24 +307,6 @@ lzma_decode(void *coder_ptr, lzma_dict *restrict dictptr,
                might_finish_without_eopm = true;
        }
 
-       // Lookup table used to update the literal state.
-       // Compared to other state updates, this would need two branches.
-       // The lookup table is used by both Resumable and Non-resumable modes.
-       static const lzma_lzma_state next_state[] = {
-               STATE_LIT_LIT,
-               STATE_LIT_LIT,
-               STATE_LIT_LIT,
-               STATE_LIT_LIT,
-               STATE_MATCH_LIT_LIT,
-               STATE_REP_LIT_LIT,
-               STATE_SHORTREP_LIT_LIT,
-               STATE_MATCH_LIT,
-               STATE_REP_LIT,
-               STATE_SHORTREP_LIT,
-               STATE_MATCH_LIT,
-               STATE_REP_LIT
-       };
-
        // The main decoder loop. The "switch" is used to resume the decoder at
        // correct location. Once resumed, the "switch" is no longer used.
        // The decoder loops is split into two modes:
@@ -381,16 +363,18 @@ lzma_decode(void *coder_ptr, lzma_dict *restrict dictptr,
                                        dict.pos, dict_get(&dict, 0));
 
                        if (is_literal_state(state)) {
+                               update_literal_normal(state);
+
                                // Decode literal without match byte.
                                rc_bittree8(probs, 0);
                        } else {
+                               update_literal_matched(state);
+
                                // Decode literal with match byte.
                                rc_matched_literal(probs,
                                                dict_get(&dict, rep0));
                        }
 
-                       state = next_state[state];
-
                        // Write decoded literal to dictionary
                        dict_put(&dict, symbol);
                        continue;
@@ -705,6 +689,8 @@ slow:
                        symbol = 1;
 
                        if (is_literal_state(state)) {
+                               update_literal_normal(state);
+
                                // Decode literal without match byte.
                                // The "slow" version does not unroll
                                // the loop.
@@ -714,6 +700,8 @@ slow:
                                                        SEQ_LITERAL);
                                } while (symbol < (1 << 8));
                        } else {
+                               update_literal_matched(state);
+
                                // Decode literal with match byte.
                                len = (uint32_t)(dict_get(&dict, rep0)) << 1;
 
@@ -742,8 +730,6 @@ slow:
                                } while (symbol < (1 << 8));
                        }
 
-                       state = next_state[state];
-
        case SEQ_LITERAL_WRITE:
                        if (dict_put_safe(&dict, symbol)) {
                                coder->sequence = SEQ_LITERAL_WRITE;
index eba48a4151a2feb29fe4d97de0ba101f7e7ff7a3..89d4f4e522fdb1f65f9a4eaf85fa2e962fb2d80f 100644 (file)
@@ -54,18 +54,18 @@ literal(lzma_lzma1_encoder *coder, lzma_mf *mf, uint32_t position)
        if (is_literal_state(coder->state)) {
                // Previous LZMA-symbol was a literal. Encode a normal
                // literal without a match byte.
+               update_literal_normal(coder->state);
                rc_bittree(&coder->rc, subcoder, 8, cur_byte);
        } else {
                // Previous LZMA-symbol was a match. Use the last byte of
                // the match as a "match byte". That is, compare the bits
                // of the current literal and the match byte.
+               update_literal_matched(coder->state);
                const uint8_t match_byte = mf->buffer[
                                mf->read_pos - coder->reps[0] - 1
                                - mf->read_ahead];
                literal_matched(&coder->rc, subcoder, match_byte, cur_byte);
        }
-
-       update_literal(coder->state);
 }