?? out-sparc.c
字號:
} return 0;}/* Return truth value of wheterh OP is EQ or NE. */inteq_or_neq (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == EQ || GET_CODE (op) == NE);}/* Return truth value of whether OP can be used as an operands in a three address arithmetic insn (such as add %o1,7,%l2) of mode MODE. */intarith_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));}/* Return truth value of whether OP can be used as an operand in a two address arithmetic insn (such as set 123456,%o4) of mode MODE. */intarith32_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);}/* Return truth value of whether OP is a integer which fits the range constraining immediate operands in three-address insns. */intsmall_int (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == CONST_INT && SMALL_INT (op));}/* Return the best assembler insn template for moving operands[1] into operands[0] as a fullword. */static char *singlemove_string (operands) rtx *operands;{ if (GET_CODE (operands[0]) == MEM) { if (GET_CODE (operands[1]) != MEM) if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) { if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) && cc_prev_status.mdep == XEXP (operands[0], 0))) output_asm_insn ("sethi %%hi(%m0),%%g1", operands); cc_status.flags |= CC_KNOW_HI_G1; cc_status.mdep = XEXP (operands[0], 0); return "st %1,[%%lo(%m0)+%%g1]"; } else return "st %r1,%0"; else { rtx xoperands[2]; cc_status.flags &= ~CC_F0_IS_0; xoperands[0] = gen_rtx (REG, SFmode, 32); xoperands[1] = operands[1]; output_asm_insn (singlemove_string (xoperands), xoperands); xoperands[1] = xoperands[0]; xoperands[0] = operands[0]; output_asm_insn (singlemove_string (xoperands), xoperands); return ""; } } if (GET_CODE (operands[1]) == MEM) { if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) { if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) && cc_prev_status.mdep == XEXP (operands[1], 0))) output_asm_insn ("sethi %%hi(%m1),%%g1", operands); cc_status.flags |= CC_KNOW_HI_G1; cc_status.mdep = XEXP (operands[1], 0); return "ld [%%lo(%m1)+%%g1],%0"; } return "ld %1,%0"; } return "mov %1,%0";}/* Output assembler code to perform a doubleword move insn with operands OPERANDS. */char *output_move_double (operands) rtx *operands;{ enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; rtx latehalf[2]; rtx addreg0 = 0, addreg1 = 0; /* First classify both operands. */ if (REG_P (operands[0])) optype0 = REGOP; else if (offsettable_memref_p (operands[0])) optype0 = OFFSOP; else if (GET_CODE (operands[0]) == MEM) optype0 = MEMOP; else optype0 = RNDOP; if (REG_P (operands[1])) optype1 = REGOP; else if (CONSTANT_P (operands[1]) || GET_CODE (operands[1]) == CONST_DOUBLE) optype1 = CNSTOP; else if (offsettable_memref_p (operands[1])) optype1 = OFFSOP; else if (GET_CODE (operands[1]) == MEM) optype1 = MEMOP; else optype1 = RNDOP; /* Check for the cases that the operand constraints are not supposed to allow to happen. Abort if we get one, because generating code for these cases is painful. */ if (optype0 == RNDOP || optype1 == RNDOP) abort (); /* If an operand is an unoffsettable memory ref, find a register we can increment temporarily to make it refer to the second word. */ if (optype0 == MEMOP) addreg0 = find_addr_reg (XEXP (operands[0], 0)); if (optype1 == MEMOP) addreg1 = find_addr_reg (XEXP (operands[1], 0)); /* Ok, we can do one word at a time. Normally we do the low-numbered word first, but if either operand is autodecrementing then we do the high-numbered word first. In either case, set up in LATEHALF the operands to use for the high-numbered word and in some cases alter the operands in OPERANDS to be suitable for the low-numbered word. */ if (optype0 == REGOP) latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); else if (optype0 == OFFSOP) latehalf[0] = adj_offsettable_operand (operands[0], 4); else latehalf[0] = operands[0]; if (optype1 == REGOP) latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); else if (optype1 == OFFSOP) latehalf[1] = adj_offsettable_operand (operands[1], 4); else if (optype1 == CNSTOP) { if (CONSTANT_P (operands[1])) latehalf[1] = const0_rtx; else if (GET_CODE (operands[1]) == CONST_DOUBLE) { latehalf[1] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_HIGH (operands[1])); operands[1] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_LOW (operands[1])); } } else latehalf[1] = operands[1]; /* If the first move would clobber the source of the second one, do them in the other order. RMS says "This happens only for registers; such overlap can't happen in memory unless the user explicitly sets it up, and that is an undefined circumstance." but it happens on the sparc when loading parameter registers, so I am going to define that circumstance, and make it work as expected. */ /* Easy case: try moving both words at once. */ /* First check for moving between an even/odd register pair and a memory location. */ if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP && (REGNO (operands[0]) & 1) == 0) || (optype0 != REGOP && optype1 != CNSTOP && optype1 == REGOP && (REGNO (operands[1]) & 1) == 0)) { rtx op1, op2; rtx base = 0, offset = const0_rtx; /* OP1 gets the register pair, and OP2 gets the memory address. */ if (optype0 == REGOP) op1 = operands[0], op2 = XEXP (operands[1], 0); else op1 = operands[1], op2 = XEXP (operands[0], 0); /* Now see if we can trust the address to be 8-byte aligned. */ /* Trust global variables. */ if (CONSTANT_ADDRESS_P (op2)) { operands[0] = op1; operands[1] = op2; if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) && cc_prev_status.mdep == op2)) output_asm_insn ("sethi %%hi(%1),%%g1", operands); cc_status.flags |= CC_KNOW_HI_G1; cc_status.mdep = op2; if (op1 == operands[0]) return "ldd [%%lo(%1)+%%g1],%0"; else return "std [%%lo(%1)+%%g1],%0"; } if (GET_CODE (op2) == PLUS) { if (GET_CODE (XEXP (op2, 0)) == REG) base = XEXP (op2, 0), offset = XEXP (op2, 1); else if (GET_CODE (XEXP (op2, 1)) == REG) base = XEXP (op2, 1), offset = XEXP (op2, 0); } /* Trust round enough offsets from the stack or frame pointer. */ if (base && (REGNO (base) == FRAME_POINTER_REGNUM || REGNO (base) == STACK_POINTER_REGNUM)) { if (GET_CODE (offset) == CONST_INT && (INTVAL (offset) & 0x7) == 0) { if (op1 == operands[0]) return "ldd %1,%0"; else return "std %1,%0"; } } else { /* We know structs not on the stack are properly aligned. Since a double asks for 8-byte alignment, we know it must have got that if it is in a struct. But a DImode need not be 8-byte aligned, because it could be a struct containing two ints or pointers. */ /* Sun fucks us here. We cannot trust references to doubles via varying addresses. It might be on the stack even if we don't know that it is; and then it might not be double-word aligned. */#if 0 if (GET_CODE (operands[1]) == MEM && GET_MODE (operands[1]) == DFmode && MEM_IN_STRUCT_P (operands[1])) return "ldd %1,%0"; else if (GET_CODE (operands[0]) == MEM && GET_MODE (operands[0]) == DFmode && MEM_IN_STRUCT_P (operands[0])) return "std %1,%0";#endif } } if (optype0 == REGOP && optype1 == REGOP && REGNO (operands[0]) == REGNO (latehalf[1])) { /* Make any unoffsettable addresses point at high-numbered word. */ if (addreg0) output_asm_insn ("add %0,0x4,%0", &addreg0); if (addreg1) output_asm_insn ("add %0,0x4,%0", &addreg1); /* Do that word. */ output_asm_insn (singlemove_string (latehalf), latehalf); /* Undo the adds we just did. */ if (addreg0) output_asm_insn ("add %0,-0x4,%0", &addreg0); if (addreg1) output_asm_insn ("add %0,-0x4,%0", &addreg1); /* Do low-numbered word. */ return singlemove_string (operands); } else if (optype0 == REGOP && optype1 != REGOP && reg_overlap_mentioned_p (operands[0], operands[1])) { /* Do the late half first. */ output_asm_insn (singlemove_string (latehalf), latehalf); /* Then clobber. */ return singlemove_string (operands); } /* Normal case: do the two words, low-numbered first. */ output_asm_insn (singlemove_string (operands), operands); /* Make any unoffsettable addresses point at high-numbered word. */ if (addreg0) output_asm_insn ("add %0,0x4,%0", &addreg0); if (addreg1) output_asm_insn ("add %0,0x4,%0", &addreg1); /* Do that word. */ output_asm_insn (singlemove_string (latehalf), latehalf); /* Undo the adds we just did. */ if (addreg0) output_asm_insn ("add %0,-0x4,%0", &addreg0); if (addreg1) output_asm_insn ("add %0,-0x4,%0", &addreg1); return "";}static char *output_fp_move_double (operands) rtx *operands;{ if (FP_REG_P (operands[0])) { if (FP_REG_P (operands[1])) { output_asm_insn ("fmovs %1,%0", operands); operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); return "fmovs %1,%0"; } if (GET_CODE (operands[1]) == REG) { if ((REGNO (operands[1]) & 1) == 0) return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0"; else { rtx xoperands[3]; xoperands[0] = operands[0]; xoperands[1] = operands[1]; xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); output_asm_insn ("st %2,[%%fp-4]\n\tst %1,[%%fp-8]\n\tldd [%%fp-8],%0", xoperands); return ""; } } /* Use ldd if known to be aligned. */ if (GET_CODE (XEXP (operands[1], 0)) == PLUS && (((XEXP (XEXP (operands[1], 0), 0) == frame_pointer_rtx || XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx) && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT && (INTVAL (XEXP (XEXP (operands[1], 0), 1)) & 0x7) == 0)#if 0 /* An array in a structure that is a parm need not be aligned! */ /* Arrays are known to be aligned, and reg+reg addresses are used (on this machine) only for array accesses. */ || (REG_P (XEXP (XEXP (operands[1], 0), 0)) && REG_P (XEXP (XEXP (operands[1], 0), 1)))#endif )) return "ldd %1,%0"; if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) { if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) && cc_prev_status.mdep == XEXP (operands[1], 0))) output_asm_insn ("sethi %%hi(%m1),%%g1", operands); cc_status.flags |= CC_KNOW_HI_G1; cc_status.mdep = XEXP (operands[1], 0); return "ldd [%%lo(%m1)+%%g1],%0"; } /* Otherwise use two ld insns. */ { rtx xoperands[2]; output_asm_insn ("ld %1,%0", operands); xoperands[0] = gen_rtx (REG, GET_MODE (operands[0]), REGNO (operands[0]) + 1); if (GET_CODE (XEXP (operands[1], 0)) == PLUS && offsettable_address_p (1, GET_MODE (operands[1]), XEXP (operands[1], 0))) { xoperands[1] = adj_offsettable_operand (operands[1], 4); output_asm_insn ("ld %1,%0", xoperands); } else if (GET_CODE (XEXP (operands[1], 0)) == PLUS) { rtx memref = operands[1]; rtx inc_reg = XEXP (XEXP (operands[1], 0), 0); if (inc_reg == frame_pointer_rtx && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == REG && XEXP (XEXP (operands[1], 0), 1) != frame_pointer_rtx) inc_reg = XEXP (XEXP (operands[1], 0), 1); if (inc_reg == frame_pointer_rtx) { output_asm_insn ("mov %%fp,%%g1", xoperands); inc_reg = gen_rtx (REG, SImode, 1); memref = gen_rtx (GET_CODE (operands[1]), GET_MODE (operands[1]), gen_rtx (PLUS, GET_MODE (XEXP (operands[1], 0)), inc_reg, XEXP (XEXP (operands[1], 0), 1))); } xoperands[1] = inc_reg; output_asm_insn ("add 4,%1,%1", xoperands); xoperands[1] = memref; output_asm_insn ("ld %1,%0", xoperands); xoperands[1] = inc_reg; output_asm_insn ("add -4,%1,%1", xoperands); } else { xoperands[1] = gen_rtx (MEM, GET_MODE (operands[1]), plus_constant (XEXP (operands[1], 0), 4)); output_asm_insn ("ld %1,%0", xoperands); } return ""; } } else if (FP_REG_P (operands[1])) { if (GET_CODE (operands[0]) == REG) { if ((REGNO (operands[0]) & 1) == 0) return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0"; else { rtx xoperands[3]; xoperands[2] = operands[1]; xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); xoperands[0] = operands[0]; output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands); return ""; } } /* Use std if we can be sure it is well-aligned. */ if (GET_CODE (XEXP (operands[0], 0)) == PLUS && (((XEXP (XEXP (operands[0], 0), 0) == frame_pointer_rtx || XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx) && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT && (INTVAL (XEXP (XEXP (operands[0], 0), 1)) & 0x7) == 0)#if 0 /* An array in a structure that is a parm need not be aligned! */ /* Arrays are known to be aligned, and reg+reg addresses are used (on this machine) only for array accesses. */ || (REG_P (XEXP (XEXP (operands[0], 0), 0)) && REG_P (XEXP (XEXP (operands[0], 0), 1)))#endif )) return "std %1,%0"; if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) { if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) && cc_prev_status.mdep == XEXP (operands[0], 0))) output_asm_insn ("sethi %%hi(%m0),%%g1", operands); cc_status.flags |= CC_KNOW_HI_G1; cc_status.mdep = XEXP (operands[0], 0); return "std %1,[%%lo(%m0)+%%g1]"; } /* Otherwise use two st insns. */ { rtx xoperands[2]; output_asm_insn ("st %r1,%0", operands); xoperands[1] = gen_rtx (REG, GET_MODE (operands[1]), REGNO (operands[1]) + 1); if (GET_CODE (XEXP (operands[0], 0)) == PLUS && offsettable_address_p (1, GET_MODE (operands[0]), XEXP (operands[0], 0))) { xoperands[0] = adj_offsettable_operand (operands[0], 4); output_asm_insn ("st %r1,%0", xoperands); } else if (GET_CODE (XEXP (operands[0], 0)) == PLUS) { rtx memref = operands[0]; rtx inc_reg = XEXP (XEXP (operands[0], 0), 0); if (inc_reg == frame_pointer_rtx && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == REG && XEXP (XEXP (operands[0], 0), 1) != frame_pointer_rtx) inc_reg = XEXP (XEXP (operands[0], 0), 1); if (inc_reg == frame_pointer_rtx) { output_asm_insn ("mov %%fp,%%g1", xoperands); inc_reg = gen_rtx (REG, SImode, 1); memref = gen_rtx (GET_CODE (operands[0]), GET_MODE (operands[0]), gen_rtx (PLUS, GET_MODE (XEXP (operands[0], 0)), inc_reg, XEXP (XEXP (operands[0], 0), 1))); } xoperands[0] = inc_reg; output_asm_insn ("add 4,%0,%0", xoperands); xoperands[0] = memref; output_asm_insn ("st %r1,%0", xoperands); xoperands[0] = inc_reg; output_asm_insn ("add -4,%0,%0", xoperands); } else { xoperands[0] = gen_rtx (MEM, GET_MODE (operands[0]), plus_constant (XEXP (operands[0], 0), 4)); output_asm_insn ("st %r1,%0", xoperands); } return ""; } } else abort ();}/* Return a REG that occurs in ADDR with coefficient 1. ADDR can be effectively incremented by incrementing REG. */static rtxfind_addr_reg (addr) rtx addr;{ while (GET_CODE (addr) == PLUS) { if (GET_CODE (XEXP (addr, 0)) == REG && !(GET_CODE (XEXP (addr, 1)) == REG && XEXP (addr, 0) == frame_pointer_rtx))
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -