diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index 270a9a249d3..97880a5f790 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -6537,22 +6537,27 @@ same_bool_result_p (const_tree op1, const_tree op2)
 
 static tree
 and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
-		   enum tree_code code2, tree op2a, tree op2b);
+		   enum tree_code code2, tree op2a, tree op2b, basic_block);
 static tree
 and_var_with_comparison (tree type, tree var, bool invert,
-			 enum tree_code code2, tree op2a, tree op2b);
+			 enum tree_code code2, tree op2a, tree op2b,
+			 basic_block);
 static tree
 and_var_with_comparison_1 (tree type, gimple *stmt,
-			   enum tree_code code2, tree op2a, tree op2b);
+			   enum tree_code code2, tree op2a, tree op2b,
+			   basic_block);
 static tree
 or_comparisons_1 (tree, enum tree_code code1, tree op1a, tree op1b,
-		  enum tree_code code2, tree op2a, tree op2b);
+		  enum tree_code code2, tree op2a, tree op2b,
+		  basic_block);
 static tree
 or_var_with_comparison (tree, tree var, bool invert,
-			enum tree_code code2, tree op2a, tree op2b);
+			enum tree_code code2, tree op2a, tree op2b,
+			basic_block);
 static tree
 or_var_with_comparison_1 (tree, gimple *stmt,
-			  enum tree_code code2, tree op2a, tree op2b);
+			  enum tree_code code2, tree op2a, tree op2b,
+			  basic_block);
 
 /* Helper function for and_comparisons_1:  try to simplify the AND of the
    ssa variable VAR with the comparison specified by (OP2A CODE2 OP2B).
@@ -6561,7 +6566,8 @@ or_var_with_comparison_1 (tree, gimple *stmt,
 
 static tree
 and_var_with_comparison (tree type, tree var, bool invert,
-			 enum tree_code code2, tree op2a, tree op2b)
+			 enum tree_code code2, tree op2a, tree op2b,
+			 basic_block outer_cond_bb)
 {
   tree t;
   gimple *stmt = SSA_NAME_DEF_STMT (var);
@@ -6576,9 +6582,10 @@ and_var_with_comparison (tree type, tree var, bool invert,
   if (invert)
     t = or_var_with_comparison_1 (type, stmt,
 				  invert_tree_comparison (code2, false),
-				  op2a, op2b);
+				  op2a, op2b, outer_cond_bb);
   else
-    t = and_var_with_comparison_1 (type, stmt, code2, op2a, op2b);
+    t = and_var_with_comparison_1 (type, stmt, code2, op2a, op2b,
+				   outer_cond_bb);
   return canonicalize_bool (t, invert);
 }
 
@@ -6588,7 +6595,8 @@ and_var_with_comparison (tree type, tree var, bool invert,
 
 static tree
 and_var_with_comparison_1 (tree type, gimple *stmt,
-			   enum tree_code code2, tree op2a, tree op2b)
+			   enum tree_code code2, tree op2a, tree op2b,
+			   basic_block outer_cond_bb)
 {
   tree var = gimple_assign_lhs (stmt);
   tree true_test_var = NULL_TREE;
@@ -6623,7 +6631,7 @@ and_var_with_comparison_1 (tree type, gimple *stmt,
 				  gimple_assign_rhs2 (stmt),
 				  code2,
 				  op2a,
-				  op2b);
+				  op2b, outer_cond_bb);
       if (t)
 	return t;
     }
@@ -6655,12 +6663,12 @@ and_var_with_comparison_1 (tree type, gimple *stmt,
 	return (is_and
 		? boolean_false_node
 		: and_var_with_comparison (type, inner2, false, code2, op2a,
-					   op2b));
+					   op2b, outer_cond_bb));
       else if (inner2 == false_test_var)
 	return (is_and
 		? boolean_false_node
 		: and_var_with_comparison (type, inner1, false, code2, op2a,
-					   op2b));
+					   op2b, outer_cond_bb));
 
       /* Next, redistribute/reassociate the AND across the inner tests.
 	 Compute the first partial result, (inner1 AND (op2a code op2b))  */
@@ -6670,7 +6678,8 @@ and_var_with_comparison_1 (tree type, gimple *stmt,
 	  && (t = maybe_fold_and_comparisons (type, gimple_assign_rhs_code (s),
 					      gimple_assign_rhs1 (s),
 					      gimple_assign_rhs2 (s),
-					      code2, op2a, op2b)))
+					      code2, op2a, op2b,
+					      outer_cond_bb)))
 	{
 	  /* Handle the AND case, where we are reassociating:
 	     (inner1 AND inner2) AND (op2a code2 op2b)
@@ -6702,7 +6711,8 @@ and_var_with_comparison_1 (tree type, gimple *stmt,
 	  && (t = maybe_fold_and_comparisons (type, gimple_assign_rhs_code (s),
 					      gimple_assign_rhs1 (s),
 					      gimple_assign_rhs2 (s),
-					      code2, op2a, op2b)))
+					      code2, op2a, op2b,
+					      outer_cond_bb)))
 	{
 	  /* Handle the AND case, where we are reassociating:
 	     (inner1 AND inner2) AND (op2a code2 op2b)
@@ -6756,7 +6766,8 @@ and_var_with_comparison_1 (tree type, gimple *stmt,
 
 static tree
 and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
-		   enum tree_code code2, tree op2a, tree op2b)
+		   enum tree_code code2, tree op2a, tree op2b,
+		   basic_block outer_cond_bb)
 {
   tree truth_type = truth_type_for (TREE_TYPE (op1a));
 
@@ -6800,7 +6811,7 @@ and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 	case GIMPLE_ASSIGN:
 	  /* Try to simplify by copy-propagating the definition.  */
 	  return and_var_with_comparison (type, op1a, invert, code2, op2a,
-					  op2b);
+					  op2b, outer_cond_bb);
 
 	case GIMPLE_PHI:
 	  /* If every argument to the PHI produces the same result when
@@ -6851,7 +6862,8 @@ and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 					     gimple_bb (stmt)))
 			return NULL_TREE;
 		      temp = and_var_with_comparison (type, arg, invert, code2,
-						      op2a, op2b);
+						      op2a, op2b,
+						      outer_cond_bb);
 		      if (!temp)
 			return NULL_TREE;
 		      else if (!result)
@@ -6872,6 +6884,25 @@ and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
   return NULL_TREE;
 }
 
+static basic_block fosa_bb;
+static tree
+follow_outer_ssa_edges (tree val)
+{
+  if (TREE_CODE (val) == SSA_NAME
+      && !SSA_NAME_IS_DEFAULT_DEF (val))
+    {
+      basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (val));
+      if (!def_bb
+	  || def_bb == fosa_bb
+	  || (dom_info_available_p (CDI_DOMINATORS)
+	      && (def_bb == fosa_bb
+		  || dominated_by_p (CDI_DOMINATORS, fosa_bb, def_bb))))
+	return val;
+      return NULL_TREE;
+    }
+  return val;
+}
+
 /* Helper function for maybe_fold_and_comparisons and maybe_fold_or_comparisons
    : try to simplify the AND/OR of the ssa variable VAR with the comparison
    specified by (OP2A CODE2 OP2B) from match.pd.  Return NULL_EXPR if we can't
@@ -6884,7 +6915,8 @@ maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code,
 				      enum tree_code code1,
 				      tree op1a, tree op1b,
 				      enum tree_code code2, tree op2a,
-				      tree op2b)
+				      tree op2b,
+				      basic_block outer_cond_bb)
 {
   /* Allocate gimple stmt1 on the stack.  */
   gassign *stmt1
@@ -6893,6 +6925,7 @@ maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code,
   gimple_assign_set_rhs_code (stmt1, code1);
   gimple_assign_set_rhs1 (stmt1, op1a);
   gimple_assign_set_rhs2 (stmt1, op1b);
+  gimple_set_bb (stmt1, NULL);
 
   /* Allocate gimple stmt2 on the stack.  */
   gassign *stmt2
@@ -6901,6 +6934,7 @@ maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code,
   gimple_assign_set_rhs_code (stmt2, code2);
   gimple_assign_set_rhs1 (stmt2, op2a);
   gimple_assign_set_rhs2 (stmt2, op2b);
+  gimple_set_bb (stmt2, NULL);
 
   /* Allocate SSA names(lhs1) on the stack.  */
   tree lhs1 = (tree)XALLOCA (tree_ssa_name);
@@ -6922,7 +6956,9 @@ maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code,
   gimple_match_op op (gimple_match_cond::UNCOND, code,
 		      type, gimple_assign_lhs (stmt1),
 		      gimple_assign_lhs (stmt2));
-  if (op.resimplify (NULL, follow_all_ssa_edges))
+  fosa_bb = outer_cond_bb;
+  if (op.resimplify (NULL, (!outer_cond_bb
+			    ? follow_all_ssa_edges : follow_outer_ssa_edges)))
     {
       if (gimple_simplified_result_is_gimple_val (&op))
 	{
@@ -6959,17 +6995,20 @@ maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code,
 tree
 maybe_fold_and_comparisons (tree type,
 			    enum tree_code code1, tree op1a, tree op1b,
-			    enum tree_code code2, tree op2a, tree op2b)
+			    enum tree_code code2, tree op2a, tree op2b,
+			    basic_block outer_cond_bb)
 {
-  if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
+  if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b,
+				  outer_cond_bb))
     return t;
 
-  if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+  if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b,
+				  outer_cond_bb))
     return t;
 
   if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_AND_EXPR, code1,
 						     op1a, op1b, code2, op2a,
-						     op2b))
+						     op2b, outer_cond_bb))
     return t;
 
   return NULL_TREE;
@@ -6982,7 +7021,8 @@ maybe_fold_and_comparisons (tree type,
 
 static tree
 or_var_with_comparison (tree type, tree var, bool invert,
-			enum tree_code code2, tree op2a, tree op2b)
+			enum tree_code code2, tree op2a, tree op2b,
+			basic_block outer_cond_bb)
 {
   tree t;
   gimple *stmt = SSA_NAME_DEF_STMT (var);
@@ -6997,9 +7037,10 @@ or_var_with_comparison (tree type, tree var, bool invert,
   if (invert)
     t = and_var_with_comparison_1 (type, stmt,
 				   invert_tree_comparison (code2, false),
-				   op2a, op2b);
+				   op2a, op2b, outer_cond_bb);
   else
-    t = or_var_with_comparison_1 (type, stmt, code2, op2a, op2b);
+    t = or_var_with_comparison_1 (type, stmt, code2, op2a, op2b,
+				  outer_cond_bb);
   return canonicalize_bool (t, invert);
 }
 
@@ -7009,7 +7050,8 @@ or_var_with_comparison (tree type, tree var, bool invert,
 
 static tree
 or_var_with_comparison_1 (tree type, gimple *stmt,
-			  enum tree_code code2, tree op2a, tree op2b)
+			  enum tree_code code2, tree op2a, tree op2b,
+			  basic_block outer_cond_bb)
 {
   tree var = gimple_assign_lhs (stmt);
   tree true_test_var = NULL_TREE;
@@ -7042,9 +7084,7 @@ or_var_with_comparison_1 (tree type, gimple *stmt,
       tree t = or_comparisons_1 (type, innercode,
 				 gimple_assign_rhs1 (stmt),
 				 gimple_assign_rhs2 (stmt),
-				 code2,
-				 op2a,
-				 op2b);
+				 code2, op2a, op2b, outer_cond_bb);
       if (t)
 	return t;
     }
@@ -7076,12 +7116,12 @@ or_var_with_comparison_1 (tree type, gimple *stmt,
 	return (is_or
 		? boolean_true_node
 		: or_var_with_comparison (type, inner2, false, code2, op2a,
-					  op2b));
+					  op2b, outer_cond_bb));
       else if (inner2 == false_test_var)
 	return (is_or
 		? boolean_true_node
 		: or_var_with_comparison (type, inner1, false, code2, op2a,
-					  op2b));
+					  op2b, outer_cond_bb));
       
       /* Next, redistribute/reassociate the OR across the inner tests.
 	 Compute the first partial result, (inner1 OR (op2a code op2b))  */
@@ -7091,7 +7131,8 @@ or_var_with_comparison_1 (tree type, gimple *stmt,
 	  && (t = maybe_fold_or_comparisons (type, gimple_assign_rhs_code (s),
 					     gimple_assign_rhs1 (s),
 					     gimple_assign_rhs2 (s),
-					     code2, op2a, op2b)))
+					     code2, op2a, op2b,
+					     outer_cond_bb)))
 	{
 	  /* Handle the OR case, where we are reassociating:
 	     (inner1 OR inner2) OR (op2a code2 op2b)
@@ -7123,7 +7164,8 @@ or_var_with_comparison_1 (tree type, gimple *stmt,
 	  && (t = maybe_fold_or_comparisons (type, gimple_assign_rhs_code (s),
 					     gimple_assign_rhs1 (s),
 					     gimple_assign_rhs2 (s),
-					     code2, op2a, op2b)))
+					     code2, op2a, op2b,
+					     outer_cond_bb)))
 	{
 	  /* Handle the OR case, where we are reassociating:
 	     (inner1 OR inner2) OR (op2a code2 op2b)
@@ -7178,7 +7220,8 @@ or_var_with_comparison_1 (tree type, gimple *stmt,
 
 static tree
 or_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
-		  enum tree_code code2, tree op2a, tree op2b)
+		  enum tree_code code2, tree op2a, tree op2b,
+		  basic_block outer_cond_bb)
 {
   tree truth_type = truth_type_for (TREE_TYPE (op1a));
 
@@ -7222,7 +7265,7 @@ or_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 	case GIMPLE_ASSIGN:
 	  /* Try to simplify by copy-propagating the definition.  */
 	  return or_var_with_comparison (type, op1a, invert, code2, op2a,
-					 op2b);
+					 op2b, outer_cond_bb);
 
 	case GIMPLE_PHI:
 	  /* If every argument to the PHI produces the same result when
@@ -7273,7 +7316,7 @@ or_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 					     gimple_bb (stmt)))
 			return NULL_TREE;
 		      temp = or_var_with_comparison (type, arg, invert, code2,
-						     op2a, op2b);
+						     op2a, op2b, outer_cond_bb);
 		      if (!temp)
 			return NULL_TREE;
 		      else if (!result)
@@ -7304,17 +7347,20 @@ or_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 tree
 maybe_fold_or_comparisons (tree type,
 			   enum tree_code code1, tree op1a, tree op1b,
-			   enum tree_code code2, tree op2a, tree op2b)
+			   enum tree_code code2, tree op2a, tree op2b,
+			   basic_block outer_cond_bb)
 {
-  if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
+  if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b,
+				 outer_cond_bb))
     return t;
 
-  if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+  if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b,
+				 outer_cond_bb))
     return t;
 
   if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_IOR_EXPR, code1,
 						     op1a, op1b, code2, op2a,
-						     op2b))
+						     op2b, outer_cond_bb))
     return t;
 
   return NULL_TREE;
diff --git a/gcc/gimple-fold.h b/gcc/gimple-fold.h
index 82631a4512e..3a0ef54394e 100644
--- a/gcc/gimple-fold.h
+++ b/gcc/gimple-fold.h
@@ -33,9 +33,11 @@ extern bool fold_stmt (gimple_stmt_iterator *);
 extern bool fold_stmt (gimple_stmt_iterator *, tree (*) (tree));
 extern bool fold_stmt_inplace (gimple_stmt_iterator *);
 extern tree maybe_fold_and_comparisons (tree, enum tree_code, tree, tree,
-					enum tree_code, tree, tree);
+					enum tree_code, tree, tree,
+					basic_block = nullptr);
 extern tree maybe_fold_or_comparisons (tree, enum tree_code, tree, tree,
-				       enum tree_code, tree, tree);
+				       enum tree_code, tree, tree,
+				       basic_block = nullptr);
 extern bool clear_padding_type_may_have_padding_p (tree);
 extern void clear_type_padding_in_mask (tree, unsigned char *);
 extern bool optimize_atomic_compare_exchange_p (gimple *);
diff --git a/gcc/testsuite/g++.dg/torture/pr105142.C b/gcc/testsuite/g++.dg/torture/pr105142.C
new file mode 100644
index 00000000000..b2d16abc9d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr105142.C
@@ -0,0 +1,8 @@
+// { dg-do run { target lp64 } }
+
+long int c = 3623214276426624192L;
+unsigned short b;
+char a = 42;
+const long &min(const long &x, const long &y) { return x < y ? x : y; }
+__attribute__((noipa)) void test() { b = min(a, min(a, c) + 5713568809962283044L); }
+int main() { test(); if (b != 42) __builtin_abort(); }
diff --git a/gcc/tree-ssa-ifcombine.cc b/gcc/tree-ssa-ifcombine.cc
index 3a4fee535ee..ce9bbebf948 100644
--- a/gcc/tree-ssa-ifcombine.cc
+++ b/gcc/tree-ssa-ifcombine.cc
@@ -561,7 +561,8 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv,
 					    gimple_cond_rhs (inner_cond),
 					    outer_cond_code,
 					    gimple_cond_lhs (outer_cond),
-					    gimple_cond_rhs (outer_cond))))
+					    gimple_cond_rhs (outer_cond),
+					    gimple_bb (outer_cond))))
 	{
 	  tree t1, t2;
 	  gimple_stmt_iterator gsi;
