Merge "Refactor tx_size step use cases in decoder" into nextgenv2
diff --git a/aom_dsp/aom_dsp.mk b/aom_dsp/aom_dsp.mk
index 28e7f12..4735199 100644
--- a/aom_dsp/aom_dsp.mk
+++ b/aom_dsp/aom_dsp.mk
@@ -205,6 +205,7 @@
 ifeq ($(ARCH_X86_64),yes)
 DSP_SRCS-$(HAVE_SSSE3)  += x86/fwd_txfm_ssse3_x86_64.asm
 endif
+DSP_SRCS-$(HAVE_AVX2)   += x86/fwd_txfm_avx2.h
 DSP_SRCS-$(HAVE_AVX2)   += x86/fwd_txfm_avx2.c
 DSP_SRCS-$(HAVE_AVX2)   += x86/txfm_common_avx2.h
 DSP_SRCS-$(HAVE_AVX2)   += x86/fwd_dct32x32_impl_avx2.h
diff --git a/aom_dsp/x86/fwd_txfm_avx2.c b/aom_dsp/x86/fwd_txfm_avx2.c
index 670f864..d381a6e 100644
--- a/aom_dsp/x86/fwd_txfm_avx2.c
+++ b/aom_dsp/x86/fwd_txfm_avx2.c
@@ -17,6 +17,14 @@
 #undef FDCT32x32_2D_AVX2
 #undef FDCT32x32_HIGH_PRECISION
 
+// TODO(luoyi): The following macro hides an error. The second parameter type of
+// function,
+//   void FDCT32x32_2D_AVX2(const int16_t *, int16_t*, int);
+// is different from the one in,
+//   void aom_fdct32x32_avx2(const int16_t *, tran_low_t*, int);
+// In CONFIG_AOM_HIGHBITDEPTH=1 build, the second parameter type should be
+// int32_t.
+// This function should be removed after av1_fht32x32 scaling/rounding fix.
 #define FDCT32x32_2D_AVX2 aom_fdct32x32_avx2
 #define FDCT32x32_HIGH_PRECISION 1
 #include "aom_dsp/x86/fwd_dct32x32_impl_avx2.h"  // NOLINT
diff --git a/aom_dsp/x86/fwd_txfm_avx2.h b/aom_dsp/x86/fwd_txfm_avx2.h
new file mode 100644
index 0000000..2c3cfc8
--- /dev/null
+++ b/aom_dsp/x86/fwd_txfm_avx2.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#ifndef AOM_DSP_X86_FWD_TXFM_AVX2_H
+#define AOM_DSP_X86_FWD_TXFM_AVX2_H
+
+#include "./aom_config.h"
+
+static INLINE void storeu_output_avx2(const __m256i *coeff, tran_low_t *out) {
+#if CONFIG_AOM_HIGHBITDEPTH
+  const __m256i zero = _mm256_setzero_si256();
+  const __m256i sign = _mm256_cmpgt_epi16(zero, *coeff);
+
+  __m256i x0 = _mm256_unpacklo_epi16(*coeff, sign);
+  __m256i x1 = _mm256_unpackhi_epi16(*coeff, sign);
+
+  __m256i y0 = _mm256_permute2x128_si256(x0, x1, 0x20);
+  __m256i y1 = _mm256_permute2x128_si256(x0, x1, 0x31);
+
+  _mm256_storeu_si256((__m256i *)out, y0);
+  _mm256_storeu_si256((__m256i *)(out + 8), y1);
+#else
+  _mm256_storeu_si256((__m256i *)out, *coeff);
+#endif
+}
+
+#endif  // AOM_DSP_X86_FWD_TXFM_AVX2_H
diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c
index 78f4ffe..e812f15 100644
--- a/av1/common/entropymode.c
+++ b/av1/common/entropymode.c
@@ -147,6 +147,9 @@
       { 43, 81, 53, 140, 169, 204, 68, 84, 72 }     // left = tm
   }
 };
+#if CONFIG_DAALA_EC
+aom_cdf_prob av1_kf_y_mode_cdf[INTRA_MODES][INTRA_MODES][INTRA_MODES];
+#endif
 
 static const aom_prob default_if_y_probs[BLOCK_SIZE_GROUPS][INTRA_MODES - 1] = {
   { 65, 32, 18, 144, 162, 194, 41, 51, 98 },   // block_size < 8x8
@@ -368,6 +371,10 @@
 static const aom_prob default_delta_q_probs[DELTA_Q_CONTEXTS] = { 220, 220,
                                                                   220 };
 #endif
+int av1_intra_mode_ind[INTRA_MODES];
+int av1_intra_mode_inv[INTRA_MODES];
+int av1_inter_mode_ind[INTER_MODES];
+int av1_inter_mode_inv[INTER_MODES];
 
 /* Array indices are identical to previously-existing INTRAMODECONTEXTNODES. */
 const aom_tree_index av1_intra_mode_tree[TREE_SIZE(INTRA_MODES)] = {
@@ -1406,14 +1413,22 @@
   av1_copy(fc->switchable_restore_prob, default_switchable_restore_prob);
 #endif  // CONFIG_LOOP_RESTORATION
 #if CONFIG_DAALA_EC
+  av1_tree_to_cdf_1D(av1_intra_mode_tree, fc->y_mode_prob, fc->y_mode_cdf,
+                     BLOCK_SIZE_GROUPS);
+  av1_tree_to_cdf_1D(av1_intra_mode_tree, fc->uv_mode_prob, fc->uv_mode_cdf,
+                     INTRA_MODES);
   av1_tree_to_cdf_1D(av1_switchable_interp_tree, fc->switchable_interp_prob,
                      fc->switchable_interp_cdf, SWITCHABLE_FILTER_CONTEXTS);
+  av1_tree_to_cdf_1D(av1_partition_tree, fc->partition_prob, fc->partition_cdf,
+                     PARTITION_CONTEXTS);
+  av1_tree_to_cdf_1D(av1_inter_mode_tree, fc->inter_mode_probs,
+                     fc->inter_mode_cdf, INTER_MODE_CONTEXTS);
   av1_tree_to_cdf_2D(av1_ext_tx_tree, fc->intra_ext_tx_prob,
                      fc->intra_ext_tx_cdf, EXT_TX_SIZES, TX_TYPES);
   av1_tree_to_cdf_1D(av1_ext_tx_tree, fc->inter_ext_tx_prob,
                      fc->inter_ext_tx_cdf, EXT_TX_SIZES);
-  av1_tree_to_cdf_1D(av1_partition_tree, fc->partition_prob, fc->partition_cdf,
-                     PARTITION_CONTEXTS);
+  av1_tree_to_cdf_2D(av1_intra_mode_tree, av1_kf_y_mode_prob, av1_kf_y_mode_cdf,
+                     INTRA_MODES, INTRA_MODES);
   av1_tree_to_cdf(av1_segment_tree, fc->seg.tree_probs, fc->seg.tree_cdf);
 #endif
 #if CONFIG_DELTA_Q
diff --git a/av1/common/entropymode.h b/av1/common/entropymode.h
index 68a6400..3043114 100644
--- a/av1/common/entropymode.h
+++ b/av1/common/entropymode.h
@@ -165,9 +165,12 @@
   aom_prob switchable_restore_prob[RESTORE_SWITCHABLE_TYPES - 1];
 #endif  // CONFIG_LOOP_RESTORATION
 #if CONFIG_DAALA_EC
+  aom_cdf_prob y_mode_cdf[BLOCK_SIZE_GROUPS][INTRA_MODES];
+  aom_cdf_prob uv_mode_cdf[INTRA_MODES][INTRA_MODES];
   aom_cdf_prob partition_cdf[PARTITION_CONTEXTS][PARTITION_TYPES];
   aom_cdf_prob switchable_interp_cdf[SWITCHABLE_FILTER_CONTEXTS]
                                     [SWITCHABLE_FILTERS];
+  aom_cdf_prob inter_mode_cdf[INTER_MODE_CONTEXTS][INTER_MODES];
   aom_cdf_prob intra_ext_tx_cdf[EXT_TX_SIZES][TX_TYPES][TX_TYPES];
   aom_cdf_prob inter_ext_tx_cdf[EXT_TX_SIZES][TX_TYPES];
 #endif
@@ -276,6 +279,9 @@
 
 extern const aom_prob av1_kf_y_mode_prob[INTRA_MODES][INTRA_MODES]
                                         [INTRA_MODES - 1];
+#if CONFIG_DAALA_EC
+extern aom_cdf_prob av1_kf_y_mode_cdf[INTRA_MODES][INTRA_MODES][INTRA_MODES];
+#endif
 #if CONFIG_PALETTE
 extern const aom_prob av1_default_palette_y_mode_prob[PALETTE_BLOCK_SIZES]
                                                      [PALETTE_Y_MODE_CONTEXTS];
@@ -294,6 +300,12 @@
 
 extern const aom_tree_index av1_intra_mode_tree[TREE_SIZE(INTRA_MODES)];
 extern const aom_tree_index av1_inter_mode_tree[TREE_SIZE(INTER_MODES)];
+#if CONFIG_DAALA_EC
+extern int av1_intra_mode_ind[INTRA_MODES];
+extern int av1_intra_mode_inv[INTRA_MODES];
+extern int av1_inter_mode_ind[INTER_MODES];
+extern int av1_inter_mode_inv[INTER_MODES];
+#endif
 #if CONFIG_EXT_INTER
 extern const aom_tree_index
     av1_interintra_mode_tree[TREE_SIZE(INTERINTRA_MODES)];
diff --git a/av1/common/entropymv.c b/av1/common/entropymv.c
index 34918b3..a80165e 100644
--- a/av1/common/entropymv.c
+++ b/av1/common/entropymv.c
@@ -42,28 +42,45 @@
                                                                4,  -2, -3 };
 
 static const nmv_context default_nmv_context = {
-  { 32, 64, 96 },
+  { 32, 64, 96 },  // joints
+#if CONFIG_DAALA_EC
+  { 0, 0, 0, 0 },  // joint_cdf is computed from joints in av1_init_mv_probs()
+#endif
   { {
         // Vertical component
         128,                                                   // sign
         { 224, 144, 192, 168, 192, 176, 192, 198, 198, 245 },  // class
+#if CONFIG_DAALA_EC
+        { 0 },  // class_cdf is computed from class in av1_init_mv_probs()
+#endif
         { 216 },                                               // class0
         { 136, 140, 148, 160, 176, 192, 224, 234, 234, 240 },  // bits
         { { 128, 128, 64 }, { 96, 112, 64 } },                 // class0_fp
         { 64, 96, 64 },                                        // fp
-        160,                                                   // class0_hp bit
-        128,                                                   // hp
+#if CONFIG_DAALA_EC
+        { { 0 }, { 0 } },  // class0_fp_cdf is computed in av1_init_mv_probs()
+        { 0 },             // fp_cdf is computed from fp in av1_init_mv_probs()
+#endif
+        160,  // class0_hp bit
+        128,  // hp
     },
     {
         // Horizontal component
         128,                                                   // sign
         { 216, 128, 176, 160, 176, 176, 192, 198, 198, 208 },  // class
+#if CONFIG_DAALA_EC
+        { 0 },  // class_cdf is computed from class in av1_init_mv_probs()
+#endif
         { 208 },                                               // class0
         { 136, 140, 148, 160, 176, 192, 224, 234, 234, 240 },  // bits
         { { 128, 128, 64 }, { 96, 112, 64 } },                 // class0_fp
         { 64, 96, 64 },                                        // fp
-        160,                                                   // class0_hp bit
-        128,                                                   // hp
+#if CONFIG_DAALA_EC
+        { { 0 }, { 0 } },  // class0_fp_cdf is computed in av1_init_mv_probs()
+        { 0 },             // fp_cdf is computed from fp in av1_init_mv_probs()
+#endif
+        160,  // class0_hp bit
+        128,  // hp
     } },
 };
 
@@ -262,6 +279,23 @@
   for (i = 0; i < NMV_CONTEXTS; ++i) cm->fc->nmvc[i] = default_nmv_context;
 #else
   cm->fc->nmvc = default_nmv_context;
+#if CONFIG_DAALA_EC
+  {
+    int i, j;
+    av1_tree_to_cdf(av1_mv_joint_tree, cm->fc->nmvc.joints,
+                    cm->fc->nmvc.joint_cdf);
+    for (i = 0; i < 2; i++) {
+      av1_tree_to_cdf(av1_mv_class_tree, cm->fc->nmvc.comps[i].classes,
+                      cm->fc->nmvc.comps[i].class_cdf);
+      av1_tree_to_cdf(av1_mv_fp_tree, cm->fc->nmvc.comps[i].fp,
+                      cm->fc->nmvc.comps[i].fp_cdf);
+      for (j = 0; j < CLASS0_SIZE; j++) {
+        av1_tree_to_cdf(av1_mv_fp_tree, cm->fc->nmvc.comps[i].class0_fp[j],
+                        cm->fc->nmvc.comps[i].class0_fp_cdf[j]);
+      }
+    }
+  }
+#endif
 #endif
 #if CONFIG_GLOBAL_MOTION
   av1_copy(cm->fc->global_motion_types_prob, default_global_motion_types_prob);
diff --git a/av1/common/entropymv.h b/av1/common/entropymv.h
index f97dd85..f308ef3 100644
--- a/av1/common/entropymv.h
+++ b/av1/common/entropymv.h
@@ -85,16 +85,26 @@
 typedef struct {
   aom_prob sign;
   aom_prob classes[MV_CLASSES - 1];
+#if CONFIG_DAALA_EC
+  aom_cdf_prob class_cdf[MV_CLASSES];
+#endif
   aom_prob class0[CLASS0_SIZE - 1];
   aom_prob bits[MV_OFFSET_BITS];
   aom_prob class0_fp[CLASS0_SIZE][MV_FP_SIZE - 1];
   aom_prob fp[MV_FP_SIZE - 1];
+#if CONFIG_DAALA_EC
+  aom_cdf_prob class0_fp_cdf[CLASS0_SIZE][MV_FP_SIZE];
+  aom_cdf_prob fp_cdf[MV_FP_SIZE];
+#endif
   aom_prob class0_hp;
   aom_prob hp;
 } nmv_component;
 
 typedef struct {
   aom_prob joints[MV_JOINTS - 1];
+#if CONFIG_DAALA_EC
+  aom_cdf_prob joint_cdf[MV_JOINTS];
+#endif
   nmv_component comps[2];
 } nmv_context;
 
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index 3c8eac8..b6e73cd 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -378,6 +378,9 @@
   // - this is intentionally not placed in FRAME_CONTEXT since it's reset upon
   // each keyframe and not used afterwards
   aom_prob kf_y_prob[INTRA_MODES][INTRA_MODES][INTRA_MODES - 1];
+#if CONFIG_DAALA_EC
+  aom_cdf_prob kf_y_cdf[INTRA_MODES][INTRA_MODES][INTRA_MODES];
+#endif
 #if CONFIG_GLOBAL_MOTION
   Global_Motion_Params global_motion[TOTAL_REFS_PER_FRAME];
 #endif
@@ -582,6 +585,18 @@
   return cm->kf_y_prob[above][left];
 }
 
+#if CONFIG_DAALA_EC
+static INLINE const aom_cdf_prob *get_y_mode_cdf(const AV1_COMMON *cm,
+                                                 const MODE_INFO *mi,
+                                                 const MODE_INFO *above_mi,
+                                                 const MODE_INFO *left_mi,
+                                                 int block) {
+  const PREDICTION_MODE above = av1_above_block_mode(mi, above_mi, block);
+  const PREDICTION_MODE left = av1_left_block_mode(mi, left_mi, block);
+  return cm->kf_y_cdf[above][left];
+}
+#endif
+
 static INLINE void update_partition_context(MACROBLOCKD *xd, int mi_row,
                                             int mi_col, BLOCK_SIZE subsize,
                                             BLOCK_SIZE bsize) {
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 4cb7d82..f39c002 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -134,9 +134,14 @@
 #endif  // CONFIG_EXT_INTER
 #else
   int j;
-  for (i = 0; i < INTER_MODE_CONTEXTS; ++i)
+  for (i = 0; i < INTER_MODE_CONTEXTS; ++i) {
     for (j = 0; j < INTER_MODES - 1; ++j)
       av1_diff_update_prob(r, &fc->inter_mode_probs[i][j], ACCT_STR);
+#if CONFIG_DAALA_EC
+    av1_tree_to_cdf(av1_inter_mode_tree, fc->inter_mode_probs[i],
+                    fc->inter_mode_cdf[i]);
+#endif
+  }
 #endif
 }
 
@@ -204,6 +209,9 @@
   int i, j;
 
   update_mv_probs(ctx->joints, MV_JOINTS - 1, r);
+#if CONFIG_DAALA_EC
+  av1_tree_to_cdf(av1_mv_joint_tree, ctx->joints, ctx->joint_cdf);
+#endif
 
   for (i = 0; i < 2; ++i) {
     nmv_component *const comp_ctx = &ctx->comps[i];
@@ -211,13 +219,24 @@
     update_mv_probs(comp_ctx->classes, MV_CLASSES - 1, r);
     update_mv_probs(comp_ctx->class0, CLASS0_SIZE - 1, r);
     update_mv_probs(comp_ctx->bits, MV_OFFSET_BITS, r);
+#if CONFIG_DAALA_EC
+    av1_tree_to_cdf(av1_mv_class_tree, comp_ctx->classes, comp_ctx->class_cdf);
+#endif
   }
 
   for (i = 0; i < 2; ++i) {
     nmv_component *const comp_ctx = &ctx->comps[i];
-    for (j = 0; j < CLASS0_SIZE; ++j)
+    for (j = 0; j < CLASS0_SIZE; ++j) {
       update_mv_probs(comp_ctx->class0_fp[j], MV_FP_SIZE - 1, r);
+#if CONFIG_DAALA_EC
+      av1_tree_to_cdf(av1_mv_fp_tree, comp_ctx->class0_fp[j],
+                      comp_ctx->class0_fp_cdf[j]);
+#endif
+    }
     update_mv_probs(comp_ctx->fp, MV_FP_SIZE - 1, r);
+#if CONFIG_DAALA_EC
+    av1_tree_to_cdf(av1_mv_fp_tree, comp_ctx->fp, comp_ctx->fp_cdf);
+#endif
   }
 
   if (allow_hp) {
@@ -1146,11 +1165,12 @@
   const int bh = 1 << (bhl - 1);
   const int x_mis = AOMMIN(bw, cm->mi_cols - mi_col);
   const int y_mis = AOMMIN(bh, cm->mi_rows - mi_row);
+  MB_MODE_INFO *mbmi;
+
 #if CONFIG_ACCOUNTING
   aom_accounting_set_context(&pbi->accounting, mi_col, mi_row);
 #endif
 #if CONFIG_SUPERTX
-  MB_MODE_INFO *mbmi;
   if (supertx_enabled) {
     mbmi = set_mb_offsets(cm, xd, bsize, mi_row, mi_col, bw, bh, x_mis, y_mis);
   } else {
@@ -1162,8 +1182,8 @@
 #endif
   av1_read_mode_info(pbi, xd, supertx_enabled, mi_row, mi_col, r, x_mis, y_mis);
 #else
-  MB_MODE_INFO *mbmi = set_offsets(cm, xd, bsize, mi_row, mi_col, bw, bh, x_mis,
-                                   y_mis, bwl, bhl);
+  mbmi = set_offsets(cm, xd, bsize, mi_row, mi_col, bw, bh, x_mis, y_mis, bwl,
+                     bhl);
 #if CONFIG_EXT_PARTITION_TYPES
   xd->mi[0]->mbmi.partition = partition;
 #endif
@@ -3715,9 +3735,14 @@
 #endif
   }
 
-  for (j = 0; j < INTRA_MODES; j++)
+  for (j = 0; j < INTRA_MODES; j++) {
     for (i = 0; i < INTRA_MODES - 1; ++i)
       av1_diff_update_prob(&r, &fc->uv_mode_prob[j][i], ACCT_STR);
+#if CONFIG_DAALA_EC
+    av1_tree_to_cdf(av1_intra_mode_tree, fc->uv_mode_prob[j],
+                    fc->uv_mode_cdf[j]);
+#endif
+  }
 
 #if CONFIG_EXT_PARTITION_TYPES
   for (i = 0; i < PARTITION_TYPES - 1; ++i)
@@ -3744,10 +3769,18 @@
 
   if (frame_is_intra_only(cm)) {
     av1_copy(cm->kf_y_prob, av1_kf_y_mode_prob);
+#if CONFIG_DAALA_EC
+    av1_copy(cm->kf_y_cdf, av1_kf_y_mode_cdf);
+#endif
     for (k = 0; k < INTRA_MODES; k++)
-      for (j = 0; j < INTRA_MODES; j++)
+      for (j = 0; j < INTRA_MODES; j++) {
         for (i = 0; i < INTRA_MODES - 1; ++i)
           av1_diff_update_prob(&r, &cm->kf_y_prob[k][j][i], ACCT_STR);
+#if CONFIG_DAALA_EC
+        av1_tree_to_cdf(av1_intra_mode_tree, cm->kf_y_prob[k][j],
+                        cm->kf_y_cdf[k][j]);
+#endif
+      }
   } else {
 #if !CONFIG_REF_MV
     nmv_context *const nmvc = &fc->nmvc;
@@ -3799,9 +3832,14 @@
 
     read_frame_reference_mode_probs(cm, &r);
 
-    for (j = 0; j < BLOCK_SIZE_GROUPS; j++)
+    for (j = 0; j < BLOCK_SIZE_GROUPS; j++) {
       for (i = 0; i < INTRA_MODES - 1; ++i)
         av1_diff_update_prob(&r, &fc->y_mode_prob[j][i], ACCT_STR);
+#if CONFIG_DAALA_EC
+      av1_tree_to_cdf(av1_intra_mode_tree, fc->y_mode_prob[j],
+                      fc->y_mode_cdf[j]);
+#endif
+    }
 
 #if CONFIG_REF_MV
     for (i = 0; i < NMV_CONTEXTS; ++i)
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index 8260f9d..07c745d 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -26,7 +26,6 @@
 #include "aom_dsp/aom_dsp_common.h"
 
 #define ACCT_STR __func__
-
 #if CONFIG_EXT_INTRA || CONFIG_FILTER_INTRA || CONFIG_PALETTE
 static INLINE int read_uniform(aom_reader *r, int n) {
   int l = get_unsigned_bits(n);
@@ -42,9 +41,16 @@
 }
 #endif  // CONFIG_EXT_INTRA || CONFIG_FILTER_INTRA || CONFIG_PALETTE
 
+#if CONFIG_DAALA_EC
+static PREDICTION_MODE read_intra_mode(aom_reader *r, const aom_cdf_prob *cdf) {
+  return (PREDICTION_MODE)
+      av1_intra_mode_inv[aom_read_symbol(r, cdf, INTRA_MODES, ACCT_STR)];
+}
+#else
 static PREDICTION_MODE read_intra_mode(aom_reader *r, const aom_prob *p) {
   return (PREDICTION_MODE)aom_read_tree(r, av1_intra_mode_tree, p, ACCT_STR);
 }
+#endif
 
 #if CONFIG_DELTA_Q
 static int read_delta_qindex(AV1_COMMON *cm, MACROBLOCKD *xd, aom_reader *r,
@@ -85,7 +91,11 @@
 static PREDICTION_MODE read_intra_mode_y(AV1_COMMON *cm, MACROBLOCKD *xd,
                                          aom_reader *r, int size_group) {
   const PREDICTION_MODE y_mode =
+#if CONFIG_DAALA_EC
+      read_intra_mode(r, cm->fc->y_mode_cdf[size_group]);
+#else
       read_intra_mode(r, cm->fc->y_mode_prob[size_group]);
+#endif
   FRAME_COUNTS *counts = xd->counts;
   if (counts) ++counts->y_mode[size_group][y_mode];
   return y_mode;
@@ -95,7 +105,11 @@
                                           aom_reader *r,
                                           PREDICTION_MODE y_mode) {
   const PREDICTION_MODE uv_mode =
+#if CONFIG_DAALA_EC
+      read_intra_mode(r, cm->fc->uv_mode_cdf[y_mode]);
+#else
       read_intra_mode(r, cm->fc->uv_mode_prob[y_mode]);
+#endif
   FRAME_COUNTS *counts = xd->counts;
   if (counts) ++counts->uv_mode[y_mode][uv_mode];
   return uv_mode;
@@ -176,8 +190,13 @@
   // Invalid prediction mode.
   assert(0);
 #else
+#if CONFIG_DAALA_EC
+  const int mode = av1_inter_mode_inv[aom_read_symbol(
+      r, cm->fc->inter_mode_cdf[ctx], INTER_MODES, ACCT_STR)];
+#else
   const int mode = aom_read_tree(r, av1_inter_mode_tree,
                                  cm->fc->inter_mode_probs[ctx], ACCT_STR);
+#endif
   FRAME_COUNTS *counts = xd->counts;
   if (counts) ++counts->inter_mode[ctx][mode];
 
@@ -657,24 +676,48 @@
     case BLOCK_4X4:
       for (i = 0; i < 4; ++i)
         mi->bmi[i].as_mode =
+#if CONFIG_DAALA_EC
+            read_intra_mode(r, get_y_mode_cdf(cm, mi, above_mi, left_mi, i));
+#else
             read_intra_mode(r, get_y_mode_probs(cm, mi, above_mi, left_mi, i));
+#endif
       mbmi->mode = mi->bmi[3].as_mode;
       break;
     case BLOCK_4X8:
       mi->bmi[0].as_mode = mi->bmi[2].as_mode =
+#if CONFIG_DAALA_EC
+          read_intra_mode(r, get_y_mode_cdf(cm, mi, above_mi, left_mi, 0));
+#else
           read_intra_mode(r, get_y_mode_probs(cm, mi, above_mi, left_mi, 0));
+#endif
       mi->bmi[1].as_mode = mi->bmi[3].as_mode = mbmi->mode =
+#if CONFIG_DAALA_EC
+          read_intra_mode(r, get_y_mode_cdf(cm, mi, above_mi, left_mi, 1));
+#else
           read_intra_mode(r, get_y_mode_probs(cm, mi, above_mi, left_mi, 1));
+#endif
       break;
     case BLOCK_8X4:
       mi->bmi[0].as_mode = mi->bmi[1].as_mode =
+#if CONFIG_DAALA_EC
+          read_intra_mode(r, get_y_mode_cdf(cm, mi, above_mi, left_mi, 0));
+#else
           read_intra_mode(r, get_y_mode_probs(cm, mi, above_mi, left_mi, 0));
+#endif
       mi->bmi[2].as_mode = mi->bmi[3].as_mode = mbmi->mode =
+#if CONFIG_DAALA_EC
+          read_intra_mode(r, get_y_mode_cdf(cm, mi, above_mi, left_mi, 2));
+#else
           read_intra_mode(r, get_y_mode_probs(cm, mi, above_mi, left_mi, 2));
+#endif
       break;
     default:
       mbmi->mode =
+#if CONFIG_DAALA_EC
+          read_intra_mode(r, get_y_mode_cdf(cm, mi, above_mi, left_mi, 0));
+#else
           read_intra_mode(r, get_y_mode_probs(cm, mi, above_mi, left_mi, 0));
+#endif
   }
 
   mbmi->uv_mode = read_intra_mode_uv(cm, xd, r, mbmi->mode);
@@ -741,7 +784,11 @@
   int mag, d, fr, hp;
   const int sign = aom_read(r, mvcomp->sign, ACCT_STR);
   const int mv_class =
+#if CONFIG_DAALA_EC
+      aom_read_symbol(r, mvcomp->class_cdf, MV_CLASSES, ACCT_STR);
+#else
       aom_read_tree(r, av1_mv_class_tree, mvcomp->classes, ACCT_STR);
+#endif
   const int class0 = mv_class == MV_CLASS_0;
 
   // Integer part
@@ -757,9 +804,14 @@
     mag = CLASS0_SIZE << (mv_class + 2);
   }
 
-  // Fractional part
+// Fractional part
+#if CONFIG_DAALA_EC
+  fr = aom_read_symbol(r, class0 ? mvcomp->class0_fp_cdf[d] : mvcomp->fp_cdf,
+                       MV_FP_SIZE, ACCT_STR);
+#else
   fr = aom_read_tree(r, av1_mv_fp_tree,
                      class0 ? mvcomp->class0_fp[d] : mvcomp->fp, ACCT_STR);
+#endif
 
   // High precision part (if hp is not used, the default value of the hp is 1)
   hp = usehp ? aom_read(r, class0 ? mvcomp->class0_hp : mvcomp->hp, ACCT_STR)
@@ -777,7 +829,11 @@
   const int use_hp = allow_hp && av1_use_mv_hp(ref);
   MV diff = { 0, 0 };
   joint_type =
+#if CONFIG_DAALA_EC
+      (MV_JOINT_TYPE)aom_read_symbol(r, ctx->joint_cdf, MV_JOINTS, ACCT_STR);
+#else
       (MV_JOINT_TYPE)aom_read_tree(r, av1_mv_joint_tree, ctx->joints, ACCT_STR);
+#endif
 
   if (mv_joint_vertical(joint_type))
     diff.row = read_mv_component(r, &ctx->comps[0], use_hp);
diff --git a/av1/decoder/decoder.c b/av1/decoder/decoder.c
index 9952650..bcc6a1b 100644
--- a/av1/decoder/decoder.c
+++ b/av1/decoder/decoder.c
@@ -52,6 +52,10 @@
                           SWITCHABLE_FILTERS, av1_switchable_interp_tree);
     av1_indices_from_tree(av1_ext_tx_ind, av1_ext_tx_inv, TX_TYPES,
                           av1_ext_tx_tree);
+    av1_indices_from_tree(av1_intra_mode_ind, av1_intra_mode_inv, INTRA_MODES,
+                          av1_intra_mode_tree);
+    av1_indices_from_tree(av1_inter_mode_ind, av1_inter_mode_inv, INTER_MODES,
+                          av1_inter_mode_tree);
 #endif
   }
 }
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index e0fb7ec..5ae920b 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -192,13 +192,19 @@
       structure. */
   av1_indices_from_tree(av1_ext_tx_ind, av1_ext_tx_inv, TX_TYPES,
                         av1_ext_tx_tree);
+  av1_indices_from_tree(av1_intra_mode_ind, av1_intra_mode_inv, INTRA_MODES,
+                        av1_intra_mode_tree);
+  av1_indices_from_tree(av1_inter_mode_ind, av1_inter_mode_inv, INTER_MODES,
+                        av1_inter_mode_tree);
 #endif
 }
 
+#if !CONFIG_DAALA_EC
 static void write_intra_mode(aom_writer *w, PREDICTION_MODE mode,
                              const aom_prob *probs) {
   av1_write_token(w, av1_intra_mode_tree, probs, &intra_mode_encodings[mode]);
 }
+#endif
 
 #if CONFIG_EXT_INTER
 static void write_interintra_mode(aom_writer *w, INTERINTRA_MODE mode,
@@ -252,10 +258,17 @@
     }
   }
 #else
-  const aom_prob *const inter_probs = cm->fc->inter_mode_probs[mode_ctx];
   assert(is_inter_mode(mode));
-  av1_write_token(w, av1_inter_mode_tree, inter_probs,
-                  &inter_mode_encodings[INTER_OFFSET(mode)]);
+#if CONFIG_DAALA_EC
+  aom_write_symbol(w, av1_inter_mode_ind[INTER_OFFSET(mode)],
+                   cm->fc->inter_mode_cdf[mode_ctx], INTER_MODES);
+#else
+  {
+    const aom_prob *const inter_probs = cm->fc->inter_mode_probs[mode_ctx];
+    av1_write_token(w, av1_inter_mode_tree, inter_probs,
+                    &inter_mode_encodings[INTER_OFFSET(mode)]);
+  }
+#endif
 #endif
 }
 
@@ -1233,7 +1246,13 @@
 
   if (!is_inter) {
     if (bsize >= BLOCK_8X8) {
+#if CONFIG_DAALA_EC
+      aom_write_symbol(w, av1_intra_mode_ind[mode],
+                       cm->fc->y_mode_cdf[size_group_lookup[bsize]],
+                       INTRA_MODES);
+#else
       write_intra_mode(w, mode, cm->fc->y_mode_prob[size_group_lookup[bsize]]);
+#endif
     } else {
       int idx, idy;
       const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize];
@@ -1241,11 +1260,21 @@
       for (idy = 0; idy < 2; idy += num_4x4_h) {
         for (idx = 0; idx < 2; idx += num_4x4_w) {
           const PREDICTION_MODE b_mode = mi->bmi[idy * 2 + idx].as_mode;
+#if CONFIG_DAALA_EC
+          aom_write_symbol(w, av1_intra_mode_ind[b_mode], cm->fc->y_mode_cdf[0],
+                           INTRA_MODES);
+#else
           write_intra_mode(w, b_mode, cm->fc->y_mode_prob[0]);
+#endif
         }
       }
     }
+#if CONFIG_DAALA_EC
+    aom_write_symbol(w, av1_intra_mode_ind[mbmi->uv_mode],
+                     cm->fc->uv_mode_cdf[mode], INTRA_MODES);
+#else
     write_intra_mode(w, mbmi->uv_mode, cm->fc->uv_mode_prob[mode]);
+#endif
 #if CONFIG_EXT_INTRA
     write_intra_angle_info(cm, xd, w);
 #endif  // CONFIG_EXT_INTRA
@@ -1622,8 +1651,13 @@
     write_selected_tx_size(cm, xd, w);
 
   if (bsize >= BLOCK_8X8) {
+#if CONFIG_DAALA_EC
+    aom_write_symbol(w, av1_intra_mode_ind[mbmi->mode],
+                     get_y_mode_cdf(cm, mi, above_mi, left_mi, 0), INTRA_MODES);
+#else
     write_intra_mode(w, mbmi->mode,
                      get_y_mode_probs(cm, mi, above_mi, left_mi, 0));
+#endif
   } else {
     const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize];
     const int num_4x4_h = num_4x4_blocks_high_lookup[bsize];
@@ -1632,13 +1666,23 @@
     for (idy = 0; idy < 2; idy += num_4x4_h) {
       for (idx = 0; idx < 2; idx += num_4x4_w) {
         const int block = idy * 2 + idx;
+#if CONFIG_DAALA_EC
+        aom_write_symbol(w, av1_intra_mode_ind[mi->bmi[block].as_mode],
+                         get_y_mode_cdf(cm, mi, above_mi, left_mi, block),
+                         INTRA_MODES);
+#else
         write_intra_mode(w, mi->bmi[block].as_mode,
                          get_y_mode_probs(cm, mi, above_mi, left_mi, block));
+#endif
       }
     }
   }
-
+#if CONFIG_DAALA_EC
+  aom_write_symbol(w, av1_intra_mode_ind[mbmi->uv_mode],
+                   cm->fc->uv_mode_cdf[mbmi->mode], INTRA_MODES);
+#else
   write_intra_mode(w, mbmi->uv_mode, cm->fc->uv_mode_prob[mbmi->mode]);
+#endif
 #if CONFIG_EXT_INTRA
   write_intra_angle_info(cm, xd, w);
 #endif  // CONFIG_EXT_INTRA
@@ -3592,9 +3636,14 @@
 #endif
   update_seg_probs(cpi, header_bc);
 
-  for (i = 0; i < INTRA_MODES; ++i)
+  for (i = 0; i < INTRA_MODES; ++i) {
     prob_diff_update(av1_intra_mode_tree, fc->uv_mode_prob[i],
                      counts->uv_mode[i], INTRA_MODES, header_bc);
+#if CONFIG_DAALA_EC
+    av1_tree_to_cdf(av1_intra_mode_tree, fc->uv_mode_prob[i],
+                    fc->uv_mode_cdf[i]);
+#endif
+  }
 
 #if CONFIG_EXT_PARTITION_TYPES
   prob_diff_update(av1_partition_tree, fc->partition_prob[0],
@@ -3621,17 +3670,30 @@
 
   if (frame_is_intra_only(cm)) {
     av1_copy(cm->kf_y_prob, av1_kf_y_mode_prob);
+#if CONFIG_DAALA_EC
+    av1_copy(cm->kf_y_cdf, av1_kf_y_mode_cdf);
+#endif
     for (i = 0; i < INTRA_MODES; ++i)
-      for (j = 0; j < INTRA_MODES; ++j)
+      for (j = 0; j < INTRA_MODES; ++j) {
         prob_diff_update(av1_intra_mode_tree, cm->kf_y_prob[i][j],
                          counts->kf_y_mode[i][j], INTRA_MODES, header_bc);
+#if CONFIG_DAALA_EC
+        av1_tree_to_cdf(av1_intra_mode_tree, cm->kf_y_prob[i][j],
+                        cm->kf_y_cdf[i][j]);
+#endif
+      }
   } else {
 #if CONFIG_REF_MV
     update_inter_mode_probs(cm, header_bc, counts);
 #else
-    for (i = 0; i < INTER_MODE_CONTEXTS; ++i)
+    for (i = 0; i < INTER_MODE_CONTEXTS; ++i) {
       prob_diff_update(av1_inter_mode_tree, cm->fc->inter_mode_probs[i],
                        counts->inter_mode[i], INTER_MODES, header_bc);
+#if CONFIG_DAALA_EC
+      av1_tree_to_cdf(av1_inter_mode_tree, cm->fc->inter_mode_probs[i],
+                      cm->fc->inter_mode_cdf[i]);
+#endif
+    }
 #endif
 
 #if CONFIG_EXT_INTER
@@ -3713,9 +3775,14 @@
       }
     }
 
-    for (i = 0; i < BLOCK_SIZE_GROUPS; ++i)
+    for (i = 0; i < BLOCK_SIZE_GROUPS; ++i) {
       prob_diff_update(av1_intra_mode_tree, cm->fc->y_mode_prob[i],
                        counts->y_mode[i], INTRA_MODES, header_bc);
+#if CONFIG_DAALA_EC
+      av1_tree_to_cdf(av1_intra_mode_tree, cm->fc->y_mode_prob[i],
+                      cm->fc->y_mode_cdf[i]);
+#endif
+    }
 
     av1_write_nmv_probs(cm, cm->allow_high_precision_mv, header_bc,
 #if CONFIG_REF_MV
@@ -3723,6 +3790,10 @@
 #else
                         &counts->mv);
 #endif
+#if CONFIG_DAALA_EC
+    av1_tree_to_cdf(av1_mv_joint_tree, cm->fc->nmvc.joints,
+                    cm->fc->nmvc.joint_cdf);
+#endif
     update_ext_tx_probs(cm, header_bc);
 #if CONFIG_SUPERTX
     if (!xd->lossless[0]) update_supertx_probs(cm, header_bc);
diff --git a/av1/encoder/encodemv.c b/av1/encoder/encodemv.c
index 7276fee..53dac12 100644
--- a/av1/encoder/encodemv.c
+++ b/av1/encoder/encodemv.c
@@ -45,9 +45,13 @@
   // Sign
   aom_write(w, sign, mvcomp->sign);
 
-  // Class
+// Class
+#if CONFIG_DAALA_EC
+  aom_write_symbol(w, mv_class, mvcomp->class_cdf, MV_CLASSES);
+#else
   av1_write_token(w, av1_mv_class_tree, mvcomp->classes,
                   &mv_class_encodings[mv_class]);
+#endif
 
   // Integer bits
   if (mv_class == MV_CLASS_0) {
@@ -58,10 +62,16 @@
     for (i = 0; i < n; ++i) aom_write(w, (d >> i) & 1, mvcomp->bits[i]);
   }
 
-  // Fractional bits
+// Fractional bits
+#if CONFIG_DAALA_EC
+  aom_write_symbol(
+      w, fr, mv_class == MV_CLASS_0 ? mvcomp->class0_fp_cdf[d] : mvcomp->fp_cdf,
+      MV_FP_SIZE);
+#else
   av1_write_token(w, av1_mv_fp_tree,
                   mv_class == MV_CLASS_0 ? mvcomp->class0_fp[d] : mvcomp->fp,
                   &mv_fp_encodings[fr]);
+#endif
 
   // High precision bit
   if (usehp)
@@ -203,6 +213,9 @@
     update_mv(w, comp_counts->sign, &comp->sign, MV_UPDATE_PROB);
     write_mv_update(av1_mv_class_tree, comp->classes, comp_counts->classes,
                     MV_CLASSES, w);
+#if CONFIG_DAALA_EC
+    av1_tree_to_cdf(av1_mv_class_tree, comp->classes, comp->class_cdf);
+#endif
     write_mv_update(av1_mv_class0_tree, comp->class0, comp_counts->class0,
                     CLASS0_SIZE, w);
     for (j = 0; j < MV_OFFSET_BITS; ++j)
