On Wed, 6 Nov 2024, Jan Hubicka wrote: > Hi, > this is updated patch which adds -fmalloc-dce flag to control malloc/free > removal. I ended up copying what -fallocation-dse does so -fmalloc-dce=1 > enables malloc/free removal provided return value is unused otherwise and > -fmalloc-dce=2 allows additional NULL pointer checks which it folds to > non-NULL > direction. > > I also added compensation for the gcc.dg/analyzer/pr101837.c testcase and > added testcase that std::nothrow variant of operator new is now optimized way. > > With the -fmalloc-dce=n I can also add a level which emits runtime check for > half > of address space and calloc overflow if it seems useful, but perhaps > incrementally. Adding size parameter tracking is not that hard (I posted WIP > patch for that). > > Bootstrapped/regtested x86_64-linux, OK? > > * common.opt: Add -fmalloc-dce. > * doc/invoke.texi: Document it; also add missing -flifetime-dse entry. > * tree-ssa-dce.cc (is_removable_allocation_p): Break out from > ... > (mark_stmt_if_obviously_necessary): ... here; also check that > operator new satisfies gimple_call_from_new_or_delete. > (checks_return_value_of_removable_allocation_p): New Function. > (mark_all_reaching_defs_necessary_1): add missing case ofr
for > STRDUP and STRNDUP > (propagate_necessity): Use is_removable_allocation_p and > checks_return_value_of_removable_allocation_p. > (eliminate_unnecessary_stmts): Update conditionals that use > removed allocation; use is_removable_allocation_p. > > gcc/testsuite/ChangeLog: > > * g++.dg/cdce3.C: Disable allocation dce. > * g++.dg/tree-ssa/pr19476-1.C: Likewise. > * g++.dg/tree-ssa/pr19476-2.C: Likewise. > * g++.dg/tree-ssa/pr19476-3.C: Likewise. > * g++.dg/tree-ssa/pr19476-4.C: Likewise. > * gcc.dg/analyzer/pr101837.c: Disable malloc dce. > * gcc.dg/tree-ssa/pr19831-3.c: Update. > * gfortran.dg/pr68078.f90: Disable malloc DCE. > * g++.dg/tree-ssa/dce-1.C: New test. > > diff --git a/gcc/common.opt b/gcc/common.opt > index 0b1f1ec26e1..1a79f71789e 100644 > --- a/gcc/common.opt > +++ b/gcc/common.opt > @@ -2282,6 +2282,13 @@ fmax-errors= > Common Joined RejectNegative UInteger Var(flag_max_errors) > -fmax-errors=<number> Maximum number of errors to report. > > +fmalloc-dce > +Common Var(flag_malloc_dce,2) Init(2) Optimization > +Allow removal of malloc and free pairs when allocated block is unused > + > +fmalloc-dce= > +Common Joined RejectNegative UInteger Var(flag_malloc_dse) Optimization > IntegerRange(0, 2) > + > fmem-report > Common Var(mem_report) > Report on permanent memory allocation. > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index 7146163d66d..ba69ebe591c 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -585,7 +585,7 @@ Objective-C and Objective-C++ Dialects}. > -fipa-bit-cp -fipa-vrp -fipa-pta -fipa-profile -fipa-pure-const > -fipa-reference -fipa-reference-addressable > -fipa-stack-alignment -fipa-icf -fira-algorithm=@var{algorithm} > --flate-combine-instructions -flive-patching=@var{level} > +-flate-combine-instructions -flifetime-dse -flive-patching=@var{level} > -fira-region=@var{region} -fira-hoist-pressure > -fira-loop-pressure -fno-ira-share-save-slots > -fno-ira-share-spill-slots > @@ -595,7 +595,7 @@ Objective-C and Objective-C++ Dialects}. > -floop-block -floop-interchange -floop-strip-mine > -floop-unroll-and-jam -floop-nest-optimize > -floop-parallelize-all -flra-remat -flto -flto-compression-level > --flto-partition=@var{alg} -fmerge-all-constants > +-flto-partition=@var{alg} -fmalloc-dce -fmerge-all-constants > -fmerge-constants -fmodulo-sched -fmodulo-sched-allow-regmoves > -fmove-loop-invariants -fmove-loop-stores -fno-branch-count-reg > -fno-defer-pop -fno-fp-int-builtin-inexact -fno-function-cse > @@ -14568,8 +14568,12 @@ affected by @option{-flimit-function-alignment} > > > @opindex fno-allocation-dce > +@opindex fallocation-dce > @item -fno-allocation-dce > -Do not remove unused C++ allocations in dead code elimination. > +Do not remove unused C++ allocations (using operator @code{new} and operator > @code{delete}) > +in dead code elimination. > + > +See also @option{-fmalloc-dce}. > > @opindex fallow-store-data-races > @item -fallow-store-data-races > @@ -15442,6 +15446,18 @@ number of iterations). > > Enabled by @option{-O3}, @option{-fprofile-use}, and @option{-fauto-profile}. > > +@opindex fno-malloc-dce > +@opindex fmalloc-dce > +@item -fmalloc-dce > +Control whether @code{malloc} (and its variatns such as @code{calloc} or variants > +@code{strdup}), can be optimized away provided its return value is only used > +as a parameter of @code{free} call or compared with @code{NULL}. If > +@option{-fmalloc-dce=1} is used, only calls to @code{free} are allowed while > +with @option{-fmalloc-dce=2} also comparsions with @code{NULL} pointer are > +considered safe to remove. > + > +The default is @option{-fmalloc-dce=2}. See also @option{-fallocation-dce}. > + > @opindex fmove-loop-invariants > @item -fmove-loop-invariants > Enables the loop invariant motion pass in the RTL loop optimizer. Enabled > diff --git a/gcc/testsuite/g++.dg/cdce3.C b/gcc/testsuite/g++.dg/cdce3.C > index 2543317f6b2..9aecf58a8b8 100644 > --- a/gcc/testsuite/g++.dg/cdce3.C > +++ b/gcc/testsuite/g++.dg/cdce3.C > @@ -1,6 +1,6 @@ > /* { dg-do run } */ > /* { dg-require-effective-target c99_runtime } */ > -/* { dg-options "-O2 -fmath-errno -fdump-tree-cdce-details -lm" } */ > +/* { dg-options "-O2 -fmath-errno -fdump-tree-cdce-details -lm > -fno-allocation-dce" } */ > /* { dg-additional-options "-DLARGE_LONG_DOUBLE" { target large_long_double > } } */ > /* { dg-additional-options "-DGNU_EXTENSION" { target pow10 } } */ > /* { dg-add-options ieee } */ > diff --git a/gcc/testsuite/g++.dg/tree-ssa/dce-1.C > b/gcc/testsuite/g++.dg/tree-ssa/dce-1.C > new file mode 100644 > index 00000000000..1d5115ccb14 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/tree-ssa/dce-1.C > @@ -0,0 +1,9 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-optimized" } */ > +#include <new> > +void test () > +{ > + int *a = new (std::nothrow) int; > + delete a; > +} > +/* { dg-final { scan-tree-dump-not "operator new" "optimized" } } */ > diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr19476-1.C > b/gcc/testsuite/g++.dg/tree-ssa/pr19476-1.C > index 25867185648..d17be88642f 100644 > --- a/gcc/testsuite/g++.dg/tree-ssa/pr19476-1.C > +++ b/gcc/testsuite/g++.dg/tree-ssa/pr19476-1.C > @@ -1,5 +1,5 @@ > /* { dg-do compile } */ > -/* { dg-options "-O -fdump-tree-dom2 -fdelete-null-pointer-checks" } */ > +/* { dg-options "-O -fdump-tree-dom2 -fdelete-null-pointer-checks > -fno-allocation-dce" } */ > /* { dg-skip-if "" keeps_null_pointer_checks } */ > > // See pr19476-5.C for a version without including <new>. > diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr19476-2.C > b/gcc/testsuite/g++.dg/tree-ssa/pr19476-2.C > index 0f657d5bd0c..aab7d04ab92 100644 > --- a/gcc/testsuite/g++.dg/tree-ssa/pr19476-2.C > +++ b/gcc/testsuite/g++.dg/tree-ssa/pr19476-2.C > @@ -1,5 +1,5 @@ > /* { dg-do compile } */ > -/* { dg-options "-O2 -fdump-tree-optimized -fdelete-null-pointer-checks" } */ > +/* { dg-options "-O2 -fdump-tree-optimized -fdelete-null-pointer-checks > -fno-allocation-dce" } */ > /* { dg-skip-if "" keeps_null_pointer_checks } */ > > #include <new> > diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr19476-3.C > b/gcc/testsuite/g++.dg/tree-ssa/pr19476-3.C > index fd5117fceb8..0894178c470 100644 > --- a/gcc/testsuite/g++.dg/tree-ssa/pr19476-3.C > +++ b/gcc/testsuite/g++.dg/tree-ssa/pr19476-3.C > @@ -1,5 +1,5 @@ > /* { dg-do compile } */ > -/* { dg-options "-O3 -fcheck-new -fdump-tree-optimized" } */ > +/* { dg-options "-O3 -fcheck-new -fdump-tree-optimized -fno-allocation-dce" > } */ > > #include <new> > > diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr19476-4.C > b/gcc/testsuite/g++.dg/tree-ssa/pr19476-4.C > index 5f137391cc6..e5c216a64fa 100644 > --- a/gcc/testsuite/g++.dg/tree-ssa/pr19476-4.C > +++ b/gcc/testsuite/g++.dg/tree-ssa/pr19476-4.C > @@ -1,5 +1,5 @@ > /* { dg-do compile } */ > -/* { dg-options "-O3 -fno-delete-null-pointer-checks -fdump-tree-optimized" > } */ > +/* { dg-options "-O3 -fno-delete-null-pointer-checks -fdump-tree-optimized > -fno-allocation-dce" } */ > > #include <new> > > diff --git a/gcc/testsuite/gcc.dg/analyzer/pr101837.c > b/gcc/testsuite/gcc.dg/analyzer/pr101837.c > index f99374df604..1a1f7f63637 100644 > --- a/gcc/testsuite/gcc.dg/analyzer/pr101837.c > +++ b/gcc/testsuite/gcc.dg/analyzer/pr101837.c > @@ -1,4 +1,4 @@ > -/* { dg-additional-options "-O3 -fsanitize=undefined" } */ > +/* { dg-additional-options "-O3 -fsanitize=undefined -fno-malloc-dce" } */ > > void memory_exhausted(); > void memcheck(void *ptr) { > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c > b/gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c > index f5cb72daa33..e6ae6582ab2 100644 > --- a/gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c > +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c > @@ -29,10 +29,5 @@ void test6(void) > Assume p was non-NULL for test2. > For test5, it doesn't matter if p is NULL or non-NULL. */ > > -/* { dg-final { scan-tree-dump-times "free" 0 "optimized" { xfail *-*-* } } > } */ > -/* { dg-final { scan-tree-dump-times "malloc" 0 "optimized" { xfail *-*-* } > } } */ > - > -/* But make sure we don't partially optimize for now. */ > - > -/* { dg-final { scan-tree-dump-times "free" 3 "optimized" } } */ > -/* { dg-final { scan-tree-dump-times "malloc" 3 "optimized" } } */ > +/* { dg-final { scan-tree-dump-times "free" 0 "optimized" } } */ > +/* { dg-final { scan-tree-dump-times "malloc" 0 "optimized" } } */ > diff --git a/gcc/testsuite/gfortran.dg/pr68078.f90 > b/gcc/testsuite/gfortran.dg/pr68078.f90 > index ebe26d55d2b..6494aa62362 100644 > --- a/gcc/testsuite/gfortran.dg/pr68078.f90 > +++ b/gcc/testsuite/gfortran.dg/pr68078.f90 > @@ -1,4 +1,6 @@ > ! { dg-do run { target i?86-*-linux* x86_64-*-linux* } } > +! disable DCE so the allocations are not optimized away > +! { dg-additional-options "-fno-malloc-dce" } > ! { dg-additional-sources set_vm_limit.c } > ! > ! This test calls set_vm_limit to set an artificially low address space > diff --git a/gcc/tree-ssa-dce.cc b/gcc/tree-ssa-dce.cc > index c44eff35b84..f4807adb926 100644 > --- a/gcc/tree-ssa-dce.cc > +++ b/gcc/tree-ssa-dce.cc > @@ -240,6 +240,60 @@ mark_operand_necessary (tree op) > worklist.safe_push (stmt); > } > > +/* Return true if STMT is a call to allocation function that can be > + optimized out if the memory block is never used for anything else > + then NULL pointer check or free. > + If NON_NULL_CHECK is false, we can furhter assume that return value > + is never checked to be non-NULL. */ > + > +static bool > +is_removable_allocation_p (gcall *stmt, bool non_null_check) > +{ > + tree callee = gimple_call_fndecl (stmt); > + if (callee != NULL_TREE > + && fndecl_built_in_p (callee, BUILT_IN_NORMAL)) > + switch (DECL_FUNCTION_CODE (callee)) > + { > + case BUILT_IN_MALLOC: > + case BUILT_IN_ALIGNED_ALLOC: > + case BUILT_IN_CALLOC: > + CASE_BUILT_IN_ALLOCA: > + case BUILT_IN_STRDUP: > + case BUILT_IN_STRNDUP: > + return non_null_check ? flag_malloc_dce > 1 : flag_malloc_dce; > + > + case BUILT_IN_GOMP_ALLOC: > + return true; > + > + default:; > + } > + > + if (callee != NULL_TREE > + && flag_allocation_dce > + && gimple_call_from_new_or_delete (stmt) > + && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)) > + return true; > + return false; > +} > + > +/* Return true if STMT is a conditional > + if (ptr != NULL) > + where ptr was returned by a removable allocation function. */ > + > +static bool > +checks_return_value_of_removable_allocation_p (gimple *stmt) > +{ > + gcall *def_stmt; > + return gimple_code (stmt) == GIMPLE_COND > + && (gimple_cond_code (stmt) == EQ_EXPR > + || gimple_cond_code (stmt) == NE_EXPR) > + && integer_zerop (gimple_cond_rhs (stmt)) > + && TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME > + && (def_stmt = dyn_cast <gcall *> > + (SSA_NAME_DEF_STMT (gimple_cond_lhs (stmt)))) > + && is_removable_allocation_p (def_stmt, true); > +} > + > > /* Mark STMT as necessary if it obviously is. Add it to the worklist if > it can make other statements necessary. > @@ -271,38 +325,23 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool > aggressive) > > case GIMPLE_CALL: > { > + gcall *call = as_a <gcall *> (stmt); > + > /* Never elide a noreturn call we pruned control-flow for. */ > - if ((gimple_call_flags (stmt) & ECF_NORETURN) > - && gimple_call_ctrl_altering_p (stmt)) > + if ((gimple_call_flags (call) & ECF_NORETURN) > + && gimple_call_ctrl_altering_p (call)) > { > - mark_stmt_necessary (stmt, true); > + mark_stmt_necessary (call, true); > return; > } > > - tree callee = gimple_call_fndecl (stmt); > - if (callee != NULL_TREE > - && fndecl_built_in_p (callee, BUILT_IN_NORMAL)) > - switch (DECL_FUNCTION_CODE (callee)) > - { > - case BUILT_IN_MALLOC: > - case BUILT_IN_ALIGNED_ALLOC: > - case BUILT_IN_CALLOC: > - CASE_BUILT_IN_ALLOCA: > - case BUILT_IN_STRDUP: > - case BUILT_IN_STRNDUP: > - case BUILT_IN_GOMP_ALLOC: > - return; > - > - default:; > - } > > - if (callee != NULL_TREE > - && flag_allocation_dce > - && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)) > + if (is_removable_allocation_p (call, false)) > return; > > + > /* For __cxa_atexit calls, don't mark as necessary right away. */ > - if (is_removable_cxa_atexit_call (stmt)) > + if (is_removable_cxa_atexit_call (call)) > return; > > /* IFN_GOACC_LOOP calls are necessary in that they are used to > @@ -311,9 +350,9 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool > aggressive) > survive from aggressive loop removal for it has loop exit and > is assumed to be finite. Therefore, we need to explicitly mark > these calls. (An example is libgomp.oacc-c-c++-common/pr84955.c) */ > - if (gimple_call_internal_p (stmt, IFN_GOACC_LOOP)) > + if (gimple_call_internal_p (call, IFN_GOACC_LOOP)) > { > - mark_stmt_necessary (stmt, true); > + mark_stmt_necessary (call, true); > return; > } > break; > @@ -667,6 +706,8 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref > ATTRIBUTE_UNUSED, > case BUILT_IN_ALIGNED_ALLOC: > case BUILT_IN_CALLOC: > CASE_BUILT_IN_ALLOCA: > + case BUILT_IN_STRDUP: > + case BUILT_IN_STRNDUP: > case BUILT_IN_FREE: > case BUILT_IN_GOMP_ALLOC: > case BUILT_IN_GOMP_FREE: > @@ -891,19 +932,11 @@ propagate_necessity (bool aggressive) > { > tree ptr = gimple_call_arg (stmt, 0); > gcall *def_stmt; > - tree def_callee; > /* If the pointer we free is defined by an allocation > function do not add the call to the worklist. */ > if (TREE_CODE (ptr) == SSA_NAME > && (def_stmt = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (ptr))) > - && (def_callee = gimple_call_fndecl (def_stmt)) > - && ((DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL > - && (DECL_FUNCTION_CODE (def_callee) == > BUILT_IN_ALIGNED_ALLOC > - || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC > - || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC > - || DECL_FUNCTION_CODE (def_callee) == > BUILT_IN_GOMP_ALLOC)) > - || (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee) > - && gimple_call_from_new_or_delete (def_stmt)))) > + && is_removable_allocation_p (def_stmt, false)) > { > if (is_delete_operator > && !valid_new_delete_pair_p (def_stmt, stmt)) > @@ -925,6 +958,9 @@ propagate_necessity (bool aggressive) > } > } > > + if (checks_return_value_of_removable_allocation_p (stmt)) > + continue; > + > FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) > mark_operand_necessary (use); > > @@ -1379,7 +1415,6 @@ eliminate_unnecessary_stmts (bool aggressive) > basic_block bb; > gimple_stmt_iterator gsi, psi; > gimple *stmt; > - tree call; > auto_vec<edge> to_remove_edges; > > if (dump_file && (dump_flags & TDF_DETAILS)) > @@ -1448,6 +1483,23 @@ eliminate_unnecessary_stmts (bool aggressive) > gimple_set_plf (stmt, STMT_NECESSARY, false); > } > } > + /* Conditional checking that return value of allocation is non-NULL > + can be turned to constant if the allocation itself > + is unnecesary. */ > + if (gimple_plf (stmt, STMT_NECESSARY) > + && gimple_code (stmt) == GIMPLE_COND > + && TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME) > + { > + gimple *def_stmt = SSA_NAME_DEF_STMT (gimple_cond_lhs (stmt)); > + if (!gimple_nop_p (def_stmt) > + && !gimple_plf (def_stmt, STMT_NECESSARY)) > + { > + gcc_checking_assert > + (checks_return_value_of_removable_allocation_p (stmt)); > + gimple_cond_set_lhs (as_a <gcond *>(stmt), integer_one_node); please use a correctly typed constant, use build_one_cst (TREE_TYPE (gimple_cond_rhs (stmt))) for example. Alternatively use gimple_cond_make_{false,true} (based on gimple_cond_code) or also set rhs, to integer_zero_node. OK with those changes. It warrants a changes.html entry. Thanks, Richard. > + update_stmt (stmt); > + } > + } > > /* If GSI is not necessary then remove it. */ > if (!gimple_plf (stmt, STMT_NECESSARY)) > @@ -1482,11 +1534,11 @@ eliminate_unnecessary_stmts (bool aggressive) > remove_dead_stmt (&gsi, bb, to_remove_edges); > continue; > } > - else if (is_gimple_call (stmt)) > + else if (gcall *call_stmt = dyn_cast <gcall *> (stmt)) > { > - tree name = gimple_call_lhs (stmt); > + tree name = gimple_call_lhs (call_stmt); > > - notice_special_calls (as_a <gcall *> (stmt)); > + notice_special_calls (call_stmt); > > /* When LHS of var = call (); is dead, simplify it into > call (); saving one operand. */ > @@ -1496,36 +1548,30 @@ eliminate_unnecessary_stmts (bool aggressive) > /* Avoid doing so for allocation calls which we > did not mark as necessary, it will confuse the > special logic we apply to malloc/free pair removal. */ > - && (!(call = gimple_call_fndecl (stmt)) > - || ((DECL_BUILT_IN_CLASS (call) != BUILT_IN_NORMAL > - || (DECL_FUNCTION_CODE (call) != > BUILT_IN_ALIGNED_ALLOC > - && DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC > - && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC > - && !ALLOCA_FUNCTION_CODE_P > - (DECL_FUNCTION_CODE (call)))) > - && !DECL_IS_REPLACEABLE_OPERATOR_NEW_P (call)))) > + && !is_removable_allocation_p (call_stmt, false)) > { > something_changed = true; > if (dump_file && (dump_flags & TDF_DETAILS)) > { > fprintf (dump_file, "Deleting LHS of call: "); > - print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); > + print_gimple_stmt (dump_file, call_stmt, 0, TDF_SLIM); > fprintf (dump_file, "\n"); > } > > - gimple_call_set_lhs (stmt, NULL_TREE); > - maybe_clean_or_replace_eh_stmt (stmt, stmt); > - update_stmt (stmt); > + gimple_call_set_lhs (call_stmt, NULL_TREE); > + maybe_clean_or_replace_eh_stmt (call_stmt, call_stmt); > + update_stmt (call_stmt); > release_ssa_name (name); > > /* GOMP_SIMD_LANE (unless three argument) or ASAN_POISON > without lhs is not needed. */ > - if (gimple_call_internal_p (stmt)) > - switch (gimple_call_internal_fn (stmt)) > + if (gimple_call_internal_p (call_stmt)) > + switch (gimple_call_internal_fn (call_stmt)) > { > case IFN_GOMP_SIMD_LANE: > - if (gimple_call_num_args (stmt) >= 3 > - && !integer_nonzerop (gimple_call_arg (stmt, 2))) > + if (gimple_call_num_args (call_stmt) >= 3 > + && !integer_nonzerop > + (gimple_call_arg (call_stmt, 2))) > break; > /* FALLTHRU */ > case IFN_ASAN_POISON: > @@ -1535,8 +1581,8 @@ eliminate_unnecessary_stmts (bool aggressive) > break; > } > } > - else if (gimple_call_internal_p (stmt)) > - switch (gimple_call_internal_fn (stmt)) > + else if (gimple_call_internal_p (call_stmt)) > + switch (gimple_call_internal_fn (call_stmt)) > { > case IFN_ADD_OVERFLOW: > maybe_optimize_arith_overflow (&gsi, PLUS_EXPR); > @@ -1548,11 +1594,11 @@ eliminate_unnecessary_stmts (bool aggressive) > maybe_optimize_arith_overflow (&gsi, MULT_EXPR); > break; > case IFN_UADDC: > - if (integer_zerop (gimple_call_arg (stmt, 2))) > + if (integer_zerop (gimple_call_arg (call_stmt, 2))) > maybe_optimize_arith_overflow (&gsi, PLUS_EXPR); > break; > case IFN_USUBC: > - if (integer_zerop (gimple_call_arg (stmt, 2))) > + if (integer_zerop (gimple_call_arg (call_stmt, 2))) > maybe_optimize_arith_overflow (&gsi, MINUS_EXPR); > break; > default: > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)