diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c
index 978916057f0..1f47f3a4268 100644
--- a/gcc/ipa-param-manipulation.c
+++ b/gcc/ipa-param-manipulation.c
@@ -953,6 +953,99 @@ ipa_param_body_adjustments::carry_over_param (tree t)
   return new_parm;
 }
 
+/* Return true if BLOCKS_TO_COPY is NULL or if PHI has an argument ARG in
+   position that corresponds to an edge that is coming from a block that has
+   the corresponding bit set in BLOCKS_TO_COPY.  */
+
+static bool
+phi_arg_will_live_p (gphi *phi, bitmap blocks_to_copy, tree arg)
+{
+  bool arg_will_survive = false;
+  if (!blocks_to_copy)
+    arg_will_survive = true;
+  else
+    for (unsigned i = 0; i < gimple_phi_num_args (phi); i++)
+      if (gimple_phi_arg_def (phi, i) == arg
+	  && bitmap_bit_p (blocks_to_copy,
+			   gimple_phi_arg_edge (phi, i)->src->index))
+	{
+	  arg_will_survive = true;
+	  break;
+	}
+  return arg_will_survive;
+}
+
+/* Populate m_dead_stmts given that DEAD_PARAM is going to be removed without
+   any replacement or splitting.  */
+
+void
+ipa_param_body_adjustments::mark_dead_statements (tree dead_param)
+{
+  if (!is_gimple_reg (dead_param))
+    return;
+  tree parm_ddef = ssa_default_def (m_id->src_cfun, dead_param);
+  if (!parm_ddef || has_zero_uses (parm_ddef))
+    return;
+
+  auto_vec<tree, 4> stack;
+  m_dead_ssas.add (parm_ddef);
+  stack.safe_push (parm_ddef);
+  while (!stack.is_empty ())
+    {
+      tree t = stack.pop ();
+
+      imm_use_iterator imm_iter;
+      gimple *stmt;
+
+      insert_decl_map (m_id, t, error_mark_node);
+      FOR_EACH_IMM_USE_STMT (stmt, imm_iter, t)
+	{
+	  if (is_gimple_call (stmt)
+	      || (m_id->blocks_to_copy
+		  && !bitmap_bit_p (m_id->blocks_to_copy,
+				    gimple_bb (stmt)->index)))
+	    continue;
+
+	  if (is_gimple_debug (stmt))
+	    {
+	      m_dead_stmts.add (stmt);
+	      gcc_assert (gimple_debug_bind_p (stmt));
+	    }
+	  else if (gimple_code (stmt) == GIMPLE_PHI)
+	    {
+	      gphi *phi = as_a <gphi *> (stmt);
+	      if (phi_arg_will_live_p (phi, m_id->blocks_to_copy, t))
+		{
+		  m_dead_stmts.add (phi);
+		  tree res = gimple_phi_result (phi);
+		  if (!m_dead_ssas.contains (res))
+		    {
+		      stack.safe_push (res);
+		      m_dead_ssas.add (res);
+		    }
+		}
+	    }
+	  else if (is_gimple_assign (stmt))
+	    {
+	      m_dead_stmts.add (stmt);
+	      if (!gimple_clobber_p (stmt))
+		{
+		  tree lhs = gimple_assign_lhs (stmt);
+		  gcc_assert (TREE_CODE (lhs) == SSA_NAME);
+		  if (!m_dead_ssas.contains (lhs))
+		    {
+		      m_dead_ssas.add (lhs);
+		      stack.safe_push (lhs);
+		    }
+		}
+	    }
+	  else
+	    /* IPA-SRA does not analyze other types of statements.  */
+	    gcc_unreachable ();
+	}
+    }
+}
+
 /* Common initialization performed by all ipa_param_body_adjustments
    constructors.  OLD_FNDECL is the declaration we take original arguments
    from, (it may be the same as M_FNDECL).  VARS, if non-NULL, is a pointer to
@@ -1095,6 +1188,11 @@ ipa_param_body_adjustments::common_initialization (tree old_fndecl,
 		/* Declare this new variable.  */
 		DECL_CHAIN (var) = *vars;
 		*vars = var;
+
+		/* If this is not a split but a real removal, init hash sets
+		   that will guide what not to copy to the new body.  */
+		if (!isra_dummy_decls[i])
+		  mark_dead_statements (m_oparms[i]);
 	      }
 	  }
 	else
@@ -1151,9 +1249,10 @@ ipa_param_body_adjustments
 ::ipa_param_body_adjustments (vec<ipa_adjusted_param, va_gc> *adj_params,
 			      tree fndecl)
   : m_adj_params (adj_params), m_adjustments (NULL), m_reset_debug_decls (),
-    m_split_modifications_p (false), m_fndecl (fndecl), m_id (NULL),
-    m_oparms (), m_new_decls (), m_new_types (), m_replacements (),
-    m_removed_decls (), m_removed_map (), m_method2func (false)
+    m_split_modifications_p (false), m_dead_stmts (), m_dead_ssas (),
+    m_fndecl (fndecl), m_id (NULL), m_oparms (), m_new_decls (),
+    m_new_types (), m_replacements (), m_removed_decls (), m_removed_map (),
+    m_method2func (false)
 {
   common_initialization (fndecl, NULL, NULL);
 }
@@ -1167,9 +1266,9 @@ ipa_param_body_adjustments
 ::ipa_param_body_adjustments (ipa_param_adjustments *adjustments,
 			      tree fndecl)
   : m_adj_params (adjustments->m_adj_params), m_adjustments (adjustments),
-    m_reset_debug_decls (), m_split_modifications_p (false), m_fndecl (fndecl),
-    m_id (NULL), m_oparms (), m_new_decls (), m_new_types (),
-    m_replacements (), m_removed_decls (), m_removed_map (),
+    m_reset_debug_decls (), m_split_modifications_p (false), m_dead_stmts (),
+    m_dead_ssas (), m_fndecl (fndecl), m_id (NULL), m_oparms (), m_new_decls (),
+    m_new_types (), m_replacements (), m_removed_decls (), m_removed_map (),
     m_method2func (false)
 {
   common_initialization (fndecl, NULL, NULL);
@@ -1190,9 +1289,10 @@ ipa_param_body_adjustments
 			      copy_body_data *id, tree *vars,
 			      vec<ipa_replace_map *, va_gc> *tree_map)
   : m_adj_params (adjustments->m_adj_params), m_adjustments (adjustments),
-    m_reset_debug_decls (), m_split_modifications_p (false), m_fndecl (fndecl),
-    m_id (id), m_oparms (), m_new_decls (), m_new_types (), m_replacements (),
-    m_removed_decls (), m_removed_map (), m_method2func (false)
+    m_reset_debug_decls (), m_split_modifications_p (false), m_dead_stmts (),
+    m_dead_ssas (),m_fndecl (fndecl), m_id (id), m_oparms (), m_new_decls (),
+    m_new_types (), m_replacements (), m_removed_decls (), m_removed_map (),
+    m_method2func (false)
 {
   common_initialization (old_fndecl, vars, tree_map);
 }
