Hi All,

While toying with the switch conversion GIMPLE pass I noticed that the pass
generates a dead statement.  I wanted to investigate why this happens and
potentially fix this.  However after looking into the part of the pass
responsible for generating the code in question I still have no idea why the
dead statement is generated.  Can someone more experienced look at this and
tell me what is going on, please?

Let's say I'm compiling this C testcase

int main()
{
    switch (a % 4)
    {
        case 0: return 10;
        case 1: return 20;
        case 2: return 30;
        default: return 40;
    }
}

Since the switch computes a linear function, the linear transformation feature
of switch conversion triggers -- with cofficients A = 10 and B = 10 in this
case.  This is the relevant GCC source code.  It is a part of the
switch_conversion::build_one_array () function:

      if (dump_file && coeff_a.to_uhwi () > 0)
        fprintf (dump_file, "Linear transformation with A = %" PRId64
                 " and B = %" PRId64 "\n", coeff_a.to_shwi (),
                 coeff_b.to_shwi ());
      
      /* We must use type of constructor values.  */
      gimple_seq seq = NULL;
      tree tmp = gimple_convert (&seq, type, m_index_expr);
      tree tmp2 = gimple_build (&seq, MULT_EXPR, type,
                                wide_int_to_tree (type, coeff_a), tmp);
      tree tmp3 = gimple_build (&seq, PLUS_EXPR, type, tmp2,
                                wide_int_to_tree (type, coeff_b));
      tree tmp4 = gimple_convert (&seq, TREE_TYPE (name), tmp3);
      gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
      load = gimple_build_assign (name, tmp4);

Before this code is run, the GIMPLE of the basic block in question looks like
this (output of debug_bb (m_switch_bb)):

a.0_1 = a;
_2 = a.0_1 % 4;
_9 = (unsigned int) _2;
switch (_2) <default: <L4> [INV], case 0: <L6> [INV], case 1: <L1> [INV], case 
2: <L2> [INV], case 3: <L3> [INV]>

What I would expect to see is something like this (also output of debug_bb ()
but this time after the code I listed was run):

a.0_1 = a;
_2 = a.0_1 % 4;
_9 = (unsigned int) _2;
_7 = (unsigned int) _2;
_8 = 10 * _7;
_10 = _8 + 10;
switch (_2) <default: <L4> [INV], case 0: <L6> [INV], case 1: <L1> [INV], case 
2: <L2> [INV], case 3: <L3> [INV]>

but what I instead see is this:

a.0_1 = a;
_2 = a.0_1 % 4;
_9 = (unsigned int) _2;
_7 = (unsigned int) _2;
_6 = 10 * _7;
_5 = _7 + 1;
_10 = _5 * 10;
_11 = (int) _10;
switch (_2) <default: <L4> [INV], case 0: <L6> [INV], case 1: <L1> [INV], case 
2: <L2> [INV], case 3: <L3> [INV]>

The first thing I noticed is that there are two multiplications instead of one
and that the result of one of them doesn't get used (this redundant
multiplication is the original reason I started looking into this).  But there
is also a cast to int that I don't see how the GCC code created and the order
of the non-dead multiplication and addition is switched and the added constant
(coefficient B) is 1 instead of 10 (which is correct but just not what I expect
from reading the code).

What am I not seeing here?  Does gsi_insert_seq_before do some optimizations on
the seq it inserts?

Thanks,
Filip Kastl

Reply via email to