From b818abb0b19ba265174ae38e8f683b843aa1a05f Mon Sep 17 00:00:00 2001 From: Richard Stallman Date: Thu, 10 Sep 1992 01:00:39 +0000 Subject: [PATCH] (init_optabs): Use __gcc_bcmp, not real bcmp. (expand_unop): Handle NEG for complex modes. (expand_binop): Likewise. (expand_complex_binop): New function. From-SVN: r2092 --- gcc/optabs.c | 239 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 238 insertions(+), 1 deletion(-) diff --git a/gcc/optabs.c b/gcc/optabs.c index 7af1c416671..53296a4112c 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -180,6 +180,11 @@ rtx fixunstfsi_libfunc; rtx fixunstfdi_libfunc; rtx fixunstfti_libfunc; +#ifdef GPC +/* from emit-rtl.c */ +extern rtx gen_highpart(); +#endif + /* Indexed by the rtx-code for a conditional (eg. EQ, LT,...) gives the gen_function to make a branch to test that condition. */ @@ -824,6 +829,228 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) delete_insns_since (last); } +#ifdef GPC + /* We need to open-code the complex type operations: '+, -, * and /' */ + + /* At this point we allow operations between two similar complex + numbers, and also if one of the operands is not a complex number + but rather of MODE_FLOAT or MODE_INT. However, the caller + must make sure that the MODE of the non-complex operand matches + the SUBMODE of the complex operand. + @@ Perhaps the conversion to complex numbers should be somewhere else. + @@ This is not tested very much. + */ + + if (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT) + { rtx real0 = (rtx) 0; + rtx imag0 = (rtx) 0; + rtx real1 = (rtx) 0; + rtx imag1 = (rtx) 0; + rtx realr; + rtx imagr; + rtx res; + rtx seq; + rtx equiv_value; + + /* 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) + target = gen_reg_rtx (mode); + + start_sequence (); + + realr = gen_lowpart (submode, target); + imagr = gen_highpart (submode, target); + + if (GET_MODE (op0) == mode) + { + real0 = gen_lowpart (submode, op0); + imag0 = gen_highpart (submode, op0); + } + else + real0 = op0; + + if (GET_MODE (op1) == mode) + { + real1 = gen_lowpart (submode, op1); + imag1 = gen_highpart (submode, op1); + } + else + real1 = op1; + + if (! real0 || ! real1 || ! (imag0 || imag1)) + abort (); + + switch (binoptab->code) { + case PLUS: + case MINUS: + res = expand_binop (submode, binoptab, real0, real1, + realr, unsignedp, methods); + if (res != realr) + emit_move_insn (realr, res); + + if (imag0 && imag1) + res = expand_binop (submode, binoptab, imag0, imag1, + imagr, unsignedp, methods); + else if (imag0) + res = imag0; + else if (binoptab->code == MINUS) + res = expand_unop (submode, neg_optab, imag1, imagr, unsignedp); + else + res = imag1; + + if (res != imagr) + emit_move_insn (imagr, res); + break; + case MULT: + /* (a+ib) * (c+id) = (ac-bd) + i(ad+cb) */ + + res = expand_binop (submode, binoptab, real0, real1, + realr, unsignedp, methods); + + if (imag0 && imag1) + { + rtx temp = + expand_binop (submode, sub_optab, res, + expand_binop (submode, binoptab, imag0, imag1, + 0, unsignedp, methods), + realr, unsignedp, methods); + + if (temp != realr) + emit_move_insn (realr, temp); + + res = expand_binop (submode, add_optab, + expand_binop (submode, binoptab, + real0, imag1, + 0, unsignedp, methods), + expand_binop (submode, binoptab, + real1, imag0, + 0, unsignedp, methods), + imagr, unsignedp, methods); + if (res != imagr) + emit_move_insn (imagr, res); + } + else + { + if (res != realr) + emit_move_insn (realr, res); + + if (imag0) + res = expand_binop (submode, binoptab, + real1, imag0, imagr, unsignedp, methods); + else + res = expand_binop (submode, binoptab, + real0, imag1, imagr, unsignedp, methods); + if (res != imagr) + emit_move_insn (imagr, res); + } + break; + case DIV: + /* (c+id)/(a+ib) == ((c+id)*(a-ib))/(a*a+b*b) */ + + if (! imag1) + { /* Simply divide the real and imaginary parts by `a' */ + res = expand_binop (submode, binoptab, real0, real1, + realr, unsignedp, methods); + if (res != realr) + emit_move_insn (realr, res); + + res = expand_binop (submode, binoptab, imag0, real1, + imagr, unsignedp, methods); + if (res != imagr) + emit_move_insn (imagr, res); + } + else /* Divider is of complex type */ + { /* X/(a+ib) */ + + rtx divider; + rtx real_t; + rtx imag_t; + + optab mulopt = unsignedp ? umul_widen_optab : smul_optab; + + /* Divider: a*a + b*b */ + divider = expand_binop (submode, add_optab, + expand_binop (submode, mulopt, + real1, real1, + 0, unsignedp, methods), + expand_binop (submode, mulopt, + imag1, imag1, + 0, unsignedp, methods), + 0, unsignedp, methods); + + if (! imag0) /* ((c)(a-ib))/divider */ + { + /* Calculate the divident */ + real_t = expand_binop (submode, mulopt, real0, real1, + 0, unsignedp, methods); + + imag_t = + expand_unop (submode, neg_optab, + expand_binop (submode, mulopt, real0, imag1, + 0, unsignedp, methods), + 0, unsignedp); + } + else /* ((c+id)(a-ib))/divider */ + { + /* Calculate the divident */ + real_t = expand_binop (submode, add_optab, + expand_binop (submode, mulopt, + real0, real1, + 0, unsignedp, methods), + expand_binop (submode, mulopt, + imag0, imag1, + 0, unsignedp, methods), + 0, unsignedp, methods); + + imag_t = expand_binop (submode, sub_optab, + expand_binop (submode, mulopt, + real0, imag1, + 0, unsignedp, methods), + expand_binop (submode, mulopt, + real1, imag0, + 0, unsignedp, methods), + 0, unsignedp, methods); + + } + + res = expand_binop (submode, binoptab, real_t, divider, + realr, unsignedp, methods); + if (res != realr) + emit_move_insn (realr, res); + + res = expand_binop (submode, binoptab, imag_t, divider, + imagr, unsignedp, methods); + if (res != imagr) + emit_move_insn (imagr, res); + } + break; + + default: + abort (); + } + + seq = gen_sequence (); + end_sequence (); + + if (binoptab->code != UNKNOWN) + equiv_value = gen_rtx (binoptab->code, mode, op0, op1); + else + equiv_value = 0; + + emit_no_conflict_block (seq, target, op0, op1, equiv_value); + + return target; + } +#endif /* GPC */ + /* It can't be open-coded in this mode. Use a library call if one is available and caller says that's ok. */ @@ -1144,9 +1371,19 @@ expand_unop (mode, unoptab, op0, target, unsignedp) register rtx temp; rtx last = get_last_insn (); rtx pat; +#ifdef GPC + enum machine_mode submode; +#endif class = GET_MODE_CLASS (mode); +#ifdef GPC + if (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT) + submode = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT, + class == MODE_COMPLEX_INT ? + MODE_INT : MODE_FLOAT, 0); +#endif /* GPC */ + op0 = protect_from_queue (op0, 0); if (flag_force_mem) @@ -4631,7 +4868,7 @@ init_optabs () memcpy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcpy"); bcopy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bcopy"); memcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcmp"); - bcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bcmp"); + bcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gcc_bcmp"); memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memset"); bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero");