📄 arc.c
字号:
case 'V' : /* Output cache bypass indicator for a load/store insn. Volatile memory refs are defined to use the cache bypass mechanism. */ if (GET_CODE (x) == MEM) { if (MEM_VOLATILE_P (x)) fputs (".di", file); } else output_operand_lossage ("invalid operand to %%V code"); return; case 0 : /* Do nothing special. */ break; default : /* Unknown flag. */ output_operand_lossage ("invalid operand output code"); } switch (GET_CODE (x)) { case REG : fputs (reg_names[REGNO (x)], file); break; case MEM : fputc ('[', file); if (GET_CODE (XEXP (x, 0)) == PRE_INC) output_address (plus_constant (XEXP (XEXP (x, 0), 0), GET_MODE_SIZE (GET_MODE (x)))); else if (GET_CODE (XEXP (x, 0)) == PRE_DEC) output_address (plus_constant (XEXP (XEXP (x, 0), 0), - GET_MODE_SIZE (GET_MODE (x)))); else output_address (XEXP (x, 0)); fputc (']', file); break; case CONST_DOUBLE : /* We handle SFmode constants here as output_addr_const doesn't. */ if (GET_MODE (x) == SFmode) { REAL_VALUE_TYPE d; long l; REAL_VALUE_FROM_CONST_DOUBLE (d, x); REAL_VALUE_TO_TARGET_SINGLE (d, l); fprintf (file, "0x%08lx", l); break; } /* Fall through. Let output_addr_const deal with it. */ default : output_addr_const (file, x); break; }}/* Print a memory address as an operand to reference that memory location. */voidarc_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 ATTRIBUTE_UNUSED; int noperands ATTRIBUTE_UNUSED;{ /* 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. */ extract_insn_cached (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_con
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -