diff --git a/gcc/common.opt b/gcc/common.opt
index a1353e0..7988653 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2208,6 +2208,10 @@ fprefetch-loop-arrays
 Common Var(flag_prefetch_loop_arrays) Init(-1) Optimization
 Generate prefetch instructions, if available, for arrays in loops.
 
+fpreserve-traps
+Common Var(flag_preserve_traps)
+Treat trapping instructions as visible side-effects.
+
 fprofile
 Common Var(profile_flag)
 Enable basic program profiling code.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index af2ce18..277eef5 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -655,7 +655,7 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-fcall-saved-@var{reg}  -fcall-used-@var{reg} @gol
 -ffixed-@var{reg}  -fexceptions @gol
 -fnon-call-exceptions  -fdelete-dead-exceptions  -funwind-tables @gol
--fasynchronous-unwind-tables @gol
+-fasynchronous-unwind-tables -fpreserve-traps @gol
 -fno-gnu-unique @gol
 -finhibit-size-directive  -fcommon  -fno-ident @gol
 -fpcc-struct-return  -fpic  -fPIC  -fpie  -fPIE  -fno-plt @gol
@@ -16262,6 +16262,17 @@ Generate unwind table in DWARF format, if supported by target machine.  The
 table is exact at each instruction boundary, so it can be used for stack
 unwinding from asynchronous events (such as debugger or garbage collector).
 
+@item -fpreserve-traps
+@opindex fpreserve-traps
+Prevent trapping instructions that don't otherwise contribute to the
+execution of a program, from being optimized away.  This option is
+orthogonal to exception handling, though the @option{-fnon-call-exceptions}
+option may be used to throw exceptions from a trapping instruction,
+if supported by the target.  The set of instructions considered trapping
+may be controlled with @option{-ftrapping-math} and @option{-ftrapv}.
+This option treats traps as observable side-effects, hence a trapping
+instruction prevents a function from being @code{pure} or @code{const}.
+
 @item -fno-gnu-unique
 @opindex fno-gnu-unique
 @opindex fgnu-unique
diff --git a/gcc/gimple.c b/gcc/gimple.c
index f1044e9..66edc1e 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -2090,7 +2090,8 @@ gimple_move_vops (gimple *new_stmt, gimple *old_stmt)
    statement to have side effects if:
 
    - It is a GIMPLE_CALL not marked with ECF_PURE or ECF_CONST.
-   - Any of its operands are marked TREE_THIS_VOLATILE or TREE_SIDE_EFFECTS.  */
+   - Any of its operands are marked TREE_THIS_VOLATILE or TREE_SIDE_EFFECTS.
+   - It may trap and -fpreserve-traps has been specified.  */
 
 bool
 gimple_has_side_effects (const gimple *s)
@@ -2108,6 +2109,12 @@ gimple_has_side_effects (const gimple *s)
       && gimple_asm_volatile_p (as_a <const gasm *> (s)))
     return true;
 
+  /* Treat trapping instructions as having side-effects when
+     -fpreserve_traps has been specified.  */
+  if (flag_preserve_traps
+      && gimple_could_trap_p (s))
+    return true;
+
   if (is_gimple_call (s))
     {
       int flags = gimple_call_flags (s);
@@ -2129,7 +2136,7 @@ gimple_has_side_effects (const gimple *s)
    S is a GIMPLE_ASSIGN, the LHS of the assignment is also checked.  */
 
 bool
-gimple_could_trap_p_1 (gimple *s, bool include_mem, bool include_stores)
+gimple_could_trap_p_1 (const gimple *s, bool include_mem, bool include_stores)
 {
   tree t, div = NULL_TREE;
   enum tree_code op;
@@ -2146,7 +2153,7 @@ gimple_could_trap_p_1 (gimple *s, bool include_mem, bool include_stores)
   switch (gimple_code (s))
     {
     case GIMPLE_ASM:
-      return gimple_asm_volatile_p (as_a <gasm *> (s));
+      return gimple_asm_volatile_p (as_a <const gasm *> (s));
 
     case GIMPLE_CALL:
       t = gimple_call_fndecl (s);
@@ -2192,7 +2199,7 @@ gimple_could_trap_p_1 (gimple *s, bool include_mem, bool include_stores)
 /* Return true if statement S can trap.  */
 
 bool
-gimple_could_trap_p (gimple *s)
+gimple_could_trap_p (const gimple *s)
 {
   return gimple_could_trap_p_1 (s, true, true);
 }
diff --git a/gcc/gimple.h b/gcc/gimple.h
index e7dc2a4..1a2e120 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1601,8 +1601,8 @@ void gimple_set_lhs (gimple *, tree);
 gimple *gimple_copy (gimple *);
 void gimple_move_vops (gimple *, gimple *);
 bool gimple_has_side_effects (const gimple *);
-bool gimple_could_trap_p_1 (gimple *, bool, bool);
-bool gimple_could_trap_p (gimple *);
+bool gimple_could_trap_p_1 (const gimple *, bool, bool);
+bool gimple_could_trap_p (const gimple *);
 bool gimple_assign_rhs_could_trap_p (gimple *);
 extern void dump_gimple_statistics (void);
 unsigned get_gimple_rhs_num_ops (enum tree_code);
diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index f045108..e2a4bcf 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -765,6 +765,14 @@ check_stmt (gimple_stmt_iterator *gsip, funct_state local, bool ipa)
       if (dump_file)
 	fprintf (dump_file, "    Volatile stmt is not const/pure\n");
     }
+  else if (flag_preserve_traps
+	   && gimple_code (stmt) != GIMPLE_CALL
+	   && gimple_could_trap_p (stmt))
+    {
+      local->pure_const_state = IPA_NEITHER;
+      if (dump_file)
+	fprintf (dump_file, "    Trapping stmt is not const/pure\n");
+    }
 
   /* Look for loads and stores.  */
   walk_stmt_load_store_ops (stmt, local,
