📄 sparc.c
字号:
pc_rtx)))); return 1; } /* Now have insn-emit do whatever it normally does. */ return 0;}/* Return the best assembler insn template for moving operands[1] into operands[0] as a fullword. */char *singlemove_string (operands) rtx *operands;{ if (GET_CODE (operands[0]) == MEM) { if (GET_CODE (operands[1]) != MEM) return "st %r1,%0"; else abort (); } else if (GET_CODE (operands[1]) == MEM) return "ld %1,%0"; else if (GET_CODE (operands[1]) == CONST_DOUBLE) { int i; union real_extract u; union float_extract { float f; int i; } v; /* Must be SFmode, otherwise this doesn't make sense. */ if (GET_MODE (operands[1]) != SFmode) abort (); bcopy (&CONST_DOUBLE_LOW (operands[1]), &u, sizeof u); v.f = REAL_VALUE_TRUNCATE (SFmode, u.d); i = v.i; operands[1] = gen_rtx (CONST_INT, VOIDmode, i); if (CONST_OK_FOR_LETTER_P (i, 'I')) return "mov %1,%0"; else if ((i & 0x000003FF) != 0) return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0"; else return "sethi %%hi(%a1),%0"; } else if (GET_CODE (operands[1]) == CONST_INT && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) { int i = INTVAL (operands[1]); /* If all low order 10 bits are clear, then we only need a single sethi insn to load the constant. */ if ((i & 0x000003FF) != 0) return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0"; else return "sethi %%hi(%a1),%0"; } /* Operand 1 must be a register, or a 'I' type CONST_INT. */ return "mov %1,%0";}/* Return non-zero if it is OK to assume that the given memory operand is aligned at least to a 8-byte boundary. This should only be called for memory accesses whose size is 8 bytes or larger. */intmem_aligned_8 (mem) register rtx mem;{ register rtx addr; register rtx base; register rtx offset; if (GET_CODE (mem) != MEM) return 0; /* It's gotta be a MEM! */ addr = XEXP (mem, 0);#if 1 /* Now that all misaligned double parms are copied on function entry, we can assume any 64-bit object is 64-bit aligned. */ /* See what register we use in the address. */ base = 0; if (GET_CODE (addr) == PLUS) { if (GET_CODE (XEXP (addr, 0)) == REG && GET_CODE (XEXP (addr, 1)) == CONST_INT) { base = XEXP (addr, 0); offset = XEXP (addr, 1); } } else if (GET_CODE (addr) == REG) { base = addr; offset = const0_rtx; } /* If it's the stack or frame pointer, check offset alignment. We can have improper alignment in the function entry code. */ if (base && (REGNO (base) == FRAME_POINTER_REGNUM || REGNO (base) == STACK_POINTER_REGNUM)) { if ((INTVAL (offset) & 0x7) == 0) return 1; } else /* Anything else, we know is properly aligned. */ return 1;#else /* If the operand is known to have been allocated in static storage, then it must be aligned. */ if (CONSTANT_P (addr) || GET_CODE (addr) == LO_SUM) return 1; base = 0; if (GET_CODE (addr) == PLUS) { if (GET_CODE (XEXP (addr, 0)) == REG && GET_CODE (XEXP (addr, 1)) == CONST_INT) { base = XEXP (addr, 0); offset = XEXP (addr, 1); } } else if (GET_CODE (addr) == REG) { base = addr; offset = const0_rtx; } /* Trust round enough offsets from the stack or frame pointer. If TARGET_HOPE_ALIGN, trust round enough offset from any register. If it is obviously unaligned, don't ever return true. */ if (base && (REGNO (base) == FRAME_POINTER_REGNUM || REGNO (base) == STACK_POINTER_REGNUM || TARGET_HOPE_ALIGN)) { if ((INTVAL (offset) & 0x7) == 0) return 1; } /* Otherwise, we can assume that an access is aligned if it is to an aggregate. Also, if TARGET_HOPE_ALIGN, then assume everything that isn't obviously unaligned is aligned. */ else if (MEM_IN_STRUCT_P (mem) || TARGET_HOPE_ALIGN) return 1;#endif /* An obviously unaligned address. */ return 0;}enum optype { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP };/* Output assembler code to perform a doubleword move insn with operands OPERANDS. This is very similar to the following output_move_quad function. */char *output_move_double (operands) rtx *operands;{ register rtx op0 = operands[0]; register rtx op1 = operands[1]; register enum optype optype0; register enum optype optype1; rtx latehalf[2]; rtx addreg0 = 0; rtx addreg1 = 0; /* First classify both operands. */ if (REG_P (op0)) optype0 = REGOP; else if (offsettable_memref_p (op0)) optype0 = OFFSOP; else if (GET_CODE (op0) == MEM) optype0 = MEMOP; else optype0 = RNDOP; if (REG_P (op1)) optype1 = REGOP; else if (CONSTANT_P (op1)) optype1 = CNSTOP; else if (offsettable_memref_p (op1)) optype1 = OFFSOP; else if (GET_CODE (op1) == 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 || (optype0 == MEM && optype1 == MEM)) 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 (op0, 0)); if (optype1 == MEMOP) addreg1 = find_addr_reg (XEXP (op1, 0)); /* Ok, we can do one word at a time. Set up in LATEHALF the operands to use for the high-numbered (least significant) 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 (op0) + 1); else if (optype0 == OFFSOP) latehalf[0] = adj_offsettable_operand (op0, 4); else latehalf[0] = op0; if (optype1 == REGOP) latehalf[1] = gen_rtx (REG, SImode, REGNO (op1) + 1); else if (optype1 == OFFSOP) latehalf[1] = adj_offsettable_operand (op1, 4); else if (optype1 == CNSTOP) split_double (op1, &operands[1], &latehalf[1]); else latehalf[1] = op1; /* Easy case: try moving both words at once. Check for moving between an even/odd register pair and a memory location. */ if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP && (REGNO (op0) & 1) == 0) || (optype0 != REGOP && optype0 != CNSTOP && optype1 == REGOP && (REGNO (op1) & 1) == 0)) { register rtx mem; if (optype0 == REGOP) mem = op1; else mem = op0; if (mem_aligned_8 (mem)) return (mem == op1 ? "ldd %1,%0" : "std %1,%0"); } /* If the first move would clobber the source of the second one, do them in the other order. */ /* Overlapping registers. */ if (optype0 == REGOP && optype1 == REGOP && REGNO (op0) == REGNO (latehalf[1])) { /* Do that word. */ output_asm_insn (singlemove_string (latehalf), latehalf); /* Do low-numbered word. */ return singlemove_string (operands); } /* Loading into a register which overlaps a register used in the address. */ else if (optype0 == REGOP && optype1 != REGOP && reg_overlap_mentioned_p (op0, op1)) { /* ??? This fails if the address is a double register address, each of which is clobbered by operand 0. */ /* 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 "";}/* Output assembler code to perform a quadword move insn with operands OPERANDS. This is very similar to the preceding output_move_double function. */char *output_move_quad (operands) rtx *operands;{ register rtx op0 = operands[0]; register rtx op1 = operands[1]; register enum optype optype0; register enum optype optype1; rtx wordpart[4][2]; rtx addreg0 = 0; rtx addreg1 = 0; /* First classify both operands. */ if (REG_P (op0)) optype0 = REGOP; else if (offsettable_memref_p (op0)) optype0 = OFFSOP; else if (GET_CODE (op0) == MEM) optype0 = MEMOP; else optype0 = RNDOP; if (REG_P (op1)) optype1 = REGOP; else if (CONSTANT_P (op1)) optype1 = CNSTOP; else if (offsettable_memref_p (op1)) optype1 = OFFSOP; else if (GET_CODE (op1) == 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 || (optype0 == MEM && optype1 == MEM)) abort (); /* If an operand is an unoffsettable memory ref, find a register we can increment temporarily to make it refer to the later words. */ if (optype0 == MEMOP) addreg0 = find_addr_reg (XEXP (op0, 0)); if (optype1 == MEMOP) addreg1 = find_addr_reg (XEXP (op1, 0)); /* Ok, we can do one word at a time. Set up in wordpart the operands to use for each word of the arguments. */ if (optype0 == REGOP) { wordpart[0][0] = gen_rtx (REG, SImode, REGNO (op0) + 0); wordpart[1][0] = gen_rtx (REG, SImode, REGNO (op0) + 1); wordpart[2][0] = gen_rtx (REG, SImode, REGNO (op0) + 2); wordpart[3][0] = gen_rtx (REG, SImode, REGNO (op0) + 3); } else if (optype0 == OFFSOP) { wordpart[0][0] = adj_offsettable_operand (op0, 0); wordpart[1][0] = adj_offsettable_operand (op0, 4); wordpart[2][0] = adj_offsettable_operand (op0, 8); wordpart[3][0] = adj_offsettable_operand (op0, 12); } else { wordpart[0][0] = op0; wordpart[1][0] = op0; wordpart[2][0] = op0; wordpart[3][0] = op0; } if (optype1 == REGOP) { wordpart[0][1] = gen_rtx (REG, SImode, REGNO (op1) + 0); wordpart[1][1] = gen_rtx (REG, SImode, REGNO (op1) + 1); wordpart[2][1] = gen_rtx (REG, SImode, REGNO (op1) + 2); wordpart[3][1] = gen_rtx (REG, SImode, REGNO (op1) + 3); } else if (optype1 == OFFSOP) { wordpart[0][1] = adj_offsettable_operand (op1, 0); wordpart[1][1] = adj_offsettable_operand (op1, 4); wordpart[2][1] = adj_offsettable_operand (op1, 8); wordpart[3][1] = adj_offsettable_operand (op1, 12); } else if (optype1 == CNSTOP) { /* This case isn't implemented yet, because there is no internal representation for quad-word constants, and there is no split_quad function. */#if 0 split_quad (op1, &wordpart[0][1], &wordpart[1][1], &wordpart[2][1], &wordpart[3][1]);#else abort ();#endif } else { wordpart[0][1] = op1; wordpart[1][1] = op1; wordpart[2][1] = op1; wordpart[3][1] = op1; } /* Easy case: try moving the quad as two pairs. Check for moving between an even/odd register pair and a memory location. */ /* ??? Should also handle the case of non-offsettable addresses here. We can at least do the first pair as a ldd/std, and then do the third and fourth words individually. */ if ((optype0 == REGOP && optype1 == OFFSOP && (REGNO (op0) & 1) == 0) || (optype0 == OFFSOP && optype1 == REGOP && (REGNO (op1) & 1) == 0)) { rtx mem; if (optype0 == REGOP) mem = op1; else mem = op0; if (mem_aligned_8 (mem)) { operands[2] = adj_offsettable_operand (mem, 8); if (mem == op1) return "ldd %1,%0;ldd %2,%S0"; else return "std %1,%0;std %S1,%2"; } } /* If the first move would clobber the source of the second one, do them in the other order. */ /* Overlapping registers. */ if (optype0 == REGOP && optype1 == REGOP && (REGNO (op0) == REGNO (wordpart[1][3]) || REGNO (op0) == REGNO (wordpart[1][2]) || REGNO (op0) == REGNO (wordpart[1][1]))) { /* Do fourth word. */ output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]); /* Do the third word. */ output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]); /* Do the second word. */ output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]); /* Do lowest-numbered word. */ return singlemove_string (wordpart[0]); } /* Loading into a register which overlaps a register used in the address. */ if (optype0 == REGOP && optype1 != REGOP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -