📄 pa.c
字号:
} else if (FP_REG_P (operands[1])) { output_asm_insn ("fstds%F0 %1,%0", operands); } else if (operands[1] == CONST0_RTX (GET_MODE (operands[0]))) { if (GET_CODE (operands[0]) == REG) { rtx xoperands[2]; xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); xoperands[0] = operands[0]; output_asm_insn ("copy %%r0,%0\n\tcopy %%r0,%1", xoperands); } /* This is a pain. You have to be prepared to deal with an arbitrary address here including pre/post increment/decrement. so avoid this in the MD. */ else abort (); } else abort (); return "";}/* 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) addr = XEXP (addr, 0); else if (GET_CODE (XEXP (addr, 1)) == REG) addr = XEXP (addr, 1); else if (CONSTANT_P (XEXP (addr, 0))) addr = XEXP (addr, 1); else if (CONSTANT_P (XEXP (addr, 1))) addr = XEXP (addr, 0); else abort (); } if (GET_CODE (addr) == REG) return addr; abort ();}/* Emit code to perform a block move. Restriction: If the length argument is non-constant, alignment must be 4. OPERANDS[0] is the destination pointer as a REG, clobbered. OPERANDS[1] is the source pointer as a REG, clobbered. if SIZE_IS_CONSTANT OPERANDS[2] is a register for temporary storage. OPERANDS[4] is the size as a CONST_INT else OPERANDS[2] is a REG which will contain the size, clobbered. OPERANDS[3] is a register for temporary storage. OPERANDS[5] is the alignment safe to use, as a CONST_INT. */char *output_block_move (operands, size_is_constant) rtx *operands; int size_is_constant;{ int align = INTVAL (operands[5]); unsigned long n_bytes; /* We can't move more than four bytes at a time because the PA has no longer integer move insns. (Could use fp mem ops?) */ if (align > 4) align = 4; if (size_is_constant) { unsigned long offset; rtx temp; n_bytes = INTVAL (operands[4]); if (n_bytes == 0) return ""; if (align >= 4) { /* Don't unroll too large blocks. */ if (n_bytes > 32) goto copy_with_loop; /* Read and store using two registers, and hide latency by deferring the stores until three instructions after the corresponding load. The last load insn will read the entire word were the last bytes are, possibly past the end of the source block, but since loads are aligned, this is harmless. */ output_asm_insn ("ldws,ma 4(0,%1),%2", operands); for (offset = 4; offset < n_bytes; offset += 4) { output_asm_insn ("ldws,ma 4(0,%1),%3", operands); output_asm_insn ("stws,ma %2,4(0,%0)", operands); temp = operands[2]; operands[2] = operands[3]; operands[3] = temp; } if (n_bytes % 4 == 0) /* Store the last word. */ output_asm_insn ("stw %2,0(0,%0)", operands); else { /* Store the last, partial word. */ operands[4] = GEN_INT (n_bytes % 4); output_asm_insn ("stbys,e %2,%4(0,%0)", operands); } return ""; } if (align >= 2 && n_bytes >= 2) { output_asm_insn ("ldhs,ma 2(0,%1),%2", operands); for (offset = 2; offset + 2 <= n_bytes; offset += 2) { output_asm_insn ("ldhs,ma 2(0,%1),%3", operands); output_asm_insn ("sths,ma %2,2(0,%0)", operands); temp = operands[2]; operands[2] = operands[3]; operands[3] = temp; } if (n_bytes % 2 != 0) output_asm_insn ("ldb 0(0,%1),%3", operands); output_asm_insn ("sths,ma %2,2(0,%0)", operands); if (n_bytes % 2 != 0) output_asm_insn ("stb %3,0(0,%0)", operands); return ""; } output_asm_insn ("ldbs,ma 1(0,%1),%2", operands); for (offset = 1; offset + 1 <= n_bytes; offset += 1) { output_asm_insn ("ldbs,ma 1(0,%1),%3", operands); output_asm_insn ("stbs,ma %2,1(0,%0)", operands); temp = operands[2]; operands[2] = operands[3]; operands[3] = temp; } output_asm_insn ("stb %2,0(0,%0)", operands); return ""; } if (align != 4) abort(); copy_with_loop: if (size_is_constant) { /* Size is compile-time determined, and also not very small (such small cases are handled above). */ operands[4] = GEN_INT (n_bytes - 4); output_asm_insn ("ldo %4(0),%2", operands); } else { /* Decrement counter by 4, and if it becomes negative, jump past the word copying loop. */ output_asm_insn ("addib,<,n -4,%2,.+16", operands); } /* Copying loop. Note that the first load is in the annulled delay slot of addib. Is it OK on PA to have a load in a delay slot, i.e. is a possible page fault stopped in time? */ output_asm_insn ("ldws,ma 4(0,%1),%3", operands); output_asm_insn ("addib,>= -4,%2,.-4", operands); output_asm_insn ("stws,ma %3,4(0,%0)", operands); /* The counter is negative, >= -4. The remaining number of bytes are determined by the two least significant bits. */ if (size_is_constant) { if (n_bytes % 4 != 0) { /* Read the entire word of the source block tail. */ output_asm_insn ("ldw 0(0,%1),%3", operands); operands[4] = GEN_INT (n_bytes % 4); output_asm_insn ("stbys,e %3,%4(0,%0)", operands); } } else { /* Add 4 to counter. If it becomes zero, we're done. */ output_asm_insn ("addib,=,n 4,%2,.+16", operands); /* Read the entire word of the source block tail. (Also this load is in an annulled delay slot.) */ output_asm_insn ("ldw 0(0,%1),%3", operands); /* Make %0 point at the first byte after the destination block. */ output_asm_insn ("addl %2,%0,%0", operands); /* Store the leftmost bytes, up to, but not including, the address in %0. */ output_asm_insn ("stbys,e %3,0(0,%0)", operands); } return "";}/* Count the number of insns necessary to handle this block move. Basic structure is the same as emit_block_move, except that we count insns rather than emit them. */intcompute_movstrsi_length (insn) rtx insn;{ rtx pat = PATTERN (insn); int size_is_constant; int align = INTVAL (XEXP (XVECEXP (pat, 0, 6), 0)); unsigned long n_bytes; int insn_count = 0; if (GET_CODE (XEXP (XVECEXP (pat, 0, 5), 0)) == CONST_INT) { size_is_constant = 1; n_bytes = INTVAL (XEXP (XVECEXP (pat, 0, 5), 0)); } else { size_is_constant = 0; n_bytes = 0; } /* We can't move more than four bytes at a time because the PA has no longer integer move insns. (Could use fp mem ops?) */ if (align > 4) align = 4; if (size_is_constant) { unsigned long offset; if (n_bytes == 0) return 0; if (align >= 4) { /* Don't unroll too large blocks. */ if (n_bytes > 32) goto copy_with_loop; /* first load */ insn_count = 1; /* Count the unrolled insns. */ for (offset = 4; offset < n_bytes; offset += 4) insn_count += 2; /* Count last store or partial store. */ insn_count += 1; return insn_count * 4; } if (align >= 2 && n_bytes >= 2) { /* initial load. */ insn_count = 1; /* Unrolled loop. */ for (offset = 2; offset + 2 <= n_bytes; offset += 2) insn_count += 2; /* ??? odd load/store */ if (n_bytes % 2 != 0) insn_count += 2; /* ??? final store from loop. */ insn_count += 1; return insn_count * 4; } /* First load. */ insn_count = 1; /* The unrolled loop. */ for (offset = 1; offset + 1 <= n_bytes; offset += 1) insn_count += 2; /* Final store. */ insn_count += 1; return insn_count * 4; } if (align != 4) abort(); copy_with_loop: /* setup for constant and non-constant case. */ insn_count = 1; /* The copying loop. */ insn_count += 3; /* The counter is negative, >= -4. The remaining number of bytes are determined by the two least significant bits. */ if (size_is_constant) { if (n_bytes % 4 != 0) insn_count += 2; } else insn_count += 4; return insn_count * 4;}char *output_and (operands) rtx *operands;{ if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0) { unsigned HOST_WIDE_INT mask = INTVAL (operands[2]); int ls0, ls1, ms0, p, len; for (ls0 = 0; ls0 < 32; ls0++) if ((mask & (1 << ls0)) == 0) break; for (ls1 = ls0; ls1 < 32; ls1++) if ((mask & (1 << ls1)) != 0) break; for (ms0 = ls1; ms0 < 32; ms0++) if ((mask & (1 << ms0)) == 0) break; if (ms0 != 32) abort(); if (ls1 == 32) { len = ls0; if (len == 0) abort (); operands[2] = GEN_INT (len); return "extru %1,31,%2,%0"; } else { /* We could use this `depi' for the case above as well, but `depi' requires one more register file access than an `extru'. */ p = 31 - ls0; len = ls1 - ls0; operands[2] = GEN_INT (p); operands[3] = GEN_INT (len); return "depi 0,%2,%3,%0"; } } else return "and %1,%2,%0";}char *output_ior (operands) rtx *operands;{ unsigned HOST_WIDE_INT mask = INTVAL (operands[2]); int bs0, bs1, p, len; if (INTVAL (operands[2]) == 0) return "copy %1,%0"; for (bs0 = 0; bs0 < 32; bs0++) if ((mask & (1 << bs0)) != 0) break; for (bs1 = bs0; bs1 < 32; bs1++) if ((mask & (1 << bs1)) == 0) break; if (bs1 != 32 && ((unsigned HOST_WIDE_INT) 1 << bs1) <= mask) abort(); p = 31 - bs0; len = bs1 - bs0; operands[2] = GEN_INT (p); operands[3] = GEN_INT (len); return "depi -1,%2,%3,%0";}/* Output an ascii string. */voidoutput_ascii (file, p, size) FILE *file; unsigned char *p; int size;{ int i; int chars_output; unsigned char partial_output[16]; /* Max space 4 chars can occupy. */ /* The HP assembler can only take strings of 256 characters at one time. This is a limitation on input line length, *not* the length of the string. Sigh. Even worse, it seems that the restriction is in number of input characters (see \xnn & \whatever). So we have to do this very carefully. */ fprintf (file, "\t.STRING \""); chars_output = 0; for (i = 0; i < size; i += 4) { int co = 0; int io = 0; for (io = 0, co = 0; io < MIN (4, size - i); io++) { register unsigned int c = p[i + io]; if (c == '\"' || c == '\\') partial_output[co++] = '\\'; if (c >= ' ' && c < 0177) partial_output[co++] = c; else { unsigned int hexd; partial_output[co++] = '\\'; partial_output[co++] = 'x'; hexd = c / 16 - 0 + '0'; if (hexd > '9') hexd -= '9' - 'a' + 1; partial_output[co++] = hexd; hexd = c % 16 - 0 + '0'; if (hexd > '9') hexd -= '9' - 'a' + 1; partial_output[co++] = hexd; } } if (chars_output + co > 243) { fprintf (file, "\"\n\t.STRING \""); chars_output = 0; } fwrite (partial_output, 1, co, file); chars_output += co; co = 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -