gcc/ChangeLog:
* config/loongarch/loongarch.md (optab): Add (rotatert "rotr").
(<optab:any_shift><mode>3, <optab:any_div><mode>3,
sub<mode>3, rotr<mode>3, mul<mode>3): Add a "*" to the insn name
so we can redefine the names with define_expand.
(*<optab:any_shift>si3_extend): Remove "*" so we can use them
in expanders.
(*subsi3_extended, *mulsi3_extended): Likewise, also remove the
trailing "ed" for consistency.
(*<optab:any_div>si3_extended): Add mode for sign_extend to
prevent an ICE using it in expanders.
(shift_w, arith_w): New define_code_iterator.
(<optab:any_w><mode>3): New define_expand. Expand with
<optab:any_w>si3_extend for SImode if TARGET_64BIT.
(<optab:arith_w><mode>3): Likewise.
(mul<mode>3): Expand to mulsi3_extended for SImode if
TARGET_64BIT and ISA_HAS_DIV32.
(<optab:any_div><mode>3): Expand to <optab:any_div>si3_extended
for SImode if TARGET_64BIT.
(rotl<mode>3): Expand to rotrsi3_extend for SImode if
TARGET_64BIT.
(bytepick_w_<bytepick_imm>): Add mode for lshiftrt and ashift.
(bitsize, bytepick_imm, bytepick_w_ashift_amount): New
define_mode_attr.
(bytepick_w_<bytepick_imm>_extend): Adjust for the RTL change
caused by 32-bit shift expanding. Now bytepick_imm only covers
2 and 3, separate one remaining case to ...
(bytepick_w_1_extend): ... here, new define_insn.
gcc/testsuite/ChangeLog:
* gcc.target/loongarch/bitwise_extend.c: New test.
---
Bootstrapped and regtested on loongarch64-linux-gnu. Ok for trunk?
gcc/config/loongarch/loongarch.md | 131 +++++++++++++++---
.../gcc.target/loongarch/bitwise_extend.c | 45 ++++++
2 files changed, 154 insertions(+), 22 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/loongarch/bitwise_extend.c
diff --git a/gcc/config/loongarch/loongarch.md
b/gcc/config/loongarch/loongarch.md
index bc09712bce7..e1629c5a339 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -546,6 +546,7 @@ (define_code_attr u_bool [(sign_extend "false") (zero_extend
"true")])
(define_code_attr optab [(ashift "ashl")
(ashiftrt "ashr")
(lshiftrt "lshr")
+ (rotatert "rotr")
(ior "ior")
(xor "xor")
(and "and")
@@ -624,6 +625,49 @@ (define_int_attr bytepick_imm [(8 "1")
(48 "6")
(56 "7")])
+;; Expand some 32-bit operations to si3_extend operations if TARGET_64BIT
+;; so the redundant sign extension can be removed if the output is used as
+;; an input of a bitwise operation. Note plus, rotl, and div are handled
+;; separately.
+(define_code_iterator shift_w [any_shift rotatert])
+(define_code_iterator arith_w [minus mult])
+
+(define_expand "<optab><mode>3"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (shift_w:GPR (match_operand:GPR 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ ""
+{
+ if (TARGET_64BIT && <MODE>mode == SImode)
+ {
+ rtx t = gen_reg_rtx (DImode);
+ emit_insn (gen_<optab>si3_extend (t, operands[1], operands[2]));
+ t = gen_lowpart (SImode, t);
+ SUBREG_PROMOTED_VAR_P (t) = 1;
+ SUBREG_PROMOTED_SET (t, SRP_SIGNED);
+ emit_move_insn (operands[0], t);
+ DONE;
+ }
+})
+
+(define_expand "<optab><mode>3"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (arith_w:GPR (match_operand:GPR 1 "register_operand" "r")
+ (match_operand:GPR 2 "register_operand" "r")))]
+ ""
+{
+ if (TARGET_64BIT && <MODE>mode == SImode)
+ {
+ rtx t = gen_reg_rtx (DImode);
+ emit_insn (gen_<optab>si3_extend (t, operands[1], operands[2]));
+ t = gen_lowpart (SImode, t);
+ SUBREG_PROMOTED_VAR_P (t) = 1;
+ SUBREG_PROMOTED_SET (t, SRP_SIGNED);
+ emit_move_insn (operands[0], t);
+ DONE;
+ }
+})
+
;;
;; ....................
;;
@@ -781,7 +825,7 @@ (define_insn "sub<mode>3"
[(set_attr "type" "fadd")
(set_attr "mode" "<UNITMODE>")])
-(define_insn "sub<mode>3"
+(define_insn "*sub<mode>3"
[(set (match_operand:GPR 0 "register_operand" "=r")
(minus:GPR (match_operand:GPR 1 "register_operand" "r")
(match_operand:GPR 2 "register_operand" "r")))]
@@ -791,7 +835,7 @@ (define_insn "sub<mode>3"
(set_attr "mode" "<MODE>")])
-(define_insn "*subsi3_extended"
+(define_insn "subsi3_extend"
[(set (match_operand:DI 0 "register_operand" "=r")
(sign_extend:DI
(minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
@@ -818,7 +862,7 @@ (define_insn "mul<mode>3"
[(set_attr "type" "fmul")
(set_attr "mode" "<MODE>")])
-(define_insn "mul<mode>3"
+(define_insn "*mul<mode>3"
[(set (match_operand:GPR 0 "register_operand" "=r")
(mult:GPR (match_operand:GPR 1 "register_operand" "r")
(match_operand:GPR 2 "register_operand" "r")))]
@@ -827,7 +871,7 @@ (define_insn "mul<mode>3"
[(set_attr "type" "imul")
(set_attr "mode" "<MODE>")])
-(define_insn "*mulsi3_extended"
+(define_insn "mulsi3_extend"
[(set (match_operand:DI 0 "register_operand" "=r")
(sign_extend:DI
(mult:SI (match_operand:SI 1 "register_operand" "r")
@@ -1001,8 +1045,19 @@ (define_expand "<optab><mode>3"
(match_operand:GPR 2 "register_operand")))]
""
{
- if (GET_MODE (operands[0]) == SImode && TARGET_64BIT && !ISA_HAS_DIV32)
+ if (GET_MODE (operands[0]) == SImode && TARGET_64BIT)
{
+ if (ISA_HAS_DIV32)
+ {
+ rtx t = gen_reg_rtx (DImode);
+ emit_insn (gen_<optab>si3_extended (t, operands[1], operands[2]));
+ t = gen_lowpart (SImode, t);
+ SUBREG_PROMOTED_VAR_P (t) = 1;
+ SUBREG_PROMOTED_SET (t, SRP_SIGNED);
+ emit_move_insn (operands[0], t);
+ DONE;
+ }
+
rtx reg1 = gen_reg_rtx (DImode);
rtx reg2 = gen_reg_rtx (DImode);
rtx rd = gen_reg_rtx (DImode);
@@ -1038,7 +1093,7 @@ (define_insn "*<optab><mode>3"
(define_insn "<optab>si3_extended"
[(set (match_operand:DI 0 "register_operand" "=r,&r,&r")
- (sign_extend
+ (sign_extend:DI
(any_div:SI (match_operand:SI 1 "register_operand" "r,r,0")
(match_operand:SI 2 "register_operand" "r,r,r"))))]
"TARGET_64BIT && ISA_HAS_DIV32"
@@ -2985,7 +3040,7 @@ (define_expand "cpymemsi"
;;
;; ....................
-(define_insn "<optab><mode>3"
+(define_insn "*<optab><mode>3"
[(set (match_operand:GPR 0 "register_operand" "=r")
(any_shift:GPR (match_operand:GPR 1 "register_operand" "r")
(match_operand:SI 2 "arith_operand" "rI")))]
@@ -3000,7 +3055,7 @@ (define_insn "<optab><mode>3"
[(set_attr "type" "shift")
(set_attr "mode" "<MODE>")])
-(define_insn "*<optab>si3_extend"
+(define_insn "<optab>si3_extend"
[(set (match_operand:DI 0 "register_operand" "=r")
(sign_extend:DI
(any_shift:SI (match_operand:SI 1 "register_operand" "r")
@@ -3015,7 +3070,7 @@ (define_insn "*<optab>si3_extend"
[(set_attr "type" "shift")
(set_attr "mode" "SI")])
-(define_insn "rotr<mode>3"
+(define_insn "*rotr<mode>3"
[(set (match_operand:GPR 0 "register_operand" "=r,r")
(rotatert:GPR (match_operand:GPR 1 "register_operand" "r,r")
(match_operand:SI 2 "arith_operand" "r,I")))]
@@ -3044,6 +3099,19 @@ (define_expand "rotl<mode>3"
""
{
operands[3] = gen_reg_rtx (SImode);
+
+ if (TARGET_64BIT && <MODE>mode == SImode)
+ {
+ rtx t = gen_reg_rtx (DImode);
+
+ emit_insn (gen_negsi2 (operands[3], operands[2]));
+ emit_insn (gen_rotrsi3_extend (t, operands[1], operands[3]));
+ t = gen_lowpart (SImode, t);
+ SUBREG_PROMOTED_VAR_P (t) = 1;
+ SUBREG_PROMOTED_SET (t, SRP_SIGNED);
+ emit_move_insn (operands[0], t);
+ DONE;
+ }
});
;; The following templates were added to generate "bstrpick.d + alsl.d"
@@ -4113,26 +4181,45 @@ (define_expand "<FCLASS_MASK:fclass_optab><ANYF:mode>2"
(define_insn "bytepick_w_<bytepick_imm>"
[(set (match_operand:SI 0 "register_operand" "=r")
- (ior:SI (lshiftrt (match_operand:SI 1 "register_operand" "r")
- (const_int <bytepick_w_lshiftrt_amount>))
- (ashift (match_operand:SI 2 "register_operand" "r")
- (const_int bytepick_w_ashift_amount))))]
+ (ior:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int <bytepick_w_lshiftrt_amount>))
+ (ashift:SI (match_operand:SI 2 "register_operand" "r")
+ (const_int bytepick_w_ashift_amount))))]
""
"bytepick.w\t%0,%1,%2,<bytepick_imm>"
[(set_attr "mode" "SI")])
+(define_mode_attr bitsize [(QI "8") (HI "16")])
+(define_mode_attr bytepick_imm [(QI "3") (HI "2")])
+(define_mode_attr bytepick_w_ashift_amount [(QI "24") (HI "16")])
+
(define_insn "bytepick_w_<bytepick_imm>_extend"
[(set (match_operand:DI 0 "register_operand" "=r")
- (sign_extend:DI
- (subreg:SI
- (ior:DI (subreg:DI (lshiftrt
- (match_operand:SI 1 "register_operand" "r")
- (const_int <bytepick_w_lshiftrt_amount>)) 0)
- (subreg:DI (ashift
- (match_operand:SI 2 "register_operand" "r")
- (const_int bytepick_w_ashift_amount)) 0)) 0)))]
+ (ior:DI
+ (ashift:DI
+ (sign_extend:DI
+ (subreg:SHORT (match_operand:DI 1 "register_operand" "r") 0))
+ (const_int <bytepick_w_ashift_amount>))
+ (zero_extract:DI (match_operand:DI 2 "register_operand" "r")
+ (const_int <bytepick_w_ashift_amount>)
+ (const_int <bitsize>))))]
"TARGET_64BIT"
- "bytepick.w\t%0,%1,%2,<bytepick_imm>"
+ "bytepick.w\t%0,%2,%1,<bytepick_imm>"
+ [(set_attr "mode" "SI")])
+
+(define_insn "bytepick_w_1_extend"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ior:DI
+ (ashift:DI
+ (sign_extract:DI (match_operand:DI 1 "register_operand" "r")
+ (const_int 24)
+ (const_int 0))
+ (const_int 8))
+ (zero_extract:DI (match_operand:DI 2 "register_operand" "r")
+ (const_int 8)
+ (const_int 24))))]
+ "TARGET_64BIT"
+ "bytepick.w\t%0,%2,%1,1"
[(set_attr "mode" "SI")])
(define_insn "bytepick_d_<bytepick_imm>"
diff --git a/gcc/testsuite/gcc.target/loongarch/bitwise_extend.c
b/gcc/testsuite/gcc.target/loongarch/bitwise_extend.c
new file mode 100644
index 00000000000..c2bc489a734
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/bitwise_extend.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=loongarch64 -mdiv32" } */
+/* { dg-final { scan-assembler-not "slli\\.w" } } */
+
+int
+f1 (int a, int b)
+{
+ return (a << b) | b;
+}
+
+int
+f2 (int a, int b)
+{
+ return (a - b) | b;
+}
+
+int
+f3 (int a, int b)
+{
+ return (a * b) | b;
+}
+
+int
+f4 (int a, int b)
+{
+ return (unsigned) a >> b | (unsigned) a << (32 - b) | b;
+}
+
+int
+f5 (int a, int b)
+{
+ return (unsigned) a << b | (unsigned) a >> (32 - b) | b;
+}
+
+int
+f6 (int a, int b)
+{
+ return (a % b) | b;
+}
+
+int
+f7 (int a, int b)
+{
+ return (a + b) | b;
+}