On September 28, 2019 12:24:40 AM GMT+02:00, Martin Jambor <mjam...@suse.cz> wrote: >Hi, > >On Thu, Sep 26 2019, Richard Biener wrote: >> On Wed, 25 Sep 2019, Martin Jambor wrote: >> >>> Hi, >>> >>> PR 91853 and its duplicate PR 91894 show that IPA-SRA can stumble >when >>> presented with code with mismatched types, whether because it is a >K&R C >>> or happening through an originally indirect call (or probably also >>> because of LTO). >>> >>> The problem is that we try to work with a register value - in this >case >>> an integer constant - like if it was a pointer to a structure and >try to >>> dereference it in the caller, leading to expressions like ADDR_EXPR >of a >>> constant zero. Old IPA-SRA dealt with these simply by checking type >>> compatibility which is difficult in an LTO-capable IPA pass, >basically >>> we would at least have to remember and stream a bitmap for each call >>> telling which arguments are pointers which looks a bit excessive >given >>> that we just don't want to ICE. >>> >>> So this patch attempts to deal with the situation rather than avoid >it. >>> When an integer is used instead of a pointer, there is some chance >that >>> it actually contains the pointer value and so I create a NOP_EXPR to >>> convert it to a pointer (which in the testcase is actually a >widening >>> conversion). For other register types, I don't bother and simply >pull >>> an undefined pointer default definition SSA name and use that. I >wonder >>> whether I should somehow warn as well. Hopefully there is no code >doing >>> that that can conceivably work - maybe someone coding for x86_16 and >>> passing a vector of integers as a segment and offset pointer? :-) >>> >>> What do people think? In any event, this patch passed bootstrap and >>> testing and deals with the issue, so if it is OK, I'd like to commit >it >>> to trunk. >> >> Humm... while I believe this "mostly" matches what we do in >inlining >> (but that also has some type verification disabling inlining for >really >> odd cases IIRC) I think the appropriate fix is in the IPA-SRA >> decision stage (at WPA) where we should see that we cannot modify >> a call in this way. That of course requires streaming of the actual >> call stmt (or at least it's "ABI signature"), not sure if you already >> do that. > >No, I don't. As I wrote above, even though would be enough to know >which actual arguments are pointers and which are not, I'd rather avoid >that too if we can. > >I am looking into doing something similar that inlining does, but I'd >very much like to avoid re-creating a variant of PR 70929 for IPA-SRA >too, so I am looking into that PR. > >> >> So in inlining we do >> >> static gimple * >> setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn, >> basic_block bb, tree *vars) >> { >> ... >> if (value >> && value != error_mark_node >> && !useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE >(value))) >> { >> /* If we can match up types by promotion/demotion do so. */ >> if (fold_convertible_p (TREE_TYPE (p), value)) >> rhs = fold_convert (TREE_TYPE (p), value); >> else >> { >> /* ??? For valid programs we should not end up here. >> Still if we end up with truly mismatched types here, >fall >> back >> to using a VIEW_CONVERT_EXPR or a literal zero to not >leak >> invalid >> GIMPLE to the following passes. */ >> if (!is_gimple_reg_type (TREE_TYPE (value)) >> || TYPE_SIZE (TREE_TYPE (p)) == TYPE_SIZE (TREE_TYPE >> (value))) >> rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (p), >value); >> else >> rhs = build_zero_cst (TREE_TYPE (p)); >> } >> } >> >> I suggest that if we go a similar way that we copy this behavior >> rather than inventing sth similar but slightly different. Maybe >> split it out as >> >> tree >> force_value_to_type (tree type, tree val) > >Makes sense, like the patch below? It has passed bootstrap and testing >on an x86_64-linux. > >> >> which you then would need to eventually re-gimplify of course >> (we could in theory refactor setup_one_parameter to work with >> GIMPLE...) > >If we start with a gimple_val, the code above should at worst produce >something we can feed into gimple_assign_set_rhs_from_tree, which is >not >ideal but is better than full re-gimplification?
Yeah, that should work. Patch is OK. Thanks, Richard. >Thanks, > >Martin > > >2019-09-27 Martin Jambor <mjam...@suse.cz> > > PR ipa/91853 > * tree-inline.c (force_value_to_type): New function. > (setup_one_parameter): Use force_value_to_type to convert type. > * tree-inline.c (force_value_to_type): Declare. > * ipa-param-manipulation.c (ipa_param_adjustments::modify_call): Deal > with register type mismatches. > > testsuite/ > * gcc.dg/ipa/pr91853.c: New test. >--- > gcc/ipa-param-manipulation.c | 11 ++++++-- > gcc/testsuite/gcc.dg/ipa/pr91853.c | 30 ++++++++++++++++++++++ > gcc/tree-inline.c | 41 +++++++++++++++++------------- > gcc/tree-inline.h | 1 + > 4 files changed, 64 insertions(+), 19 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/ipa/pr91853.c > >diff --git a/gcc/ipa-param-manipulation.c >b/gcc/ipa-param-manipulation.c >index 913b96fefa4..bbf646726e2 100644 >--- a/gcc/ipa-param-manipulation.c >+++ b/gcc/ipa-param-manipulation.c >@@ -651,8 +651,15 @@ ipa_param_adjustments::modify_call (gcall *stmt, > bool deref_base = false; > unsigned int deref_align = 0; > if (TREE_CODE (base) != ADDR_EXPR >- && POINTER_TYPE_P (TREE_TYPE (base))) >- off = build_int_cst (apm->alias_ptr_type, apm->unit_offset); >+ && is_gimple_reg_type (TREE_TYPE (base))) >+ { >+ /* Detect type mismatches in calls in invalid programs and make a >+ poor attempt to gracefully convert them so that we don't ICE. >*/ >+ if (!POINTER_TYPE_P (TREE_TYPE (base))) >+ base = force_value_to_type (ptr_type_node, base); >+ >+ off = build_int_cst (apm->alias_ptr_type, apm->unit_offset); >+ } > else > { > bool addrof; >diff --git a/gcc/testsuite/gcc.dg/ipa/pr91853.c >b/gcc/testsuite/gcc.dg/ipa/pr91853.c >new file mode 100644 >index 00000000000..4bad7803751 >--- /dev/null >+++ b/gcc/testsuite/gcc.dg/ipa/pr91853.c >@@ -0,0 +1,30 @@ >+/* { dg-do compile } */ >+/* { dg-options "--param ipa-cp-value-list-size=0 -Os -fno-inline" } >*/ >+ >+struct _wincore >+{ >+ int y; >+ int width; >+}; >+int a; >+void fn2 (void); >+static int fn1 (dpy, winInfo) struct _XDisplay *dpy; >+struct _wincore *winInfo; >+{ >+ a = winInfo->width; >+ fn2 (); >+} >+ >+void fn4 (int, int, int); >+static int fn3 (dpy, winInfo, visrgn) struct _XDisplay *dpy; >+int winInfo, visrgn; >+{ >+ int b = fn1 (0, winInfo); >+ fn4 (0, 0, visrgn); >+} >+ >+int >+fn5 (event) struct _XEvent *event; >+{ >+ fn3 (0, 0, 0); >+} >diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c >index e4ae1b058fd..4c972f3ce60 100644 >--- a/gcc/tree-inline.c >+++ b/gcc/tree-inline.c >@@ -3333,6 +3333,29 @@ insert_init_stmt (copy_body_data *id, >basic_block bb, gimple *init_stmt) > } > } > >+/* Deal with mismatched formal/actual parameters, in a rather >brute-force way >+ if need be (which should only be necessary for invalid programs). >Attempt >+ to convert VAL to TYPE and return the result if it is possible, >just return >+ a zero constant of the given type if it fails. */ >+ >+tree >+force_value_to_type (tree type, tree value) >+{ >+ /* If we can match up types by promotion/demotion do so. */ >+ if (fold_convertible_p (type, value)) >+ return fold_convert (type, value); >+ >+ /* ??? For valid programs we should not end up here. >+ Still if we end up with truly mismatched types here, fall back >+ to using a VIEW_CONVERT_EXPR or a literal zero to not leak >invalid >+ GIMPLE to the following passes. */ >+ if (!is_gimple_reg_type (TREE_TYPE (value)) >+ || TYPE_SIZE (type) == TYPE_SIZE (TREE_TYPE (value))) >+ return fold_build1 (VIEW_CONVERT_EXPR, type, value); >+ else >+ return build_zero_cst (type); >+} >+ >/* Initialize parameter P with VALUE. If needed, produce init >statement > at the end of BB. When BB is NULL, we return init statement to be > output later. */ >@@ -3349,23 +3372,7 @@ setup_one_parameter (copy_body_data *id, tree p, >tree value, tree fn, > if (value > && value != error_mark_node > && !useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE (value))) >- { >- /* If we can match up types by promotion/demotion do so. */ >- if (fold_convertible_p (TREE_TYPE (p), value)) >- rhs = fold_convert (TREE_TYPE (p), value); >- else >- { >- /* ??? For valid programs we should not end up here. >- Still if we end up with truly mismatched types here, fall back >- to using a VIEW_CONVERT_EXPR or a literal zero to not leak >invalid >- GIMPLE to the following passes. */ >- if (!is_gimple_reg_type (TREE_TYPE (value)) >- || TYPE_SIZE (TREE_TYPE (p)) == TYPE_SIZE (TREE_TYPE (value))) >- rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (p), value); >- else >- rhs = build_zero_cst (TREE_TYPE (p)); >- } >- } >+ rhs = force_value_to_type (TREE_TYPE (p), value); > > /* Make an equivalent VAR_DECL. Note that we must NOT remap the type > here since the type of this decl must be visible to the calling >diff --git a/gcc/tree-inline.h b/gcc/tree-inline.h >index 87a149c357b..b226dc03833 100644 >--- a/gcc/tree-inline.h >+++ b/gcc/tree-inline.h >@@ -250,6 +250,7 @@ extern tree copy_fn (tree, tree&, tree&); > extern const char *copy_forbidden (struct function *fun); >extern tree copy_decl_for_dup_finish (copy_body_data *id, tree decl, >tree copy); > extern tree copy_decl_to_var (tree, copy_body_data *); >+extern tree force_value_to_type (tree type, tree value); > > /* This is in tree-inline.c since the routine uses > data structures from the inliner. */