📄 m32c.c
字号:
{ 0, "i", "#0" }, { 0, "s", "#0" }, { 0, "+si", "#1+2" }, { 0, "l", "#0" }, { 'l', "l", "0" }, { 'd', "i", "0" }, { 'd', "s", "0" }, { 'd', "+si", "1+2" }, { 'D', "i", "0" }, { 'D', "s", "0" }, { 'D', "+si", "1+2" }, { 'x', "i", "#0" }, { 'X', "i", "#0" }, { 'm', "i", "#0" }, { 'b', "i", "#0" }, { 'p', "i", "0" }, { 0, 0, 0 }};/* This is in order according to the bitfield that pushm/popm use. */static char const *pushm_regs[] = { "fb", "sb", "a1", "a0", "r3", "r2", "r1", "r0"};/* Implements PRINT_OPERAND. */voidm32c_print_operand (FILE * file, rtx x, int code){ int i, j, b; const char *comma; HOST_WIDE_INT ival; int unsigned_const = 0; /* Multiplies; constants are converted to sign-extended format but we need unsigned, so 'u' and 'U' tell us what size unsigned we need. */ if (code == 'u') { unsigned_const = 2; code = 0; } if (code == 'U') { unsigned_const = 1; code = 0; } /* This one is only for debugging; you can put it in a pattern to force this error. */ if (code == '!') { fprintf (stderr, "dj: unreviewed pattern:"); if (current_output_insn) debug_rtx (current_output_insn); gcc_unreachable (); } /* PSImode operations are either .w or .l depending on the target. */ if (code == '&') { if (TARGET_A16) fprintf (file, "w"); else fprintf (file, "l"); return; } /* Inverted conditionals. */ if (code == 'C') { switch (GET_CODE (x)) { case LE: fputs ("gt", file); break; case LEU: fputs ("gtu", file); break; case LT: fputs ("ge", file); break; case LTU: fputs ("geu", file); break; case GT: fputs ("le", file); break; case GTU: fputs ("leu", file); break; case GE: fputs ("lt", file); break; case GEU: fputs ("ltu", file); break; case NE: fputs ("eq", file); break; case EQ: fputs ("ne", file); break; default: gcc_unreachable (); } return; } /* Regular conditionals. */ if (code == 'c') { switch (GET_CODE (x)) { case LE: fputs ("le", file); break; case LEU: fputs ("leu", file); break; case LT: fputs ("lt", file); break; case LTU: fputs ("ltu", file); break; case GT: fputs ("gt", file); break; case GTU: fputs ("gtu", file); break; case GE: fputs ("ge", file); break; case GEU: fputs ("geu", file); break; case NE: fputs ("ne", file); break; case EQ: fputs ("eq", file); break; default: gcc_unreachable (); } return; } /* Used in negsi2 to do HImode ops on the two parts of an SImode operand. */ if (code == 'h' && GET_MODE (x) == SImode) { x = m32c_subreg (HImode, x, SImode, 0); code = 0; } if (code == 'H' && GET_MODE (x) == SImode) { x = m32c_subreg (HImode, x, SImode, 2); code = 0; } /* 'x' and 'X' need to be ignored for non-immediates. */ if ((code == 'x' || code == 'X') && GET_CODE (x) != CONST_INT) code = 0; encode_pattern (x); for (i = 0; conversions[i].pattern; i++) if (conversions[i].code == code && streq (conversions[i].pattern, pattern)) { for (j = 0; conversions[i].format[j]; j++) /* backslash quotes the next character in the output pattern. */ if (conversions[i].format[j] == '\\') { fputc (conversions[i].format[j + 1], file); j++; } /* Digits in the output pattern indicate that the corresponding RTX is to be output at that point. */ else if (ISDIGIT (conversions[i].format[j])) { rtx r = patternr[conversions[i].format[j] - '0']; switch (GET_CODE (r)) { case REG: fprintf (file, "%s", reg_name_with_mode (REGNO (r), GET_MODE (r))); break; case CONST_INT: switch (code) { case 'b': /* Bit position. */ fprintf (file, "%d", (int) exact_log2 (INTVAL (r))); break; case 'x': /* Unsigned byte. */ fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (r) & 0xff); break; case 'X': /* Unsigned word. */ fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (r) & 0xffff); break; case 'p': /* pushm and popm encode a register set into a single byte. */ comma = ""; for (b = 7; b >= 0; b--) if (INTVAL (r) & (1 << b)) { fprintf (file, "%s%s", comma, pushm_regs[b]); comma = ","; } break; case 'm': /* "Minus". Output -X */ ival = (-INTVAL (r) & 0xffff); if (ival & 0x8000) ival = ival - 0x10000; fprintf (file, HOST_WIDE_INT_PRINT_DEC, ival); break; default: ival = INTVAL (r); if (conversions[i].format[j + 1] == '[' && ival < 0) { /* We can simulate negative displacements by taking advantage of address space wrapping when the offset can span the entire address range. */ rtx base = patternr[conversions[i].format[j + 2] - '0']; if (GET_CODE (base) == REG) switch (REGNO (base)) { case A0_REGNO: case A1_REGNO: if (TARGET_A24) ival = 0x1000000 + ival; else ival = 0x10000 + ival; break; case SB_REGNO: if (TARGET_A16) ival = 0x10000 + ival; break; } } else if (code == 'd' && ival < 0 && j == 0) /* The "mova" opcode is used to do addition by computing displacements, but again, we need displacements to be unsigned *if* they're the only component of the displacement (i.e. no "symbol-4" type displacement). */ ival = (TARGET_A24 ? 0x1000000 : 0x10000) + ival; if (conversions[i].format[j] == '0') { /* More conversions to unsigned. */ if (unsigned_const == 2) ival &= 0xffff; if (unsigned_const == 1) ival &= 0xff; } if (streq (conversions[i].pattern, "mi") || streq (conversions[i].pattern, "mmi")) { /* Integers used as addresses are unsigned. */ ival &= (TARGET_A24 ? 0xffffff : 0xffff); } fprintf (file, HOST_WIDE_INT_PRINT_DEC, ival); break; } break; case CONST_DOUBLE: /* We don't have const_double constants. If it happens, make it obvious. */ fprintf (file, "[const_double 0x%lx]", (unsigned long) CONST_DOUBLE_HIGH (r)); break; case SYMBOL_REF: assemble_name (file, XSTR (r, 0)); break; case LABEL_REF: output_asm_label (r); break; default: fprintf (stderr, "don't know how to print this operand:"); debug_rtx (r); gcc_unreachable (); } } else { if (conversions[i].format[j] == 'z') { /* Some addressing modes *must* have a displacement, so insert a zero here if needed. */ int k; for (k = j + 1; conversions[i].format[k]; k++) if (ISDIGIT (conversions[i].format[k])) { rtx reg = patternr[conversions[i].format[k] - '0']; if (GET_CODE (reg) == REG && (REGNO (reg) == SB_REGNO || REGNO (reg) == FB_REGNO || REGNO (reg) == SP_REGNO)) fputc ('0', file); } continue; } /* Signed displacements off symbols need to have signs blended cleanly. */ if (conversions[i].format[j] == '+' && (!code || code == 'I') && ISDIGIT (conversions[i].format[j + 1]) && GET_CODE (patternr[conversions[i].format[j + 1] - '0']) == CONST_INT && INTVAL (patternr[conversions[i].format[j + 1] - '0']) < 0) continue; fputc (conversions[i].format[j], file); } break; } if (!conversions[i].pattern) { fprintf (stderr, "unconvertible operand %c `%s'", code ? code : '-', pattern); debug_rtx (x); fprintf (file, "[%c.%s]", code ? code : '-', pattern); } return;}/* Implements PRINT_OPERAND_PUNCT_VALID_P. See m32c_print_operand above for descriptions of what these do. */intm32c_print_operand_punct_valid_p (int c){ if (c == '&' || c == '!') return 1; return 0;}/* Implements PRINT_OPERAND_ADDRESS. Nothing unusual here. */voidm32c_print_operand_address (FILE * stream, rtx address){ gcc_assert (GET_CODE (address) == MEM); m32c_print_operand (stream, XEXP (address, 0), 0);}/* Implements ASM_OUTPUT_REG_PUSH. Control registers are pushed differently than general registers. */voidm32c_output_reg_push (FILE * s, int regno){ if (regno == FLG_REGNO) fprintf (s, "\tpushc\tflg\n"); else fprintf (s, "\tpush.%c\t%s", " bwll"[reg_push_size (regno)], reg_names[regno]);}/* Likewise for ASM_OUTPUT_REG_POP. */voidm32c_output_reg_pop (FILE * s, int regno){ if (regno == FLG_REGNO) fprintf (s, "\tpopc\tflg\n"); else fprintf (s, "\tpop.%c\t%s", " bwll"[reg_push_size (regno)], reg_names[regno]);}/* Defining target-specific uses of `__attribute__' *//* Used to simplify the logic below. Find the attributes wherever they may be. */#define M32C_ATTRIBUTES(decl) \ (TYPE_P (decl)) ? TYPE_ATTRIBUTES (decl) \ : DECL_ATTRIBUTES (decl) \ ? (DECL_ATTRIBUTES (decl)) \ : TYPE_ATTRIBUTES (TREE_TYPE (decl))/* Returns TRUE if the given tree has the "interrupt" attribute. */static intinterrupt_p (tree node ATTRIBUTE_UNUSED){ tree list = M32C_ATTRIBUTES (node); while (list) { if (is_attribute_p ("interrupt", TREE_PURPOSE (list))) return 1; list = TREE_CHAIN (list); } return 0;}static treeinterrupt_handler (tree * node ATTRIBUTE_UNUSED, tree name ATTRIBUTE_UNUSED, tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, bool * no_add_attrs ATTRIBUTE_UNUSED){ return NULL_TREE;}#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE m32c_attribute_tablestatic const struct attribute_spec m32c_attribute_table[] = { {"interrupt", 0, 0, false, false, false, interrupt_handler}, {0, 0, 0, 0, 0, 0, 0}};#undef TARGET_COMP_TYPE_ATTRIBUTES#define TARGET_COMP_TYPE_ATTRIBUTES m32c_comp_type_attributesstatic intm32c_comp_type_attributes (tree type1 ATTRIBUTE_UNUSED, tree type2 ATTRIBUTE_UNUSED){ /* 0=incompatible 1=compatible 2=warning */ return 1;}#undef TARGET_INSERT_ATTRIBUTES#define TARGET_INSERT_ATTRIBUTES m32c_insert_attributesstatic voidm32c_insert_attributes (tree node ATTRIBUTE_UNUSED, tree * attr_ptr ATTRIBUTE_UNUSED){ /* Nothing to do here. */}/* Predicates *//* Returns TRUE if we support a move between the first two operands. At the moment, we just want to discourage mem to mem moves until after reload, because reload has a hard time with our limited number of address registers, and we can get into a situation where we need three of them when we only have two. */boolm32c_mov_ok (rtx * operands, enum machine_mode mode ATTRIBUTE_UNUSED){ rtx op0 = operands[0]; rtx op1 = operands[1]; if (TARGET_A24) return true;#define DEBUG_MOV_OK 0#if DEBUG_MOV_OK fprintf (stderr, "m32c_mov_ok %s\n", mode_name[mode]); debug_rtx (op0); debug_rtx (op1);#endif if (GET_CODE (op0) == SUBREG) op0 = XEXP (op0, 0); if (GET_CODE (op1) == SUBREG) op1 = XEXP (op1, 0); if (GET_CODE (op0) == MEM && GET_CODE (op1) == MEM && ! reload_completed) {#if DEBUG_MOV_OK fprintf (stderr, " - no, mem to mem\n");#endif return false; }#if DEBUG_MOV_OK fprintf (stderr, " - ok\n");#endif return true;}/* Expanders *//* Subregs are non-orthogonal for us, because our registers are all different sizes. */static rtxm32c_subreg (enum machine_mode outer, rtx x, enum machine_mode inner, int byte){ int r, nr = -1; /* Converting MEMs to different types that are the same size, we just rewrite them. */ if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) == 0 && GET_CODE (SUBREG_REG (x)) == MEM && (GET_MODE_SIZE (GET_MODE (x)) == GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) { rtx oldx = x; x = gen_rtx_MEM (GET_MODE (x), XEXP (SUBREG_REG (x), 0)); MEM_COPY_ATTRIBUTES (x, SUBREG_REG (oldx)); } /* Push/pop get done as smaller push/pops. */ if (GET_CODE (x) == MEM && (GET_CODE (XEXP (x, 0)) == PRE_DEC || GET_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -