📄 avr.c
字号:
default: abort (); } return NULL;}/* Return the condition name as a string. Used in conditional jump constructing */static const char *cond_string (code) enum rtx_code code;{ switch (code) { case NE: return "ne"; case EQ: return "eq"; case GE: if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE) return "pl"; else return "ge"; case LT: if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE) return "mi"; else return "lt"; case GEU: return "sh"; case LTU: return "lo"; default: abort (); }}/* Output ADDR to FILE as address */voidprint_operand_address (file, addr) FILE *file; rtx addr;{ switch (GET_CODE (addr)) { case REG: fprintf (file, ptrreg_to_str (REGNO (addr))); break; case PRE_DEC: fprintf (file, "-%s", ptrreg_to_str (REGNO (XEXP (addr, 0)))); break; case POST_INC: fprintf (file, "%s+", ptrreg_to_str (REGNO (XEXP (addr, 0)))); break; default: if (CONSTANT_ADDRESS_P (addr) && ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FLAG (addr)) || GET_CODE (addr) == LABEL_REF)) { fprintf (file, "pm("); output_addr_const (file,addr); fprintf (file ,")"); } else output_addr_const (file, addr); }}/* Output X as assembler operand to file FILE */ voidprint_operand (file, x, code) FILE *file; rtx x; int code;{ int abcd = 0; if (code >= 'A' && code <= 'D') abcd = code - 'A'; if (code == '~') { if (!AVR_MEGA) fputc ('r', file); } else if (REG_P (x)) { if (x == zero_reg_rtx) fprintf (file, "__zero_reg__"); else fprintf (file, reg_names[true_regnum (x) + abcd]); } else if (GET_CODE (x) == CONST_INT) fprintf (file, "%d", INTVAL (x) + abcd); else if (GET_CODE (x) == MEM) { rtx addr = XEXP (x,0); if (CONSTANT_P (addr) && abcd) { fputc ('(', file); output_address (addr); fprintf (file, ")+%d", abcd); } else if (code == 'o') { if (GET_CODE (addr) != PLUS) fatal_insn ("bad address, not (reg+disp):", addr); print_operand (file, XEXP (addr, 1), 0); } else if (GET_CODE (addr) == PLUS) { print_operand_address (file, XEXP (addr,0)); if (REGNO (XEXP (addr, 0)) == REG_X) fatal_insn ("internal compiler error. Bad address:" ,addr); fputc ('+', file); print_operand (file, XEXP (addr,1), code); } else print_operand_address (file, addr); } else if (GET_CODE (x) == CONST_DOUBLE) { long val; REAL_VALUE_TYPE rv; if (GET_MODE (x) != SFmode) fatal_insn ("internal compiler error. Unknown mode:", x); REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_SINGLE (rv, val); fprintf (file, "0x%lx", val); } else if (code == 'j') fputs (cond_string (GET_CODE (x)), file); else if (code == 'k') fputs (cond_string (reverse_condition (GET_CODE (x))), file); else print_operand_address (file, x);}/* Recognize operand OP of mode MODE used in call instructions */intcall_insn_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (GET_CODE (op) == MEM) { rtx inside = XEXP (op, 0); if (register_operand (inside, Pmode)) return 1; if (CONSTANT_ADDRESS_P (inside)) return 1; } return 0;}/* Update the condition code in the INSN. */voidnotice_update_cc (body, insn) rtx body ATTRIBUTE_UNUSED; rtx insn;{ rtx set; switch (get_attr_cc (insn)) { case CC_NONE: /* Insn does not affect CC at all. */ break; case CC_SET_N: CC_STATUS_INIT; break; case CC_SET_ZN: set = single_set (insn); CC_STATUS_INIT; if (set) { cc_status.flags |= CC_NO_OVERFLOW; cc_status.value1 = SET_DEST (set); } break; case CC_SET_CZN: /* Insn sets the Z,N,C flags of CC to recog_operand[0]. The V flag may or may not be known but that's ok because alter_cond will change tests to use EQ/NE. */ set = single_set (insn); CC_STATUS_INIT; if (set) { cc_status.value1 = SET_DEST (set); cc_status.flags |= CC_OVERFLOW_UNUSABLE; } break; case CC_COMPARE: set = single_set (insn); CC_STATUS_INIT; if (set) cc_status.value1 = SET_SRC (set); break; case CC_CLOBBER: /* Insn doesn't leave CC in a usable state. */ CC_STATUS_INIT; /* Correct CC for the ashrqi3 with the shift count as CONST_INT != 6 */ set = single_set (insn); if (set) { rtx src = SET_SRC (set); if (GET_CODE (src) == ASHIFTRT && GET_MODE (src) == QImode) { rtx x = XEXP (src, 1); if (GET_CODE (x) == CONST_INT && INTVAL (x) != 6) { cc_status.value1 = SET_DEST (set); cc_status.flags |= CC_OVERFLOW_UNUSABLE; } } } break; }}/* Return maximum number of consecutive registers of class CLASS needed to hold a value of mode MODE. */intclass_max_nregs (class, mode) enum reg_class class ATTRIBUTE_UNUSED; enum machine_mode mode;{ return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD);}/* Choose mode for jump insn: 1 - relative jump in range -63 <= x <= 62 ; 2 - relative jump in range -2046 <= x <= 2045 ; 3 - absolute jump (only for ATmega[16]03). */intavr_jump_mode (x, insn) rtx x; /* jump operand */ rtx insn; /* jump insn */{ int dest_addr = INSN_ADDRESSES (INSN_UID (GET_MODE (x) == LABEL_REF ? XEXP (x, 0) : x)); int cur_addr = INSN_ADDRESSES (INSN_UID (insn)); int jump_distance = cur_addr - dest_addr; if (-63 <= jump_distance && jump_distance <= 62) return 1; else if (-2046 <= jump_distance && jump_distance <= 2045) return 2; else if (AVR_MEGA) return 3; return 2;}/* return an AVR condition jump commands. X is a comparison RTX. LEN is a number returned by avr_jump_mode function. if REVERSE nonzero then condition code in X must be reversed. */const char *ret_cond_branch (x, len, reverse) rtx x; int len; int reverse;{ RTX_CODE cond = reverse ? reverse_condition (GET_CODE (x)) : GET_CODE (x); switch (cond) { case GT: if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE) return (len == 1 ? (AS1 (breq,.+2) CR_TAB AS1 (brpl,%0)) : len == 2 ? (AS1 (breq,.+4) CR_TAB AS1 (brmi,.+2) CR_TAB AS1 (rjmp,%0)) : (AS1 (breq,.+6) CR_TAB AS1 (brmi,.+4) CR_TAB AS1 (jmp,%0))); else return (len == 1 ? (AS1 (breq,.+2) CR_TAB AS1 (brge,%0)) : len == 2 ? (AS1 (breq,.+4) CR_TAB AS1 (brlt,.+2) CR_TAB AS1 (rjmp,%0)) : (AS1 (breq,.+6) CR_TAB AS1 (brlt,.+4) CR_TAB AS1 (jmp,%0))); case GTU: return (len == 1 ? (AS1 (breq,.+2) CR_TAB AS1 (brsh,%0)) : len == 2 ? (AS1 (breq,.+4) CR_TAB AS1 (brlo,.+2) CR_TAB AS1 (rjmp,%0)) : (AS1 (breq,.+6) CR_TAB AS1 (brlo,.+4) CR_TAB AS1 (jmp,%0))); case LE: if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE) return (len == 1 ? (AS1 (breq,%0) CR_TAB AS1 (brmi,%0)) : len == 2 ? (AS1 (breq,.+2) CR_TAB AS1 (brpl,.+2) CR_TAB AS1 (rjmp,%0)) : (AS1 (breq,.+2) CR_TAB AS1 (brpl,.+4) CR_TAB AS1 (jmp,%0))); else return (len == 1 ? (AS1 (breq,%0) CR_TAB AS1 (brlt,%0)) : len == 2 ? (AS1 (breq,.+2) CR_TAB AS1 (brge,.+2) CR_TAB AS1 (rjmp,%0)) : (AS1 (breq,.+2) CR_TAB AS1 (brge,.+4) CR_TAB AS1 (jmp,%0))); case LEU: return (len == 1 ? (AS1 (breq,%0) CR_TAB AS1 (brlo,%0)) : len == 2 ? (AS1 (breq,.+2) CR_TAB AS1 (brsh,.+2) CR_TAB AS1 (rjmp,%0)) : (AS1 (breq,.+2) CR_TAB AS1 (brsh,.+4) CR_TAB AS1 (jmp,%0))); default: if (reverse) { switch (len) { case 1: return AS1 (br%k1,%0); case 2: return (AS1 (br%j1,.+2) CR_TAB AS1 (rjmp,%0)); default: return (AS1 (br%j1,.+4) CR_TAB AS1 (jmp,%0)); } } else { switch (len) { case 1: return AS1 (br%j1,%0); case 2: return (AS1 (br%k1,.+2) CR_TAB AS1 (rjmp,%0)); default: return (AS1 (br%k1,.+4) CR_TAB AS1 (jmp,%0)); } } } return "";}/* Predicate function for immediate operand which fits to byte (8bit) */intbyte_immediate_operand (op, mode) register rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return (GET_CODE (op) == CONST_INT && INTVAL (op) <= 0xff && INTVAL (op) >= 0);}/* Output all insn addresses and their sizes into the assembly language output file. This is helpful for debugging whether the length attributes in the md file are correct. Output insn cost for next insn. */voidfinal_prescan_insn (insn, operand, num_operands) rtx insn, *operand ATTRIBUTE_UNUSED; int num_operands ATTRIBUTE_UNUSED;{ int uid = INSN_UID (insn); if (TARGET_INSN_SIZE_DUMP || TARGET_ALL_DEBUG) { fprintf (asm_out_file, "/*DEBUG: 0x%x\t\t%d\t%d */\n", INSN_ADDRESSES (uid), INSN_ADDRESSES (uid) - last_insn_address, rtx_cost (PATTERN (insn), INSN)); } last_insn_address = INSN_ADDRESSES (uid); if (TARGET_RTL_DUMP) { fprintf (asm_out_file, "/*****************\n"); print_rtl_single (asm_out_file, insn); fprintf (asm_out_file, "*****************/\n"); }}/* Return 0 if undefined, 1 if always true or always false. */intavr_simplify_comparision_p (mode, operator, x) enum machine_mode mode; RTX_CODE operator; rtx x;{ unsigned int max = (mode == QImode ? 0xff : mode == HImode ? 0xffff : mode == SImode ? 0xffffffff : 0); if (max && operator && GET_CODE (x) == CONST_INT) { if (unsigned_condition (operator) != operator) max >>= 1; if (max != (INTVAL (x) & max) && INTVAL (x) != 0xff) return 1; } return 0;}/* Returns nonzero if REGNO is the number of a hard register in which function arguments are sometimes passed. */intfunction_arg_regno_p(r) int r;{ return (r >= 8 && r <= 25);}/* Initializing the variable cum for the state at the beginning of the argument list. */voidinit_cumulative_args (cum, fntype, libname, indirect) CUMULATIVE_ARGS *cum; tree fntype; rtx libname; int indirect ATTRIBUTE_UNUSED;{ cum->nregs = 18; cum->regno = FIRST_CUM_REG; if (!libname && fntype) { int stdarg = (TYPE_ARG_TYPES (fntype) != 0 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)); if (stdarg) cum->nregs = 0; }}/* Returns the number of registers to allocate for a function argument. */static intavr_num_arg_regs (mode, type) enum machine_mode mode; tree type;{ int size; if (mode == BLKmode) size = int_size_in_bytes (type); else size = GET_MODE_SIZE (mode); /* Align all function arguments to start in even-numbered registers. Odd-sized arguments leave holes above them. */ return (size + 1) & ~1;}/* Controls whether a function argument is passed in a register, and which register. */rtxfunction_arg (cum, mode, type, named) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type; int named ATTRIBUTE_UNUSED;{ int bytes = avr_num_arg_regs (mode, type);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -