📄 arc.c
字号:
arc_print_operand_address (file, addr) FILE *file; rtx addr;{ register rtx base, index = 0; int offset = 0; switch (GET_CODE (addr)) { case REG : fputs (reg_names[REGNO (addr)], file); break; case SYMBOL_REF : if (/*???*/ 0 && SYMBOL_REF_FLAG (addr)) { fprintf (file, "%%st("); output_addr_const (file, addr); fprintf (file, ")"); } else output_addr_const (file, addr); break; case PLUS : if (GET_CODE (XEXP (addr, 0)) == CONST_INT) offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1); else if (GET_CODE (XEXP (addr, 1)) == CONST_INT) offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0); else base = XEXP (addr, 0), index = XEXP (addr, 1); if (GET_CODE (base) != REG) abort (); fputs (reg_names[REGNO (base)], file); if (index == 0) { if (offset != 0) fprintf (file, ",%d", offset); } else if (GET_CODE (index) == REG) fprintf (file, ",%s", reg_names[REGNO (index)]); else if (GET_CODE (index) == SYMBOL_REF) fputc (',', file), output_addr_const (file, index); else abort (); break; case PRE_INC : case PRE_DEC : /* We shouldn't get here as we've lost the mode of the memory object (which says how much to inc/dec by. */ abort (); break; default : output_addr_const (file, addr); break; }}/* Update compare/branch separation marker. */static voidrecord_cc_ref (insn) rtx insn;{ last_insn_set_cc_p = current_insn_set_cc_p; switch (get_attr_cond (insn)) { case COND_SET : case COND_SET_ZN : case COND_SET_ZNC : if (get_attr_length (insn) == 1) current_insn_set_cc_p = 1; else current_insn_set_cc_p = 0; break; default : current_insn_set_cc_p = 0; break; }}/* Conditional execution support. This is based on the ARM port but for now is much simpler. A finite state machine takes care of noticing whether or not instructions can be conditionally executed, and thus decrease execution time and code size by deleting branch instructions. The fsm is controlled by final_prescan_insn, and controls the actions of PRINT_OPERAND. The patterns in the .md file for the branch insns also have a hand in this. *//* The state of the fsm controlling condition codes are: 0: normal, do nothing special 1: don't output this insn 2: don't output this insn 3: make insns conditional 4: make insns conditional State transitions (state->state by whom, under what condition): 0 -> 1 final_prescan_insn, if insn is conditional branch 0 -> 2 final_prescan_insn, if the `target' is an unconditional branch 1 -> 3 branch patterns, after having not output the conditional branch 2 -> 4 branch patterns, after having not output the conditional branch 3 -> 0 ASM_OUTPUT_INTERNAL_LABEL, if the `target' label is reached (the target label has CODE_LABEL_NUMBER equal to arc_ccfsm_target_label). 4 -> 0 final_prescan_insn, if `target' unconditional branch is reached If the jump clobbers the conditions then we use states 2 and 4. A similar thing can be done with conditional return insns. We also handle separating branches from sets of the condition code. This is done here because knowledge of the ccfsm state is required, we may not be outputting the branch. */voidarc_final_prescan_insn (insn, opvec, noperands) rtx insn; rtx *opvec; int noperands;{ /* BODY will hold the body of INSN. */ register rtx body = PATTERN (insn); /* This will be 1 if trying to repeat the trick (ie: do the `else' part of an if/then/else), and things need to be reversed. */ int reverse = 0; /* If we start with a return insn, we only succeed if we find another one. */ int seeking_return = 0; /* START_INSN will hold the insn from where we start looking. This is the first insn after the following code_label if REVERSE is true. */ rtx start_insn = insn; /* Update compare/branch separation marker. */ record_cc_ref (insn); /* Allow -mdebug-ccfsm to turn this off so we can see how well it does. We can't do this in macro FINAL_PRESCAN_INSN because its called from final_scan_insn which has `optimize' as a local. */ if (optimize < 2 || TARGET_NO_COND_EXEC) return; /* If in state 4, check if the target branch is reached, in order to change back to state 0. */ if (arc_ccfsm_state == 4) { if (insn == arc_ccfsm_target_insn) { arc_ccfsm_target_insn = NULL; arc_ccfsm_state = 0; } return; } /* If in state 3, it is possible to repeat the trick, if this insn is an unconditional branch to a label, and immediately following this branch is the previous target label which is only used once, and the label this branch jumps to is not too far off. Or in other words "we've done the `then' part, see if we can do the `else' part." */ if (arc_ccfsm_state == 3) { if (simplejump_p (insn)) { start_insn = next_nonnote_insn (start_insn); if (GET_CODE (start_insn) == BARRIER) { /* ??? Isn't this always a barrier? */ start_insn = next_nonnote_insn (start_insn); } if (GET_CODE (start_insn) == CODE_LABEL && CODE_LABEL_NUMBER (start_insn) == arc_ccfsm_target_label && LABEL_NUSES (start_insn) == 1) reverse = TRUE; else return; } else if (GET_CODE (body) == RETURN) { start_insn = next_nonnote_insn (start_insn); if (GET_CODE (start_insn) == BARRIER) start_insn = next_nonnote_insn (start_insn); if (GET_CODE (start_insn) == CODE_LABEL && CODE_LABEL_NUMBER (start_insn) == arc_ccfsm_target_label && LABEL_NUSES (start_insn) == 1) { reverse = TRUE; seeking_return = 1; } else return; } else return; } if (GET_CODE (insn) != JUMP_INSN) return; /* This jump might be paralleled with a clobber of the condition codes, the jump should always come first. */ if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0) body = XVECEXP (body, 0, 0); if (reverse || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE)) { int insns_skipped = 0, fail = FALSE, succeed = FALSE; /* Flag which part of the IF_THEN_ELSE is the LABEL_REF. */ int then_not_else = TRUE; /* Nonzero if next insn must be the target label. */ int next_must_be_target_label_p; rtx this_insn = start_insn, label = 0; /* Register the insn jumped to. */ if (reverse) { if (!seeking_return) label = XEXP (SET_SRC (body), 0); } else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF) label = XEXP (XEXP (SET_SRC (body), 1), 0); else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF) { label = XEXP (XEXP (SET_SRC (body), 2), 0); then_not_else = FALSE; } else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN) seeking_return = 1; else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN) { seeking_return = 1; then_not_else = FALSE; } else abort (); /* See how many insns this branch skips, and what kind of insns. If all insns are okay, and the label or unconditional branch to the same label is not too far away, succeed. */ for (insns_skipped = 0, next_must_be_target_label_p = FALSE; !fail && !succeed && insns_skipped < MAX_INSNS_SKIPPED; insns_skipped++) { rtx scanbody; this_insn = next_nonnote_insn (this_insn); if (!this_insn) break; if (next_must_be_target_label_p) { if (GET_CODE (this_insn) == BARRIER) continue; if (GET_CODE (this_insn) == CODE_LABEL && this_insn == label) { arc_ccfsm_state = 1; succeed = TRUE; } else fail = TRUE; break; } scanbody = PATTERN (this_insn); switch (GET_CODE (this_insn)) { case CODE_LABEL: /* Succeed if it is the target label, otherwise fail since control falls in from somewhere else. */ if (this_insn == label) { arc_ccfsm_state = 1; succeed = TRUE; } else fail = TRUE; break; case BARRIER: /* Succeed if the following insn is the target label. Otherwise fail. If return insns are used then the last insn in a function will be a barrier. */ next_must_be_target_label_p = TRUE; break; case CALL_INSN: /* Can handle a call insn if there are no insns after it. IE: The next "insn" is the target label. We don't have to worry about delay slots as such insns are SEQUENCE's inside INSN's. ??? It is possible to handle such insns though. */ if (get_attr_cond (this_insn) == COND_CANUSE) next_must_be_target_label_p = TRUE; else fail = TRUE; break; case JUMP_INSN: /* If this is an unconditional branch to the same label, succeed. If it is to another label, do nothing. If it is conditional, fail. */ /* ??? Probably, the test for the SET and the PC are unnecessary. */ if (GET_CODE (scanbody) == SET && GET_CODE (SET_DEST (scanbody)) == PC) { if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF && XEXP (SET_SRC (scanbody), 0) == label && !reverse) { arc_ccfsm_state = 2; succeed = TRUE; } else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE) fail = TRUE; } else if (GET_CODE (scanbody) == RETURN && seeking_return) { arc_ccfsm_state = 2; succeed = TRUE; } else if (GET_CODE (scanbody) == PARALLEL) { if (get_attr_cond (this_insn) != COND_CANUSE) fail = TRUE; } break; case INSN: /* We can only do this with insns that can use the condition codes (and don't set them). */ if (GET_CODE (scanbody) == SET || GET_CODE (scanbody) == PARALLEL) { if (get_attr_cond (this_insn) != COND_CANUSE) fail = TRUE; } /* We can't handle other insns like sequences. */ else fail = TRUE; break; default: break; } } if (succeed) { if ((!seeking_return) && (arc_ccfsm_state == 1 || reverse)) arc_ccfsm_target_label = CODE_LABEL_NUMBER (label); else if (seeking_return || arc_ccfsm_state == 2) { while (this_insn && GET_CODE (PATTERN (this_insn)) == USE) { this_insn = next_nonnote_insn (this_insn); if (this_insn && (GET_CODE (this_insn) == BARRIER || GET_CODE (this_insn) == CODE_LABEL)) abort (); } if (!this_insn) { /* Oh dear! we ran off the end, give up. */ insn_extract (insn); arc_ccfsm_state = 0; arc_ccfsm_target_insn = NULL; return; } arc_ccfsm_target_insn = this_insn; } else abort (); /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from what it was. */ if (!reverse) arc_ccfsm_current_cc = get_arc_condition_code (XEXP (SET_SRC (body), 0)); if (reverse || then_not_else) arc_ccfsm_current_cc = ARC_INVERSE_CONDITION_CODE (arc_ccfsm_current_cc); } /* Restore recog_operand. Getting the attributes of other insns can destroy this array, but final.c assumes that it remains intact across this call; since the insn has been recognized already we call insn_extract direct. */ insn_extract (insn); }}/* Record that we are currently outputting label NUM with prefix PREFIX. It it's the label we're looking for, reset the ccfsm machinery. Called from ASM_OUTPUT_INTERNAL_LABEL. */voidarc_ccfsm_at_label (prefix, num) char *prefix; int num;{ if (arc_ccfsm_state == 3 && arc_ccfsm_target_label == num && !strcmp (prefix, "L")) { arc_ccfsm_state = 0; arc_ccfsm_target_insn = NULL_RTX; }}/* See if the current insn, which is a conditional branch, is to be deleted. */intarc_ccfsm_branch_deleted_p (){ if (arc_ccfsm_state == 1 || arc_ccfsm_state == 2) return 1; return 0;}/* Record a branch isn't output because subsequent insns can be conditionalized. */voidarc_ccfsm_record_branch_deleted (){ /* Indicate we're conditionalizing insns now. */ arc_ccfsm_state += 2; /* If the next insn is a subroutine call, we still need a nop between the cc setter and user. We need to undo the effect of calling record_cc_ref for the just deleted branch. */ current_insn_set_cc_p = last_insn_set_cc_p;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -