TEST_F(PostVerify, ConstantPropagation) {
  TRACE(CONSTP, 1, "------------- post ---------------\n");
  auto cls = find_class_named(classes, "Lredex/ConstantPropagationTest;");
  ASSERT_NE(cls, nullptr);
  for (auto& meth : cls->get_vmethods()) {
    if(meth->get_name()->str().find("if") == std::string::npos) {
      continue;
    }
    IRCode* code = new IRCode(meth);
    EXPECT_NE(code, nullptr);
    code->build_cfg(/* editable */ true);
    if (meth->get_name()->str().find("plus_one") != std::string::npos) {
      TRACE(CONSTP, 1, "%s\n", SHOW(meth));
      TRACE(CONSTP, 1, "%s\n", SHOW(code));
    }

    EXPECT_EQ(0, count_ifs(code->cfg()));
    if (meth->get_name()->str().find("plus_one") != std::string::npos) {
      EXPECT_EQ(0, count_ops(code->cfg(), OPCODE_ADD_INT_LIT8));
    }

    if (meth->get_name()->str().find("overflow") != std::string::npos) {
      // make sure we don't fold overflow at compile time
      EXPECT_EQ(1, count_ops(code->cfg(), OPCODE_ADD_INT_LIT8));
    }
    code->clear_cfg();
  }
}
Resampler::Resampler(int src_x, int src_y,
                     int dst_x, int dst_y,
                     Boundary_Op boundary_op,
                     Resample_Real sample_low, Resample_Real sample_high,
                     const char* Pfilter_name,
                     Contrib_List* Pclist_x,
                     Contrib_List* Pclist_y,
                     Resample_Real filter_x_scale,
                     Resample_Real filter_y_scale,
                     Resample_Real src_x_ofs,
                     Resample_Real src_y_ofs)
{
   int i, j;
   Resample_Real support, (*func)(Resample_Real);

   resampler_assert(src_x > 0);
   resampler_assert(src_y > 0);
   resampler_assert(dst_x > 0);
   resampler_assert(dst_y > 0);

#if RESAMPLER_DEBUG_OPS
   total_ops = 0;
#endif

   m_lo = sample_low;
   m_hi = sample_high;

   m_delay_x_resample = false;
   m_intermediate_x = 0;
   m_Pdst_buf = NULL;
   m_Ptmp_buf = NULL;
   m_clist_x_forced = false;
   m_Pclist_x = NULL;
   m_clist_y_forced = false;
   m_Pclist_y = NULL;
   m_Psrc_y_count = NULL;
   m_Psrc_y_flag = NULL;
   m_Pscan_buf = NULL;
   m_status = STATUS_OKAY;

   m_resample_src_x = src_x;
   m_resample_src_y = src_y;
   m_resample_dst_x = dst_x;
   m_resample_dst_y = dst_y;

   m_boundary_op = boundary_op;

   if ((m_Pdst_buf = (Sample*)malloc(m_resample_dst_x * sizeof(Sample))) == NULL)
   {
      m_status = STATUS_OUT_OF_MEMORY;
      return;
   }

   // Find the specified filter.

   if (Pfilter_name == NULL)
      Pfilter_name = RESAMPLER_DEFAULT_FILTER;

   for (i = 0; i < NUM_FILTERS; i++)
      if (strcmp(Pfilter_name, g_filters[i].name) == 0)
         break;

   if (i == NUM_FILTERS)
   {
      m_status = STATUS_BAD_FILTER_NAME;
      return;
   }

   func = g_filters[i].func;
   support = g_filters[i].support;

   /* Create contributor lists, unless the user supplied custom lists. */

   if (!Pclist_x)
   {
      m_Pclist_x = make_clist(m_resample_src_x, m_resample_dst_x, m_boundary_op, func, support, filter_x_scale, src_x_ofs);
      if (!m_Pclist_x)
      {
         m_status = STATUS_OUT_OF_MEMORY;
         return;
      }
   }
   else
   {
      m_Pclist_x = Pclist_x;
      m_clist_x_forced = true;
   }

   if (!Pclist_y)
   {
      m_Pclist_y = make_clist(m_resample_src_y, m_resample_dst_y, m_boundary_op, func, support, filter_y_scale, src_y_ofs);
      if (!m_Pclist_y)
      {
         m_status = STATUS_OUT_OF_MEMORY;
         return;
      }
   }
   else
   {
      m_Pclist_y = Pclist_y;
      m_clist_y_forced = true;
   }

   if ((m_Psrc_y_count = (int*)calloc(m_resample_src_y, sizeof(int))) == NULL)
   {
      m_status = STATUS_OUT_OF_MEMORY;
      return;
   }

   if ((m_Psrc_y_flag = (unsigned char*)calloc(m_resample_src_y, sizeof(unsigned char))) == NULL)
   {
      m_status = STATUS_OUT_OF_MEMORY;
      return;
   }

   /* Count how many times each source line
   * contributes to a destination line.
   */

   for (i = 0; i < m_resample_dst_y; i++)
      for (j = 0; j < m_Pclist_y[i].n; j++)
         m_Psrc_y_count[resampler_range_check(m_Pclist_y[i].p[j].pixel, m_resample_src_y)]++;

   if ((m_Pscan_buf = (Scan_Buf*)malloc(sizeof(Scan_Buf))) == NULL)
   {
      m_status = STATUS_OUT_OF_MEMORY;
      return;
   }

   for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
   {
      m_Pscan_buf->scan_buf_y[i] = -1;
      m_Pscan_buf->scan_buf_l[i] = NULL;
   }

   m_cur_src_y = m_cur_dst_y = 0;
   {
      // Determine which axis to resample first by comparing the number of multiplies required
      // for each possibility.
      int x_ops = count_ops(m_Pclist_x, m_resample_dst_x);
      int y_ops = count_ops(m_Pclist_y, m_resample_dst_y);

      // Hack 10/2000: Weight Y axis ops a little more than X axis ops.
      // (Y axis ops use more cache resources.)
      int xy_ops = x_ops * m_resample_src_y +
         (4 * y_ops * m_resample_dst_x)/3;

      int yx_ops = (4 * y_ops * m_resample_src_x)/3 +
         x_ops * m_resample_dst_y;

#if RESAMPLER_DEBUG_OPS
      printf("src: %i %i\n", m_resample_src_x, m_resample_src_y);
      printf("dst: %i %i\n", m_resample_dst_x, m_resample_dst_y);
      printf("x_ops: %i\n", x_ops);
      printf("y_ops: %i\n", y_ops);
      printf("xy_ops: %i\n", xy_ops);
      printf("yx_ops: %i\n", yx_ops);
#endif

      // Now check which resample order is better. In case of a tie, choose the order
      // which buffers the least amount of data.
      if ((xy_ops > yx_ops) ||
         ((xy_ops == yx_ops) && (m_resample_src_x < m_resample_dst_x))
         )
      {
         m_delay_x_resample = true;
         m_intermediate_x = m_resample_src_x;
      }
      else
      {
         m_delay_x_resample = false;
         m_intermediate_x = m_resample_dst_x;
      }
#if RESAMPLER_DEBUG_OPS
      printf("delaying: %i\n", m_delay_x_resample);
#endif
   }

   if (m_delay_x_resample)
   {
      if ((m_Ptmp_buf = (Sample*)malloc(m_intermediate_x * sizeof(Sample))) == NULL)
      {
         m_status = STATUS_OUT_OF_MEMORY;
         return;
      }
   }
}