I felt like it'd be good to resolve some unfinished business in convert_to_integer before starting messing with other convert_to_* functions. This is a response to <https://gcc.gnu.org/ml/gcc-patches/2015-09/msg01255.html>.
> > + if (!dofold) > > + { > > + expr = build1 (CONVERT_EXPR, > > + lang_hooks.types.type_for_size > > + (TYPE_PRECISION (intype), 0), > > + expr); > > + return build1 (CONVERT_EXPR, type, expr); > > + } > > When we're not folding, I don't think we want to do the two-step > conversion, just the second one. And we might want to use NOP_EXPR > instead of CONVERT_EXPR, but I'm not sure about that. Changed. I kept CONVERT_EXPR there even though NOP_EXPR seemed to work as well. > > @@ -818,10 +828,15 @@ convert_to_integer (tree type, tree expr) > > if (TYPE_UNSIGNED (typex)) > > typex = signed_type_for (typex); > > } > > - return convert (type, > > - fold_build2 (ex_form, typex, > > - convert (typex, arg0), > > - convert (typex, arg1))); > > + if (dofold) > > + return convert (type, > > + fold_build2 (ex_form, typex, > > + convert (typex, arg0), > > + convert (typex, arg1))); > > + arg0 = build1 (CONVERT_EXPR, typex, arg0); > > + arg1 = build1 (CONVERT_EXPR, typex, arg1); > > + expr = build2 (ex_form, typex, arg0, arg1); > > + return build1 (CONVERT_EXPR, type, expr); > > This code path seems to be for pushing a conversion down into a binary > expression. We shouldn't do this at all when we aren't folding. I tend to agree, but this case is tricky. What's this code about is e.g. for int fn (long p, long o) { return p + o; } we want to narrow the operation and do the addition on unsigned ints and then convert to int. We do it here because we're still missing the promotion/demotion pass on GIMPLE (PR45397 / PR47477). Disabling this optimization here would regress a few testcases, so I kept the code as it was. Thoughts? > > @@ -845,9 +860,14 @@ convert_to_integer (tree type, tree expr) > > > > if (!TYPE_UNSIGNED (typex)) > > typex = unsigned_type_for (typex); > > + if (!dofold) > > + return build1 (CONVERT_EXPR, type, > > + build1 (ex_form, typex, > > + build1 (CONVERT_EXPR, typex, > > + TREE_OPERAND (expr, 0)))); > > Likewise. Changed. > > @@ -867,6 +887,14 @@ convert_to_integer (tree type, tree expr) > > the conditional and never loses. A COND_EXPR may have a throw > > as one operand, which then has void type. Just leave void > > operands as they are. */ > > + if (!dofold) > > + return build3 (COND_EXPR, type, TREE_OPERAND (expr, 0), > > + VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1))) > > + ? TREE_OPERAND (expr, 1) > > + : build1 (CONVERT_EXPR, type, TREE_OPERAND > > (expr, 1)), > > + VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 2))) > > + ? TREE_OPERAND (expr, 2) > > + : build1 (CONVERT_EXPR, type, TREE_OPERAND > > (expr, 2))); > > Likewise. Changed. > > @@ -903,6 +933,10 @@ convert_to_integer (tree type, tree expr) > > return build1 (FIXED_CONVERT_EXPR, type, expr); > > > > case COMPLEX_TYPE: > > + if (!dofold) > > + return build1 (CONVERT_EXPR, type, > > + build1 (REALPART_EXPR, > > + TREE_TYPE (TREE_TYPE (expr)), expr)); > > Why can't we call convert here rather than build1 a CONVERT_EXPR? I don't know if there was any particular reason but just build1 seems dubious so I've changed this to convert and didn't see any problems. > It would be good to ask a fold/convert maintainer to review the changes > to this file, too. Certainly; comments welcome. Moreover, there are some places in the C++ FE where we still call convert_to_integer and not convert_to_integer_nofold -- should they be changed to the _nofold variant? Bootstrapped/regtested on x86_64-linux, ok for branch? diff --git gcc/convert.c gcc/convert.c index fdb9b9a..40db767 100644 --- gcc/convert.c +++ gcc/convert.c @@ -571,13 +571,7 @@ convert_to_integer_1 (tree type, tree expr, bool dofold) coexistence of multiple valid pointer sizes, so fetch the one we need from the type. */ if (!dofold) - { - expr = build1 (CONVERT_EXPR, - lang_hooks.types.type_for_size - (TYPE_PRECISION (intype), 0), - expr); - return build1 (CONVERT_EXPR, type, expr); - } + return build1 (CONVERT_EXPR, type, expr); expr = fold_build1 (CONVERT_EXPR, lang_hooks.types.type_for_size (TYPE_PRECISION (intype), 0), @@ -622,6 +616,8 @@ convert_to_integer_1 (tree type, tree expr, bool dofold) else code = NOP_EXPR; + if (!dofold) + return build1 (code, type, expr); return fold_build1 (code, type, expr); } @@ -847,6 +843,9 @@ convert_to_integer_1 (tree type, tree expr, bool dofold) /* This is not correct for ABS_EXPR, since we must test the sign before truncation. */ { + if (!dofold) + break; + /* Do the arithmetic in type TYPEX, then convert result to TYPE. */ tree typex = type; @@ -860,11 +859,6 @@ convert_to_integer_1 (tree type, tree expr, bool dofold) if (!TYPE_UNSIGNED (typex)) typex = unsigned_type_for (typex); - if (!dofold) - return build1 (CONVERT_EXPR, type, - build1 (ex_form, typex, - build1 (CONVERT_EXPR, typex, - TREE_OPERAND (expr, 0)))); return convert (type, fold_build1 (ex_form, typex, convert (typex, @@ -887,21 +881,15 @@ convert_to_integer_1 (tree type, tree expr, bool dofold) the conditional and never loses. A COND_EXPR may have a throw as one operand, which then has void type. Just leave void operands as they are. */ - if (!dofold) - return build3 (COND_EXPR, type, TREE_OPERAND (expr, 0), + if (dofold) + return + fold_build3 (COND_EXPR, type, TREE_OPERAND (expr, 0), VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1))) ? TREE_OPERAND (expr, 1) - : build1 (CONVERT_EXPR, type, TREE_OPERAND (expr, 1)), + : convert (type, TREE_OPERAND (expr, 1)), VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 2))) ? TREE_OPERAND (expr, 2) - : build1 (CONVERT_EXPR, type, TREE_OPERAND (expr, 2))); - return fold_build3 (COND_EXPR, type, TREE_OPERAND (expr, 0), - VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1))) - ? TREE_OPERAND (expr, 1) - : convert (type, TREE_OPERAND (expr, 1)), - VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 2))) - ? TREE_OPERAND (expr, 2) - : convert (type, TREE_OPERAND (expr, 2))); + : convert (type, TREE_OPERAND (expr, 2))); default: break; @@ -934,9 +922,9 @@ convert_to_integer_1 (tree type, tree expr, bool dofold) case COMPLEX_TYPE: if (!dofold) - return build1 (CONVERT_EXPR, type, - build1 (REALPART_EXPR, - TREE_TYPE (TREE_TYPE (expr)), expr)); + return convert (type, + build1 (REALPART_EXPR, + TREE_TYPE (TREE_TYPE (expr)), expr)); return convert (type, fold_build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (expr)), expr)); Marek