📄 optabs.c
字号:
{ x = convert_to_mode (wider_mode, x, unsignedp); y = convert_to_mode (wider_mode, y, unsignedp); emit_cmp_insn (x, y, 0, unsignedp, align); } } return; } abort ();}/* These three functions generate an insn body and return it rather than emitting the insn. They do not protect from queued increments, because they may be used 1) in protect_from_queue itself and 2) in other passes where there is no queue. *//* Generate and return an insn body to add Y to X. */rtxgen_add2_insn (x, y) rtx x, y;{ return (GEN_FCN (add_optab->handlers[(int) GET_MODE (x)].insn_code) (x, x, y));}inthave_add2_insn (mode) enum machine_mode mode;{ return add_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing;}/* Generate and return an insn body to subtract Y from X. */rtxgen_sub2_insn (x, y) rtx x, y;{ return (GEN_FCN (sub_optab->handlers[(int) GET_MODE (x)].insn_code) (x, x, y));}inthave_sub2_insn (mode) enum machine_mode mode;{ return add_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing;}/* Generate the body of an instruction to copy Y into X. */rtxgen_move_insn (x, y) rtx x, y;{ register enum machine_mode mode = GET_MODE (x); if (mode == VOIDmode) mode = GET_MODE (y); return (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y));}#if 0/* Tables of patterns for extending one integer mode to another. */enum insn_code zero_extend_optab[MAX_MACHINE_MODE][MAX_MACHINE_MODE];enum insn_code sign_extend_optab[MAX_MACHINE_MODE][MAX_MACHINE_MODE];/* Generate the body of an insn to extend Y (with mode MFROM) into X (with mode MTO). Do zero-extension if UNSIGNEDP is nonzero. */rtxgen_extend_insn (x, y, mto, mfrom, unsignedp) rtx x, y; enum machine_mode mto, mfrom; int unsignedp;{ return (GEN_FCN ((unsignedp ? zero_extend_optab : sign_extend_optab) [(int)mto][(int)mfrom]) (x, y));}static voidinit_extends (){ bzero (sign_extend_optab, sizeof sign_extend_optab); bzero (zero_extend_optab, sizeof zero_extend_optab); sign_extend_optab[(int) SImode][(int) HImode] = CODE_FOR_extendhisi2; sign_extend_optab[(int) SImode][(int) QImode] = CODE_FOR_extendqisi2; sign_extend_optab[(int) HImode][(int) QImode] = CODE_FOR_extendqihi2; zero_extend_optab[(int) SImode][(int) HImode] = CODE_FOR_zero_extendhisi2; zero_extend_optab[(int) SImode][(int) QImode] = CODE_FOR_zero_extendqisi2; zero_extend_optab[(int) HImode][(int) QImode] = CODE_FOR_zero_extendqihi2;}#endif/* can_fix_p and can_float_p say whether the target machine can directly convert a given fixed point type to a given floating point type, or vice versa. The returned value is the CODE_FOR_... value to use, or CODE_FOR_nothing if these modes cannot be directly converted. */static enum insn_code fixtab[2][2][2];static enum insn_code fixtrunctab[2][2][2];static enum insn_code floattab[2][2];/* *TRUNCP_PTR is set to 1 if it is necessary to output an explicit FTRUNC insn before the fix insn; otherwise 0. */static enum insn_codecan_fix_p (fixmode, fltmode, unsignedp, truncp_ptr) enum machine_mode fltmode, fixmode; int unsignedp; int *truncp_ptr;{ *truncp_ptr = 0; if (fixtrunctab[fltmode != SFmode][fixmode == DImode][unsignedp] != CODE_FOR_nothing) return fixtrunctab[fltmode != SFmode][fixmode == DImode][unsignedp]; if (ftrunc_optab->handlers[(int) fltmode].insn_code != CODE_FOR_nothing) { *truncp_ptr = 1; return fixtab[fltmode != SFmode][fixmode == DImode][unsignedp]; } return CODE_FOR_nothing;}static enum insn_codecan_float_p (fltmode, fixmode) enum machine_mode fixmode, fltmode;{ return floattab[fltmode != SFmode][fixmode == DImode];}voidinit_fixtab (){ enum insn_code *p; for (p = fixtab[0][0]; p < fixtab[0][0] + sizeof fixtab / sizeof (fixtab[0][0][0]); p++) *p = CODE_FOR_nothing; for (p = fixtrunctab[0][0]; p < fixtrunctab[0][0] + sizeof fixtrunctab / sizeof (fixtrunctab[0][0][0]); p++) *p = CODE_FOR_nothing;#ifdef HAVE_fixsfsi2 if (HAVE_fixsfsi2) fixtab[0][0][0] = CODE_FOR_fixsfsi2;#endif#ifdef HAVE_fixsfdi2 if (HAVE_fixsfdi2) fixtab[0][1][0] = CODE_FOR_fixsfdi2;#endif#ifdef HAVE_fixdfsi2 if (HAVE_fixdfsi2) fixtab[1][0][0] = CODE_FOR_fixdfsi2;#endif#ifdef HAVE_fixdfdi2 if (HAVE_fixdfdi2) fixtab[1][1][0] = CODE_FOR_fixdfdi2;#endif#ifdef HAVE_fixunssfsi2 if (HAVE_fixunssfsi2) fixtab[0][0][1] = CODE_FOR_fixunssfsi2;#endif#ifdef HAVE_fixunssfdi2 if (HAVE_fixunssfdi2) fixtab[0][1][1] = CODE_FOR_fixunssfdi2;#endif#ifdef HAVE_fixunsdfsi2 if (HAVE_fixunsdfsi2) fixtab[1][0][1] = CODE_FOR_fixunsdfsi2;#endif#ifdef HAVE_fixunsdfdi2 if (HAVE_fixunsdfdi2) fixtab[1][1][1] = CODE_FOR_fixunsdfdi2;#endif#ifdef HAVE_fix_truncsfsi2 if (HAVE_fix_truncsfsi2) fixtrunctab[0][0][0] = CODE_FOR_fix_truncsfsi2;#endif#ifdef HAVE_fix_truncsfdi2 if (HAVE_fix_truncsfdi2) fixtrunctab[0][1][0] = CODE_FOR_fix_truncsfdi2;#endif#ifdef HAVE_fix_truncdfsi2 if (HAVE_fix_truncdfsi2) fixtrunctab[1][0][0] = CODE_FOR_fix_truncdfsi2;#endif#ifdef HAVE_fix_truncdfdi2 if (HAVE_fix_truncdfdi2) fixtrunctab[1][1][0] = CODE_FOR_fix_truncdfdi2;#endif#ifdef HAVE_fixuns_truncsfsi2 if (HAVE_fixuns_truncsfsi2) fixtrunctab[0][0][1] = CODE_FOR_fixuns_truncsfsi2;#endif#ifdef HAVE_fixuns_truncsfdi2 if (HAVE_fixuns_truncsfdi2) fixtrunctab[0][1][1] = CODE_FOR_fixuns_truncsfdi2;#endif#ifdef HAVE_fixuns_truncdfsi2 if (HAVE_fixuns_truncdfsi2) fixtrunctab[1][0][1] = CODE_FOR_fixuns_truncdfsi2;#endif#ifdef HAVE_fixuns_truncdfdi2 if (HAVE_fixuns_truncdfdi2) fixtrunctab[1][1][1] = CODE_FOR_fixuns_truncdfdi2;#endif#ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC /* This flag says the same insns that convert to a signed fixnum also convert validly to an unsigned one. */ { int i; int j; for (i = 0; i < 2; i++) for (j = 0; j < 2; j++) fixtrunctab[i][j][1] = fixtrunctab[i][j][0]; }#endif}voidinit_floattab (){ enum insn_code *p; for (p = floattab[0]; p < floattab[0] + sizeof floattab / sizeof (floattab[0][0]); p++) *p = CODE_FOR_nothing;#ifdef HAVE_floatsisf2 if (HAVE_floatsisf2) floattab[0][0] = CODE_FOR_floatsisf2;#endif#ifdef HAVE_floatdisf2 if (HAVE_floatdisf2) floattab[0][1] = CODE_FOR_floatdisf2;#endif#ifdef HAVE_floatsidf2 if (HAVE_floatsidf2) floattab[1][0] = CODE_FOR_floatsidf2;#endif#ifdef HAVE_floatdidf2 if (HAVE_floatdidf2) floattab[1][1] = CODE_FOR_floatdidf2;#endif}/* Generate code to convert FROM to floating point and store in TO. FROM must be fixed point. UNSIGNEDP nonzero means regard FROM as unsigned. Normally this is done by correcting the final value if it is negative. */voidexpand_float (real_to, from, unsignedp) rtx real_to, from; int unsignedp;{ enum insn_code icode; register rtx to; /* Constants should get converted in `fold'. We lose here since we don't know the mode. */ if (GET_MODE (from) == VOIDmode) abort (); to = real_to = protect_from_queue (real_to, 1); from = protect_from_queue (from, 0); if (flag_force_mem) { from = force_not_mem (from); } /* If we are about to do some arithmetic to correct for an unsigned operand, do it in a pseudo-register. */ if (unsignedp && ! (GET_CODE (to) == REG && REGNO (to) >= FIRST_PSEUDO_REGISTER)) to = gen_reg_rtx (GET_MODE (to)); /* Now do the basic conversion. Do it in the specified modes if possible; otherwise convert either input, output or both with wider mode; otherwise use a library call. */ if ((icode = can_float_p (GET_MODE (to), GET_MODE (from))) != CODE_FOR_nothing) { emit_unop_insn (icode, to, from, FLOAT); } else if (GET_MODE (to) == SFmode && ((icode = can_float_p (DFmode, GET_MODE (from))) != CODE_FOR_nothing)) { to = gen_reg_rtx (DFmode); emit_unop_insn (icode, to, from, FLOAT); } /* If we can't float a SI, maybe we can float a DI. If so, convert to DI and then float. */ else if (GET_MODE (from) != DImode && (can_float_p (GET_MODE (to), DImode) != CODE_FOR_nothing || can_float_p (DFmode, DImode) != CODE_FOR_nothing)) { register rtx tem = gen_reg_rtx (DImode); convert_move (tem, from, unsignedp); from = tem; /* If we extend FROM then we don't need to correct the final value for unsignedness. */ unsignedp = 0; if ((icode = can_float_p (GET_MODE (to), GET_MODE (from))) != CODE_FOR_nothing) { emit_unop_insn (icode, to, from, FLOAT); } else if ((icode = can_float_p (DFmode, DImode)) != CODE_FOR_nothing) { to = gen_reg_rtx (DFmode); emit_unop_insn (icode, to, from, FLOAT); } } /* No hardware instruction available; call a library to convert from SImode or DImode into DFmode. */ else { if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode)) { from = convert_to_mode (SImode, from, unsignedp); unsignedp = 0; } emit_library_call (gen_rtx (SYMBOL_REF, Pmode, (GET_MODE (from) == SImode ? "__floatsidf" : "__floatdidf")), 0, DFmode, 1, from, GET_MODE (from)); to = copy_to_reg (hard_libcall_value (DFmode)); } /* If FROM was unsigned but we treated it as signed, then in the case where it is negative (and therefore TO is negative), correct its value by 2**bitwidth. */ if (unsignedp) { rtx label = gen_label_rtx (); rtx temp; REAL_VALUE_TYPE offset; do_pending_stack_adjust (); emit_cmp_insn (to, GET_MODE (to) == DFmode ? dconst0_rtx : fconst0_rtx, 0, 0, 0); emit_jump_insn (gen_bge (label)); /* On SCO 3.2.1, ldexp rejects values outside [0.5, 1). */ offset = REAL_VALUE_LDEXP (0.5, GET_MODE_BITSIZE (GET_MODE (from)) + 1); temp = expand_binop (GET_MODE (to), add_optab, to, immed_real_const_1 (offset, GET_MODE (to)), to, 0, OPTAB_LIB_WIDEN); if (temp != to) emit_move_insn (to, temp); do_pending_stack_adjust (); emit_label (label); } /* Copy result to requested destination if we have been computing in a temp location. */ if (to != real_to) { if (GET_MODE (real_to) == GET_MODE (to)) emit_move_insn (real_to, to); else convert_move (real_to, to, 0); }}/* expand_fix: generate code to convert FROM to fixed point and store in TO. FROM must be floating point. */static rtxftruncify (x) rtx x;{ rtx temp = gen_reg_rtx (GET_MODE (x)); return expand_unop (GET_MODE (x), ftrunc_optab, x, temp, 0);}voidexpand_fix (to, from, unsignedp) register rtx to, from; int unsignedp;{ enum insn_code icode; register rtx target; int must_trunc = 0; while (1) { icode = can_fix_p (GET_MODE (to), GET_MODE (from), unsignedp, &must_trunc); if (icode != CODE_FOR_nothing) { if (must_trunc) from = ftruncify (from); emit_unop_insn (icode, to, from, FIX); return; }#if 0 /* Turned off. It fails because the positive numbers that become temporarily negative are rounded up instead of down. */ /* If no insns for unsigned conversion, we can go via a signed number. But make sure we won't overflow in the compiler. */ if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_INT /* Make sure we won't lose significant bits doing this. */ && GET_MODE_BITSIZE (GET_MODE (from)) > GET_MODE_BITSIZE (GET_MODE (to))) { icode = can_fix_p (GET_MODE (to), GET_MODE (from), 0, &must_trunc); if (icode != CODE_FOR_nothing) { REAL_VALUE_TYPE offset; rtx temp, temp1; int bitsize = GET_MODE_BITSIZE (GET_MODE (to)); if (must_trunc) from = ftruncify (from); /* Subtract 2**(N-1), convert to signed number, then add 2**(N-1). */ /* On SCO 3.2.1, ldexp rejects values outside [0.5, 1). */ offset = REAL_VALUE_LDEXP (0.5, bitsize); temp = expand_binop (GET_MODE (from), sub_optab, from, immed_real_const_1 (offset, GET_MODE (from)), 0, 0, OPTAB_LIB_WIDEN);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -