📄 i370.c
字号:
mvs_page_code = code; mvs_page_lit = lit; return 1; } mvs_page_code += code; mvs_page_lit += lit; return 0;}#endif /* TARGET_HLASM */#ifdef TARGET_ELF_ABIintmvs_check_page (file, code, lit) FILE *file; int code, lit;{ if (file) assembler_source = file; if (mvs_page_code + code + mvs_page_lit + lit > MAX_MVS_PAGE_LENGTH) { /* hop past the literal pool */ fprintf (assembler_source, "\tB\t.LPGE%d\n", mvs_page_num); /* dump the literal pool. The .baligns are optional, since * ltorg will align to the size of the largest literal * (which is possibly 8 bytes) */ fprintf (assembler_source, "\t.balign\t4\n"); fprintf (assembler_source, "\t.LTORG\n"); fprintf (assembler_source, "\t.balign\t4\n"); /* we continue execution here ... */ fprintf (assembler_source, ".LPGE%d:\n", mvs_page_num); fprintf (assembler_source, "\t.DROP\t%d\n", BASE_REGISTER); mvs_page_num++; /* BASR puts the contents of the PSW into r3 * that is, r3 will be loaded with the address of "." */ fprintf (assembler_source, "\tBASR\tr%d,0\n", BASE_REGISTER); fprintf (assembler_source, ".LPG%d:\n", mvs_page_num); fprintf (assembler_source, "\t.USING\t.,r%d\n", BASE_REGISTER); mvs_page_code = code; mvs_page_lit = lit; return 1; } mvs_page_code += code; mvs_page_lit += lit; return 0;}#endif /* TARGET_ELF_ABI *//* ===================================================== *//* defines and functions specific to the HLASM assembler */#ifdef TARGET_HLASM/* Check for C/370 runtime function, they don't use standard calling conventions. True is returned if the function is in the table. NAME is the name of the current function. */intmvs_function_check (name) const char *name;{ int lower, middle, upper; int i; lower = 0; upper = MVS_FUNCTION_TABLE_LENGTH - 1; while (lower <= upper) { middle = (lower + upper) / 2; i = strcmp (name, mvs_function_table[middle]); if (i == 0) return 1; if (i < 0) upper = middle - 1; else lower = middle + 1; } return 0;}/* Generate a hash for a given key. */#ifdef LONGEXTERNALstatic intmvs_hash_alias (key) const char *key;{ int h; int i; int l = strlen (key); h = key[0]; for (i = 1; i < l; i++) h = ((h * MVS_SET_SIZE) + key[i]) % MVS_HASH_PRIME; return (h);}#endif/* Add the alias to the current alias list. */voidmvs_add_alias (realname, aliasname, emitted) const char *realname; const char *aliasname; int emitted;{ alias_node_t *ap; ap = (alias_node_t *) xmalloc (sizeof (alias_node_t)); if (strlen (realname) > MAX_LONG_LABEL_SIZE) { warning ("real name is too long - alias ignored"); return; } if (strlen (aliasname) > MAX_MVS_LABEL_SIZE) { warning ("alias name is too long - alias ignored"); return; } strcpy (ap->real_name, realname); strcpy (ap->alias_name, aliasname); ap->alias_emitted = emitted; ap->alias_next = alias_anchor; alias_anchor = ap;}/* Check to see if the name needs aliasing. ie. the name is either: 1. Longer than 8 characters 2. Contains an underscore 3. Is mixed case */intmvs_need_alias (realname) const char *realname;{ int i, j = strlen (realname); if (mvs_function_check (realname)) return 0;#if 0 if (!strcmp (realname, "gccmain")) return 0; if (!strcmp (realname, "main")) return 0;#endif if (j > MAX_MVS_LABEL_SIZE) return 1; if (strchr (realname, '_') != 0) return 1; if (ISUPPER (realname[0])) { for (i = 1; i < j; i++) { if (ISLOWER (realname[i])) return 1; } } else { for (i = 1; i < j; i++) { if (ISUPPER (realname[i])) return 1; } } return 0;}/* Get the alias from the list. If 1 is returned then it's in the alias list, 0 if it was not */intmvs_get_alias (realname, aliasname) const char *realname; char *aliasname;{#ifdef LONGEXTERNAL alias_node_t *ap; for (ap = alias_anchor; ap; ap = ap->alias_next) { if (!strcmp (ap->real_name, realname)) { strcpy (aliasname, ap->alias_name); return 1; } } if (mvs_need_alias (realname)) { char c1, c2; c1 = realname[0]; c2 = realname[1]; if (ISLOWER (c1)) c1 = TOUPPER (c1); else if (c1 == '_') c1 = 'A'; if (ISLOWER (c2)) c2 = TOUPPER (c2); else if (c2 == '_' || c2 == '\0') c2 = '#'; sprintf (aliasname, "%c%c%06d", c1, c2, mvs_hash_alias (realname)); mvs_add_alias (realname, aliasname, 0); return 1; }#else if (strlen (realname) > MAX_MVS_LABEL_SIZE) { strncpy (aliasname, realname, MAX_MVS_LABEL_SIZE); aliasname[MAX_MVS_LABEL_SIZE] = '\0'; return 1; }#endif return 0;}/* Check to see if the alias is in the list. If 1 is returned then it's in the alias list, 2 it was emitted */intmvs_check_alias (realname, aliasname) const char *realname; char *aliasname;{#ifdef LONGEXTERNAL alias_node_t *ap; for (ap = alias_anchor; ap; ap = ap->alias_next) { if (!strcmp (ap->real_name, realname)) { int rc = (ap->alias_emitted == 1) ? 1 : 2; strcpy (aliasname, ap->alias_name); ap->alias_emitted = 1; return rc; } } if (mvs_need_alias (realname)) { char c1, c2; c1 = realname[0]; c2 = realname[1]; if (ISLOWER (c1)) c1 = TOUPPER (c1); else if (c1 == '_') c1 = 'A'; if (ISLOWER (c2)) c2 = TOUPPER (c2); else if (c2 == '_' || c2 == '\0') c2 = '#'; sprintf (aliasname, "%c%c%06d", c1, c2, mvs_hash_alias (realname)); mvs_add_alias (realname, aliasname, 0); alias_anchor->alias_emitted = 1; return 2; }#else if (strlen (realname) > MAX_MVS_LABEL_SIZE) { strncpy (aliasname, realname, MAX_MVS_LABEL_SIZE); aliasname[MAX_MVS_LABEL_SIZE] = '\0'; return 1; }#endif return 0;}/* defines and functions specific to the HLASM assembler */#endif /* TARGET_HLASM *//* ===================================================== *//* ===================================================== *//* defines and functions specific to the gas assembler */#ifdef TARGET_ELF_ABI/* Check for C/370 runtime function, they don't use standard calling conventions. True is returned if the function is in the table. NAME is the name of the current function. *//* no special calling conventions (yet ??) */intmvs_function_check (name) const char *name ATTRIBUTE_UNUSED;{ return 0;}#endif /* TARGET_ELF_ABI *//* ===================================================== *//* Return 1 if OP is a valid S operand for an RS, SI or SS type instruction. OP is the current operation. MODE is the current operation mode. */ints_operand (op, mode) register rtx op; enum machine_mode mode;{ extern int volatile_ok; register enum rtx_code code = GET_CODE (op); if (CONSTANT_ADDRESS_P (op)) return 1; if (mode == VOIDmode || GET_MODE (op) != mode) return 0; if (code == MEM) { register rtx x = XEXP (op, 0); if (!volatile_ok && op->volatil) return 0; if (REG_P (x) && REG_OK_FOR_BASE_P (x)) return 1; if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && REG_OK_FOR_BASE_P (XEXP (x, 0)) && GET_CODE (XEXP (x, 1)) == CONST_INT && (unsigned) INTVAL (XEXP (x, 1)) < 4096) return 1; } return 0;}/* Return 1 if OP is a valid R or S operand for an RS, SI or SS type instruction. OP is the current operation. MODE is the current operation mode. */intr_or_s_operand (op, mode) register rtx op; enum machine_mode mode;{ extern int volatile_ok; register enum rtx_code code = GET_CODE (op); if (CONSTANT_ADDRESS_P (op)) return 1; if (mode == VOIDmode || GET_MODE (op) != mode) return 0; if (code == REG) return 1; else if (code == MEM) { register rtx x = XEXP (op, 0); if (!volatile_ok && op->volatil) return 0; if (REG_P (x) && REG_OK_FOR_BASE_P (x)) return 1; if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && REG_OK_FOR_BASE_P (XEXP (x, 0)) && GET_CODE (XEXP (x, 1)) == CONST_INT && (unsigned) INTVAL (XEXP (x, 1)) < 4096) return 1; } return 0;}/* Some remarks about unsigned_jump_follows_p(): gcc is built around the assumption that branches are signed or unsigned, whereas the 370 doesn't care; its the compares that are signed or unsigned. Thus, we need to somehow know if we need to do a signed or an unsigned compare, and we do this by looking ahead in the instruction sequence until we find a jump. We then note whether this jump is signed or unsigned, and do the compare appropriately. Note that we have to scan ahead indefinitley, as the gcc optimizer may insert any number of instructions between the compare and the jump. Note that using conditional branch expanders seems to be be a more elegant/correct way of doing this. See, for instance, the Alpha cmpdi and bgt patterns. Note also that for the i370, various arithmetic insn's set the condition code as well. The unsigned_jump_follows_p() routine returns a 1 if the next jump is unsigned. INSN is the current instruction. */intunsigned_jump_follows_p (insn) register rtx insn;{ rtx orig_insn = insn; while (1) { register rtx tmp_insn; enum rtx_code coda; insn = NEXT_INSN (insn); if (!insn) fatal_insn ("internal error--no jump follows compare:", orig_insn); if (GET_CODE (insn) != JUMP_INSN) continue; tmp_insn = XEXP (insn, 3); if (GET_CODE (tmp_insn) != SET) continue; if (GET_CODE (XEXP (tmp_insn, 0)) != PC) continue; tmp_insn = XEXP (tmp_insn, 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -