📄 i386.c
字号:
/* Split one or more DImode RTL references into pairs of SImode references. The RTL can be REG, offsettable MEM, integer constant, or CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to split and "num" is its length. lo_half and hi_half are output arrays that parallel "operands". */voidsplit_di (operands, num, lo_half, hi_half) rtx operands[]; int num; rtx lo_half[], hi_half[];{ while (num--) { if (GET_CODE (operands[num]) == REG) { lo_half[num] = gen_rtx (REG, SImode, REGNO (operands[num])); hi_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]) + 1); } else if (CONSTANT_P (operands[num])) { split_double (operands[num], &lo_half[num], &hi_half[num]); } else if (offsettable_memref_p (operands[num])) { lo_half[num] = operands[num]; hi_half[num] = adj_offsettable_operand (operands[num], 4); } else abort(); }}/* Return 1 if this is a valid binary operation on a 387. OP is the expression matched, and MODE is its mode. */intbinary_387_op (op, mode) register rtx op; enum machine_mode mode;{ if (mode != VOIDmode && mode != GET_MODE (op)) return 0; switch (GET_CODE (op)) { case PLUS: case MINUS: case MULT: case DIV: return GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT; default: return 0; }}/* Return 1 if this is a valid conversion operation on a 387. OP is the expression matched, and MODE is its mode. */intconvert_387_op (op, mode) register rtx op; enum machine_mode mode;{ if (mode != VOIDmode && mode != GET_MODE (op)) return 0; switch (GET_CODE (op)) { case FLOAT: return GET_MODE (XEXP (op, 0)) == SImode; case FLOAT_EXTEND: return mode == DFmode && GET_MODE (XEXP (op, 0)) == SFmode; default: return 0; }}/* Return 1 if this is a valid shift or rotate operation on a 386. OP is the expression matched, and MODE is its mode. */intshift_op (op, mode) register rtx op; enum machine_mode mode;{ rtx operand = XEXP (op, 0); if (mode != VOIDmode && mode != GET_MODE (op)) return 0; if (GET_MODE (operand) != GET_MODE (op) || GET_MODE_CLASS (GET_MODE (op)) != MODE_INT) return 0; return (GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE || GET_CODE (op) == ROTATERT);}/* Output code to perform a 387 binary operation in INSN, one of PLUS, MINUS, MULT or DIV. OPERANDS are the insn operands, where operands[3] is the expression of the binary operation. The output may either be emitted here, or returned to the caller, like all output_* functions. There is no guarantee that the operands are the same mode, as they might be within FLOAT or FLOAT_EXTEND expressions. */char *output_387_binary_op (insn, operands) rtx insn; rtx *operands;{ rtx temp; char *base_op; static char buf[100]; switch (GET_CODE (operands[3])) { case PLUS: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) base_op = "fiadd"; else base_op = "fadd"; break; case MINUS: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) base_op = "fisub"; else base_op = "fsub"; break; case MULT: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) base_op = "fimul"; else base_op = "fmul"; break; case DIV: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) base_op = "fidiv"; else base_op = "fdiv"; break; default: abort (); } strcpy (buf, base_op); switch (GET_CODE (operands[3])) { case MULT: case PLUS: if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2])) { temp = operands[2]; operands[2] = operands[1]; operands[1] = temp; } if (GET_CODE (operands[2]) == MEM) return strcat (buf, AS1 (%z2,%2)); if (NON_STACK_REG_P (operands[1])) { output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1))); RET; } else if (NON_STACK_REG_P (operands[2])) { output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1))); RET; } if (find_regno_note (insn, REG_DEAD, REGNO (operands[2]))) return strcat (buf, AS2 (p,%2,%0)); if (STACK_TOP_P (operands[0])) return strcat (buf, AS2 (,%y2,%0)); else return strcat (buf, AS2 (,%2,%0)); case MINUS: case DIV: if (GET_CODE (operands[1]) == MEM) return strcat (buf, AS1 (r%z1,%1)); if (GET_CODE (operands[2]) == MEM) return strcat (buf, AS1 (%z2,%2)); if (NON_STACK_REG_P (operands[1])) { output_op_from_reg (operands[1], strcat (buf, AS1 (r%z0,%1))); RET; } else if (NON_STACK_REG_P (operands[2])) { output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1))); RET; } if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2])) abort (); if (find_regno_note (insn, REG_DEAD, REGNO (operands[2]))) return strcat (buf, AS2 (rp,%2,%0)); if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) return strcat (buf, AS2 (p,%1,%0)); if (STACK_TOP_P (operands[0])) { if (STACK_TOP_P (operands[1])) return strcat (buf, AS2 (,%y2,%0)); else return strcat (buf, AS2 (r,%y1,%0)); } else if (STACK_TOP_P (operands[1])) return strcat (buf, AS2 (,%1,%0)); else return strcat (buf, AS2 (r,%2,%0)); default: abort (); }}/* Output code for INSN to convert a float to a signed int. OPERANDS are the insn operands. The output may be SFmode or DFmode and the input operand may be SImode or DImode. As a special case, make sure that the 387 stack top dies if the output mode is DImode, because the hardware requires this. */char *output_fix_trunc (insn, operands) rtx insn; rtx *operands;{ int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; rtx xops[6]; if (! STACK_TOP_P (operands[1]) || (GET_MODE (operands[0]) == DImode && ! stack_top_dies)) abort (); xops[0] = stack_pointer_rtx; xops[1] = AT_SP (SImode); xops[2] = adj_offsettable_operand (xops[1], 2); xops[3] = GEN_INT (4); xops[4] = GEN_INT (0xc00); xops[5] = operands[2]; output_asm_insn (AS2 (sub%L0,%3,%0), xops); output_asm_insn (AS1 (fnstc%W5,%1), xops); output_asm_insn (AS2 (mov%W5,%1,%5), xops); output_asm_insn (AS2 (or%W5,%4,%5), xops); output_asm_insn (AS2 (mov%W5,%5,%2), xops); output_asm_insn (AS1 (fldc%W5,%2), xops); if (NON_STACK_REG_P (operands[0])) output_to_reg (operands[0], stack_top_dies); else if (GET_CODE (operands[0]) == MEM) { /* If frame pointer elimination is being done, the MEM reference might be an index off of the stack pointer. In that case, since we have already adjusted %esp above, adjust the operand address so it points where it should. */ if (! frame_pointer_needed && reg_mentioned_p (stack_pointer_rtx, operands[0])) operands[0] = adj_offsettable_operand (operands[0], 4); if (stack_top_dies) output_asm_insn (AS1 (fistp%z0,%0), operands); else output_asm_insn (AS1 (fist%z0,%0), operands); } else abort (); output_asm_insn (AS1 (fldc%W5,%1), xops); output_asm_insn (AS2 (add%L0,%3,%0), xops); RET;}/* Output code for INSN to compare OPERANDS. The two operands might not have the same mode: one might be within a FLOAT or FLOAT_EXTEND expression. If the compare is in mode CCFPEQmode, use an opcode that will not fault if a qNaN is present. */char *output_float_compare (insn, operands) rtx insn; rtx *operands;{ int stack_top_dies; rtx body = XVECEXP (PATTERN (insn), 0, 0); int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode; if (! STACK_TOP_P (operands[0])) abort (); stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; if (STACK_REG_P (operands[1]) && stack_top_dies && find_regno_note (insn, REG_DEAD, REGNO (operands[1])) && REGNO (operands[1]) != FIRST_STACK_REG) { /* If both the top of the 387 stack dies, and the other operand is also a stack register that dies, then this must be a `fcompp' float compare */ if (unordered_compare) output_asm_insn ("fucompp", operands); else output_asm_insn ("fcompp", operands); } else { static char buf[100]; /* Decide if this is the integer or float compare opcode, or the unordered float compare. */ if (unordered_compare) strcpy (buf, "fucom"); else if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT) strcpy (buf, "fcom"); else strcpy (buf, "ficom"); /* Modify the opcode if the 387 stack is to be popped. */ if (stack_top_dies) strcat (buf, "p"); if (NON_STACK_REG_P (operands[1])) output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1))); else output_asm_insn (strcat (buf, AS1 (%z1,%y1)), operands); } /* Now retrieve the condition code. */ return output_fp_cc0_set (insn);}/* Output opcodes to transfer the results of FP compare or test INSN from the FPU to the CPU flags. If TARGET_IEEE_FP, ensure that if the result of the compare or test is unordered, no comparison operator succeeds except NE. Return an output template, if any. */char *output_fp_cc0_set (insn) rtx insn;{ rtx xops[3]; rtx unordered_label; rtx next; enum rtx_code code; xops[0] = gen_rtx (REG, HImode, 0); output_asm_insn (AS1 (fnsts%W0,%0), xops); if (! TARGET_IEEE_FP) return "sahf"; next = next_cc0_user (insn); if (GET_CODE (next) == JUMP_INSN && GET_CODE (PATTERN (next)) == SET && SET_DEST (PATTERN (next)) == pc_rtx && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE) { code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0)); } else if (GET_CODE (PATTERN (next)) == SET) { code = GET_CODE (SET_SRC (PATTERN (next))); } else abort (); xops[0] = gen_rtx (REG, QImode, 0); switch (code) { case GT: xops[1] = GEN_INT (0x45); output_asm_insn (AS2 (and%B0,%1,%h0), xops); /* je label */ break; case LT: xops[1] = GEN_INT (0x45); xops[2] = GEN_INT (0x01); output_asm_insn (AS2 (and%B0,%1,%h0), xops); output_asm_insn (AS2 (cmp%B0,%2,%h0), xops); /* je label */ break; case GE: xops[1] = GEN_INT (0x05); output_asm_insn (AS2 (and%B0,%1,%h0), xops); /* je label */ break; case LE: xops[1] = GEN_INT (0x45); xops[2] = GEN_INT (0x40); output_asm_insn (AS2 (and%B0,%1,%h0), xops); output_asm_insn (AS1 (dec%B0,%h0), xops); output_asm_insn (AS2 (cmp%B0,%2,%h0), xops); /* jb label */ break; case EQ: xops[1] = GEN_INT (0x45); xops[2] = GEN_INT (0x40); output_asm_insn (AS2 (and%B0,%1,%h0), xops); output_asm_insn (AS2 (cmp%B0,%2,%h0), xops); /* je label */ break; case NE: xops[1] = GEN_INT (0x44); xops[2] = GEN_INT (0x40); output_asm_insn (AS2 (and%B0,%1,%h0), xops); output_asm_insn (AS2 (xor%B0,%2,%h0), xops); /* jne label */ break; case GTU: case LTU: case GEU: case LEU: default: abort (); } RET;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -