;; from the same template.
(define_code_iterator any_mod [mod umod])
+;; These code iterators allow unsigned and signed divmod to be generated
+;; from the same template.
+(define_code_iterator only_div [div udiv])
+(define_code_attr paired_mod [(div "mod") (udiv "umod")])
+
;; These code iterators allow the signed and unsigned scc operations to use
;; the same template.
(define_code_iterator any_gt [gt gtu])
(lt "") (ltu "u")
(le "") (leu "u")
(fix "") (unsigned_fix "u")
+ (div "") (udiv "u")
(float "") (unsigned_float "u")])
;; <su> is like <u>, but the signed form expands to "s" rather than "".
th_mempair_output_move (rtx[4], bool, machine_mode, RTX_CODE);
#endif
+extern bool riscv_use_divmod_expander (void);
#endif /* ! GCC_RISCV_PROTOS_H */
unsigned short memory_cost;
unsigned short fmv_cost;
bool slow_unaligned_access;
+ bool use_divmod_expansion;
};
/* Information about one micro-arch we know about. */
5, /* memory_cost */
8, /* fmv_cost */
true, /* slow_unaligned_access */
+ false, /* use_divmod_expansion */
};
/* Costs to use when optimizing for Sifive 7 Series. */
3, /* memory_cost */
8, /* fmv_cost */
true, /* slow_unaligned_access */
+ false, /* use_divmod_expansion */
};
/* Costs to use when optimizing for T-HEAD c906. */
5, /* memory_cost */
8, /* fmv_cost */
false, /* slow_unaligned_access */
+ false /* use_divmod_expansion */
};
/* Costs to use when optimizing for size. */
2, /* memory_cost */
8, /* fmv_cost */
false, /* slow_unaligned_access */
+ false, /* use_divmod_expansion */
};
static tree riscv_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
gen_lowpart (QImode, shift)));
}
+/* Return TRUE if we should use the divmod expander, FALSE otherwise. This
+ allows the behavior to be tuned for specific implementations as well as
+ when optimizing for size. */
+
+bool
+riscv_use_divmod_expander (void)
+{
+ return tune_param->use_divmod_expansion;
+}
+
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
[(set_attr "type" "idiv")
(set_attr "mode" "DI")])
+(define_expand "<u>divmod<mode>4"
+ [(parallel
+ [(set (match_operand:GPR 0 "register_operand")
+ (only_div:GPR (match_operand:GPR 1 "register_operand")
+ (match_operand:GPR 2 "register_operand")))
+ (set (match_operand:GPR 3 "register_operand")
+ (<paired_mod>:GPR (match_dup 1) (match_dup 2)))])]
+ "TARGET_DIV && riscv_use_divmod_expander ()"
+ {
+ rtx tmp = gen_reg_rtx (<MODE>mode);
+ emit_insn (gen_<u>div<GPR:mode>3 (operands[0], operands[1], operands[2]));
+ emit_insn (gen_mul<GPR:mode>3 (tmp, operands[0], operands[2]));
+ emit_insn (gen_sub<GPR:mode>3 (operands[3], operands[1], tmp));
+ DONE;
+ })
+
(define_insn "*<optab>si3_extended"
[(set (match_operand:DI 0 "register_operand" "=r")
(sign_extend:DI
--- /dev/null
+/* { dg-do compile } */
+
+void
+foo(int a, int b, int *c, int *d)
+{
+ *c = a / b;
+ *d = a % b;
+}
+
+/* { dg-final { scan-assembler-times "\tdiv" 1 } } */
+/* { dg-final { scan-assembler-times "\trem" 1} } */
--- /dev/null
+/* { dg-do compile } */
+/* Skip this everywhere for now. Once we have a target with
+ divmod enabled, only skip for -O0, -O1, -Og, -Oz, -Os. */
+/* { dg-skip-if "" { *-*-* } { } } */
+
+void
+foo(int a, int b, int *c, int *d)
+{
+ *c = a / b;
+ *d = a % b;
+}
+
+/* { dg-final { scan-assembler-not "\trem" } } */
+/* { dg-final { scan-assembler-times "\tdiv" 1 } } */
+/* { dg-final { scan-assembler-times "\tmul" 1 } } */
+/* { dg-final { scan-assembler-times "\tsub" 1 } } */