📄 optabs.c
字号:
unsignedp), convert_modes (wider_mode, mode, op1, unsignedp), t0, t1, unsignedp)) { convert_move (targ0, t0, unsignedp); convert_move (targ1, t1, unsignedp); return 1; } else delete_insns_since (last); } } } delete_insns_since (entry_last); return 0;}/* Generate code to perform an operation specified by UNOPTAB on operand OP0, with result having machine-mode MODE. UNSIGNEDP is for the case where we have to widen the operands to perform the operation. It says to use zero-extension. If TARGET is nonzero, the value is generated there, if it is convenient to do so. In all cases an rtx is returned for the locus of the value; this may or may not be TARGET. */rtxexpand_unop (mode, unoptab, op0, target, unsignedp) enum machine_mode mode; optab unoptab; rtx op0; rtx target; int unsignedp;{ enum mode_class class; enum machine_mode wider_mode; register rtx temp; rtx last = get_last_insn (); rtx pat; class = GET_MODE_CLASS (mode); op0 = protect_from_queue (op0, 0); if (flag_force_mem) { op0 = force_not_mem (op0); } if (target) target = protect_from_queue (target, 1); if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) { int icode = (int) unoptab->handlers[(int) mode].insn_code; enum machine_mode mode0 = insn_operand_mode[icode][1]; rtx xop0 = op0; if (target) temp = target; else temp = gen_reg_rtx (mode); if (GET_MODE (xop0) != VOIDmode && GET_MODE (xop0) != mode0) xop0 = convert_to_mode (mode0, xop0, unsignedp); /* Now, if insn doesn't accept our operand, put it into a pseudo. */ if (! (*insn_operand_predicate[icode][1]) (xop0, mode0)) xop0 = copy_to_mode_reg (mode0, xop0); if (! (*insn_operand_predicate[icode][0]) (temp, mode)) temp = gen_reg_rtx (mode); pat = GEN_FCN (icode) (temp, xop0); if (pat) { if (GET_CODE (pat) == SEQUENCE && ! add_equal_note (pat, temp, unoptab->code, xop0, NULL_RTX)) { delete_insns_since (last); return expand_unop (mode, unoptab, op0, NULL_RTX, unsignedp); } emit_insn (pat); return temp; } else delete_insns_since (last); } /* It can't be done in this mode. Can we open-code it in a wider mode? */ if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; wider_mode = GET_MODE_WIDER_MODE (wider_mode)) { if (unoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing) { rtx xop0 = op0; /* For certain operations, we need not actually extend the narrow operand, as long as we will truncate the results to the same narrowness. */ xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, (unoptab == neg_optab || unoptab == one_cmpl_optab) && class == MODE_INT); temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX, unsignedp); if (temp) { if (class != MODE_INT) { if (target == 0) target = gen_reg_rtx (mode); convert_move (target, temp, 0); return target; } else return gen_lowpart (mode, temp); } else delete_insns_since (last); } } /* These can be done a word at a time. */ if (unoptab == one_cmpl_optab && class == MODE_INT && GET_MODE_SIZE (mode) > UNITS_PER_WORD && unoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) { int i; rtx insns; if (target == 0 || target == op0) target = gen_reg_rtx (mode); start_sequence (); /* Do the actual arithmetic. */ for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++) { rtx target_piece = operand_subword (target, i, 1, mode); rtx x = expand_unop (word_mode, unoptab, operand_subword_force (op0, i, mode), target_piece, unsignedp); if (target_piece != x) emit_move_insn (target_piece, x); } insns = get_insns (); end_sequence (); emit_no_conflict_block (insns, target, op0, NULL_RTX, gen_rtx (unoptab->code, mode, copy_rtx (op0))); return target; } /* Open-code the complex negation operation. */ else if (unoptab == neg_optab && (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)) { rtx target_piece; rtx x; rtx seq; /* Find the correct mode for the real and imaginary parts */ enum machine_mode submode = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT, class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT, 0); if (submode == BLKmode) abort (); if (target == 0) target = gen_reg_rtx (mode); start_sequence (); target_piece = gen_imagpart (submode, target); x = expand_unop (submode, unoptab, gen_imagpart (submode, op0), target_piece, unsignedp); if (target_piece != x) emit_move_insn (target_piece, x); target_piece = gen_realpart (submode, target); x = expand_unop (submode, unoptab, gen_realpart (submode, op0), target_piece, unsignedp); if (target_piece != x) emit_move_insn (target_piece, x); seq = get_insns (); end_sequence (); emit_no_conflict_block (seq, target, op0, 0, gen_rtx (unoptab->code, mode, copy_rtx (op0))); return target; } /* Now try a library call in this mode. */ if (unoptab->handlers[(int) mode].libfunc) { rtx insns; rtx funexp = unoptab->handlers[(int) mode].libfunc; rtx value; start_sequence (); /* Pass 1 for NO_QUEUE so we don't lose any increments if the libcall is cse'd or moved. */ value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc, NULL_RTX, 1, mode, 1, op0, mode); insns = get_insns (); end_sequence (); target = gen_reg_rtx (mode); emit_libcall_block (insns, target, value, gen_rtx (unoptab->code, mode, op0)); return target; } /* It can't be done in this mode. Can we do it in a wider mode? */ if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) { for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; wider_mode = GET_MODE_WIDER_MODE (wider_mode)) { if ((unoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing) || unoptab->handlers[(int) wider_mode].libfunc) { rtx xop0 = op0; /* For certain operations, we need not actually extend the narrow operand, as long as we will truncate the results to the same narrowness. */ xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, (unoptab == neg_optab || unoptab == one_cmpl_optab) && class == MODE_INT); temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX, unsignedp); if (temp) { if (class != MODE_INT) { if (target == 0) target = gen_reg_rtx (mode); convert_move (target, temp, 0); return target; } else return gen_lowpart (mode, temp); } else delete_insns_since (last); } } } /* If there is no negate operation, try doing a subtract from zero. The US Software GOFAST library needs this. */ if (unoptab == neg_optab) { rtx temp; temp = expand_binop (mode, sub_optab, CONST0_RTX (mode), op0, target, unsignedp, OPTAB_LIB_WIDEN); if (temp) return temp; } return 0;}/* Emit code to compute the absolute value of OP0, with result to TARGET if convenient. (TARGET may be 0.) The return value says where the result actually is to be found. MODE is the mode of the operand; the mode of the result is different but can be deduced from MODE. UNSIGNEDP is relevant if extension is needed. */rtxexpand_abs (mode, op0, target, unsignedp, safe) enum machine_mode mode; rtx op0; rtx target; int unsignedp; int safe;{ rtx temp, op1; /* First try to do it with a special abs instruction. */ temp = expand_unop (mode, abs_optab, op0, target, 0); if (temp != 0) return temp; /* If this machine has expensive jumps, we can do integer absolute value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)), where W is the width of MODE. */ if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2) { rtx extended = expand_shift (RSHIFT_EXPR, mode, op0, size_int (GET_MODE_BITSIZE (mode) - 1), NULL_RTX, 0); temp = expand_binop (mode, xor_optab, extended, op0, target, 0, OPTAB_LIB_WIDEN); if (temp != 0) temp = expand_binop (mode, sub_optab, temp, extended, target, 0, OPTAB_LIB_WIDEN); if (temp != 0) return temp; } /* If that does not win, use conditional jump and negate. */ op1 = gen_label_rtx (); if (target == 0 || ! safe || GET_MODE (target) != mode || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target)) || (GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER)) target = gen_reg_rtx (mode); emit_move_insn (target, op0); NO_DEFER_POP; /* If this mode is an integer too wide to compare properly, compare word by word. Rely on CSE to optimize constant cases. */ if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode)) do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx, NULL_RTX, op1); else { temp = compare_from_rtx (target, CONST0_RTX (mode), GE, 0, mode, NULL_RTX, 0); if (temp == const1_rtx) return target; else if (temp != const0_rtx) { if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0) emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op1)); else abort (); } } op0 = expand_unop (mode, neg_optab, target, target, 0); if (op0 != target) emit_move_insn (target, op0); emit_label (op1); OK_DEFER_POP; return target;}/* Emit code to compute the absolute value of OP0, with result to TARGET if convenient. (TARGET may be 0.) The return value says where the result actually is to be found. MODE is the mode of the operand; the mode of the result is different but can be deduced from MODE. UNSIGNEDP is relevant for complex integer modes. */rtxexpand_complex_abs (mode, op0, target, unsignedp) enum machine_mode mode; rtx op0; rtx target; int unsignedp;{ enum mode_class class = GET_MODE_CLASS (mode); enum machine_mode wider_mode; register rtx temp; rtx entry_last = get_last_insn (); rtx last; rtx pat; /* Find the correct mode for the real and imaginary parts. */ enum machine_mode submode = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT, class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT, 0); if (submode == BLKmode) abort (); op0 = protect_from_queue (op0, 0); if (flag_force_mem) { op0 = force_not_mem (op0); } last = get_last_insn (); if (target) target = protect_from_queue (target, 1); if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) { int icode = (int) abs_optab->handlers[(int) mode].insn_code; enum machine_mode mode0 = insn_operand_mode[icode][1]; rtx xop0 = op0; if (target) temp = target; else temp = gen_reg_rtx (submode); if (GET_MODE (xop0) != VOIDmode && GET_MODE (xop0) != mode0) xop0 = convert_to_mode (mode0, xop0, unsignedp); /* Now, if insn doesn't accept our operand, put it into a pseudo. */ if (! (*insn_operand_predicate[icode][1]) (xop0, mode0)) xop0 = copy_to_mode_reg (mode0, xop0); if (! (*insn_operand_predicate[icode][0]) (temp, submode)) temp = gen_reg_rtx (s
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -