Index: config/aarch64/aarch64.c
===================================================================
--- config/aarch64/aarch64.c	(revision 250186)
+++ config/aarch64/aarch64.c	(working copy)
@@ -1653,7 +1653,7 @@ aarch64_split_128bit_move (rtx dst, rtx
 
   machine_mode mode = GET_MODE (dst);
 
-  gcc_assert (mode == TImode || mode == TFmode);
+  gcc_assert (mode == TImode || mode == TFmode || mode == TDmode);
   gcc_assert (!(side_effects_p (src) || side_effects_p (dst)));
   gcc_assert (mode == GET_MODE (src) || GET_MODE (src) == VOIDmode);
 
@@ -1673,11 +1673,16 @@ aarch64_split_128bit_move (rtx dst, rtx
 	      emit_insn (gen_aarch64_movtilow_di (dst, src_lo));
 	      emit_insn (gen_aarch64_movtihigh_di (dst, src_hi));
 	    }
-	  else
+	  else if (mode == TFmode)
 	    {
 	      emit_insn (gen_aarch64_movtflow_di (dst, src_lo));
 	      emit_insn (gen_aarch64_movtfhigh_di (dst, src_hi));
 	    }
+	  else
+	    {
+	      emit_insn (gen_aarch64_movtdlow_di (dst, src_lo));
+	      emit_insn (gen_aarch64_movtdhigh_di (dst, src_hi));
+	    }
 	  return;
 	}
       else if (GP_REGNUM_P (dst_regno) && FP_REGNUM_P (src_regno))
@@ -1690,11 +1695,16 @@ aarch64_split_128bit_move (rtx dst, rtx
 	      emit_insn (gen_aarch64_movdi_tilow (dst_lo, src));
 	      emit_insn (gen_aarch64_movdi_tihigh (dst_hi, src));
 	    }
-	  else
+	  else if (mode == TFmode)
 	    {
 	      emit_insn (gen_aarch64_movdi_tflow (dst_lo, src));
 	      emit_insn (gen_aarch64_movdi_tfhigh (dst_hi, src));
 	    }
+	  else if (mode == TDmode)
+	    {
+	      emit_insn (gen_aarch64_movdi_tdlow (dst_lo, src));
+	      emit_insn (gen_aarch64_movdi_tdhigh (dst_hi, src));
+	    }
 	  return;
 	}
     }
@@ -4420,10 +4430,11 @@ aarch64_classify_address (struct aarch64
   rtx op0, op1;
 
   /* On BE, we use load/store pair for all large int mode load/stores.
-     TI/TFmode may also use a load/store pair.  */
+     TI/TF/TDmode may also use a load/store pair.  */
   bool load_store_pair_p = (outer_code == PARALLEL
 			    || mode == TImode
 			    || mode == TFmode
+			    || mode == TDmode
 			    || (BYTES_BIG_ENDIAN
 				&& aarch64_vect_struct_mode_p (mode)));
 
@@ -4473,7 +4484,7 @@ aarch64_classify_address (struct aarch64
 	  info->base = op0;
 	  info->offset = op1;
 
-	  /* TImode and TFmode values are allowed in both pairs of X
+	  /* TImode and TFmode and TDmode values are allowed in both pairs of X
 	     registers and individual Q registers.  The available
 	     address modes are:
 	     X,X: 7-bit signed scaled offset
@@ -4482,7 +4493,7 @@ aarch64_classify_address (struct aarch64
 	     When performing the check for pairs of X registers i.e.  LDP/STP
 	     pass down DImode since that is the natural size of the LDP/STP
 	     instruction memory accesses.  */
-	  if (mode == TImode || mode == TFmode)
+	  if (mode == TImode || mode == TFmode || mode == TDmode)
 	    return (aarch64_offset_7bit_signed_scaled_p (DImode, offset)
 		    && (offset_9bit_signed_unscaled_p (mode, offset)
 			|| offset_12bit_unsigned_scaled_p (mode, offset)));
@@ -4558,14 +4569,14 @@ aarch64_classify_address (struct aarch64
 	  info->offset = XEXP (XEXP (x, 1), 1);
 	  offset = INTVAL (info->offset);
 
-	  /* TImode and TFmode values are allowed in both pairs of X
+	  /* TImode and TFmode and TDmode values are allowed in both pairs of X
 	     registers and individual Q registers.  The available
 	     address modes are:
 	     X,X: 7-bit signed scaled offset
 	     Q:   9-bit signed offset
 	     We conservatively require an offset representable in either mode.
 	   */
-	  if (mode == TImode || mode == TFmode)
+	  if (mode == TImode || mode == TFmode || mode == TDmode)
 	    return (aarch64_offset_7bit_signed_scaled_p (mode, offset)
 		    && offset_9bit_signed_unscaled_p (mode, offset));
 
@@ -4714,7 +4725,7 @@ aarch64_legitimize_address_displacement
   HOST_WIDE_INT offset = INTVAL (*disp);
   HOST_WIDE_INT base = offset & ~(GET_MODE_SIZE (mode) < 4 ? 0xfff : 0x3ffc);
 
-  if (mode == TImode || mode == TFmode
+  if (mode == TImode || mode == TFmode || mode == TDmode
       || (offset & (GET_MODE_SIZE (mode) - 1)) != 0)
     base = (offset + 0x100) & ~0x1ff;
 
@@ -5649,7 +5660,7 @@ aarch64_legitimize_address (rtx x, rtx /
       /* Small negative offsets are supported.  */
       else if (IN_RANGE (offset, -256, 0))
 	base_offset = 0;
-      else if (mode == TImode || mode == TFmode)
+      else if (mode == TImode || mode == TFmode || mode == TDmode)
 	base_offset = (offset + 0x100) & ~0x1ff;
       /* Use 12-bit offset by access size.  */
       else
@@ -5681,6 +5692,15 @@ aarch64_constant_pool_reload_icode (mach
     case TFmode:
       return CODE_FOR_aarch64_reload_movcptfdi;
 
+    case SDmode:
+      return CODE_FOR_aarch64_reload_movcpsddi;
+
+    case DDmode:
+      return CODE_FOR_aarch64_reload_movcpdddi;
+
+    case TDmode:
+      return CODE_FOR_aarch64_reload_movcptddi;
+
     case V8QImode:
       return CODE_FOR_aarch64_reload_movcpv8qidi;
 
@@ -5731,25 +5751,27 @@ aarch64_secondary_reload (bool in_p ATTR
 
   /* Without the TARGET_SIMD instructions we cannot move a Q register
      to a Q register directly.  We need a scratch.  */
-  if (REG_P (x) && (mode == TFmode || mode == TImode) && mode == GET_MODE (x)
+  if (REG_P (x) && (mode == TFmode || mode == TDmode || mode == TImode) && mode == GET_MODE (x)
       && FP_REGNUM_P (REGNO (x)) && !TARGET_SIMD
       && reg_class_subset_p (rclass, FP_REGS))
     {
       if (mode == TFmode)
         sri->icode = CODE_FOR_aarch64_reload_movtf;
+      else if (mode == TDmode)
+        sri->icode = CODE_FOR_aarch64_reload_movtd;
       else if (mode == TImode)
         sri->icode = CODE_FOR_aarch64_reload_movti;
       return NO_REGS;
     }
 
-  /* A TFmode or TImode memory access should be handled via an FP_REGS
+  /* A TFmode or TImode or TDmode memory access should be handled via an FP_REGS
      because AArch64 has richer addressing modes for LDR/STR instructions
      than LDP/STP instructions.  */
   if (TARGET_FLOAT && rclass == GENERAL_REGS
       && GET_MODE_SIZE (mode) == 16 && MEM_P (x))
     return FP_REGS;
 
-  if (rclass == FP_REGS && (mode == TImode || mode == TFmode) && CONSTANT_P(x))
+  if (rclass == FP_REGS && (mode == TImode || mode == TFmode || mode == TDmode) && CONSTANT_P(x))
       return GENERAL_REGS;
 
   return NO_REGS;
@@ -10215,6 +10237,10 @@ aarch64_legitimate_pic_operand_p (rtx x)
 static bool
 aarch64_valid_floating_const (machine_mode mode, rtx x)
 {
+  /* FIXME: Handle decimal floating point constants. */
+  if (GET_MODE_CLASS (mode) == MODE_DECIMAL_FLOAT)
+    return false;
+
   if (!CONST_DOUBLE_P (x))
     return false;
 
@@ -10636,6 +10662,18 @@ aarch64_gimplify_va_arg_expr (tree valis
 	  field_t = long_double_type_node;
 	  field_ptr_t = long_double_ptr_type_node;
 	  break;
+	case SDmode:
+	  field_t = dfloat32_type_node;
+	  field_ptr_t = dfloat32_ptr_type_node;
+	  break;
+	case DDmode:
+	  field_t = dfloat64_type_node;
+	  field_ptr_t = dfloat64_ptr_type_node;
+	  break;
+	case TDmode:
+	  field_t = dfloat128_type_node;
+	  field_ptr_t = dfloat128_ptr_type_node;
+	  break;
 	case HFmode:
 	  field_t = aarch64_fp16_type_node;
 	  field_ptr_t = aarch64_fp16_ptr_type_node;
@@ -10802,7 +10840,9 @@ aapcs_vfp_sub_candidate (const_tree type
     case REAL_TYPE:
       mode = TYPE_MODE (type);
       if (mode != DFmode && mode != SFmode
-	  && mode != TFmode && mode != HFmode)
+	  && mode != TFmode && mode != HFmode
+	  && mode != DDmode && mode != SDmode
+	  && mode != TDmode)
 	return -1;
 
       if (*modep == VOIDmode)
@@ -11030,7 +11070,9 @@ aarch64_vfp_is_call_or_return_candidate
 
   if (is_ha != NULL) *is_ha = false;
 
-  if ((!composite_p && GET_MODE_CLASS (mode) == MODE_FLOAT)
+  if ((!composite_p
+       && (GET_MODE_CLASS (mode) == MODE_FLOAT
+	   || GET_MODE_CLASS (mode) == MODE_DECIMAL_FLOAT))
       || aarch64_short_vector_p (type, mode))
     {
       *count = 1;
@@ -15028,6 +15070,9 @@ aarch64_libgcc_floating_mode_supported_p
 static bool
 aarch64_scalar_mode_supported_p (machine_mode mode)
 {
+  if (DECIMAL_FLOAT_MODE_P (mode))
+    return default_decimal_float_supported_p ();
+
   return (mode == HFmode
 	  ? true
 	  : default_scalar_mode_supported_p (mode));
Index: config/aarch64/aarch64.md
===================================================================
--- config/aarch64/aarch64.md	(revision 250186)
+++ config/aarch64/aarch64.md	(working copy)
@@ -1081,11 +1081,11 @@ (define_insn "*movhf_aarch64"
    (set_attr "simd" "yes,yes,yes,yes,*,*,*,*,*")]
 )
 
-(define_insn "*movsf_aarch64"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=w,w  ,?r,w,w  ,w,m,r,m ,r")
-	(match_operand:SF 1 "general_operand"      "Y ,?rY, w,w,Ufc,m,w,m,rY,r"))]
-  "TARGET_FLOAT && (register_operand (operands[0], SFmode)
-    || aarch64_reg_or_fp_zero (operands[1], SFmode))"
+(define_insn "*mov<mode>_aarch64"
+  [(set (match_operand:SFD 0 "nonimmediate_operand" "=w,w  ,?r,w,w  ,w,m,r,m ,r")
+	(match_operand:SFD 1 "general_operand"      "Y ,?rY, w,w,Ufc,m,w,m,rY,r"))]
+  "TARGET_FLOAT && (register_operand (operands[0], <MODE>mode)
+    || aarch64_reg_or_fp_zero (operands[1], <MODE>mode))"
   "@
    movi\\t%0.2s, #0
    fmov\\t%s0, %w1
@@ -1102,11 +1102,11 @@ (define_insn "*movsf_aarch64"
    (set_attr "simd" "yes,*,*,*,*,*,*,*,*,*")]
 )
 
-(define_insn "*movdf_aarch64"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=w,w  ,?r,w,w  ,w,m,r,m ,r")
-	(match_operand:DF 1 "general_operand"      "Y ,?rY, w,w,Ufc,m,w,m,rY,r"))]
-  "TARGET_FLOAT && (register_operand (operands[0], DFmode)
-    || aarch64_reg_or_fp_zero (operands[1], DFmode))"
+(define_insn "*mov<mode>_aarch64"
+  [(set (match_operand:DFD 0 "nonimmediate_operand" "=w,w  ,?r,w,w  ,w,m,r,m ,r")
+	(match_operand:DFD 1 "general_operand"      "Y ,?rY, w,w,Ufc,m,w,m,rY,r"))]
+  "TARGET_FLOAT && (register_operand (operands[0], <MODE>mode)
+    || aarch64_reg_or_fp_zero (operands[1], <MODE>mode))"
   "@
    movi\\t%d0, #0
    fmov\\t%d0, %x1
@@ -1123,13 +1123,13 @@ (define_insn "*movdf_aarch64"
    (set_attr "simd" "yes,*,*,*,*,*,*,*,*,*")]
 )
 
-(define_insn "*movtf_aarch64"
-  [(set (match_operand:TF 0
+(define_insn "*mov<mode>_aarch64"
+  [(set (match_operand:TFD 0
 	 "nonimmediate_operand" "=w,?&r,w ,?r,w,?w,w,m,?r,m ,m")
-	(match_operand:TF 1
+	(match_operand:TFD 1
 	 "general_operand"      " w,?r, ?r,w ,Y,Y ,m,w,m ,?r,Y"))]
-  "TARGET_FLOAT && (register_operand (operands[0], TFmode)
-    || aarch64_reg_or_fp_zero (operands[1], TFmode))"
+  "TARGET_FLOAT && (register_operand (operands[0], <MODE>mode)
+    || aarch64_reg_or_fp_zero (operands[1], <MODE>mode))"
   "@
    mov\\t%0.16b, %1.16b
    #
@@ -1149,8 +1149,8 @@ (define_insn "*movtf_aarch64"
 )
 
 (define_split
-   [(set (match_operand:TF 0 "register_operand" "")
-	 (match_operand:TF 1 "aarch64_reg_or_imm" ""))]
+   [(set (match_operand:TFD 0 "register_operand" "")
+	 (match_operand:TFD 1 "aarch64_reg_or_imm" ""))]
   "reload_completed && aarch64_split_128bit_move_p (operands[0], operands[1])"
   [(const_int 0)]
   {
Index: config/aarch64/iterators.md
===================================================================
--- config/aarch64/iterators.md	(revision 250186)
+++ config/aarch64/iterators.md	(working copy)
@@ -44,14 +44,23 @@ (define_mode_iterator GPF [SF DF])
 ;; Iterator for all scalar floating point modes (HF, SF, DF)
 (define_mode_iterator GPF_F16 [(HF "AARCH64_ISA_F16") SF DF])
 
-;; Iterator for all scalar floating point modes (HF, SF, DF and TF)
-(define_mode_iterator GPF_TF_F16 [HF SF DF TF])
+;; Iterator for all scalar floating point modes (HF, SF, DF and TF [SD, DD, and TD])
+(define_mode_iterator GPF_TF_F16 [HF SF DF TF SD DD TD])
+
+;; Iterator for scalar 32bit fp modes (SF, SD)
+(define_mode_iterator SFD [SD SF])
+
+;; Iterator for scalar 64bit fp modes (DF, DD)
+(define_mode_iterator DFD [DD DF])
+
+;; Iterator for scalar 128bit fp modes (TF, TD)
+(define_mode_iterator TFD [TD TF])
 
 ;; Double vector modes.
 (define_mode_iterator VDF [V2SF V4HF])
 
-;; Iterator for all scalar floating point modes (SF, DF and TF)
-(define_mode_iterator GPF_TF [SF DF TF])
+;; Iterator for all scalar floating point modes (SF, DF and TF [SD, DD, and TD])
+(define_mode_iterator GPF_TF [SF DF TF SD DD TD])
 
 ;; Integer vector modes.
 (define_mode_iterator VDQ_I [V8QI V16QI V4HI V8HI V2SI V4SI V2DI])
@@ -224,7 +233,7 @@ (define_mode_iterator VB [V8QI V16QI])
 ;; 2 and 4 lane SI modes.
 (define_mode_iterator VS [V2SI V4SI])
 
-(define_mode_iterator TX [TI TF])
+(define_mode_iterator TX [TI TF TD])
 
 ;; Opaque structure modes.
 (define_mode_iterator VSTRUCT [OI CI XI])
Index: testsuite/c-c++-common/dfp/pr39986.c
===================================================================
--- testsuite/c-c++-common/dfp/pr39986.c	(revision 250186)
+++ testsuite/c-c++-common/dfp/pr39986.c	(working copy)
@@ -14,19 +14,19 @@ _Decimal128 f = -678901.234e-6dl;
 /* The first value is DPD, the second is BID.  The order differs depending
    on whether the target is big-endian or little-endian.  */
 
-/* { dg-final { scan-assembler ".long\t(572653859|822183807)\n" } } */
+/* { dg-final { scan-assembler ".(word|long)\t(572653859|822183807)\n" } } */
 
-/* { dg-final { scan-assembler ".long\t(-1572863965|-1308622825)\n" } } */
+/* { dg-final { scan-assembler ".(word|long)\t(-1572863965|-1308622825)\n" } } */
 
-/* { dg-final { scan-assembler ".long\t(52|34)\n" } } */
-/* { dg-final { scan-assembler ".long\t(572784640|824180736)\n" } } */
+/* { dg-final { scan-assembler ".(word|long)\t(52|34)\n" } } */
+/* { dg-final { scan-assembler ".(word|long)\t(572784640|824180736)\n" } } */
 
-/* { dg-final { scan-assembler ".long\t(4736|4500)\n" } } */
-/* { dg-final { scan-assembler ".long\t(-1574174720|-1319108608)\n" } } */
+/* { dg-final { scan-assembler ".(word|long)\t(4736|4500)\n" } } */
+/* { dg-final { scan-assembler ".(word|long)\t(-1574174720|-1319108608)\n" } } */
 
-/* { dg-final { scan-assembler ".long\t(-1975952433|957645077)\n" } } */
-/* { dg-final { scan-assembler ".long\t(190215|132222)\n" } } */
-/* { dg-final { scan-assembler ".long\t(574193664|835452928)\n" } } */
+/* { dg-final { scan-assembler ".(word|long)\t(-1975952433|957645077)\n" } } */
+/* { dg-final { scan-assembler ".(word|long)\t(190215|132222)\n" } } */
+/* { dg-final { scan-assembler ".(word|long)\t(574193664|835452928)\n" } } */
 
-/* { dg-final { scan-assembler ".long\t(931280180|678901234)\n" } } */
-/* { dg-final { scan-assembler ".long\t(-1576681472|-1339162624)\n" } } */
+/* { dg-final { scan-assembler ".(word|long)\t(931280180|678901234)\n" } } */
+/* { dg-final { scan-assembler ".(word|long)\t(-1576681472|-1339162624)\n" } } */
