[Ada] Eliminate redundant range checks on conversions
authorEric Botcazou <ebotcazou@adacore.com>
Mon, 12 Aug 2019 08:59:28 +0000 (08:59 +0000)
committerPierre-Marie de Rodat <pmderodat@gcc.gnu.org>
Mon, 12 Aug 2019 08:59:28 +0000 (08:59 +0000)
commit4e896dad492f7484cc239f105454713a3c4596eb
treecd09f826db06fdc86d3ce5f01813709dbebd678f
parent5aa76fe17be6f6c222d16d5a51f60ed7755c6ad6
[Ada] Eliminate redundant range checks on conversions

This gets rid of redundant range checks generated in 5 out of the 9
cases of scalar conversions, i.e. (integer, fixed-point, floating-point)
converted to (integer, fixed-point, floating-point).

The problem is that the Real_Range_Check routine rewrites the conversion
node into a conversion to the base type so, when its parent node is
analyzed, a new conversion to the subtype may be introduced, depending
on the context, giving rise to a second range check against the subtype
bounds.

This change makes Real_Range_Check rewrite the expression of the
conversion node instead of the node, so that the type of the node is
preserved and no new conversion is introduced.  As a matter of fact,
this is exactly what happens in the float-to-float case which goes to
the Generate_Range_Check circuit instead and does not suffer from the
duplication of range checks.

For the following procedure, the compiler must now generate exactly one
range check per nested function:

procedure P is

  type I1 is new Integer range -100 .. 100;

  type I2 is new Integer range -200 .. 200;

  type D1 is delta 0.5 range -100.0 .. 100.0;

  type D2 is delta 0.5 range -200.0 .. 200.0;

  type F1 is new Long_Float range -100.0 .. 100.0;

  type F2 is new Long_Float range -200.0 .. 200.0;

  function Conv (A : I2) return I1 is
  begin
    return I1 (A);
  end;

  function Conv (A : D2) return I1 is
  begin
    return I1 (A);
  end;

  function Conv (A : F2) return I1 is
  begin
    return I1 (A);
  end;

  function Conv (A : I2) return D1 is
  begin
    return D1 (A);
  end;

  function Conv (A : D2) return D1 is
  begin
    return D1 (A);
  end;

  function Conv (A : F2) return D1 is
  begin
    return D1 (A);
  end;

  function Conv (A : I2) return F1 is
  begin
    return F1 (A);
  end;

  function Conv (A : D2) return F1 is
  begin
    return F1 (A);
  end;

  function Conv (A : F2) return F1 is
  begin
    return F1 (A);
  end;

begin
  null;
end;

2019-08-12  Eric Botcazou  <ebotcazou@adacore.com>

gcc/ada/

* exp_ch4.adb (Real_Range_Check): Do not rewrite the conversion
node but its expression instead, after having fetched its
current value.  Clear the Do_Range_Check flag on entry.  Return
early for a rewritten float-to-float conversion.  Remove
redundant local variable.  Suppress all checks when inserting
the temporary and do not reanalyze the node.

From-SVN: r274287
gcc/ada/ChangeLog
gcc/ada/exp_ch4.adb