diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 1fd00146ca9e9..f47e036a8034e 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -12647,6 +12647,72 @@ "" ) +;; Implement zero_extract using uxtb/uxth instruction with +;; the ror #N qualifier when applicable. + +(define_insn "*arm_zeroextractsi2_8_8" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (zero_extract:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int 8) (const_int 8)))] + "TARGET_ARM && arm_arch6" + "uxtb%?\\t%0, %1, ror #8" + [(set_attr "predicable" "yes") + (set_attr "type" "extend")] +) + +(define_insn "*arm_zeroextractsi2_8_16" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (zero_extract:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int 8) (const_int 16)))] + "TARGET_ARM && arm_arch6" + "uxtb%?\\t%0, %1, ror #16" + [(set_attr "predicable" "yes") + (set_attr "type" "extend")] +) + +(define_insn "*arm_zeroextractsi2_16_8" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (zero_extract:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int 16) (const_int 8)))] + "TARGET_ARM && arm_arch6" + "uxth%?\\t%0, %1, ror #8" + [(set_attr "predicable" "yes") + (set_attr "type" "extend")] +) + +;; Implement sign_extract using sxtb/sxth instruction with +;; the ror #N qualifier when applicable. + +(define_insn "*arm_signextractsi2_8_8" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int 8) (const_int 8)))] + "TARGET_ARM && arm_arch6" + "sxtb%?\\t%0, %1, ror #8" + [(set_attr "predicable" "yes") + (set_attr "type" "extend")] +) + +(define_insn "*arm_signextractsi2_8_16" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int 8) (const_int 16)))] + "TARGET_ARM && arm_arch6" + "sxtb%?\\t%0, %1, ror #16" + [(set_attr "predicable" "yes") + (set_attr "type" "extend")] +) + +(define_insn "*arm_signextractsi2_16_8" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int 16) (const_int 8)))] + "TARGET_ARM && arm_arch6" + "sxth%?\\t%0, %1, ror #8" + [(set_attr "predicable" "yes") + (set_attr "type" "extend")] +) + ;; Patterns for LDRD/STRD in Thumb2 mode (define_insn "*thumb2_ldrd" diff --git a/gcc/testsuite/gcc.target/arm/extend-ror.c b/gcc/testsuite/gcc.target/arm/extend-ror.c new file mode 100644 index 0000000000000..8b52a93e253a2 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/extend-ror.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-skip-if "avoid conflicting multilib options" { *-*-* } { "-march=*" } { "-march=armv6" } } */ +/* { dg-require-effective-target arm_arm_ok } */ +/* { dg-add-options arm_arch_v6 } */ +/* { dg-additional-options "-O -marm" } */ + +unsigned int zeroextractsi2_8_8(unsigned int x) +{ + return (unsigned char)(x>>8); +} + +unsigned int zeroextractsi2_8_16(unsigned int x) +{ + return (unsigned char)(x>>16); +} + +unsigned int signextractsi2_8_8(unsigned int x) +{ + return (int)(signed char)(x>>8); +} + +unsigned int signextractsi2_8_16(unsigned int x) +{ + return (int)(signed char)(x>>16); +} + +unsigned int zeroextractsi2_16_8(unsigned int x) +{ + return (unsigned short)(x>>8); +} + +unsigned int signextractsi2_16_8(unsigned int x) +{ + return (int)(short)(x>>8); +} + +/* { dg-final { scan-assembler-times ", ror #8" 4 } } */ +/* { dg-final { scan-assembler-times ", ror #16" 2 } } */