diff --git a/gcc/combine.c b/gcc/combine.c
index cff76cd3303..fdb03f5d305 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -4166,6 +4166,40 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
 	}
     }
 
+  /* Check for a case where we generate an IF_THEN_ELSE that depends on a
+     logical right shift.  If we have nonzero_bit information that indicates the
+     shift will ultimately lead down to a single bit generate the equivalent
+     zero_extract pattern to see if the target has an appropriate instruction
+     that can handle this.  */
+
+  else if (insn_code_number < 0 && asm_noperands (newpat) < 0
+	   && GET_CODE (newpat) == SET
+	   && GET_CODE (XEXP (newpat, 1)) == IF_THEN_ELSE)
+    {
+      rtx cond, true_rtx, false_rtx, new_rtx;
+
+      cond = if_then_else_cond (XEXP (newpat, 1), &true_rtx,
+				&false_rtx);
+      if (GET_CODE (cond) == LSHIFTRT)
+      {
+	  unsigned HOST_WIDE_INT nonzero
+	    = nonzero_bits (XEXP (cond, 0), GET_MODE (XEXP (cond, 0)));
+	  unsigned HOST_WIDE_INT shift_amount = UINTVAL (XEXP (cond, 1));
+
+	  if (nonzero >> shift_amount == 1)
+	    {
+	      new_rtx = make_extraction (GET_MODE (cond), XEXP (cond, 0),
+					 shift_amount, 0, 1,
+					 1, 0, 1);
+
+	      newpat = simplify_replace_rtx (newpat, cond, new_rtx);
+
+	      insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+	    }
+
+      }
+    }
+
   /* If it still isn't recognized, fail and change things back the way they
      were.  */
   if ((insn_code_number < 0
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index c7c4d1dd519..552dc712304 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -897,7 +897,8 @@
 
 (define_insn "*tb<optab><mode>1"
   [(set (pc) (if_then_else
-	      (EQL (zero_extract:DI (match_operand:GPI 0 "register_operand" "r")
+	      (EQL (zero_extract:GPI
+				    (match_operand:GPI 0 "register_operand" "r")
 				    (const_int 1)
 				    (match_operand 1
 				      "aarch64_simd_shift_imm_<mode>" "n"))
@@ -5530,21 +5531,21 @@
 ;; Bitfields
 ;; -------------------------------------------------------------------
 
-(define_expand "<optab>"
-  [(set (match_operand:DI 0 "register_operand")
-	(ANY_EXTRACT:DI (match_operand:DI 1 "register_operand")
+;; Defines extsv, extv patterns
+(define_expand "<optab><mode>"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+	(ANY_EXTRACT:GPI (match_operand:GPI 1 "register_operand")
 			(match_operand 2
-			  "aarch64_simd_shift_imm_offset_di")
-			(match_operand 3 "aarch64_simd_shift_imm_di")))]
+			  "aarch64_simd_shift_imm_offset_<mode>")
+			(match_operand 3 "aarch64_simd_shift_imm_<mode>")))]
   ""
   {
     if (!IN_RANGE (INTVAL (operands[2]) + INTVAL (operands[3]),
-		   1, GET_MODE_BITSIZE (DImode) - 1))
+		   1, GET_MODE_BITSIZE (<MODE>mode)))
      FAIL;
   }
 )
 
-
 (define_insn "*<optab><mode>"
   [(set (match_operand:GPI 0 "register_operand" "=r")
 	(ANY_EXTRACT:GPI (match_operand:GPI 1 "register_operand" "r")
@@ -5553,7 +5554,7 @@
 			 (match_operand 3
 			   "aarch64_simd_shift_imm_<mode>" "n")))]
   "IN_RANGE (INTVAL (operands[2]) + INTVAL (operands[3]),
-	     1, GET_MODE_BITSIZE (<MODE>mode) - 1)"
+	     1, GET_MODE_BITSIZE (<MODE>mode))"
   "<su>bfx\\t%<w>0, %<w>1, %3, %2"
   [(set_attr "type" "bfx")]
 )
diff --git a/gcc/expmed.c b/gcc/expmed.c
index e7c03fbf92c..f39ab04ced2 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -1564,7 +1564,7 @@ extract_bit_field_using_extv (const extraction_insn *extv, rtx op0,
       if (REG_P (target)
 	  && TRULY_NOOP_TRUNCATION_MODES_P (GET_MODE (target), ext_mode))
 	{
-	  target = gen_lowpart (ext_mode, target);
+	  target = gen_lowpart_if_possible (ext_mode, target);
 	  if (partial_subreg_p (GET_MODE (spec_target), ext_mode))
 	    spec_target_subreg = target;
 	}
diff --git a/gcc/testsuite/gcc.target/aarch64/pr86901.c b/gcc/testsuite/gcc.target/aarch64/pr86901.c
new file mode 100644
index 00000000000..5dd6fdf75f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr86901.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef unsigned int uint32_t;
+
+float g (float);
+
+static inline uint32_t
+top12 (float x)
+{
+  union
+  {
+    float f;
+    uint32_t i;
+  } u = {x};
+  return (u.i >> 20) & 0x7ff;
+}
+
+void
+f2 (float y, float *p)
+{
+  if (__builtin_expect (top12 (y) < top12 (1.0), 1))
+    *p = y * y;
+  else
+    g (y);
+}
+
+/* { dg-final { scan-assembler "fmov\tw" } } */
