rtx ops[3];
int need_tst = 0;
+ /* The 68HC12 has a sign-extension instruction. Use it when the
+ destination is the register (X,D). First sign-extend the low
+ part and fill X with the sign-extension of the high part. */
+ if (TARGET_M6812 && X_REG_P (operands[0]))
+ {
+ if (!D_REG_P (operands[1]))
+ {
+ ops[0] = gen_rtx (REG, QImode, HARD_D_REGNUM);
+ ops[1] = operands[1];
+ m68hc11_gen_movqi (insn, ops);
+ }
+ return \"sex\\tb,d\\n\\tsex\\ta,x\";
+ }
+
ops[2] = gen_label_rtx ();
if (X_REG_P (operands[1]))
ops[0] = gen_label_rtx ();
if (D_REG_P (operands[0]))
{
+ if (TARGET_M6812)
+ {
+ if (!D_REG_P (operands[1]))
+ {
+ ops[0] = gen_rtx (REG, QImode, HARD_D_REGNUM);
+ ops[1] = operands[1];
+ m68hc11_gen_movqi (insn, ops);
+ }
+ return \"sex\\tb,d\";
+ }
output_asm_insn (\"clra\", operands);
if (H_REG_P (operands[1]))
{
"*
{
extern rtx ix_reg;
- rtx ops[1];
+ rtx ops[2];
int x_reg_used;
if (Y_REG_P (operands[1]))
return \"#\";
- ops[0] = gen_label_rtx ();
-
if (X_REG_P (operands[1]))
{
output_asm_insn (\"xgdx\", operands);
x_reg_used = reg_mentioned_p (ix_reg, operands[1]);
if (x_reg_used)
{
- output_asm_insn (\"ldd\\t%1\", operands);
+ ops[0] = gen_rtx (REG, HImode, HARD_D_REGNUM);
+ ops[1] = operands[1];
+ m68hc11_gen_movhi (insn, ops);
}
}
+
+ CC_STATUS_INIT;
+ if (TARGET_M6812 && 0)
+ {
+ /* This sequence of code is larger than the one for 68HC11.
+ Don't use it; keep it for documentation. */
+ if (!D_REG_P (operands[1]) && !x_reg_used)
+ {
+ ops[0] = gen_rtx (REG, HImode, HARD_D_REGNUM);
+ ops[1] = operands[1];
+ m68hc11_gen_movhi (insn, ops);
+ }
+ output_asm_insn (\"sex\\ta,x\", operands);
+ output_asm_insn (\"xgdx\", operands);
+ output_asm_insn (\"sex\\ta,d\", operands);
+ return \"xgdx\";
+ }
+
output_asm_insn (\"ldx\\t#0\", operands);
if (D_REG_P (operands[1]) || x_reg_used)
{
}
else
{
- output_asm_insn (\"ldd\\t%1\", operands);
+ ops[0] = gen_rtx (REG, HImode, HARD_D_REGNUM);
+ ops[1] = operands[1];
+ m68hc11_gen_movhi (insn, ops);
}
+
+ ops[0] = gen_label_rtx ();
output_asm_insn (\"bpl\\t%l0\", ops);
output_asm_insn (\"dex\", operands);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (ops[0]));
- CC_STATUS_INIT;
return \"\";
}")
+;;--------------------------------------------------------------------
+;;- Min and Max instructions (68HC12).
+;;--------------------------------------------------------------------
+(define_insn "uminqi3"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=d,m")
+ (umin:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:QI 2 "general_operand" "m,d")))]
+ "TARGET_M6812"
+ "*
+{
+ /* Flags are set according to (sub:QI (operand 1) (operand2)).
+ The mina/minm use A as the source or destination. This is the
+ high part of D. There is no way to express that in the pattern
+ so we must use 'exg a,b' to put the operand in the good register. */
+ CC_STATUS_INIT;
+ if (D_REG_P (operands[0]))
+ {
+ return \"exg\\ta,b\\n\\tmina\\t%2\\n\\texg\\ta,b\";
+ }
+ else
+ {
+ return \"exg\\ta,b\\n\\tminm\\t%0\\n\\texg\\ta,b\";
+ }
+}")
+
+(define_insn "umaxqi3"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=d,m")
+ (umax:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:QI 2 "general_operand" "m,d")))]
+ "TARGET_M6812"
+ "*
+{
+ /* Flags are set according to (sub:QI (operand 1) (operand2)).
+ The maxa/maxm use A as the source or destination. This is the
+ high part of D. There is no way to express that in the pattern
+ so we must use 'exg a,b' to put the operand in the good register. */
+ CC_STATUS_INIT;
+ if (D_REG_P (operands[0]))
+ {
+ return \"exg\\ta,b\\n\\tmaxa\\t%2\\n\\texg\\ta,b\";
+ }
+ else
+ {
+ return \"exg\\ta,b\\n\\tmaxm\\t%0\\n\\texg\\ta,b\";
+ }
+}")
+
+(define_insn "uminhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,m")
+ (umin:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "m,d")))]
+ "TARGET_M6812"
+ "*
+{
+ /* Flags are set according to (sub:HI (operand 1) (operand2)). */
+ CC_STATUS_INIT;
+ if (D_REG_P (operands[0]))
+ {
+ return \"emind\\t%2\";
+ }
+ else
+ {
+ return \"eminm\\t%0\";
+ }
+}")
+
+(define_insn "umaxhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,m")
+ (umax:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "m,d")))]
+ "TARGET_M6812"
+ "*
+{
+ /* Flags are set according to (sub:HI (operand 1) (operand2)). */
+ CC_STATUS_INIT;
+ if (D_REG_P (operands[0]))
+ {
+ return \"emaxd\\t%2\";
+ }
+ else
+ {
+ return \"emaxm\\t%0\";
+ }
+}")
+
+
;;--------------------------------------------------------------------
;;- Add instructions.
;;--------------------------------------------------------------------
DONE;
}")
+;;
+;; Test and branch instructions for 68HC12 for EQ and NE.
+;; 'z' must not appear in the constraints because the z replacement
+;; pass does not know how to restore the replacement register.
+;;
+(define_insn "*tbeq"
+ [(set (pc)
+ (if_then_else (eq (match_operand:HI 0 "register_operand" "dxy")
+ (const_int 0))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ "TARGET_M6812"
+ "*
+{
+ /* If the flags are already set correctly, use 'bne/beq' which are
+ smaller and a little bit faster. This happens quite often due
+ to reloading of operands[0]. In that case, flags are set correctly
+ due to the load instruction. */
+ if (cc_status.value1 && rtx_equal_p (cc_status.value1, operands[0]))
+ return \"beq\\t%l1\";
+ else
+ return \"tbeq\\t%0,%l1\";
+}")
+
+(define_insn "*tbne"
+ [(set (pc)
+ (if_then_else (ne (match_operand:HI 0 "register_operand" "dxy")
+ (const_int 0))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ "TARGET_M6812"
+ "*
+{
+ if (cc_status.value1 && rtx_equal_p (cc_status.value1, operands[0]))
+ return \"bne\\t%l1\";
+ else
+ return \"tbne\\t%0,%l1\";
+}")
+
+;;
+;; Test and branch with 8-bit register. Register must be B (or A).
+;;
+(define_insn "*tbeq8"
+ [(set (pc)
+ (if_then_else (eq (match_operand:QI 0 "register_operand" "d")
+ (const_int 0))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ "TARGET_M6812"
+ "*
+{
+ if (cc_status.value1 && rtx_equal_p (cc_status.value1, operands[0]))
+ return \"beq\\t%l1\";
+ else
+ return \"tbeq\\tb,%l1\";
+}")
+
+(define_insn "*tbne8"
+ [(set (pc)
+ (if_then_else (ne (match_operand:QI 0 "register_operand" "d")
+ (const_int 0))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ "TARGET_M6812"
+ "*
+{
+ if (cc_status.value1 && rtx_equal_p (cc_status.value1, operands[0]))
+ return \"bne\\t%l1\";
+ else
+ return \"tbne\\tb,%l1\";
+}")
+
(define_insn "*beq"
[(set (pc)
(if_then_else (eq (cc0)