?? out-sparc.c
字號:
if (lucky2) { if (REGNO (operands[1]) == REGNO (operands[2])) { if (REGNO (operands[1]) == 8) output_asm_insn ("mov %%o0,%%o1"); else output_asm_insn ("mov %%o1,%%o0"); } output_asm_insn ("call .mul,2\n\tnop", operands); } else { rtx xoperands[2]; xoperands[0] = gen_rtx (REG, SImode, 8 ^ (REGNO (operands[1]) == 8)); xoperands[1] = operands[2]; output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); } } else if (lucky2) { rtx xoperands[2]; xoperands[0] = gen_rtx (REG, SImode, 8 ^ (REGNO (operands[2]) == 8)); xoperands[1] = operands[1]; output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); } else { output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1", operands); } if (REGNO (operands[0]) == 8) return ""; return "mov %%o0,%0";}/* Make floating point register f0 contain 0. SIZE is the number of registers (including f0) which should contain 0. */voidmake_f0_contain_0 (size) int size;{ if (size == 1) { if ((cc_status.flags & (CC_F0_IS_0)) == 0) output_asm_insn ("ld [%%fp-16],%%f0", 0); cc_status.flags |= CC_F0_IS_0; } else if (size == 2) { if ((cc_status.flags & CC_F0_IS_0) == 0) output_asm_insn ("ld [%%fp-16],%%f0", 0); if ((cc_status.flags & (CC_F1_IS_0)) == 0) output_asm_insn ("ld [%%fp-12],%%f1", 0); cc_status.flags |= CC_F0_IS_0 | CC_F1_IS_0; }}/* Since condition codes don't have logical links, we need to keep their setting and use together for set-cc insns. */voidgen_scc_insn (code, mode, operands) enum rtx_code code; enum machine_mode mode; rtx *operands;{ extern rtx sequence_stack; rtx last_insn = XEXP (XEXP (sequence_stack, 1), 0); rtx last_pat; /* Skip back over the CLOBBERs that may precede this insn. */ while (last_insn && GET_CODE (last_insn) == INSN && GET_CODE (PATTERN (last_insn)) == CLOBBER) last_insn = PREV_INSN (last_insn); /* We should have found the preceding compare. */ if (last_insn == 0 || GET_CODE (last_insn) != INSN) abort (); last_pat = PATTERN (last_insn); if (GET_CODE (last_pat) != SET || GET_CODE (SET_DEST (last_pat)) != CC0) abort (); /* Turn off that previous insn, now that we have got the data out of it. */ PUT_CODE (last_insn, NOTE); NOTE_LINE_NUMBER (last_insn) = NOTE_INSN_DELETED; /* Emit one replacement insn to compare operands and store result. */ emit_insn (gen_rtx (SET, VOIDmode, operands[0], gen_rtx (code, mode, SET_SRC (last_pat), const0_rtx)));}/* Output reasonable peephole for set-on-condition-code insns. Note that these insns assume a particular way of defining labels. Therefore, *both* tm-sparc.h and this function must be changed if a new syntax is needed. */char *output_scc_insn (code, operand) enum rtx_code code; rtx operand;{ rtx xoperands[2]; rtx label = gen_label_rtx (); int cc_in_fccr = cc_status.flags & CC_IN_FCCR; int antisymmetric = 0; xoperands[0] = operand; xoperands[1] = label; switch (code) { case NE: if (cc_in_fccr) output_asm_insn ("fbne,a %l0", &label); else output_asm_insn ("bne,a %l0", &label); break; case EQ: if (cc_in_fccr) output_asm_insn ("fbe,a %l0", &label); else output_asm_insn ("be,a %l0", &label); break; case GE: if (cc_in_fccr) output_asm_insn ("fbge,a %l0", &label); else output_asm_insn ("bge,a %l0", &label); antisymmetric = 1; break; case GT: if (cc_in_fccr) output_asm_insn ("fbg,a %l0", &label); else output_asm_insn ("bg,a %l0", &label); antisymmetric = 1; break; case LE: if (cc_in_fccr) output_asm_insn ("fble,a %l0", &label); else output_asm_insn ("ble,a %l0", &label); antisymmetric = 1; break; case LT: if (cc_in_fccr) output_asm_insn ("fbl,a %l0", &label); else output_asm_insn ("bl,a %l0", &label); antisymmetric = 1; break; case GEU: if (cc_in_fccr) abort (); else output_asm_insn ("bgeu,a %l0", &label); antisymmetric = 1; break; case GTU: if (cc_in_fccr) abort (); else output_asm_insn ("bgu,a %l0", &label); antisymmetric = 1; break; case LEU: if (cc_in_fccr) abort (); else output_asm_insn ("bleu,a %l0", &label); antisymmetric = 1; break; case LTU: if (cc_in_fccr) abort (); else output_asm_insn ("blu,a %l0", &label); antisymmetric = 1; break; default: abort (); } if (antisymmetric && (cc_status.flags & CC_REVERSED)) output_asm_insn ("orcc %%g0,0,%0\n\torcc %%g0,1,%0\n%l1:", xoperands); else output_asm_insn ("orcc %%g0,1,%0\n\torcc %%g0,0,%0\n%l1:", xoperands); cc_status.flags &= ~CC_IN_FCCR; return "";}/* Output a delayed branch insn with the delay insn in its branch slot. The delayed branch insn template is in TEMPLATE, with operands OPERANDS. The insn in its delay slot is INSN. As a special case, since we know that all memory transfers are via ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory reference around the branch as sethi %hi(x),%%g1 b ... ld/st [%g1+%lo(x)],... As another special case, we handle loading (SYMBOL_REF ...) and other large constants around branches as well: sethi %hi(x),%0 b ... or %0,%lo(x),%1 */char *output_delayed_branch (template, operands, insn) char *template; rtx *operands; rtx insn;{ extern rtx recog_operand[]; rtx src = XVECEXP (PATTERN (insn), 0, 1); rtx dest = XVECEXP (PATTERN (insn), 0, 0); if (GET_CODE (src) == SYMBOL_REF || (GET_CODE (src) == CONST_INT && !(SMALL_INT (src) || (INTVAL (src) & 0x3ff) == 0))) { rtx xoperands[2]; xoperands[0] = dest; xoperands[1] = src; /* Output the `sethi' insn. */ output_asm_insn ("sethi %%hi(%1),%0", xoperands); /* Output the branch instruction next. */ output_asm_insn (template, operands); /* Now output the `or' insn. */ output_asm_insn ("or %0,%%lo(%1),%0", xoperands); } else if ((GET_CODE (src) == MEM && CONSTANT_ADDRESS_P (XEXP (src, 0))) || (GET_CODE (dest) == MEM && CONSTANT_ADDRESS_P (XEXP (dest, 0)))) { rtx xoperands[2]; char *split_template; xoperands[0] = dest; xoperands[1] = src; /* Output the `sethi' insn. */ if (GET_CODE (src) == MEM) { if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) && cc_prev_status.mdep == XEXP (operands[1], 0))) output_asm_insn ("sethi %%hi(%m1),%%g1", xoperands); split_template = "ld [%%g1+%%lo(%m1)],%0"; } else { if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) && cc_prev_status.mdep == XEXP (operands[0], 0))) output_asm_insn ("sethi %%hi(%m0),%%g1", xoperands); split_template = "st %r1,[%%g1+%%lo(%m0)]"; } /* Output the branch instruction next. */ output_asm_insn (template, operands); /* Now output the load or store. No need to do a CC_STATUS_INIT, because we are branching anyway. */ output_asm_insn (split_template, xoperands); } else { extern char *insn_template[]; extern char *(*insn_outfun[])(); int insn_code_number; rtx pat = gen_rtx (SET, VOIDmode, dest, src); rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); int i; extern rtx alter_subreg(); extern int insn_n_operands[]; /* Output the branch instruction first. */ output_asm_insn (template, operands); /* Now recognize the insn which we put in its delay slot. We must do this after outputing the branch insn, since operands may just be a pointer to `recog_operand'. */ insn_code_number = recog (pat, delay_insn); if (insn_code_number == -1) abort (); for (i = 0; i < insn_n_operands[insn_code_number]; i++) { if (GET_CODE (recog_operand[i]) == SUBREG) recog_operand[i] = alter_subreg (recog_operand[i]); } /* Now get the template for what this insn would have been, without the branch. Its operands are exactly the same as they would be, so we don't need to do an insn_extract. */ template = insn_template[insn_code_number]; if (template == 0) template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); output_asm_insn (template, recog_operand); } CC_STATUS_INIT; return "";}/* Output a newly constructed insn DELAY_INSN. */char *output_delay_insn (delay_insn) rtx delay_insn;{ char *template; extern rtx recog_operand[]; extern char call_used_regs[]; extern char *insn_template[]; extern int insn_n_operands[]; extern char *(*insn_outfun[])(); extern rtx alter_subreg(); int insn_code_number; extern int insn_n_operands[]; int i; /* Now recognize the insn which we put in its delay slot. We must do this after outputing the branch insn, since operands may just be a pointer to `recog_operand'. */ insn_code_number = recog_memoized (delay_insn); if (insn_code_number == -1) abort (); /* Extract the operands of this delay insn. */ INSN_CODE (delay_insn) = insn_code_number; insn_extract (delay_insn); /* It is possible that this insn has not been properly scaned by final yet. If this insn's operands don't appear in the peephole's actual operands, then they won't be fixed up by final, so we make sure they get fixed up here. -- This is a kludge. */ for (i = 0; i < insn_n_operands[insn_code_number]; i++) { if (GET_CODE (recog_operand[i]) == SUBREG) recog_operand[i] = alter_subreg (recog_operand[i]); }#ifdef REGISTER_CONSTRAINTS if (! constrain_operands (insn_code_number)) abort ();#endif cc_prev_status = cc_status; /* Update `cc_status' for this instruction. The instruction's output routine may change it further. If the output routine for a jump insn needs to depend on the cc status, it should look at cc_prev_status. */ NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn); /* Now get the template for what this insn would have been, without the branch. */ template = insn_template[insn_code_number]; if (template == 0) template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); output_asm_insn (template, recog_operand); return "";}/* Output the insn HEAD, keeping OPERANDS protected (wherever they are). HEAD comes from the target of some branch, so before we output it, we delete it from the target, lest we execute it twice. The caller of this function promises that such code motion is permissable. */char *output_eager_then_insn (head, operands) rtx head; rtx *operands;{ extern rtx alter_subreg (); extern int insn_n_operands[]; extern rtx recog_operand[]; rtx xoperands[MAX_RECOG_OPERANDS]; int insn_code_number, i, nbytes; rtx nhead; /* Micro-hack: run peephole on head if it looks like a good idea. Right now there's only one such case worth doing... This could be made smarter if the peephole for ``2-insn combine'' were also made smarter. */ if (GET_CODE (PATTERN (head)) == SET && REG_P (SET_SRC (PATTERN (head))) && REG_P (SET_DEST (PATTERN (head))) && (nhead = next_real_insn_no_labels (head)) && GET_CODE (nhead) == INSN && GET_CODE (PATTERN (nhead)) == SET && GET_CODE (SET_DEST (PATTERN (nhead))) == CC0 && (SET_SRC (PATTERN (nhead)) == SET_SRC (PATTERN (head)) || SET_SRC (PATTERN (nhead)) == SET_DEST (PATTERN (head)))) /* Something's wrong if this does not fly. */ if (! peephole (head)) abort (); /* Save our contents of `operands', since output_delay_insn sets them. */ insn_code_number = recog_memoized (head); nbytes = insn_n_operands[insn_code_number] * sizeof (rtx); bcopy (operands, xoperands, nbytes); /* Output the delay insn, and prevent duplication later. */ delete_insn (head); output_delay_insn (head); /* Restore this insn's operands. */ bcopy (xoperands, operands, nbytes);}/* Return the next INSN, CALL_INSN or JUMP_INSN after LABEL; or 0, if there is none. Also return 0 if we cross a label. */rtxnext_real_insn_no_labels (label) rtx label;{ register rtx insn = NEXT_INSN (label); register RTX_CODE code; while (insn) { code = GET_CODE (insn); if (code == INSN) { if (GET_CODE (PATTERN (insn)) != CLOBBER && GET_CODE (PATTERN (insn)) != USE) return insn; } if (code == CALL_INSN || code == JUMP_INSN) return insn; if (code == CODE_LABEL) return 0; insn = NEXT_INSN (insn); } return 0;}intoperands_satisfy_eager_branch_peephole (operands, conditional) rtx *operands; int conditional;{ rtx label; if (conditional) { if (GET_CODE (operands[0]) != IF_THEN_ELSE) return 0; if (GET_CODE (XEXP (operands[0], 1)) == LABEL_REF) label = XEXP (XEXP (operands[0], 1), 0); else if (GET_CODE (XEXP (operands[0], 2)) == LABEL_REF) label = XEXP (XEXP (operands[0], 2), 0); else return 0; } else { label = operands[0]; } if (LABEL_NUSES (label) == 1) { rtx prev = PREV_INSN (label); while (prev && GET_CODE (prev) == NOTE) prev = PREV_INSN (prev); if (prev == 0 || GET_CODE (prev) == BARRIER) { rtx head = next_real_insn_no_labels (label); if (head && ! INSN_DELETED_P (head) && GET_CODE (head) == INSN && GET_CODE (PATTERN (head)) == SET && strict_single_insn_op_p (SET_SRC (PATTERN (head)), GET_MODE (SET_DEST (PATTERN (head)))) && strict_single_insn_op_p (SET_DEST (PATTERN (head)), GET_MODE (SET_DEST (PATTERN (head)))) /* Moves between FP regs and CPU regs are two insns. */ && !(GET_CODE (SET_SRC (PATTERN (head))) == REG && GET_CODE (SET_DEST (PATTERN (head))) == REG && (FP_REG_P (SET_SRC (PATTERN (head))) != FP_REG_P (SET_DEST (PATTERN (head)))))) { if (conditional == 2) return (GET_CODE (operands[1]) != PC && safe_insn_src_p (operands[2], VOIDmode) && strict_single_insn_op_p (operands[2], VOIDmode) && operand_clobbered_before_used_after (operands[1], label)); return 1; } } } if (conditional == 1 && GET_CODE (operands[1]) != PC && safe_insn_src_p (operands[2], VOIDmode) && strict_single_insn_op_p (operands[2], VOIDmode) && operand_clobbered_before_used_after (operands[1], label)) return 1; return 0;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -