Hi,
this is a regression present on the mainline and 6 branch: the compiler now
generates wrong code for the attached testcase at -O because of an internal
conflict about boolean types. The sequence is as follows. In .mergephi3:
boolean _22;
p__enum res;
<bb 9>:
if (_22 != 0)
goto <bb 10>;
else
goto <bb 11>;
<bb 10>:
<bb 11>:
# res_17 = PHI <2(8), 0(9), 1(10)>
is turned into:
COND_EXPR in block 9 and PHI in block 11 converted to straightline code.
PHI res_17 changed to factor conversion out from COND_EXPR.
New stmt with CAST that defines res_17.
boolean _33;
<bb 10>:
# _33 = PHI <2(8), _22(9)>
res_17 = (p__enum) _33;
[...]
<bb 12>:
if (res_17 != 0)
goto <bb 13>;
else
goto <bb 14>;
<bb 13>:
_12 = res_17 == 2;
_13 = (integer) _12
in .phiopt1. So boolean _33 can have value 2. Later forwprop3 propagates _33
into the uses of res_17:
<bb 12>:
if (_33 != 0)
goto <bb 13>;
else
goto <bb 14>;
<bb 13>:
_12 = _33 == 2;
_13 = (integer) _12;
and DOM3 deduces:
<bb 13>:
_12 = 0;
_13 = 0;
because it computes that _33 has value 1 in BB 13 since it's a boolean.
The problem was introduced by the new factor_out_conditional_conversion:
/* If arg1 is an INTEGER_CST, fold it to new type. */
if (INTEGRAL_TYPE_P (TREE_TYPE (new_arg0))
&& int_fits_type_p (arg1, TREE_TYPE (new_arg0)))
{
if (gimple_assign_cast_p (arg0_def_stmt))
new_arg1 = fold_convert (TREE_TYPE (new_arg0), arg1);
else
return NULL;
}
else
return NULL
int_fits_type_p is documented as taking only INTEGER_TYPE, but is invoked
on constant 2 and a BOOLEAN_TYPE and returns true.
BOOLEAN_TYPE is special in Ada: it has precision 8 and range [0;255] so the
outcome of int_fits_type_p is not unreasonable. But this goes against the
various transformations applied to boolean types in the compiler, which all
assume that they can only take values 0 or 1.
Hence the attached fix (which should be a no-op except for Ada), tested on
x86_64-suse-linux, OK for mainline and 6 branch?
2016-10-18 Eric Botcazou <ebotca...@adacore.com>
* tree.c (int_fits_type_p): Accept only 0 and 1 for boolean types.
2016-10-18 Eric Botcazou <ebotca...@adacore.com>
* gnat.dg/opt59.adb: New test.
* gnat.dg/opt59_pkg.ad[sb]: New helper.
--
Eric Botcazou
Index: tree.c
===================================================================
--- tree.c (revision 241294)
+++ tree.c (working copy)
@@ -9065,8 +9065,8 @@ get_narrower (tree op, int *unsignedp_pt
return win;
}
-/* Returns true if integer constant C has a value that is permissible
- for type TYPE (an INTEGER_TYPE). */
+/* Return true if integer constant C has a value that is permissible
+ for TYPE, an integral type. */
bool
int_fits_type_p (const_tree c, const_tree type)
@@ -9075,6 +9075,11 @@ int_fits_type_p (const_tree c, const_tre
bool ok_for_low_bound, ok_for_high_bound;
signop sgn_c = TYPE_SIGN (TREE_TYPE (c));
+ /* Short-circuit boolean types since various transformations assume that
+ they can only take values 0 and 1. */
+ if (TREE_CODE (type) == BOOLEAN_TYPE)
+ return integer_zerop (c) || integer_onep (c);
+
retry:
type_low_bound = TYPE_MIN_VALUE (type);
type_high_bound = TYPE_MAX_VALUE (type);
-- { dg-do run }
-- { dg-options "-O" }
with Opt59_Pkg; use Opt59_Pkg;
procedure Opt59 is
type Enum is (Zero, One, Two);
function Has_True (V : Boolean_Vector) return Boolean is
begin
for I in V'Range loop
if V (I) then
return True;
end if;
end loop;
return False;
end;
Data1 : constant Boolean_Vector := Get_BV1;
Data2 : constant Boolean_Vector := Get_BV2;
Result : Boolean_Vector;
function F return Enum is
Res : Enum := Zero;
Set1 : constant Boolean := Has_True (Data1);
Set2 : constant Boolean := Has_True (Data2);
begin
if Set1 then
Res := Two;
elsif Set2 then
Res := One;
end if;
return Res;
end;
Val : constant Enum := F;
begin
for I in Result'Range loop
Result (I) := Data1 (I) or Data2 (I);
end loop;
if Val /= Zero then
Test (Val = Two);
end if;
end;
package body Opt59_Pkg is
function Get_BV1 return Boolean_Vector is
begin
return (others => True);
end;
function Get_BV2 return Boolean_Vector is
begin
return (others => False);
end;
procedure Test (B : Boolean) is
begin
if not B then
raise Program_Error;
end if;
end;
end Opt59_Pkg;
package Opt59_Pkg is
type Boolean_Vector is array (1 .. 8) of Boolean;
function Get_BV1 return Boolean_Vector;
function Get_BV2 return Boolean_Vector;
procedure Test (B : Boolean);
end Opt59_Pkg;