return CMP_INT16_P (INTVAL (op));
}
+/* Return true if OP is a const_int requiring two instructions to load. */
+
+int
+two_insn_const_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (GET_CODE (op) != CONST_INT)
+ return 0;
+ if (INT16_P (INTVAL (op))
+ || UINT24_P (INTVAL (op))
+ || UPPER16_P (INTVAL (op)))
+ return 0;
+ return 1;
+}
+
/* Return true if OP is an acceptable argument for a single word
move source. */
output_operand_lossage ("invalid operand to %N code");
return;
+ case 'X' :
+ /* Print a const_int in hex. Used in comments. */
+ if (GET_CODE (x) == CONST_INT)
+ fprintf (file,
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+ "0x%x",
+#else
+ "0x%lx",
+#endif
+ INTVAL (x));
+ return;
+
case '#' :
fputs (IMMEDIATE_PREFIX, file);
return;
""
"
{
- /* Everything except mem = const or mem = mem can be done easily.
- If medium or large code model, symbols have to be loaded with seth/add3.
- Objects in the small data area are handled too. */
+ /* Everything except mem = const or mem = mem can be done easily. */
if (GET_CODE (operands[0]) == MEM)
operands[1] = force_reg (SImode, operands[1]);
+ /* Small Data Area reference? */
if (small_data_operand (operands[1], SImode))
{
emit_insn (gen_movsi_sda (operands[0], operands[1]));
DONE;
}
- else if (addr32_operand (operands[1], SImode))
+
+ /* If medium or large code model, symbols have to be loaded with
+ seth/add3. */
+ if (addr32_operand (operands[1], SImode))
{
emit_insn (gen_movsi_addr32 (operands[0], operands[1]));
DONE;
"register_operand (operands[0], SImode) || register_operand (operands[1], SImode)"
"@
mv %0,%1
- ldi %0,%#%1
- ldi %0,%#%1
- ld24 %0,%#%1
+ ldi %0,%#%1 ; %X1
+ ldi %0,%#%1 ; %X1
+ ld24 %0,%#%1 ; %X1
seth %0,%#%T1
seth %0,%#%T1\;or3 %0,%0,%#%B1
ld %0,%1
st %1,%0"
[(set_attr "type" "move,move,move4,move4,move4,multi,load,store")])
+; Try to use a four byte / two byte pair for constants not loadable with
+; ldi, ld24, seth.
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "two_insn_const_operand" ""))]
+ ""
+ [(set (match_dup 0) (match_dup 2))
+ (set (match_dup 0) (ior:SI (match_dup 0) (match_dup 3)))]
+ "
+{
+ unsigned HOST_WIDE_INT val = INTVAL (operands[1]);
+ unsigned HOST_WIDE_INT tmp;
+ int shift;
+
+ /* In all cases we will emit two instructions. However we try to
+ use 2 byte instructions whereever possible. We can assume the
+ constant isn't loadable with any of ldi, ld24, or seth. */
+
+ /* See if we can load a 24 bit unsigned value and invert it. */
+ if (UINT24_P (~ val))
+ {
+ emit_insn (gen_movsi (operands[0], GEN_INT (~ val)));
+ emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
+ DONE;
+ }
+
+ /* See if we can load a 24 bit unsigned value and shift it into place.
+ 0x01fffffe is just beyond ld24's range. */
+ for (shift = 1, tmp = 0x01fffffe;
+ shift < 8;
+ ++shift, tmp <<= 1)
+ {
+ if ((val & ~tmp) == 0)
+ {
+ emit_insn (gen_movsi (operands[0], GEN_INT (val >> shift)));
+ emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (shift)));
+ DONE;
+ }
+ }
+
+ /* Can't use any two byte insn, fall back to seth/or3. */
+ operands[2] = GEN_INT ((val) & 0xffff0000);
+ operands[3] = GEN_INT ((val) & 0xffff);
+}")
+
;; Small data area support.
;; The address of _SDA_BASE_ is loaded into a register and all objects in
;; the small data area are indexed off that. This is done for each reference
""
"@
and %0,%2
- and3 %0,%1,%#%2"
+ and3 %0,%1,%#%2 ; %X2"
[(set_attr "type" "binary")])
(define_insn "iorsi3"
""
"@
or %0,%2
- or3 %0,%1,%#%2"
+ or3 %0,%1,%#%2 ; %X2"
[(set_attr "type" "binary")])
(define_insn "xorsi3"
""
"@
xor %0,%2
- xor3 %0,%1,%#%2"
+ xor3 %0,%1,%#%2 ; %X2"
[(set_attr "type" "binary")])
(define_insn "negsi2"