@@ -210,12 +223,19 @@
   }
 
   for (i = 0; i < 2; ++i) {
-    for (j = 0; j < CLASS0_SIZE; ++j)
+    for (j = 0; j < CLASS0_SIZE; ++j) {
       write_mv_update(av1_mv_fp_tree, mvc->comps[i].class0_fp[j],
                       counts->comps[i].class0_fp[j], MV_FP_SIZE, w);
-
+#if CONFIG_DAALA_EC
+      av1_tree_to_cdf(av1_mv_fp_tree, mvc->comps[i].class0_fp[j],
+                      mvc->comps[i].class0_fp_cdf[j]);
+#endif
+    }
     write_mv_update(av1_mv_fp_tree, mvc->comps[i].fp, counts->comps[i].fp,
                     MV_FP_SIZE, w);
+#if CONFIG_DAALA_EC
+    av1_tree_to_cdf(av1_mv_fp_tree, mvc->comps[i].fp, mvc->comps[i].fp_cdf);
+#endif
   }
 
   if (usehp) {
@@ -239,7 +259,11 @@
 #if CONFIG_REF_MV
   (void)is_compound;
 #endif
+#if CONFIG_DAALA_EC
+  aom_write_symbol(w, j, mvctx->joint_cdf, MV_JOINTS);
+#else
   av1_write_token(w, av1_mv_joint_tree, mvctx->joints, &mv_joint_encodings[j]);
+#endif
   if (mv_joint_vertical(j))
     encode_mv_component(w, diff.row, &mvctx->comps[0], usehp);
 
diff --git a/av1/encoder/x86/hybrid_fwd_txfm_avx2.c b/av1/encoder/x86/hybrid_fwd_txfm_avx2.c
index 928af13..f4bd142 100644
--- a/av1/encoder/x86/hybrid_fwd_txfm_avx2.c
+++ b/av1/encoder/x86/hybrid_fwd_txfm_avx2.c
@@ -14,6 +14,7 @@
 #include "./av1_rtcd.h"
 #include "./aom_dsp_rtcd.h"
 
+#include "aom_dsp/x86/fwd_txfm_avx2.h"
 #include "aom_dsp/txfm_common.h"
 #include "aom_dsp/x86/txfm_common_avx2.h"
 
@@ -273,24 +274,11 @@
   in[15] = _mm256_slli_epi16(in[15], 2);
 }
 
-static INLINE void write_buffer_16x16(const __m256i *in, int stride,
-                                      tran_low_t *output) {
-  _mm256_storeu_si256((__m256i *)output, in[0]);
-  _mm256_storeu_si256((__m256i *)(output + stride), in[1]);
-  _mm256_storeu_si256((__m256i *)(output + 2 * stride), in[2]);
-  _mm256_storeu_si256((__m256i *)(output + 3 * stride), in[3]);
-  _mm256_storeu_si256((__m256i *)(output + 4 * stride), in[4]);
-  _mm256_storeu_si256((__m256i *)(output + 5 * stride), in[5]);
-  _mm256_storeu_si256((__m256i *)(output + 6 * stride), in[6]);
-  _mm256_storeu_si256((__m256i *)(output + 7 * stride), in[7]);
-  _mm256_storeu_si256((__m256i *)(output + 8 * stride), in[8]);
-  _mm256_storeu_si256((__m256i *)(output + 9 * stride), in[9]);
-  _mm256_storeu_si256((__m256i *)(output + 10 * stride), in[10]);
-  _mm256_storeu_si256((__m256i *)(output + 11 * stride), in[11]);
-  _mm256_storeu_si256((__m256i *)(output + 12 * stride), in[12]);
-  _mm256_storeu_si256((__m256i *)(output + 13 * stride), in[13]);
-  _mm256_storeu_si256((__m256i *)(output + 14 * stride), in[14]);
-  _mm256_storeu_si256((__m256i *)(output + 15 * stride), in[15]);
+static INLINE void write_buffer_16x16(const __m256i *in, tran_low_t *output) {
+  int i;
+  for (i = 0; i < 16; ++i) {
+    storeu_output_avx2(&in[i], output + (i << 4));
+  }
 }
 
 static void right_shift_16x16(__m256i *in) {
@@ -1253,7 +1241,7 @@
     default: assert(0); break;
   }
   mm256_transpose_16x16(in);
-  write_buffer_16x16(in, 16, output);
+  write_buffer_16x16(in, output);
   _mm256_zeroupper();
 }
 
@@ -1623,12 +1611,13 @@
 }
 
 static INLINE void write_buffer_32x32(const __m256i *in0, const __m256i *in1,
-                                      int stride, tran_low_t *output) {
+                                      tran_low_t *output) {
   int i = 0;
+  const int stride = 32;
   tran_low_t *coeff = output;
   while (i < 32) {
-    _mm256_storeu_si256((__m256i *)coeff, in0[i]);
-    _mm256_storeu_si256((__m256i *)(coeff + 16), in1[i]);
+    storeu_output_avx2(&in0[i], coeff);
+    storeu_output_avx2(&in1[i], coeff + 16);
     coeff += stride;
     i += 1;
   }
@@ -1885,6 +1874,6 @@
     default: assert(0); break;
   }
   nr_right_shift_32x32(in0, in1);
-  write_buffer_32x32(in0, in1, 32, output);
+  write_buffer_32x32(in0, in1, output);
   _mm256_zeroupper();
 }
diff --git a/test/fht32x32_test.cc b/test/fht32x32_test.cc
index 3d07b44..1f85761 100644
--- a/test/fht32x32_test.cc
+++ b/test/fht32x32_test.cc
@@ -90,8 +90,14 @@
   IhtFunc inv_txfm_;
 };
 
+// TODO(luoyi): Owing to the range check in DCT_DCT of av1_fht32x32_avx2, as
+// input is out of the range, we use aom_fdct32x32_avx2. However this function
+// does not support CONFIG_AOM_HIGHBITDEPTH. I need to fix the scaling/rounding
+// of av1_fht32x32_avx2 then add this test on CONFIG_AOM_HIGHBITDEPTH.
+#if !CONFIG_AOM_HIGHBITDEPTH
 TEST_P(AV1Trans32x32HT, CoeffCheck) { RunCoeffCheck(); }
 TEST_P(AV1Trans32x32HT, MemCheck) { RunMemCheck(); }
+#endif
 
 #if CONFIG_AOM_HIGHBITDEPTH
 class AV1HighbdTrans32x32HT