In the expansion of cstoresi4 insn patterns, LT[U] comparisons where the
second operand is an integer constant are canonicalized to LE[U] ones with
one less than the original.
/* example */
int test0(int a) {
return a < 100;
}
unsigned int test1(unsigned int a) {
return a <= 100u;
}
void test2(int a[], int b) {
int i;
for (i = 0; i < 16; ++i)
a[i] = (a[i] <= b);
}
;; before (TARGET_SALT)
test0:
entry sp, 32
movi a8, 0x63
salt a2, a8, a2
addi.n a2, a2, -1 ;; unwanted inverting
neg a2, a2 ;;
retw.n
test1:
entry sp, 32
movi a8, 0x64
saltu a2, a8, a2
addi.n a2, a2, -1 ;; unwanted inverting
neg a2, a2 ;;
retw.n
test2:
entry sp, 32
movi.n a9, 0x10
loop a9, .L5_LEND
.L5:
l32i.n a8, a2, 0
salt a8, a3, a8
addi.n a8, a8, -1 ;; immediate cannot be hoisted out
neg a8, a8
s32i.n a8, a2, 0
addi.n a2, a2, 4
.L5_LEND:
retw.n
This patch reverts such canonicalization by adding 1 to the comparison value
and then converting it back from LE[U] to LT[U], which better matches the
output machine instructions. This patch also makes it easier to benefit
from other optimizations such as CSE, constant propagation, or loop-invariant
hoisting by XORing the result with a register that has a value of 1, rather
than subtracting 1 and then negating the sign to invert the truth of the
result.
;; after (TARGET_SALT)
test0:
entry sp, 32
movi a8, 0x64
salt a2, a2, a8
retw.n
test1:
entry sp, 32
movi a8, 0x65
saltu a2, a2, a8
retw.n
test2:
entry sp, 32
movi.n a10, 1 ;; hoisted out
movi.n a9, 0x10
loop a9, .L5_LEND
.L5:
l32i.n a8, a2, 0
salt a8, a3, a8
xor a8, a8, a10
s32i.n a8, a2, 0
addi.n a2, a2, 4
.L5_LEND:
retw.n
gcc/ChangeLog:
* config/xtensa/xtensa.cc (xtensa_expand_scc_SALT):
New sub-function that emits the SALT/SALTU instructions.
(xtensa_expand_scc): Change the part related to the SALT/SALTU
instructions to a call to the above sub-function.
---
gcc/config/xtensa/xtensa.cc | 115 ++++++++++++++++++------------------
1 file changed, 58 insertions(+), 57 deletions(-)
diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc
index 43df10e4b63..1299e45bc7d 100644
--- a/gcc/config/xtensa/xtensa.cc
+++ b/gcc/config/xtensa/xtensa.cc
@@ -993,70 +993,71 @@ xtensa_expand_conditional_move (rtx *operands, int isflt)
}
-int
-xtensa_expand_scc (rtx operands[4], machine_mode cmp_mode)
+static bool
+xtensa_expand_scc_SALT (rtx dest, enum rtx_code code, rtx op0, rtx op1)
{
- rtx dest = operands[0];
- rtx cmp;
- rtx one_tmp, zero_tmp;
- rtx (*gen_fn) (rtx, rtx, rtx, rtx, rtx);
+ int flags;
- if (cmp_mode == SImode && TARGET_SALT)
+ /* Revert back the canonicalization of '(lt[u]:SI (reg:SI) (const_int N)'
+ to '(le[u]:SI (reg:SI) (const_int N-1)'.
+ Note that a comparison like '(le[u]:SI (reg:SI) (const_int [U]INT_MAX))'
+ will never be passed; because the result of such a comparison is a mere
+ constant. */
+ if (CONST_INT_P (op1))
+ switch (code)
+ {
+ case LE:
+ code = LT, op1 = GEN_INT (INTVAL (op1) + 1);
+ break;
+ case LEU:
+ code = LTU, op1 = GEN_INT (UINTVAL (op1) + 1u);
+ break;
+ default:
+ break;
+ }
+
+ /* b0: inverting, b1: swap(op0,op1), b2: unsigned */
+ switch (code)
{
- rtx a = operands[2], b = force_reg (SImode, operands[3]);
- enum rtx_code code = GET_CODE (operands[1]);
- bool invert_res = false;
+ case GE: flags = 1; break;
+ case GT: flags = 2; break;
+ case LE: flags = 3; break;
+ case LT: flags = 0; break;
+ case GEU: flags = 5; break;
+ case GTU: flags = 6; break;
+ case LEU: flags = 7; break;
+ case LTU: flags = 4; break;
+ default: return false;
+ }
- switch (code)
- {
- case GE:
- case GEU:
- invert_res = true;
- break;
- case GT:
- case GTU:
- std::swap (a, b);
- break;
- case LE:
- case LEU:
- invert_res = true;
- std::swap (a, b);
- break;
- default:
- break;
- }
+ op1 = force_reg (SImode, op1);
+ if (flags & 2)
+ std::swap (op0, op1);
+ emit_insn ((flags & 4) ? gen_saltu (dest, op0, op1)
+ : gen_salt (dest, op0, op1));
+ if (flags & 1)
+ /* XORing with a temporary register with a value of 1 is advantageous
+ over negation followed by addition of 1 because the temporary register
+ assignment can be subject to CSE, constant propagation, or loop-
+ invariant hoisting. */
+ emit_insn (gen_xorsi3 (dest, dest, force_reg (SImode, const1_rtx)));
- switch (code)
- {
- case GE:
- case GT:
- case LE:
- case LT:
- emit_insn (gen_salt (dest, a, b));
- if (!invert_res)
- return 1;
- break;
- case GEU:
- case GTU:
- case LEU:
- case LTU:
- emit_insn (gen_saltu (dest, a, b));
- if (!invert_res)
- return 1;
- break;
- default:
- break;
- }
+ return true;
+}
- if (invert_res)
- {
- emit_insn (gen_negsi2 (dest, dest));
- emit_insn (gen_addsi3 (dest, dest, const1_rtx));
- return 1;
- }
- }
+int
+xtensa_expand_scc (rtx operands[4], machine_mode cmp_mode)
+{
+ rtx dest = operands[0];
+ rtx cmp, one_tmp, zero_tmp;
+ rtx (*gen_fn) (rtx, rtx, rtx, rtx, rtx);
+ enum rtx_code code = GET_CODE (operands[1]);
+
+ if (TARGET_SALT && cmp_mode == SImode
+ && xtensa_expand_scc_SALT (dest, code, operands[2], operands[3]))
+ return 1;
- if (! (cmp = gen_conditional_move (GET_CODE (operands[1]), cmp_mode,
+ if (! (cmp = gen_conditional_move (code, cmp_mode,
operands[2], operands[3])))
return 0;
--
2.39.5