@@ -1519,6 +1619,19 @@ remap_split_decl_to_dummy (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
+/* Given ARG which is a SSA_NAME call argument which we are however removing
+   from the current function and which will be thus removed from the call
+   statement by ipa_param_adjustments::modify_call, return something that can
+   be used as a placeholder and which the operand scanner will accept until
+   then.  */
+
+tree
+ipa_param_body_adjustments::get_removed_call_arg_placeholder (tree arg)
+{
+  tree t = create_tmp_var (TREE_TYPE (arg));
+  insert_decl_map (m_id, t, t);
+  return t;
+}
 
 /* If the call statement pointed at by STMT_P contains any expressions that
    need to replaced with a different one as noted by ADJUSTMENTS, do so.  f the
@@ -1658,7 +1771,10 @@ ipa_param_body_adjustments::modify_call_stmt (gcall **stmt_p)
 	  else
 	    {
 	      tree t = gimple_call_arg (stmt, i);
-	      modify_expression (&t, true);
+	      if (TREE_CODE (t) == SSA_NAME && m_dead_ssas.contains(t))
+		t = get_removed_call_arg_placeholder (t);
+	      else
+		modify_expression (&t, true);
 	      vargs.safe_push (t);
 	    }
 	}
@@ -1680,7 +1796,11 @@ ipa_param_body_adjustments::modify_call_stmt (gcall **stmt_p)
   for (unsigned i = 0; i < nargs; i++)
     {
       tree *t = gimple_call_arg_ptr (stmt, i);
-      modified |= modify_expression (t, true);
+
+      if (TREE_CODE (*t) == SSA_NAME && m_dead_ssas.contains(*t))
+	*t = get_removed_call_arg_placeholder (*t);
+      else
+	modified |= modify_expression (t, true);
     }
 
   if (gimple_call_lhs (stmt))
diff --git a/gcc/ipa-param-manipulation.h b/gcc/ipa-param-manipulation.h
index 0b038ea57f1..59060ae5dcc 100644
--- a/gcc/ipa-param-manipulation.h
+++ b/gcc/ipa-param-manipulation.h
@@ -370,6 +370,12 @@ public:
   /* Set to true if there are any IPA_PARAM_OP_SPLIT adjustments among stored
      adjustments.  */
   bool m_split_modifications_p;
+
+  /* Sets of statements and SSA_NAMEs that only manipulate data from parameters
+     removed because they are not necessary.  */
+  hash_set<gimple *> m_dead_stmts;
+  hash_set<tree> m_dead_ssas;
+
 private:
   void common_initialization (tree old_fndecl, tree *vars,
 			      vec<ipa_replace_map *, va_gc> *tree_map);
@@ -383,6 +389,8 @@ private:
   bool modify_call_stmt (gcall **stmt_p);
   bool modify_cfun_body ();
   void reset_debug_stmts ();
+  void mark_dead_statements (tree dead_param);
+  tree get_removed_call_arg_placeholder (tree arg);
 
   /* Declaration of the function that is being transformed.  */
 
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-23.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-23.c
new file mode 100644
index 00000000000..f438b509614
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-23.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2"  } */
+
+extern int g;
+
+static int __attribute__((noinline))
+bar (int i, int j)
+{
+  return 2*g + i;
+}
+
+static int __attribute__((noinline))
+foo (int i, int j)
+{
+  if (i > 5)
+    j = 22;
+  return bar (i, j) + 1;
+}
+
+int
+entry (int l, int k)
+{
+  return foo (l, k);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/pr93385.c b/gcc/testsuite/gcc.dg/ipa/pr93385.c
new file mode 100644
index 00000000000..6d1d0d7cd27
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/pr93385.c
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fno-dce -fno-ipa-cp -fno-tree-dce" } */
+
+char a, b;
+
+#ifdef __SIZEOF_INT128__
+#define T unsigned __int128
+#else
+#define T unsigned
+#endif
+
+static inline int
+c (T d)
+{
+  char e = 0;
+  d %= (unsigned) d;
+  e -= 0;
+  __builtin_strncpy (&a, &e, 1);
+  return e + b;
+}
+
+int
+main (void)
+{
+  c (~0);
+  return 0;
+}
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 3160ca3f88a..60087dd5e7b 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -1524,6 +1524,11 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
 	  : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)))
     return NULL;
 
+  if (!is_gimple_debug (stmt)
+      && id->param_body_adjs
+      && id->param_body_adjs->m_dead_stmts.contains (stmt))
+    return NULL;
+
   /* Begin by recognizing trees that we'll completely rewrite for the
      inlining context.  Our output for these trees is completely
      different from our input (e.g. RETURN_EXPR is deleted and morphs
@@ -1788,10 +1793,15 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
 
       if (gimple_debug_bind_p (stmt))
 	{
+	  tree value;
+	  if (id->param_body_adjs
+	      && id->param_body_adjs->m_dead_stmts.contains (stmt))
+	    value = NULL_TREE;
+	  else
+	    value = gimple_debug_bind_get_value (stmt);
 	  gdebug *copy
 	    = gimple_build_debug_bind (gimple_debug_bind_get_var (stmt),
-				       gimple_debug_bind_get_value (stmt),
-				       stmt);
+				       value, stmt);
 	  if (id->reset_location)
 	    gimple_set_location (copy, input_location);
 	  id->debug_stmts.safe_push (copy);
@@ -2671,7 +2681,9 @@ copy_phis_for_bb (basic_block bb, copy_body_data *id)
       phi = si.phi ();
       res = PHI_RESULT (phi);
       new_res = res;
-      if (!virtual_operand_p (res))
+      if (!virtual_operand_p (res)
+	  && (!id->param_body_adjs
+	      || !id->param_body_adjs->m_dead_stmts.contains (phi)))
 	{
 	  walk_tree (&new_res, copy_tree_body_r, id, NULL);
 	  if (EDGE_COUNT (new_bb->preds) == 0)
