return true;
}
+/* Synthesize OPERANDS[0] = OPERANDS[1] + OPERANDS[2].
+
+ For 32-bit object cases with a 64-bit target.
+
+ OPERANDS[0] and OPERANDS[1] will be a REG and may be the same
+ REG.
+
+ OPERANDS[2] is a CONST_INT.
+
+ Return TRUE if the operation was fully synthesized and the caller
+ need not generate additional code. Return FALSE if the operation
+ was not synthesized and the caller is responsible for emitting the
+ proper sequence. */
+
+
+bool
+synthesize_add_extended (rtx operands[3])
+{
+
+/* If operands[2] is a 12-bit signed immediate,
+ no synthesis needs to be done. */
+
+ if (SMALL_OPERAND (INTVAL (operands[2])))
+ return false;
+
+ HOST_WIDE_INT ival = INTVAL (operands[2]);
+ int budget1 = riscv_const_insns (operands[2], true);
+ int budget2 = riscv_const_insns (GEN_INT (-INTVAL (operands[2])), true);
+
+/* If operands[2] can be split into two 12-bit signed immediates,
+ split add into two adds. */
+
+ if (SUM_OF_TWO_S12 (ival))
+ {
+ HOST_WIDE_INT saturated = HOST_WIDE_INT_M1U << (IMM_BITS - 1);
+
+ if (ival >= 0)
+ saturated = ~saturated;
+
+ ival -= saturated;
+
+ rtx temp = gen_reg_rtx (DImode);
+ emit_insn (gen_addsi3_extended (temp, operands[1], GEN_INT (saturated)));
+ temp = gen_lowpart (SImode, temp);
+ SUBREG_PROMOTED_VAR_P (temp) = 1;
+ SUBREG_PROMOTED_SET (temp, SRP_SIGNED);
+ emit_insn (gen_rtx_SET (operands[0], temp));
+ rtx t = gen_reg_rtx (DImode);
+ emit_insn (gen_addsi3_extended (t, operands[0], GEN_INT (ival)));
+ t = gen_lowpart (SImode, t);
+ SUBREG_PROMOTED_VAR_P (t) = 1;
+ SUBREG_PROMOTED_SET (t, SRP_SIGNED);
+ emit_move_insn (operands[0], t);
+ return true;
+ }
+
+
+/* If the negated value is cheaper to synthesize, subtract that from
+ operands[1]. */
+
+ if (budget2 < budget1)
+ {
+ rtx tmp = gen_reg_rtx (SImode);
+ emit_insn (gen_rtx_SET (tmp, GEN_INT (-INTVAL (operands[2]))));
+
+ rtx t = gen_reg_rtx (DImode);
+ emit_insn (gen_subsi3_extended (t, operands[1], tmp));
+ t = gen_lowpart (SImode, t);
+ SUBREG_PROMOTED_VAR_P (t) = 1;
+ SUBREG_PROMOTED_SET (t, SRP_SIGNED);
+ emit_move_insn (operands[0], t);
+ return true;
+ }
+
+ rtx tsrc = force_reg (SImode, operands[2]);
+ rtx tdest = gen_reg_rtx (DImode);
+ emit_insn (gen_addsi3_extended (tdest, operands[1], tsrc));
+ tdest = gen_lowpart (SImode, tdest);
+ SUBREG_PROMOTED_VAR_P (tdest) = 1;
+ SUBREG_PROMOTED_SET (tdest, SRP_SIGNED);
+ emit_move_insn (operands[0], tdest);
+ return true;
+
+}
+
+
/*
HINT : argument specify the target cache
(match_operand:SI 2 "reg_or_const_int_operand")))]
""
{
+ /* We may be able to find a faster sequence, if so, then we are
+ done. Otherwise let expansion continue normally. */
+ if (CONST_INT_P (operands[2])
+ && ((!TARGET_64BIT && synthesize_add (operands))
+ || (TARGET_64BIT && synthesize_add_extended (operands))))
+ DONE;
+
+ /* Constants have already been handled already. */
if (TARGET_64BIT)
{
- rtx t = gen_reg_rtx (DImode);
-
- if (CONST_INT_P (operands[2]) && !SMALL_OPERAND (operands[2]))
- operands[2] = force_reg (SImode, operands[2]);
- emit_insn (gen_addsi3_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);
+ rtx tdest = gen_reg_rtx (DImode);
+ emit_insn (gen_addsi3_extended (tdest, operands[1], operands[2]));
+ tdest = gen_lowpart (SImode, tdest);
+ SUBREG_PROMOTED_VAR_P (tdest) = 1;
+ SUBREG_PROMOTED_SET (tdest, SRP_SIGNED);
+ emit_move_insn (operands[0], tdest);
DONE;
}
- /* We may be able to find a faster sequence, if so, then we are
- done. Otherwise let expansion continue normally. */
- if (CONST_INT_P (operands[2]) && synthesize_add (operands))
- DONE;
})
(define_expand "adddi3"
--- /dev/null
+/* { dg-do compile { target rv64 } } */
+/* { dg-options "-march=rv64gcb -mabi=lp64d" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+
+
+#define T(C) int foo_##C (int x) { return x + C; }
+#define TM(C) int foo_M##C (int x) { return x + -C; }
+
+/* These cases were selected because they all can be synthesized
+ at expansion time without synthesizing the constant directly.
+
+ That makes the assembler scan testing simpler. I've verified
+ by hand that cases that should synthesize the constant do in
+ fact still generate code that way. */
+T (2050)
+T (4094)
+
+TM (2049)
+TM (4096)
+
+/* We have 4/5 tests which should use shNadd insns and 4
+ which used paired addi insns. */
+/* { dg-final { scan-assembler-times "addiw\t" 8 } } */