pa.c
来自「GCC编译器源代码」· C语言 代码 · 共 2,308 行 · 第 1/5 页
C
2,308 行
/* 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. OPERANDS[0] is the destination pointer as a REG, clobbered. OPERANDS[1] is the source pointer as a REG, clobbered. OPERANDS[2] is a register for temporary storage. OPERANDS[4] is the size as a CONST_INT OPERANDS[3] is a register for temporary storage. OPERANDS[5] is the alignment safe to use, as a CONST_INT. OPERANDS[6] is another temporary register. */char *output_block_move (operands, size_is_constant) rtx *operands; int size_is_constant;{ int align = INTVAL (operands[5]); unsigned long n_bytes = INTVAL (operands[4]); /* 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; /* Note that we know each loop below will execute at least twice (else we would have open-coded the copy). */ switch (align) { case 4: /* Pre-adjust the loop counter. */ operands[4] = GEN_INT (n_bytes - 8); output_asm_insn ("ldi %4,%2", operands); /* Copying loop. */ output_asm_insn ("ldws,ma 4(0,%1),%3", operands); output_asm_insn ("ldws,ma 4(0,%1),%6", operands); output_asm_insn ("stws,ma %3,4(0,%0)", operands); output_asm_insn ("addib,>= -8,%2,.-12", operands); output_asm_insn ("stws,ma %6,4(0,%0)", operands); /* Handle the residual. There could be up to 7 bytes of residual to copy! */ if (n_bytes % 8 != 0) { operands[4] = GEN_INT (n_bytes % 4); if (n_bytes % 8 >= 4) output_asm_insn ("ldws,ma 4(0,%1),%3", operands); if (n_bytes % 4 != 0) output_asm_insn ("ldw 0(0,%1),%6", operands); if (n_bytes % 8 >= 4) output_asm_insn ("stws,ma %3,4(0,%0)", operands); if (n_bytes % 4 != 0) output_asm_insn ("stbys,e %6,%4(0,%0)", operands); } return ""; case 2: /* Pre-adjust the loop counter. */ operands[4] = GEN_INT (n_bytes - 4); output_asm_insn ("ldi %4,%2", operands); /* Copying loop. */ output_asm_insn ("ldhs,ma 2(0,%1),%3", operands); output_asm_insn ("ldhs,ma 2(0,%1),%6", operands); output_asm_insn ("sths,ma %3,2(0,%0)", operands); output_asm_insn ("addib,>= -4,%2,.-12", operands); output_asm_insn ("sths,ma %6,2(0,%0)", operands); /* Handle the residual. */ if (n_bytes % 4 != 0) { if (n_bytes % 4 >= 2) output_asm_insn ("ldhs,ma 2(0,%1),%3", operands); if (n_bytes % 2 != 0) output_asm_insn ("ldb 0(0,%1),%6", operands); if (n_bytes % 4 >= 2) output_asm_insn ("sths,ma %3,2(0,%0)", operands); if (n_bytes % 2 != 0) output_asm_insn ("stb %6,0(0,%0)", operands); } return ""; case 1: /* Pre-adjust the loop counter. */ operands[4] = GEN_INT (n_bytes - 2); output_asm_insn ("ldi %4,%2", operands); /* Copying loop. */ output_asm_insn ("ldbs,ma 1(0,%1),%3", operands); output_asm_insn ("ldbs,ma 1(0,%1),%6", operands); output_asm_insn ("stbs,ma %3,1(0,%0)", operands); output_asm_insn ("addib,>= -2,%2,.-12", operands); output_asm_insn ("stbs,ma %6,1(0,%0)", operands); /* Handle the residual. */ if (n_bytes % 2 != 0) { output_asm_insn ("ldb 0(0,%1),%3", operands); output_asm_insn ("stb %3,0(0,%0)", operands); } return ""; default: abort (); }}/* 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 align = INTVAL (XEXP (XVECEXP (pat, 0, 6), 0)); unsigned long n_bytes = INTVAL (XEXP (XVECEXP (pat, 0, 5), 0)); unsigned int n_insns = 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; /* The basic copying loop. */ n_insns = 6; /* Residuals. */ if (n_bytes % (2 * align) != 0) { if ((n_bytes % (2 * align)) >= align) n_insns += 2; if ((n_bytes % align) != 0) n_insns += 2; } /* Lengths are expressed in bytes now; each insn is 4 bytes. */ return n_insns * 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. */ fputs ("\t.STRING \"", file); 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) { fputs ("\"\n\t.STRING \"", file); chars_output = 0; } fwrite (partial_output, 1, co, file); chars_output += co; co = 0; } fputs ("\"\n", file);}/* Try to rewrite floating point comparisons & branches to avoid useless add,tr insns. CHECK_NOTES is nonzero if we should examine REG_DEAD notes to see if FPCC is dead. CHECK_NOTES is nonzero for the first attempt to remove useless add,tr insns. It is zero for the second pass as reorg sometimes leaves bogus REG_DEAD notes lying around. When CHECK_NOTES is zero we can only eliminate add,tr insns when there's a 1:1 correspondence between fcmp and ftest/fbranch instructions. */voidremove_useless_addtr_insns (insns, check_notes) rtx insns; int check_notes;{ rtx insn; int all; static int pass = 0; /* This is fairly cheap, so always run it when optimizing. */ if (optimize > 0) { int fcmp_count = 0; int fbranch_count = 0; /* Walk all the insns in this function looking for fcmp & fbranch instructions. Keep track of how many of each we find. */ insns = get_insns (); for (insn = insns; insn; insn = next_insn (insn)) { rtx tmp; /* Ignore anything that isn't an INSN or a JUMP_INSN. */ if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN) continue; tmp = PATTERN (insn); /* It must be a set. */ if (GET_CODE (tmp) != SET) continue; /* If the destination is CCFP, then we've found an fcmp insn. */ tmp = SET_DEST (tmp); if (GET_CODE (tmp) == REG && REGNO (tmp) == 0) { fcmp_count++; continue; } tmp = PATTERN (insn); /* If this is an fbranch instruction, bump the fbranch counter. */ if (GET_CODE (tmp) == SET && SET_DEST (tmp) == pc_rtx && GET_CODE (SET_SRC (tmp)) == IF_THEN_ELSE && GET_CODE (XEXP (SET_SRC (tmp), 0)) == NE && GET_CODE (XEXP (XEXP (SET_SRC (tmp), 0), 0)) == REG && REGNO (XEXP (XEXP (SET_SRC (tmp), 0), 0)) == 0) { fbranch_count++; continue; } } /* Find all floating point compare + branch insns. If possible, reverse the comparison & the branch to avoid add,tr insns. */ for (insn = insns; insn; insn = next_insn (insn)) { rtx tmp, next; /* Ignore anything that isn't an INSN. */ if (GET_CODE (insn) != INSN) continue; tmp = PATTERN (insn); /* It must be a set. */ if (GET_CODE (tmp) != SET) continue; /* The destination must be CCFP, which is register zero. */ tmp = SET_DEST (tmp); if (GET_CODE (tmp) != REG || REGNO (tmp) != 0) continue; /* INSN should be a set of CCFP. See if the result of this insn is used in a reversed FP conditional branch. If so, reverse our condition and the branch. Doing so avoids useless add,tr insns. */ next = next_insn (insn); while (next) { /* Jumps, calls and labels stop our search. */ if (GET_CODE (next) == JUMP_INSN || GET_CODE (next) == CALL_INSN || GET_CODE (next) == CODE_LABEL) break; /* As does another fcmp insn. */ if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SET && GET_CODE (SET_DEST (PATTERN (next))) == REG && REGNO (SET_DEST (PATTERN (next))) == 0) break; next = next_insn (next); } /* Is NEXT_INSN a branch? */ if (next && GET_CODE (next) == JUMP_INSN) { rtx pattern = PATTERN (next); /* If it a reversed fp conditional branch (eg uses add,tr) and CCFP dies, then reverse our conditional and the branch to avoid the add,tr. */ if (GET_CODE (pattern) == SET && SET_DEST (pattern) == pc_rtx && GET_CODE (SET_SRC (pattern)) == IF_THEN_ELSE && GET_CODE (XEXP (SET_SRC (pattern), 0)) == NE && GET_CODE (XEXP (XEXP (SET_SRC (pattern), 0), 0)) == REG && REGNO (XEXP (XEXP (SET_SRC (pattern), 0), 0)) == 0 && GET_CODE (XEXP (SET_SRC (pattern), 1)) == PC && (fcmp_count == fbranch_count || (check_notes && find_regno_note (next, REG_DEAD, 0)))) { /* Reverse the branch. */ tmp = XEXP (SET_SRC (pattern), 1); XEXP (SET_SRC (pattern), 1) = XEXP (SET_SRC (pattern), 2); XEXP (SET_SRC (pattern), 2) = tmp; INSN_CODE (next) = -1; /* Reverse our condition. */ tmp = PATTERN (insn); PUT_CODE (XEXP (tmp, 1), reverse_condition (GET_CODE (XEXP (tmp, 1)))); } } } } pass = !pass;}/* You may have trouble believing
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?