📄 vax.c
字号:
2 - indirect */static intvax_address_cost_1 (register rtx addr){ int reg = 0, indexed = 0, indir = 0, offset = 0, predec = 0; rtx plus_op0 = 0, plus_op1 = 0; restart: switch (GET_CODE (addr)) { case PRE_DEC: predec = 1; case REG: case SUBREG: case POST_INC: reg = 1; break; case MULT: indexed = 1; /* 2 on VAX 2 */ break; case CONST_INT: /* byte offsets cost nothing (on a VAX 2, they cost 1 cycle) */ if (offset == 0) offset = (unsigned HOST_WIDE_INT)(INTVAL(addr)+128) > 256; break; case CONST: case SYMBOL_REF: offset = 1; /* 2 on VAX 2 */ break; case LABEL_REF: /* this is probably a byte offset from the pc */ if (offset == 0) offset = 1; break; case PLUS: if (plus_op0) plus_op1 = XEXP (addr, 0); else plus_op0 = XEXP (addr, 0); addr = XEXP (addr, 1); goto restart; case MEM: indir = 2; /* 3 on VAX 2 */ addr = XEXP (addr, 0); goto restart; default: break; } /* Up to 3 things can be added in an address. They are stored in plus_op0, plus_op1, and addr. */ if (plus_op0) { addr = plus_op0; plus_op0 = 0; goto restart; } if (plus_op1) { addr = plus_op1; plus_op1 = 0; goto restart; } /* Indexing and register+offset can both be used (except on a VAX 2) without increasing execution time over either one alone. */ if (reg && indexed && offset) return reg + indir + offset + predec; return reg + indexed + indir + offset + predec;}static intvax_address_cost (rtx x){ return (1 + (GET_CODE (x) == REG ? 0 : vax_address_cost_1 (x)));}/* Cost of an expression on a VAX. This version has costs tuned for the CVAX chip (found in the VAX 3 series) with comments for variations on other models. FIXME: The costs need review, particularly for TRUNCATE, FLOAT_EXTEND and FLOAT_TRUNCATE. We need a -mcpu option to allow provision of costs on a per cpu basis. */static boolvax_rtx_costs (rtx x, int code, int outer_code, int *total){ enum machine_mode mode = GET_MODE (x); int i = 0; /* may be modified in switch */ const char *fmt = GET_RTX_FORMAT (code); /* may be modified in switch */ switch (code) { /* On a VAX, constants from 0..63 are cheap because they can use the 1 byte literal constant format. Compare to -1 should be made cheap so that decrement-and-branch insns can be formed more easily (if the value -1 is copied to a register some decrement-and-branch patterns will not match). */ case CONST_INT: if (INTVAL (x) == 0) return true; if (outer_code == AND) { *total = ((unsigned HOST_WIDE_INT) ~INTVAL (x) <= 077) ? 1 : 2; return true; } if ((unsigned HOST_WIDE_INT) INTVAL (x) <= 077 || (outer_code == COMPARE && INTVAL (x) == -1) || ((outer_code == PLUS || outer_code == MINUS) && (unsigned HOST_WIDE_INT) -INTVAL (x) <= 077)) { *total = 1; return true; } /* FALLTHRU */ case CONST: case LABEL_REF: case SYMBOL_REF: *total = 3; return true; case CONST_DOUBLE: if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) *total = vax_float_literal (x) ? 5 : 8; else *total = ((CONST_DOUBLE_HIGH (x) == 0 && (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x) < 64) || (outer_code == PLUS && CONST_DOUBLE_HIGH (x) == -1 && (unsigned HOST_WIDE_INT)-CONST_DOUBLE_LOW (x) < 64)) ? 2 : 5; return true; case POST_INC: *total = 2; return true; /* Implies register operand. */ case PRE_DEC: *total = 3; return true; /* Implies register operand. */ case MULT: switch (mode) { case DFmode: *total = 16; /* 4 on VAX 9000 */ break; case SFmode: *total = 9; /* 4 on VAX 9000, 12 on VAX 2 */ break; case DImode: *total = 16; /* 6 on VAX 9000, 28 on VAX 2 */ break; case SImode: case HImode: case QImode: *total = 10; /* 3-4 on VAX 9000, 20-28 on VAX 2 */ break; default: *total = MAX_COST; /* Mode is not supported. */ return true; } break; case UDIV: if (mode != SImode) { *total = MAX_COST; /* Mode is not supported. */ return true; } *total = 17; break; case DIV: if (mode == DImode) *total = 30; /* Highly variable. */ else if (mode == DFmode) /* divide takes 28 cycles if the result is not zero, 13 otherwise */ *total = 24; else *total = 11; /* 25 on VAX 2 */ break; case MOD: *total = 23; break; case UMOD: if (mode != SImode) { *total = MAX_COST; /* Mode is not supported. */ return true; } *total = 29; break; case FLOAT: *total = (6 /* 4 on VAX 9000 */ + (mode == DFmode) + (GET_MODE (XEXP (x, 0)) != SImode)); break; case FIX: *total = 7; /* 17 on VAX 2 */ break; case ASHIFT: case LSHIFTRT: case ASHIFTRT: if (mode == DImode) *total = 12; else *total = 10; /* 6 on VAX 9000 */ break; case ROTATE: case ROTATERT: *total = 6; /* 5 on VAX 2, 4 on VAX 9000 */ if (GET_CODE (XEXP (x, 1)) == CONST_INT) fmt = "e"; /* all constant rotate counts are short */ break; case PLUS: case MINUS: *total = (mode == DFmode) ? 13 : 8; /* 6/8 on VAX 9000, 16/15 on VAX 2 */ /* Small integer operands can use subl2 and addl2. */ if ((GET_CODE (XEXP (x, 1)) == CONST_INT) && (unsigned HOST_WIDE_INT)(INTVAL (XEXP (x, 1)) + 63) < 127) fmt = "e"; break; case IOR: case XOR: *total = 3; break; case AND: /* AND is special because the first operand is complemented. */ *total = 3; if (GET_CODE (XEXP (x, 0)) == CONST_INT) { if ((unsigned HOST_WIDE_INT)~INTVAL (XEXP (x, 0)) > 63) *total = 4; fmt = "e"; i = 1; } break; case NEG: if (mode == DFmode) *total = 9; else if (mode == SFmode) *total = 6; else if (mode == DImode) *total = 4; else *total = 2; break; case NOT: *total = 2; break; case ZERO_EXTRACT: case SIGN_EXTRACT: *total = 15; break; case MEM: if (mode == DImode || mode == DFmode) *total = 5; /* 7 on VAX 2 */ else *total = 3; /* 4 on VAX 2 */ x = XEXP (x, 0); if (GET_CODE (x) != REG && GET_CODE (x) != POST_INC) *total += vax_address_cost_1 (x); return true; case FLOAT_EXTEND: case FLOAT_TRUNCATE: case TRUNCATE: *total = 3; /* FIXME: Costs need to be checked */ break; default: return false; } /* Now look inside the expression. Operands which are not registers or short constants add to the cost. FMT and I may have been adjusted in the switch above for instructions which require special handling. */ while (*fmt++ == 'e') { rtx op = XEXP (x, i); i += 1; code = GET_CODE (op); /* A NOT is likely to be found as the first operand of an AND (in which case the relevant cost is of the operand inside the not) and not likely to be found anywhere else. */ if (code == NOT) op = XEXP (op, 0), code = GET_CODE (op); switch (code) { case CONST_INT: if ((unsigned HOST_WIDE_INT)INTVAL (op) > 63 && GET_MODE (x) != QImode) *total += 1; /* 2 on VAX 2 */ break; case CONST: case LABEL_REF: case SYMBOL_REF: *total += 1; /* 2 on VAX 2 */ break; case CONST_DOUBLE: if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT) { /* Registers are faster than floating point constants -- even those constants which can be encoded in a single byte. */ if (vax_float_literal (op)) *total += 1; else *total += (GET_MODE (x) == DFmode) ? 3 : 2; } else { if (CONST_DOUBLE_HIGH (op) != 0 || (unsigned)CONST_DOUBLE_LOW (op) > 63) *total += 2; } break; case MEM: *total += 1; /* 2 on VAX 2 */ if (GET_CODE (XEXP (op, 0)) != REG) *total += vax_address_cost_1 (XEXP (op, 0)); break; case REG: case SUBREG: break; default: *total += 1; break; } } return true;}/* Output code to add DELTA to the first argument, and then jump to FUNCTION. Used for C++ multiple inheritance. .mask ^m<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11> #conservative entry mask addl2 $DELTA, 4(ap) #adjust first argument jmp FUNCTION+2 #jump beyond FUNCTION's entry mask*/static voidvax_output_mi_thunk (FILE * file, tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED, tree function){ fprintf (file, "\t.word 0x0ffc\n\taddl2 $" HOST_WIDE_INT_PRINT_DEC, delta); asm_fprintf (file, ",4(%Rap)\n"); fprintf (file, "\tjmp "); assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); fprintf (file, "+2\n"); }static rtxvax_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED, int incoming ATTRIBUTE_UNUSED){ return gen_rtx_REG (Pmode, VAX_STRUCT_VALUE_REGNUM);}/* Worker function for NOTICE_UPDATE_CC. */voidvax_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED){ if (GET_CODE (exp) == SET) { if (GET_CODE (SET_SRC (exp)) == CALL) CC_STATUS_INIT; else if (GET_CODE (SET_DEST (exp)) != ZERO_EXTRACT && GET_CODE (SET_DEST (exp)) != PC) { cc_status.flags = 0; /* The integer operations below don't set carry or set it in an incompatible way. That's ok though as the Z bit is all we need when doing unsigned comparisons on the result of these insns (since they're always with 0). Set CC_NO_OVERFLOW to generate the correct unsigned branches. */ switch (GET_CODE (SET_SRC (exp))) { case NEG: if (GET_MODE_CLASS (GET_MODE (exp)) == MODE_FLOAT) break; case AND: case IOR: case XOR: case NOT: case MEM: case REG: cc_status.flags = CC_NO_OVERFLOW; break; default: break; } cc_status.value1 = SET_DEST (exp); cc_status.value2 = SET_SRC (exp); } } else if (GET_CODE (exp) == PARALLEL && GET_CODE (XVECEXP (exp, 0, 0)) == SET) { if (GET_CODE (SET_SRC (XVECEXP (exp, 0, 0))) == CALL) CC_STATUS_INIT; else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) != PC) { cc_status.flags = 0; cc_status.value1 = SET_DEST (XVECEXP (exp, 0, 0)); cc_status.value2 = SET_SRC (XVECEXP (exp, 0, 0)); } else /* PARALLELs whose first element sets the PC are aob, sob insns. They do change the cc's. */ CC_STATUS_INIT; } else CC_STATUS_INIT; if (cc_status.value1 && GET_CODE (cc_status.value1) == REG && cc_status.value2 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) cc_status.value2 = 0; if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM && cc_status.value2 && GET_CODE (cc_status.value2) == MEM) cc_status.value2 = 0; /* Actual condition, one line up, should be that value2's address depends on value1, but that is too much of a pain. */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -