diff --git a/gcc/config/xtensa/predicates.md b/gcc/config/xtensa/predicates.md
index 19b9f4cd7efea1fa2debeff71aea94545d198f1c..e676fa4fb95ce843ecae4d0c2cdd36e8e8a69c0a 100644
--- a/gcc/config/xtensa/predicates.md
+++ b/gcc/config/xtensa/predicates.md
@@ -159,6 +159,26 @@
   return real_equal (CONST_DOUBLE_REAL_VALUE (op), &dconst1);
 })
 
+(define_predicate "fix_scaling_operand"
+  (match_code "const_double")
+{
+  REAL_VALUE_TYPE r = *CONST_DOUBLE_REAL_VALUE (op);
+  int exp = REAL_EXP (&r) - 1;
+
+  SET_REAL_EXP (&r, 1);
+  return real_equal (&r, &dconst1) && IN_RANGE (exp, 2, 15);
+})
+
+(define_predicate "float_scaling_operand"
+  (match_code "const_double")
+{
+  REAL_VALUE_TYPE r = *CONST_DOUBLE_REAL_VALUE (op);
+  int exp = REAL_EXP (&r) - 1;
+
+  SET_REAL_EXP (&r, 1);
+  return real_equal (&r, &dconst1) && IN_RANGE (-exp, 1, 15);
+})
+
 (define_predicate "fpmem_offset_operand"
   (and (match_code "const_int")
        (match_test "xtensa_mem_offset (INTVAL (op), SFmode)")))
diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md
index 0fcbb0b7bc37d52f2796654c583a311a63189689..376d0f75544632bb2930f405464bfafe59f168aa 100644
--- a/gcc/config/xtensa/xtensa.md
+++ b/gcc/config/xtensa/xtensa.md
@@ -91,6 +91,18 @@
 ;; the same template.
 (define_mode_iterator SHI [SI HI])
 
+;; This iterator and attribute allow signed/unsigned FP truncations to be
+;; generated from one template.
+(define_code_iterator any_fix [fix unsigned_fix])
+(define_code_attr m_fix [(fix "trunc") (unsigned_fix "utrunc")])
+(define_code_attr s_fix [(fix "") (unsigned_fix "uns")])
+
+;; This iterator and attribute allow signed/unsigned FP conversions to be
+;; generated from one template.
+(define_code_iterator any_float [float unsigned_float])
+(define_code_attr m_float [(float "float") (unsigned_float "ufloat")])
+(define_code_attr s_float [(float "") (unsigned_float "uns")])
+
 
 ;; Attributes.
 
@@ -1132,38 +1144,60 @@
 
 ;; Conversions.
 
-(define_insn "fix_truncsfsi2"
+(define_insn "fix<s_fix>_truncsfsi2"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+	(any_fix:SI (match_operand:SF 1 "register_operand" "f")))]
+  "TARGET_HARD_FLOAT"
+  "<m_fix>.s\t%0, %1, 0"
+  [(set_attr "type"	"fconv")
+   (set_attr "mode"	"SF")
+   (set_attr "length"	"3")])
+
+(define_insn "*fix<s_fix>_truncsfsi2_2x"
   [(set (match_operand:SI 0 "register_operand" "=a")
-	(fix:SI (match_operand:SF 1 "register_operand" "f")))]
+	(any_fix:SI (plus:SF (match_operand:SF 1 "register_operand" "f")
+			     (match_dup 1))))]
   "TARGET_HARD_FLOAT"
-  "trunc.s\t%0, %1, 0"
+  "<m_fix>.s\t%0, %1, 1"
   [(set_attr "type"	"fconv")
    (set_attr "mode"	"SF")
    (set_attr "length"	"3")])
 
-(define_insn "fixuns_truncsfsi2"
+(define_insn "*fix<s_fix>_truncsfsi2_scaled"
   [(set (match_operand:SI 0 "register_operand" "=a")
-	(unsigned_fix:SI (match_operand:SF 1 "register_operand" "f")))]
+	(any_fix:SI (mult:SF (match_operand:SF 1 "register_operand" "f")
+			     (match_operand:SF 2 "fix_scaling_operand" "F"))))]
   "TARGET_HARD_FLOAT"
-  "utrunc.s\t%0, %1, 0"
+{
+  static char result[64];
+  sprintf (result, "<m_fix>.s\t%%0, %%1, %d",
+	   REAL_EXP (CONST_DOUBLE_REAL_VALUE (operands[2])) - 1);
+  return result;
+}
   [(set_attr "type"	"fconv")
    (set_attr "mode"	"SF")
    (set_attr "length"	"3")])
 
-(define_insn "floatsisf2"
+(define_insn "float<s_float>sisf2"
   [(set (match_operand:SF 0 "register_operand" "=f")
-	(float:SF (match_operand:SI 1 "register_operand" "a")))]
+	(any_float:SF (match_operand:SI 1 "register_operand" "a")))]
   "TARGET_HARD_FLOAT"
-  "float.s\t%0, %1, 0"
+  "<m_float>.s\t%0, %1, 0"
   [(set_attr "type"	"fconv")
    (set_attr "mode"	"SF")
    (set_attr "length"	"3")])
 
-(define_insn "floatunssisf2"
+(define_insn "*float<s_float>sisf2_scaled"
   [(set (match_operand:SF 0 "register_operand" "=f")
-	(unsigned_float:SF (match_operand:SI 1 "register_operand" "a")))]
+	(mult:SF (any_float:SF (match_operand:SI 1 "register_operand" "a"))
+		 (match_operand:SF 2 "float_scaling_operand" "F")))]
   "TARGET_HARD_FLOAT"
-  "ufloat.s\t%0, %1, 0"
+{
+  static char result[64];
+  sprintf (result, "<m_float>.s\t%%0, %%1, %d",
+	   1 - REAL_EXP (CONST_DOUBLE_REAL_VALUE (operands[2])));
+  return result;
+}
   [(set_attr "type"	"fconv")
    (set_attr "mode"	"SF")
    (set_attr "length"	"3")])