}
-/* Generate asm equivalent for various shifts. This only handles cases
- that are not already carefully hand-optimized in ?sh<mode>3_out.
+/* Helper for the next function: Shift register REG by 1 bit position
+ according to the shift CODE of ASHIFT, LSHIFTRT or ASHIFTRT.
+ PLEN == 0: Asm output respective shift instruction(s).
+ PLEN != 0: Add the length of the sequence in words to *PLEN. */
+
+static void
+avr_out_shift_1 (rtx_code code, rtx reg, int *plen)
+{
+ const int n_bytes = GET_MODE_SIZE (GET_MODE (reg));
+ const int dir = code == ASHIFT ? 1 : -1;
+ const int regno = REGNO (reg);
+ const int first = code == ASHIFT ? 0 : n_bytes - 1;
+ for (int i = 0; i < n_bytes; ++i)
+ {
+ rtx reg8 = all_regs_rtx[regno + first + i * dir];
+ if (code == ASHIFT)
+ avr_asm_len (i == 0 ? "lsl %0" : "rol %0", ®8, plen, 1);
+ else if (code == LSHIFTRT)
+ avr_asm_len (i == 0 ? "lsr %0" : "ror %0", ®8, plen, 1);
+ else if (code == ASHIFTRT)
+ avr_asm_len (i == 0 ? "asr %0" : "ror %0", ®8, plen, 1);
+ else
+ gcc_unreachable ();
+ }
+}
+
+
+/* Generate asm code to perform a shift of code CODE on register OPERANDS[0].
+ This only handles cases that are not already carefully hand-optimized
+ in ?sh<mode>3_out. Always returns "".
- OPERANDS[0] resp. %0 in TEMPL is the operand to be shifted.
OPERANDS[2] is the shift count as CONST_INT, MEM or REG.
OPERANDS[3] is a QImode scratch register from LD regs if
- available and SCRATCH, otherwise (no scratch available)
-
- TEMPL is an assembler template that shifts by one position.
- T_LEN is the length of this template.
+ available and SCRATCH, otherwise (no scratch available).
PLEN != 0: Set *PLEN to the length of the sequence in words.
PLEN == 0: Output instructions. */
-void
-out_shift_with_cnt (const char *templ, rtx_insn *insn, rtx operands[],
- int *plen, int t_len)
+static const char*
+avr_out_shift_with_cnt (rtx_code code, rtx_insn *insn, rtx operands[],
+ int *plen)
{
bool second_label = true;
bool saved_in_tmp = false;
bool use_zero_reg = false;
+ const int t_len = GET_MODE_SIZE (GET_MODE (operands[0]));
rtx op[5];
op[0] = operands[0];
int max_len = 10; /* If larger than this, always use a loop. */
if (count <= 0)
- return;
+ return "";
if (count < 8 && !scratch)
use_zero_reg = true;
/* Output shifts inline with no loop - faster. */
while (count-- > 0)
- avr_asm_len (templ, op, plen, t_len);
+ avr_out_shift_1 (code, op[0], plen);
- return;
+ return "";
}
if (scratch)
avr_asm_len ("rjmp 2f", op, plen, 1);
avr_asm_len ("1:", op, plen, 0);
- avr_asm_len (templ, op, plen, t_len);
+ avr_out_shift_1 (code, op[0], plen);
if (second_label)
avr_asm_len ("2:", op, plen, 0);
if (saved_in_tmp)
avr_asm_len ("mov %3,%4", op, plen, 1);
+
+ return "";
}
else if (CONSTANT_P (operands[2]))
fatal_insn ("internal compiler error. Incorrect shift:", insn);
- out_shift_with_cnt ("lsl %0",
- insn, operands, plen, 1);
- return "";
+ return avr_out_shift_with_cnt (ASHIFT, insn, operands, plen);
}
} // switch
}
- out_shift_with_cnt ("lsl %A0" CR_TAB
- "rol %B0", insn, operands, plen, 2);
- return "";
+ return avr_out_shift_with_cnt (ASHIFT, insn, operands, plen);
}
}
}
- out_shift_with_cnt ("lsl %A0" CR_TAB
- "rol %B0" CR_TAB
- "rol %C0", insn, op, plen, 3);
- return "";
+ return avr_out_shift_with_cnt (ASHIFT, insn, op, plen);
}
}
}
- out_shift_with_cnt ("lsl %A0" CR_TAB
- "rol %B0" CR_TAB
- "rol %C0" CR_TAB
- "rol %D0", insn, operands, plen, 4);
- return "";
+ return avr_out_shift_with_cnt (ASHIFT, insn, operands, plen);
}
else if (CONSTANT_P (operands[2]))
fatal_insn ("internal compiler error. Incorrect shift:", insn);
- out_shift_with_cnt ("asr %0",
- insn, operands, plen, 1);
- return "";
+ return avr_out_shift_with_cnt (ASHIFTRT, insn, operands, plen);
}
} // switch
}
- out_shift_with_cnt ("asr %B0" CR_TAB
- "ror %A0", insn, operands, plen, 2);
- return "";
+ return avr_out_shift_with_cnt (ASHIFTRT, insn, operands, plen);
}
} /* switch */
}
- out_shift_with_cnt ("asr %C0" CR_TAB
- "ror %B0" CR_TAB
- "ror %A0", insn, op, plen, 3);
- return "";
+ return avr_out_shift_with_cnt (ASHIFTRT, insn, op, plen);
}
} // switch
}
- out_shift_with_cnt ("asr %D0" CR_TAB
- "ror %C0" CR_TAB
- "ror %B0" CR_TAB
- "ror %A0", insn, operands, plen, 4);
- return "";
+ return avr_out_shift_with_cnt (ASHIFTRT, insn, operands, plen);
}
/* 8-bit logic shift right ((unsigned char)x >> i) */
else if (CONSTANT_P (operands[2]))
fatal_insn ("internal compiler error. Incorrect shift:", insn);
- out_shift_with_cnt ("lsr %0",
- insn, operands, plen, 1);
- return "";
+ return avr_out_shift_with_cnt (LSHIFTRT, insn, operands, plen);
}
}
}
- out_shift_with_cnt ("lsr %B0" CR_TAB
- "ror %A0", insn, operands, plen, 2);
- return "";
+ return avr_out_shift_with_cnt (LSHIFTRT, insn, operands, plen);
}
} /* switch */
}
- out_shift_with_cnt ("lsr %C0" CR_TAB
- "ror %B0" CR_TAB
- "ror %A0", insn, op, plen, 3);
- return "";
+ return avr_out_shift_with_cnt (LSHIFTRT, insn, op, plen);
}
} // switch
}
- out_shift_with_cnt ("lsr %D0" CR_TAB
- "ror %C0" CR_TAB
- "ror %B0" CR_TAB
- "ror %A0", insn, operands, plen, 4);
- return "";
+ return avr_out_shift_with_cnt (LSHIFTRT, insn, operands, plen);
}