📄 m32r.c
字号:
abort (); REAL_VALUE_FROM_CONST_DOUBLE (d, x); REAL_VALUE_TO_DECIMAL (d, "%.20e", str); fprintf (file, "%s", str); return; } case 'B' : /* Bottom half */ case 'T' : /* Top half */ /* Output the argument to a `seth' insn (sets the Top half-word). For constants output arguments to a seth/or3 pair to set Top and Bottom halves. For symbols output arguments to a seth/add3 pair to set Top and Bottom halves. The difference exists because for constants seth/or3 is more readable but for symbols we need to use the same scheme as `ld' and `st' insns (16 bit addend is signed). */ switch (GET_CODE (x)) { case CONST_INT : case CONST_DOUBLE : { rtx first, second; split_double (x, &first, &second); x = WORDS_BIG_ENDIAN ? second : first; fprintf (file,#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT "0x%x",#else "0x%lx",#endif (code == 'B' ? INTVAL (x) & 0xffff : (INTVAL (x) >> 16) & 0xffff)); } return; case CONST : case SYMBOL_REF : if (code == 'B' && small_data_operand (x, VOIDmode)) { fputs ("sda(", file); output_addr_const (file, x); fputc (')', file); return; } /* fall through */ case LABEL_REF : fputs (code == 'T' ? "shigh(" : "low(", file); output_addr_const (file, x); fputc (')', file); return; default : output_operand_lossage ("invalid operand to %T/%B code"); return; } break; case 'U' : /* ??? wip */ /* Output a load/store with update indicator if appropriate. */ if (GET_CODE (x) == MEM) { if (GET_CODE (XEXP (x, 0)) == PRE_INC || GET_CODE (XEXP (x, 0)) == PRE_DEC) fputs (".a", file); } else output_operand_lossage ("invalid operand to %U code"); return; case 'N' : /* Print a constant value negated. */ if (GET_CODE (x) == CONST_INT) output_addr_const (file, GEN_INT (- INTVAL (x))); else 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;#if 0 /* ??? no longer used */ case '@' : fputs (reg_names[SDA_REGNUM], file); return;#endif case 0 : /* Do nothing special. */ break; default : /* Unknown flag. */ output_operand_lossage ("invalid operand output code"); } switch (GET_CODE (x)) { case REG : fputs (reg_names[REGNO (x)], file); break; case MEM : addr = XEXP (x, 0); if (GET_CODE (addr) == PRE_INC) { if (GET_CODE (XEXP (addr, 0)) != REG) abort (); fprintf (file, "@+%s", reg_names[REGNO (XEXP (addr, 0))]); } else if (GET_CODE (addr) == PRE_DEC) { if (GET_CODE (XEXP (addr, 0)) != REG) abort (); fprintf (file, "@-%s", reg_names[REGNO (XEXP (addr, 0))]); } else if (GET_CODE (addr) == POST_INC) { if (GET_CODE (XEXP (addr, 0)) != REG) abort (); fprintf (file, "@%s+", reg_names[REGNO (XEXP (addr, 0))]); } else { fputs ("@(", file); output_address (XEXP (x, 0)); fputc (')', file); } break; case CONST_DOUBLE : /* We handle SFmode constants here as output_addr_const doesn't. */ if (GET_MODE (x) == SFmode) { REAL_VALUE_TYPE d; long l; REAL_VALUE_FROM_CONST_DOUBLE (d, x); REAL_VALUE_TO_TARGET_SINGLE (d, l); fprintf (file, "0x%08lx", l); break; } /* Fall through. Let output_addr_const deal with it. */ default : output_addr_const (file, x); break; }}/* Print a memory address as an operand to reference that memory location. */voidm32r_print_operand_address (file, addr) FILE * file; rtx addr;{ register rtx base; register rtx index = 0; int offset = 0; switch (GET_CODE (addr)) { case REG : fputs (reg_names[REGNO (addr)], file); break; case PLUS : if (GET_CODE (XEXP (addr, 0)) == CONST_INT) offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1); else if (GET_CODE (XEXP (addr, 1)) == CONST_INT) offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0); else base = XEXP (addr, 0), index = XEXP (addr, 1); if (GET_CODE (base) == REG) { /* Print the offset first (if present) to conform to the manual. */ if (index == 0) { if (offset != 0) fprintf (file, "%d,", offset); fputs (reg_names[REGNO (base)], file); } /* The chip doesn't support this, but left in for generality. */ else if (GET_CODE (index) == REG) fprintf (file, "%s,%s", reg_names[REGNO (base)], reg_names[REGNO (index)]); /* Not sure this can happen, but leave in for now. */ else if (GET_CODE (index) == SYMBOL_REF) { output_addr_const (file, index); fputc (',', file); fputs (reg_names[REGNO (base)], file); } else abort (); } else if (GET_CODE (base) == LO_SUM) { if (index != 0 || GET_CODE (XEXP (base, 0)) != REG) abort (); if (small_data_operand (XEXP (base, 1), VOIDmode)) fputs ("sda(", file); else fputs ("low(", file); output_addr_const (file, plus_constant (XEXP (base, 1), offset)); fputs ("),", file); fputs (reg_names[REGNO (XEXP (base, 0))], file); } else abort (); break; case LO_SUM : if (GET_CODE (XEXP (addr, 0)) != REG) abort (); if (small_data_operand (XEXP (addr, 1), VOIDmode)) fputs ("sda(", file); else fputs ("low(", file); output_addr_const (file, XEXP (addr, 1)); fputs ("),", file); fputs (reg_names[REGNO (XEXP (addr, 0))], file); break; case PRE_INC : /* Assume SImode */ fprintf (file, "+%s", reg_names[REGNO (XEXP (addr, 0))]); break; case PRE_DEC : /* Assume SImode */ fprintf (file, "-%s", reg_names[REGNO (XEXP (addr, 0))]); break; case POST_INC : /* Assume SImode */ fprintf (file, "%s+", reg_names[REGNO (XEXP (addr, 0))]); break; default : output_addr_const (file, addr); break; }}/* Return true if the operands are the constants 0 and 1. */intzero_and_one (operand1, operand2) rtx operand1; rtx operand2;{ return GET_CODE (operand1) == CONST_INT && GET_CODE (operand2) == CONST_INT && ( ((INTVAL (operand1) == 0) && (INTVAL (operand2) == 1)) ||((INTVAL (operand1) == 1) && (INTVAL (operand2) == 0)));}/* Return non-zero if the operand is suitable for use in a conditional move sequence. */intconditional_move_operand (operand, int_mode) rtx operand; int int_mode;{ enum machine_mode mode = (enum machine_mode)int_mode; /* Only defined for simple integers so far... */ if (mode != SImode && mode != HImode && mode != QImode) return FALSE; /* At the moment we can hanndle moving registers and loading constants. */ /* To be added: Addition/subtraction/bitops/multiplication of registers. */ switch (GET_CODE (operand)) { case REG: return 1; case CONST_INT: return INT8_P (INTVAL (operand)); default:#if 0 fprintf (stderr, "Test for cond move op of type: %s\n", GET_RTX_NAME (GET_CODE (operand)));#endif return 0; }}/* Return true if the code is a test of the carry bit */intcarry_compare_operand (op, int_mode) rtx op; int int_mode;{ rtx x; if (GET_MODE (op) != SImode && GET_MODE (op) != VOIDmode) return FALSE; if (GET_CODE (op) != NE && GET_CODE (op) != EQ) return FALSE; x = XEXP (op, 0); if (GET_CODE (x) != REG || REGNO (x) != CARRY_REGNUM) return FALSE; x = XEXP (op, 1); if (GET_CODE (x) != CONST_INT || INTVAL (x) != 0) return FALSE; return TRUE;}/* Generate the correct assembler code to handle the conditional loading of a value into a register. It is known that the operands satisfy the conditional_move_operand() function above. The destination is operand[0]. The condition is operand [1]. The 'true' value is operand [2] and the 'false' value is operand [3]. */char *emit_cond_move (operands, insn) rtx * operands; rtx insn;{ static char buffer [100]; char * dest = reg_names [REGNO (operands [0])]; buffer [0] = 0; /* Destination must be a register. */ if (GET_CODE (operands [0]) != REG) abort(); if (! conditional_move_operand (operands [2], SImode)) abort(); if (! conditional_move_operand (operands [3], SImode)) abort(); /* Check to see if the test is reversed. */ if (GET_CODE (operands [1]) == NE) { rtx tmp = operands [2]; operands [2] = operands [3]; operands [3] = tmp; } sprintf (buffer, "mvfc %s, cbr", dest); /* If the true value was '0' then we need to invert the results of the move. */ if (INTVAL (operands [2]) == 0) sprintf (buffer + strlen (buffer), "\n\txor3 %s, %s, #1", dest, dest); return buffer;}/* Use a library function to move some bytes. */static voidblock_move_call (dest_reg, src_reg, bytes_rtx) rtx dest_reg; rtx src_reg; rtx bytes_rtx;{ /* We want to pass the size as Pmode, which will normally be SImode but will be DImode if we are using 64 bit longs and pointers. */ if (GET_MODE (bytes_rtx) != VOIDmode && GET_MODE (bytes_rtx) != Pmode) bytes_rtx = convert_to_mode (Pmode, bytes_rtx, 1);#ifdef TARGET_MEM_FUNCTIONS emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0, VOIDmode, 3, dest_reg, Pmode, src_reg, Pmode, convert_to_mode (TYPE_MODE (sizetype), bytes_rtx, TREE_UNSIGNED (sizetype)), TYPE_MODE (sizetype));#else emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0, VOIDmode, 3, src_reg, Pmode, dest_reg, Pmode, convert_to_mode (TYPE_MODE (integer_type_node), bytes_rtx, TREE_UNSIGNED (integer_type_node)), TYPE_MODE (integer_type_node));#endif}/* The maximum number of bytes to copy using pairs of load/store instructions. If a block is larger than this then a loop will be generated to copy MAX_MOVE_BYTES chunks at a time. The value of 32 is a semi-arbitary choice. A customer uses Dhrystome as their benchmark, and Dhrystone has a 31 byte string copy in it. */#define MAX_MOVE_BYTES 32/* Expand string/block move operations. operands[0] is the pointer to the destination. operands[1] is the pointer to the source. operands[2] is the number of bytes to move. operands[3] is the alignment. */voidm32r_expand_block_move (operands) rtx operands[];{ rtx orig_dst = operands[0]; rtx orig_src = operands[1]; rtx bytes_rtx = operands[2]; rtx align_rtx = operands[3]; int constp = GET_CODE (bytes_rtx) == CONST_INT; HOST_WIDE_INT bytes = constp ? INTVAL (bytes_rtx) : 0; int align = INTVAL (align_rtx); int leftover; rtx src_reg; rtx dst_reg; if (constp && bytes <= 0) return; /* Move the address into scratch registers. */ dst_reg = copy_addr_to_reg (XEXP (orig_dst, 0)); src_reg = copy_addr_to_reg (XEXP (orig_src, 0)); if (align > UNITS_PER_WORD) align = UNITS_PER_WORD; /* If we prefer size over speed, always use a function call. If we do not know the size, use a function call. If the blocks are not word aligned, use a function call. */ if (optimize_size || ! constp || align != UNITS_PER_WORD) { block_move_call (dst_reg, src_reg, bytes_rtx); return; } leftover = bytes % MAX_MOVE_BYTES; bytes -= leftover; /* If necessary, generate a loop to handle the bulk of the copy. */ if (bytes) { rtx label; rtx final_src; rtx at_a_time = GEN_INT (MAX_MOVE_BYTES); rtx rounded_total = GEN_INT (bytes); /* If we are going to have to perform this loop more than once, then generate a label and compute the address the source register will contain upon completion of the final itteration. */ if (bytes > MAX_MOVE_BYTES) { final_src = gen_reg_rtx (Pmode); if (INT16_P(bytes)) emit_insn (gen_addsi3 (final_src, src_reg, rounded_total)); else { emit_insn (gen_movsi (final_src, rounded_t
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -