📄 optabs.c
字号:
register rtx t0 = gen_reg_rtx (wider_mode); register rtx t1 = gen_reg_rtx (wider_mode); if (expand_twoval_binop (binoptab, convert_to_mode (wider_mode, op0, unsignedp), convert_to_mode (wider_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. But it is faster to convert a SUBREG due to mode promotion. */ if ((unoptab == neg_optab || unoptab == one_cmpl_optab) && GET_MODE_SIZE (wider_mode) <= UNITS_PER_WORD && class == MODE_INT && ! (GET_CODE (xop0) == SUBREG && SUBREG_PROMOTED_VAR_P (xop0))) xop0 = gen_rtx (SUBREG, wider_mode, force_reg (mode, xop0), 0); else xop0 = convert_to_mode (wider_mode, xop0, unsignedp); 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, 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, 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; start_sequence (); /* Pass 1 for NO_QUEUE so we don't lose any increments if the libcall is cse'd or moved. */ emit_library_call (unoptab->handlers[(int) mode].libfunc, 1, mode, 1, op0, mode); insns = get_insns (); end_sequence (); target = gen_reg_rtx (mode); emit_libcall_block (insns, target, hard_libcall_value (mode), 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. */ if ((unoptab == neg_optab || unoptab == one_cmpl_optab) && GET_MODE_SIZE (wider_mode) <= UNITS_PER_WORD && class == MODE_INT && ! (GET_CODE (xop0) == SUBREG && SUBREG_PROMOTED_VAR_P (xop0))) xop0 = gen_rtx (SUBREG, wider_mode, force_reg (mode, xop0), 0); else xop0 = convert_to_mode (wider_mode, xop0, unsignedp); 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); } } } 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 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 (submode); pat = GEN_FCN (icode) (temp, xop0); if (pat) { if (GET_CODE (pat) == SEQUENCE && ! add_equal_note (pat, temp, abs_optab->code, xop0, NULL_RTX)) { delete_insns_since (last); return expand_unop (mode, abs_optab, 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? */ for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; wider_mode = GET_MODE_WIDER_MODE (wider_mode)) { if (abs_optab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing) { rtx xop0 = op0; xop0 = convert_to_mode (wider_mode, xop0, unsignedp); temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp); if (temp) { if (class != MODE_COMPLEX_INT) { if (target == 0) target = gen_reg_rtx (submode); convert_move (target, temp, 0); return target; } else return gen_lowpart (submode, temp); } else delete_insns_since (last); } } /* Open-code the complex absolute-value operation if we can open-code sqrt. Otherwise it's not worth while. */ if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing) { rtx real, imag, total; real = gen_realpart (submode, op0); imag = gen_imagpart (submode, op0); /* Square both parts. */ real = expand_mult (mode, real, real, NULL_RTX, 0); imag = expand_mult (mode, imag, imag, NULL_RTX, 0); /* Sum the parts. */ total = expand_binop (submode, add_optab, real, imag, 0, 0, OPTAB_LIB_WIDEN); /* Get sqrt in TARGET. Set TARGET to where the result is. */ target = expand_unop (submode, sqrt_optab, total, target, 0); if (target == 0) delete_insns_since (last); else return target; } /* Now try a library call in this mode. */ if (abs_optab->handlers[(int) mode].libfunc) { rtx insns; rtx funexp = abs_optab->handlers[(int) mode].libfunc; start_sequence (); /* Pass 1 for NO_QUEUE so we don't lose any increments if the libcall is cse'd or moved. */ emit_library_call (abs_optab->handlers[(int) mode].libfunc, 1, mode, 1, op0, mode); insns = get_insns (); end_sequence (); target = gen_reg_rtx (submode); emit_libcall_block (insns, target, hard_libcall_value (submode), gen_rtx (abs_optab->code, mode, op0));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -