rtx gen_lowpart_general (machine_mode mode, rtx x) { rtx result = gen_lowpart_common (mode, x); if (result) return result; /* Handle SUBREGs and hard REGs that were rejected by simplify_gen_subreg. */ else if (REG_P (x) || GET_CODE (x) == SUBREG) { result = gen_lowpart_common (mode, copy_to_reg (x)); gcc_assert (result != 0); return result; } else { /* The only additional case we can do is MEM. */ gcc_assert (MEM_P (x)); /* The following exposes the use of "x" to CSE. */ scalar_int_mode xmode; if (is_a <scalar_int_mode> (GET_MODE (x), &xmode) && GET_MODE_SIZE (xmode) <= UNITS_PER_WORD && TRULY_NOOP_TRUNCATION_MODES_P (mode, xmode) && !reload_completed) return gen_lowpart_general (mode, force_reg (xmode, x)); poly_int64 offset = byte_lowpart_offset (mode, GET_MODE (x)); return adjust_address (x, mode, offset); } }
static void nds32_emit_load_store (rtx reg, rtx mem, enum machine_mode mode, int offset, bool load_p) { rtx new_mem; new_mem = adjust_address (mem, mode, offset); if (load_p) emit_move_insn (reg, new_mem); else emit_move_insn (new_mem, reg); }
rtx gen_lowpart_general (machine_mode mode, rtx x) { rtx result = gen_lowpart_common (mode, x); if (result) return result; /* Handle SUBREGs and hard REGs that were rejected by simplify_gen_subreg. */ else if (REG_P (x) || GET_CODE (x) == SUBREG) { result = gen_lowpart_common (mode, copy_to_reg (x)); gcc_assert (result != 0); return result; } else { int offset = 0; /* The only additional case we can do is MEM. */ gcc_assert (MEM_P (x)); /* The following exposes the use of "x" to CSE. */ if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD && SCALAR_INT_MODE_P (GET_MODE (x)) && TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (x)) && !reload_completed) return gen_lowpart_general (mode, force_reg (GET_MODE (x), x)); if (WORDS_BIG_ENDIAN) offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)); if (BYTES_BIG_ENDIAN) /* Adjust the address so that the address-after-the-data is unchanged. */ offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)) - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); return adjust_address (x, mode, offset); } }
rtx gen_lowpart_general (enum machine_mode mode, rtx x) { rtx result = gen_lowpart_common (mode, x); if (result) return result; else if (REG_P (x)) { /* Must be a hard reg that's not valid in MODE. */ result = gen_lowpart_common (mode, copy_to_reg (x)); gcc_assert (result != 0); return result; } else { int offset = 0; /* The only additional case we can do is MEM. */ gcc_assert (MEM_P (x)); /* The following exposes the use of "x" to CSE. */ if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD && SCALAR_INT_MODE_P (GET_MODE (x)) && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), GET_MODE_BITSIZE (GET_MODE (x))) && ! no_new_pseudos) return gen_lowpart_general (mode, force_reg (GET_MODE (x), x)); if (WORDS_BIG_ENDIAN) offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)); if (BYTES_BIG_ENDIAN) /* Adjust the address so that the address-after-the-data is unchanged. */ offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)) - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); return adjust_address (x, mode, offset); } }
rtx fr30_move_double (rtx * operands) { rtx src = operands[1]; rtx dest = operands[0]; enum rtx_code src_code = GET_CODE (src); enum rtx_code dest_code = GET_CODE (dest); enum machine_mode mode = GET_MODE (dest); rtx val; start_sequence (); if (dest_code == REG) { if (src_code == REG) { int reverse = (REGNO (dest) == REGNO (src) + 1); /* We normally copy the low-numbered register first. However, if the first register of operand 0 is the same as the second register of operand 1, we must copy in the opposite order. */ emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, reverse, TRUE, mode), operand_subword (src, reverse, TRUE, mode))); emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, !reverse, TRUE, mode), operand_subword (src, !reverse, TRUE, mode))); } else if (src_code == MEM) { rtx addr = XEXP (src, 0); int dregno = REGNO (dest); rtx dest0; rtx dest1; rtx new_mem; /* If the high-address word is used in the address, we must load it last. Otherwise, load it first. */ int reverse = (refers_to_regno_p (dregno, dregno + 1, addr, 0) != 0); gcc_assert (GET_CODE (addr) == REG); dest0 = operand_subword (dest, reverse, TRUE, mode); dest1 = operand_subword (dest, !reverse, TRUE, mode); if (reverse) { emit_insn (gen_rtx_SET (VOIDmode, dest1, adjust_address (src, SImode, 0))); emit_insn (gen_rtx_SET (SImode, dest0, gen_rtx_REG (SImode, REGNO (addr)))); emit_insn (gen_rtx_SET (SImode, dest0, plus_constant (dest0, UNITS_PER_WORD))); new_mem = gen_rtx_MEM (SImode, dest0); MEM_COPY_ATTRIBUTES (new_mem, src); emit_insn (gen_rtx_SET (VOIDmode, dest0, new_mem)); } else { emit_insn (gen_rtx_SET (VOIDmode, dest0, adjust_address (src, SImode, 0))); emit_insn (gen_rtx_SET (SImode, dest1, gen_rtx_REG (SImode, REGNO (addr)))); emit_insn (gen_rtx_SET (SImode, dest1, plus_constant (dest1, UNITS_PER_WORD))); new_mem = gen_rtx_MEM (SImode, dest1); MEM_COPY_ATTRIBUTES (new_mem, src); emit_insn (gen_rtx_SET (VOIDmode, dest1, new_mem)); } } else if (src_code == CONST_INT || src_code == CONST_DOUBLE) { rtx words[2]; split_double (src, &words[0], &words[1]); emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, 0, TRUE, mode), words[0])); emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, 1, TRUE, mode), words[1])); } } else if (src_code == REG && dest_code == MEM) { rtx addr = XEXP (dest, 0); rtx src0; rtx src1; gcc_assert (GET_CODE (addr) == REG); src0 = operand_subword (src, 0, TRUE, mode); src1 = operand_subword (src, 1, TRUE, mode); emit_insn (gen_rtx_SET (VOIDmode, adjust_address (dest, SImode, 0), src0)); if (REGNO (addr) == STACK_POINTER_REGNUM || REGNO (addr) == FRAME_POINTER_REGNUM) emit_insn (gen_rtx_SET (VOIDmode, adjust_address (dest, SImode, UNITS_PER_WORD), src1)); else { rtx new_mem; /* We need a scratch register to hold the value of 'address + 4'. We ought to allow gcc to find one for us, but for now, just push one of the source registers. */ emit_insn (gen_movsi_push (src0)); emit_insn (gen_movsi_internal (src0, addr)); emit_insn (gen_addsi_small_int (src0, src0, GEN_INT (UNITS_PER_WORD))); new_mem = gen_rtx_MEM (SImode, src0); MEM_COPY_ATTRIBUTES (new_mem, dest); emit_insn (gen_rtx_SET (VOIDmode, new_mem, src1)); emit_insn (gen_movsi_pop (src0)); } } else /* This should have been prevented by the constraints on movdi_insn. */ gcc_unreachable (); val = get_insns (); end_sequence (); return val; }
void crx_print_operand (FILE * file, rtx x, int code) { switch (code) { case 'p' : if (GET_CODE (x) == REG) { if (GET_MODE (x) == DImode || GET_MODE (x) == DFmode) { int regno = REGNO (x); if (regno + 1 >= SP_REGNUM) abort (); fprintf (file, "{%s, %s}", reg_names[regno], reg_names[regno + 1]); return; } else { if (REGNO (x) >= SP_REGNUM) abort (); fprintf (file, "%s", reg_names[REGNO (x)]); return; } } case 'd' : { const char *crx_cmp_str; switch (GET_CODE (x)) { /* MD: compare (reg, reg or imm) but CRX: cmp (reg or imm, reg) * -> swap all non symmetric ops */ case EQ : crx_cmp_str = "eq"; break; case NE : crx_cmp_str = "ne"; break; case GT : crx_cmp_str = "lt"; break; case GTU : crx_cmp_str = "lo"; break; case LT : crx_cmp_str = "gt"; break; case LTU : crx_cmp_str = "hi"; break; case GE : crx_cmp_str = "le"; break; case GEU : crx_cmp_str = "ls"; break; case LE : crx_cmp_str = "ge"; break; case LEU : crx_cmp_str = "hs"; break; default : abort (); } fprintf (file, "%s", crx_cmp_str); return; } case 'H': /* Print high part of a double precision value. */ switch (GET_CODE (x)) { case CONST_DOUBLE: if (GET_MODE (x) == SFmode) abort (); if (GET_MODE (x) == DFmode) { /* High part of a DF const. */ REAL_VALUE_TYPE r; long l[2]; REAL_VALUE_FROM_CONST_DOUBLE (r, x); REAL_VALUE_TO_TARGET_DOUBLE (r, l); fprintf (file, "$0x%lx", l[1]); return; } /* -- Fallthrough to handle DI consts -- */ case CONST_INT: { rtx high, low; split_double (x, &low, &high); putc ('$', file); output_addr_const (file, high); return; } case REG: if (REGNO (x) + 1 >= FIRST_PSEUDO_REGISTER) abort (); fprintf (file, "%s", reg_names[REGNO (x) + 1]); return; case MEM: /* Adjust memory address to high part. */ { rtx adj_mem = x; adj_mem = adjust_address (adj_mem, GET_MODE (adj_mem), 4); output_memory_reference_mode = GET_MODE (adj_mem); output_address (XEXP (adj_mem, 0)); return; } default: abort (); } case 'L': /* Print low part of a double precision value. */ switch (GET_CODE (x)) { case CONST_DOUBLE: if (GET_MODE (x) == SFmode) abort (); if (GET_MODE (x) == DFmode) { /* High part of a DF const. */ REAL_VALUE_TYPE r; long l[2]; REAL_VALUE_FROM_CONST_DOUBLE (r, x); REAL_VALUE_TO_TARGET_DOUBLE (r, l); fprintf (file, "$0x%lx", l[0]); return; } /* -- Fallthrough to handle DI consts -- */ case CONST_INT: { rtx high, low; split_double (x, &low, &high); putc ('$', file); output_addr_const (file, low); return; } case REG: fprintf (file, "%s", reg_names[REGNO (x)]); return; case MEM: output_memory_reference_mode = GET_MODE (x); output_address (XEXP (x, 0)); return; default: abort (); } case 0 : /* default */ switch (GET_CODE (x)) { case REG: fprintf (file, "%s", reg_names[REGNO (x)]); return; case MEM: output_memory_reference_mode = GET_MODE (x); output_address (XEXP (x, 0)); return; case CONST_DOUBLE: { REAL_VALUE_TYPE r; long l; /* Always use H and L for double precision - see above */ gcc_assert (GET_MODE (x) == SFmode); REAL_VALUE_FROM_CONST_DOUBLE (r, x); REAL_VALUE_TO_TARGET_SINGLE (r, l); fprintf (file, "$0x%lx", l); return; } default: putc ('$', file); output_addr_const (file, x); return; } default: output_operand_lossage ("invalid %%xn code"); } abort (); }
rtx fr30_move_double (rtx * operands) { rtx src = operands[1]; rtx dest = operands[0]; enum rtx_code src_code = GET_CODE (src); enum rtx_code dest_code = GET_CODE (dest); enum machine_mode mode = GET_MODE (dest); rtx val; start_sequence (); if (dest_code == REG) { if (src_code == REG) { int reverse = (REGNO (dest) == REGNO (src) + 1); /* We normally copy the low-numbered register first. However, if the first register of operand 0 is the same as the second register of operand 1, we must copy in the opposite order. */ emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, reverse, TRUE, mode), operand_subword (src, reverse, TRUE, mode))); emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, !reverse, TRUE, mode), operand_subword (src, !reverse, TRUE, mode))); } else if (src_code == MEM) { rtx addr = XEXP (src, 0); int dregno = REGNO (dest); rtx dest0 = operand_subword (dest, 0, TRUE, mode);; rtx dest1 = operand_subword (dest, 1, TRUE, mode);; rtx new_mem; gcc_assert (GET_CODE (addr) == REG); /* Copy the address before clobbering it. See PR 34174. */ emit_insn (gen_rtx_SET (SImode, dest1, addr)); emit_insn (gen_rtx_SET (VOIDmode, dest0, adjust_address (src, SImode, 0))); emit_insn (gen_rtx_SET (SImode, dest1, plus_constant (dest1, UNITS_PER_WORD))); new_mem = gen_rtx_MEM (SImode, dest1); MEM_COPY_ATTRIBUTES (new_mem, src); emit_insn (gen_rtx_SET (VOIDmode, dest1, new_mem)); } else if (src_code == CONST_INT || src_code == CONST_DOUBLE) { rtx words[2]; split_double (src, &words[0], &words[1]); emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, 0, TRUE, mode), words[0])); emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, 1, TRUE, mode), words[1])); } } else if (src_code == REG && dest_code == MEM) { rtx addr = XEXP (dest, 0); rtx src0; rtx src1; gcc_assert (GET_CODE (addr) == REG); src0 = operand_subword (src, 0, TRUE, mode); src1 = operand_subword (src, 1, TRUE, mode); emit_move_insn (adjust_address (dest, SImode, 0), src0); if (REGNO (addr) == STACK_POINTER_REGNUM || REGNO (addr) == FRAME_POINTER_REGNUM) emit_insn (gen_rtx_SET (VOIDmode, adjust_address (dest, SImode, UNITS_PER_WORD), src1)); else { rtx new_mem; rtx scratch_reg_r0 = gen_rtx_REG (SImode, 0); /* We need a scratch register to hold the value of 'address + 4'. We use r0 for this purpose. It is used for example for long jumps and is already marked to not be used by normal register allocation. */ emit_insn (gen_movsi_internal (scratch_reg_r0, addr)); emit_insn (gen_addsi_small_int (scratch_reg_r0, scratch_reg_r0, GEN_INT (UNITS_PER_WORD))); new_mem = gen_rtx_MEM (SImode, scratch_reg_r0); MEM_COPY_ATTRIBUTES (new_mem, dest); emit_move_insn (new_mem, src1); emit_insn (gen_blockage ()); } } else /* This should have been prevented by the constraints on movdi_insn. */ gcc_unreachable (); val = get_insns (); end_sequence (); return val; }