📄 ip2k.c
字号:
abort (); } return "";#undef operands}const char *ip2k_gen_unsigned_comp_branch (insn, code, label) rtx insn; enum rtx_code code; rtx label;{#define operands ip2k_compare_operands enum machine_mode mode; int imm_sub = 0; int imm_cmp = 0; int can_use_skip = 0; rtx ninsn; HOST_WIDE_INT const_low; HOST_WIDE_INT const_high; operands[2] = label; mode = GET_MODE (operands[0]); if ((mode != QImode) && (mode != HImode) && (mode != SImode) && (mode != DImode)) { mode = GET_MODE (operands[1]); } /* Look for situations where we can just skip the next instruction instead of skipping and then branching! */ ninsn = next_real_insn (insn); if (ninsn && (recog_memoized (ninsn) >= 0) && get_attr_skip (ninsn) == SKIP_YES) { rtx skip_tgt = next_nonnote_insn (next_real_insn (insn)); /* The first situation is where the target of the jump is one insn after the jump insn and the insn being jumped is only one machine opcode long. */ if (label == skip_tgt) can_use_skip = 1; else { /* If our skip target is in fact a code label then we ignore the label and move onto the next useful instruction. Nothing we do here has any effect on the use of skipping instructions. */ if (GET_CODE (skip_tgt) == CODE_LABEL) skip_tgt = next_nonnote_insn (skip_tgt); /* The second situation is where we have something of the form: test_condition skip_conditional page/jump label optional_label (this may or may not exist): skippable_insn page/jump label In this case we can eliminate the first "page/jump label". */ if (GET_CODE (skip_tgt) == JUMP_INSN) { rtx set = single_set (skip_tgt); if (GET_CODE (XEXP (set, 0)) == PC && GET_CODE (XEXP (set, 1)) == LABEL_REF && label == JUMP_LABEL (skip_tgt)) can_use_skip = 2; } } } /* gcc is a little braindead and does some rather stateful things while inspecting attributes - we have to put this state back to what it's supposed to be. */ extract_constrain_insn_cached (insn); if (ip2k_compare_operands[1] == const0_rtx) { switch (code) { case LEU: code = EQ; /* Nothing is LTU 0. */ goto zero; case GTU: code = NE; /* Anything nonzero is GTU. */ /* fall-thru */ case EQ: case NE: /* Test all the bits, result in Z AND WREG. */ zero: switch (mode) { case DImode: OUT_AS2 (mov, w, %S0); OUT_AS2 (or, w, %T0); OUT_AS2 (or, w, %U0); OUT_AS2 (or, w, %V0); OUT_AS2 (or, w, %W0); OUT_AS2 (or, w, %X0); OUT_AS2 (or, w, %Y0); OUT_AS2 (or, w, %Z0); break; case SImode: OUT_AS2 (mov, w, %A0); OUT_AS2 (or, w, %B0); OUT_AS2 (or, w, %C0); OUT_AS2 (or, w, %D0); break; case HImode: OUT_AS2 (mov, w, %H0); OUT_AS2 (or, w, %L0); break; case QImode: OUT_AS2 (mov, w, %0); break; default: abort (); } if (can_use_skip) { if (code == EQ) OUT_AS1 (sz, ); else OUT_AS1 (snz, ); } else { if (code == EQ) OUT_AS1 (snz,); else OUT_AS1 (sz,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); } break; case GEU: /* Always succeed. */ OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); break; case LTU: /* Always fail. */ break; default: abort (); } return ""; } /* Look at whether we have a constant as one of our operands. If we do and it's in the position that we use to subtract from during our normal optimized comparison concept then we have to shuffle things around! */ if (mode != QImode) { if ((immediate_operand (operands[1], GET_MODE (operands[1])) && ((code == LEU) || (code == GTU))) || (immediate_operand (operands[0], GET_MODE (operands[0])) && ((code == LTU) || (code == GEU)))) { imm_sub = 1; } } /* Same as above - look if we have a constant that we can compare for equality or non-equality. If we know this then we can look for common value eliminations. Note that we want to ensure that any immediate value is operand 1 to simplify the code later! */ if ((code == EQ) || (code == NE)) { imm_cmp = immediate_operand (operands[1], GET_MODE (operands[1])); if (! imm_cmp) { imm_cmp = immediate_operand (operands[0], GET_MODE (operands[0])); if (imm_cmp) { rtx tmp = operands[1]; operands[1] = operands[0]; operands[0] = tmp; } } } switch (mode) { case QImode: switch (code) { case EQ: if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0xff)) OUT_AS2 (incsnz, w, %0); else if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0x01)) OUT_AS2 (decsnz, w, %0); else { OUT_AS2 (mov, w, %1); OUT_AS2 (csne, w, %0); } OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); break; case NE: if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0xff)) OUT_AS2 (incsz, w, %0); else if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0x01)) OUT_AS2 (decsz, w, %0); else { OUT_AS2 (mov, w, %1); OUT_AS2 (cse, w, %0); } OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); break; case GTU: OUT_AS2 (mov, w, %0); OUT_AS2 (cmp, w, %1); OUT_AS1 (sc,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); break; case GEU: OUT_AS2 (mov, w, %1); OUT_AS2 (cmp, w, %0); OUT_AS1 (snc,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); break; case LTU: OUT_AS2 (mov, w, %1); OUT_AS2 (cmp, w, %0); OUT_AS1 (sc,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); break; case LEU: OUT_AS2 (mov, w, %0); OUT_AS2 (cmp, w, %1); OUT_AS1 (snc,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); break; default: abort (); } break; case HImode: switch (code) { case EQ: { unsigned char h = 0, l = 1; if (imm_cmp) { h = (INTVAL (operands[1]) >> 8) & 0xff; l = INTVAL (operands[1]) & 0xff; if ((h == 0xff) && (l == 0xff)) { /* We should be able to do the following, but the IP2k simulator doesn't like it and we get a load of failures in gcc-c-torture. */ OUT_AS2 (incsnz, w, %L0); OUT_AS2 (incsz, w, %H0);/* OUT_AS1 (skip,); Should have this */ OUT_AS1 (page, 1f);/* Shouldn't need this! */ OUT_AS1 (jmp, 1f); /* Shouldn't need this either. */ OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); OUT_AS1 (1:,); break; } else if (h == 0) { if (l == 1) OUT_AS2 (dec, w, %L0); else { OUT_AS2 (mov, w, %L0); OUT_AS2 (sub, w, %L1); } OUT_AS2 (or, w, %H0); OUT_AS1 (snz,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); break; } else if (l == 0) { if (h == 1) OUT_AS2 (dec, w, %H0); else { OUT_AS2 (mov, w, %H0); OUT_AS2 (sub, w, %H1); } OUT_AS2 (or, w, %L0); OUT_AS1 (snz,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); break; } } OUT_AS2 (mov, w, %H1); OUT_AS2 (cse, w, %H0); OUT_AS1 (page, 2f); OUT_AS1 (jmp, 2f); if (! imm_cmp || (h != l)) OUT_AS2 (mov, w, %L1); OUT_AS2 (csne, w, %L0); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); OUT_AS1 (2:,); } break; case NE: { unsigned char h = 0, l = 1; if (imm_cmp) { h = (INTVAL (operands[1]) >> 8) & 0xff; l = INTVAL (operands[1]) & 0xff; if ((h == 0xff) && (l == 0xff)) { OUT_AS2 (incsnz, w, %L0); OUT_AS2 (incsz, w, %H0); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); break; } else if (h == 0) { if (l == 1) OUT_AS2 (dec, w, %L0); else { OUT_AS2 (mov, w, %L0); OUT_AS2 (sub, w, %L1); } OUT_AS2 (or, w, %H0); OUT_AS1 (sz,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); break; } else if (l == 0) { if (h == 1) OUT_AS2 (dec, w, %H0); else { OUT_AS2 (mov, w, %H0); OUT_AS2 (sub, w, %H1); } OUT_AS2 (or, w, %L0); OUT_AS1 (sz,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); break; } } OUT_AS2 (mov, w, %H1); if (imm_cmp && (h == l)) { OUT_AS2 (csne, w, %H0); OUT_AS2 (cse, w, %L0); } else { OUT_AS2 (cse, w, %H0); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); OUT_AS2 (mov, w, %L1); OUT_AS2 (cse, w, %L0); } OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); } break; case GTU: if (imm_sub) { /* > 0xffff never suceeds! */ if ((INTVAL (operands[1]) & 0xffff) != 0xffff) { operands[3] = GEN_INT (INTVAL (operands[1]) + 1); OUT_AS2 (mov, w, %L3); OUT_AS2 (sub, w, %L0); OUT_AS2 (mov, w, %H3); OUT_AS2 (subc, w, %H0); OUT_AS1 (snc,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); } } else { OUT_AS2 (mov, w, %L0); OUT_AS2 (sub, w, %L1); OUT_AS2 (mov, w, %H0); OUT_AS2 (subc, w, %H1); OUT_AS1 (sc,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); } break; case GEU: if (imm_sub) { if (INTVAL (operands[0]) == 0) { OUT_AS2 (mov, w, %H1); OUT_AS2 (or, w, %L1); OUT_AS1 (snz,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); } else { operands[3] = GEN_INT (INTVAL (operands[0]) - 1); OUT_AS2 (mov, w, %L3); OUT_AS2 (sub, w, %L1); OUT_AS2 (mov, w, %H3); OUT_AS2 (subc, w, %H1); OUT_AS1 (sc,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); } } else { OUT_AS2 (mov, w, %L1); OUT_AS2 (sub, w, %L0); OUT_AS2 (mov, w, %H1); OUT_AS2 (subc, w, %H0); OUT_AS1 (snc,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); } break; case LTU: if (imm_sub) { if (INTVAL (operands[0]) == 0) { OUT_AS2 (mov, w, %H1); OUT_AS2 (or, w, %L1); OUT_AS1 (sz,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); } else { operands[3] = GEN_INT (INTVAL (operands[0]) - 1); OUT_AS2 (mov, w, %L3); OUT_AS2 (sub, w, %L1); OUT_AS2 (mov, w, %H3); OUT_AS2 (subc, w, %H1); OUT_AS1 (snc,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); } } else { OUT_AS2 (mov, w, %L1); OUT_AS2 (sub, w, %L0); OUT_AS2 (mov, w, %H1); OUT_AS2 (subc, w, %H0); OUT_AS1 (sc,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); } break; case LEU: if (imm_sub) { if ((INTVAL (operands[1]) & 0xffff) == 0xffff) { /* <= 0xffff always suceeds. */ OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); } else { operands[3] = GEN_INT (INTVAL (operands[1]) + 1); OUT_AS2 (mov, w, %L3); OUT_AS2 (sub, w, %L0); OUT_AS2 (mov, w, %H3); OUT_AS2 (subc, w, %H0); OUT_AS1 (sc,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); } } else { OUT_AS2 (mov, w, %L0); OUT_AS2 (sub, w, %L1); OUT_AS2 (mov, w, %H0); OUT_AS2 (subc, w, %H1); OUT_AS1 (snc,); OUT_AS1 (page, %2); OUT_AS1 (jmp, %2); } break; default: abort (); } break; case SImode: switch (code) { case EQ: { unsigned char a = 0, b = 1, c = 2, d = 3; if (imm_cmp) { a = (INTVAL (operands[1]) >> 24) & 0xff; b = (INTVAL (operands[1]) >> 16) & 0xff; c = (INTVAL (operands[1]) >> 8) & 0xff;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -