The original implementation of the function loongarch_extend_comparands
only prevented op1 from being loaded into the register when op1 was
const0_rtx. It has now been modified so that op1 is not loaded into
the register as long as op1 is an immediate value. This allows
slt{u}i to be generated instead of slt{u} if the conditions are met.
gcc/ChangeLog:
* config/loongarch/loongarch.cc
(loongarch_canonicalize_int_order_test): Support GT GTU LT
and LTU.
(loongarch_extend_comparands): Expand the scope of op1 from
0 to all immediate values.
* config/loongarch/loongarch.md
(*sge<u>_<X:mode><GPR:mode>): New template.
gcc/testsuite/ChangeLog:
* gcc.target/loongarch/sign-extend-3.c: New test.
---
gcc/config/loongarch/loongarch.cc | 39 +++++++++++++------
gcc/config/loongarch/loongarch.md | 10 +++++
.../gcc.target/loongarch/sign-extend-3.c | 29 ++++++++++++++
3 files changed, 66 insertions(+), 12 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/loongarch/sign-extend-3.c
diff --git a/gcc/config/loongarch/loongarch.cc
b/gcc/config/loongarch/loongarch.cc
index d11fe496a01..064b251f9ca 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -5276,29 +5276,41 @@ loongarch_canonicalize_int_order_test (enum rtx_code
*code, rtx *cmp1,
if (loongarch_int_order_operand_ok_p (*code, *cmp1))
return true;
- if (CONST_INT_P (*cmp1))
switch (*code)
{
case LE:
- plus_one = trunc_int_for_mode (UINTVAL (*cmp1) + 1, mode);
- if (INTVAL (*cmp1) < plus_one)
+ if (CONST_INT_P (*cmp1))
{
- *code = LT;
- *cmp1 = force_reg (mode, GEN_INT (plus_one));
- return true;
+ plus_one = trunc_int_for_mode (UINTVAL (*cmp1) + 1, mode);
+ if (INTVAL (*cmp1) < plus_one)
+ {
+ *code = LT;
+ *cmp1 = force_reg (mode, GEN_INT (plus_one));
+ return true;
+ }
}
break;
case LEU:
- plus_one = trunc_int_for_mode (UINTVAL (*cmp1) + 1, mode);
- if (plus_one != 0)
+ if (CONST_INT_P (*cmp1))
{
- *code = LTU;
- *cmp1 = force_reg (mode, GEN_INT (plus_one));
- return true;
+ plus_one = trunc_int_for_mode (UINTVAL (*cmp1) + 1, mode);
+ if (plus_one != 0)
+ {
+ *code = LTU;
+ *cmp1 = force_reg (mode, GEN_INT (plus_one));
+ return true;
+ }
}
break;
+ case GT:
+ case GTU:
+ case LT:
+ case LTU:
+ *cmp1 = force_reg (mode, *cmp1);
+ break;
+
default:
break;
}
@@ -5393,7 +5405,10 @@ loongarch_extend_comparands (rtx_code code, rtx *op0,
rtx *op1)
else
{
*op0 = gen_rtx_SIGN_EXTEND (word_mode, *op0);
- if (*op1 != const0_rtx)
+ /* Regardless of whether *op1 is any immediate number, it is not
+ loaded into the register, in order to facilitate the generation
+ of slt{u}i. */
+ if (!CONST_INT_P (*op1))
*op1 = gen_rtx_SIGN_EXTEND (word_mode, *op1);
}
}
diff --git a/gcc/config/loongarch/loongarch.md
b/gcc/config/loongarch/loongarch.md
index 2f4817d885c..2bf63b5b008 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -518,6 +518,7 @@ (define_code_iterator equality_op [eq ne])
;; These code iterators allow the signed and unsigned scc operations to use
;; the same template.
+(define_code_iterator any_ge [ge geu])
(define_code_iterator any_gt [gt gtu])
(define_code_iterator any_lt [lt ltu])
(define_code_iterator any_le [le leu])
@@ -3528,6 +3529,15 @@ (define_insn "*sne_zero_<X:mode><GPR:mode>"
[(set_attr "type" "slt")
(set_attr "mode" "<X:MODE>")])
+(define_insn "*sge<u>_<X:mode><GPR:mode>"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (any_ge:GPR (match_operand:X 1 "register_operand" " r")
+ (const_int 1)))]
+ ""
+ "slti<u>\t%0,zero,%1"
+ [(set_attr "type" "slt")
+ (set_attr "mode" "<X:MODE>")])
+
(define_insn "*sgt<u>_<X:mode><GPR:mode>"
[(set (match_operand:GPR 0 "register_operand" "=r")
(any_gt:GPR (match_operand:X 1 "register_operand" "r")
diff --git a/gcc/testsuite/gcc.target/loongarch/sign-extend-3.c
b/gcc/testsuite/gcc.target/loongarch/sign-extend-3.c
new file mode 100644
index 00000000000..d20bd38486f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/sign-extend-3.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -O2" } */
+/* { dg-final { scan-assembler "sltui" } } */
+
+union any {
+ int any_i32;
+};
+
+extern char *opname;
+extern void test1 (int, char *);
+extern int iterms;
+
+void
+test (union any cv)
+{
+ int i, on;
+ int ix = cv.any_i32;
+ for (i = 1; i < iterms; i++)
+ {
+ on = (ix == 0 || ix == 1) ? 0 : 1;
+ if (*opname == '!')
+ {
+ on = !on;
+ ++opname;
+ }
+ test1 (on, opname);
+ }
+}
+