optabs.c revision 103445
118334Speter/* Expand the basic unary and binary arithmetic operations, for GNU compiler. 290075Sobrien Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 390075Sobrien 1999, 2000, 2001 Free Software Foundation, Inc. 418334Speter 590075SobrienThis file is part of GCC. 618334Speter 790075SobrienGCC is free software; you can redistribute it and/or modify it under 890075Sobrienthe terms of the GNU General Public License as published by the Free 990075SobrienSoftware Foundation; either version 2, or (at your option) any later 1090075Sobrienversion. 1118334Speter 1290075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1390075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1490075SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1590075Sobrienfor more details. 1618334Speter 1718334SpeterYou should have received a copy of the GNU General Public License 1890075Sobrienalong with GCC; see the file COPYING. If not, write to the Free 1990075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 2090075Sobrien02111-1307, USA. */ 2118334Speter 2218334Speter 2318334Speter#include "config.h" 2450397Sobrien#include "system.h" 2552284Sobrien#include "toplev.h" 2652284Sobrien 2752284Sobrien/* Include insn-config.h before expr.h so that HAVE_conditional_move 2890075Sobrien is properly defined. */ 2952284Sobrien#include "insn-config.h" 3018334Speter#include "rtl.h" 3118334Speter#include "tree.h" 3290075Sobrien#include "tm_p.h" 3318334Speter#include "flags.h" 3490075Sobrien#include "function.h" 3590075Sobrien#include "except.h" 3618334Speter#include "expr.h" 3790075Sobrien#include "optabs.h" 3890075Sobrien#include "libfuncs.h" 3918334Speter#include "recog.h" 4018334Speter#include "reload.h" 4190075Sobrien#include "ggc.h" 4290075Sobrien#include "real.h" 4318334Speter 4418334Speter/* Each optab contains info on how this target machine 4518334Speter can perform a particular operation 4618334Speter for all sizes and kinds of operands. 4718334Speter 4818334Speter The operation to be performed is often specified 4918334Speter by passing one of these optabs as an argument. 5018334Speter 5118334Speter See expr.h for documentation of these optabs. */ 5218334Speter 5390075Sobrienoptab optab_table[OTI_MAX]; 5418334Speter 5590075Sobrienrtx libfunc_table[LTI_MAX]; 5618334Speter 5718334Speter/* Tables of patterns for extending one integer mode to another. */ 5818334Speterenum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2]; 5918334Speter 6050397Sobrien/* Tables of patterns for converting between fixed and floating point. */ 6118334Speterenum insn_code fixtab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2]; 6218334Speterenum insn_code fixtrunctab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2]; 6318334Speterenum insn_code floattab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2]; 6418334Speter 6518334Speter/* Contains the optab used for each rtx code. */ 6618334Speteroptab code_to_optab[NUM_RTX_CODE + 1]; 6718334Speter 6818334Speter/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...) 6918334Speter gives the gen_function to make a branch to test that condition. */ 7018334Speter 7118334Speterrtxfun bcc_gen_fctn[NUM_RTX_CODE]; 7218334Speter 7318334Speter/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...) 7418334Speter gives the insn code to make a store-condition insn 7518334Speter to test that condition. */ 7618334Speter 7718334Speterenum insn_code setcc_gen_code[NUM_RTX_CODE]; 7818334Speter 7918334Speter#ifdef HAVE_conditional_move 8018334Speter/* Indexed by the machine mode, gives the insn code to make a conditional 8118334Speter move insn. This is not indexed by the rtx-code like bcc_gen_fctn and 8218334Speter setcc_gen_code to cut down on the number of named patterns. Consider a day 8318334Speter when a lot more rtx codes are conditional (eg: for the ARM). */ 8418334Speter 8518334Speterenum insn_code movcc_gen_code[NUM_MACHINE_MODES]; 8618334Speter#endif 8718334Speter 8890075Sobrienstatic int add_equal_note PARAMS ((rtx, rtx, enum rtx_code, rtx, rtx)); 8990075Sobrienstatic rtx widen_operand PARAMS ((rtx, enum machine_mode, 9018334Speter enum machine_mode, int, int)); 9190075Sobrienstatic int expand_cmplxdiv_straight PARAMS ((rtx, rtx, rtx, rtx, 9252284Sobrien rtx, rtx, enum machine_mode, 9352284Sobrien int, enum optab_methods, 9452284Sobrien enum mode_class, optab)); 9590075Sobrienstatic int expand_cmplxdiv_wide PARAMS ((rtx, rtx, rtx, rtx, 9652284Sobrien rtx, rtx, enum machine_mode, 9752284Sobrien int, enum optab_methods, 9852284Sobrien enum mode_class, optab)); 9990075Sobrienstatic void prepare_cmp_insn PARAMS ((rtx *, rtx *, enum rtx_code *, rtx, 10090075Sobrien enum machine_mode *, int *, 10190075Sobrien enum can_compare_purpose)); 10290075Sobrienstatic enum insn_code can_fix_p PARAMS ((enum machine_mode, enum machine_mode, 10318334Speter int, int *)); 10490075Sobrienstatic enum insn_code can_float_p PARAMS ((enum machine_mode, 10590075Sobrien enum machine_mode, 10690075Sobrien int)); 10790075Sobrienstatic rtx ftruncify PARAMS ((rtx)); 10890075Sobrienstatic optab new_optab PARAMS ((void)); 10990075Sobrienstatic inline optab init_optab PARAMS ((enum rtx_code)); 11090075Sobrienstatic inline optab init_optabv PARAMS ((enum rtx_code)); 11190075Sobrienstatic void init_libfuncs PARAMS ((optab, int, int, const char *, int)); 11290075Sobrienstatic void init_integral_libfuncs PARAMS ((optab, const char *, int)); 11390075Sobrienstatic void init_floating_libfuncs PARAMS ((optab, const char *, int)); 11450397Sobrien#ifdef HAVE_conditional_trap 11590075Sobrienstatic void init_traps PARAMS ((void)); 11650397Sobrien#endif 11790075Sobrienstatic void emit_cmp_and_jump_insn_1 PARAMS ((rtx, rtx, enum machine_mode, 11890075Sobrien enum rtx_code, int, rtx)); 11990075Sobrienstatic void prepare_float_lib_cmp PARAMS ((rtx *, rtx *, enum rtx_code *, 12090075Sobrien enum machine_mode *, int *)); 12118334Speter 12218334Speter/* Add a REG_EQUAL note to the last insn in SEQ. TARGET is being set to 12318334Speter the result of operation CODE applied to OP0 (and OP1 if it is a binary 12418334Speter operation). 12518334Speter 12618334Speter If the last insn does not set TARGET, don't do anything, but return 1. 12718334Speter 12818334Speter If a previous insn sets TARGET and TARGET is one of OP0 or OP1, 12918334Speter don't add the REG_EQUAL note but return 0. Our caller can then try 13018334Speter again, ensuring that TARGET is not one of the operands. */ 13118334Speter 13218334Speterstatic int 13318334Speteradd_equal_note (seq, target, code, op0, op1) 13418334Speter rtx seq; 13518334Speter rtx target; 13618334Speter enum rtx_code code; 13718334Speter rtx op0, op1; 13818334Speter{ 13918334Speter rtx set; 14018334Speter int i; 14118334Speter rtx note; 14218334Speter 14318334Speter if ((GET_RTX_CLASS (code) != '1' && GET_RTX_CLASS (code) != '2' 14418334Speter && GET_RTX_CLASS (code) != 'c' && GET_RTX_CLASS (code) != '<') 14518334Speter || GET_CODE (seq) != SEQUENCE 14618334Speter || (set = single_set (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1))) == 0 14718334Speter || GET_CODE (target) == ZERO_EXTRACT 14818334Speter || (! rtx_equal_p (SET_DEST (set), target) 14918334Speter /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside the 15018334Speter SUBREG. */ 15118334Speter && (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART 15218334Speter || ! rtx_equal_p (SUBREG_REG (XEXP (SET_DEST (set), 0)), 15318334Speter target)))) 15418334Speter return 1; 15518334Speter 15618334Speter /* If TARGET is in OP0 or OP1, check if anything in SEQ sets TARGET 15718334Speter besides the last insn. */ 15818334Speter if (reg_overlap_mentioned_p (target, op0) 15918334Speter || (op1 && reg_overlap_mentioned_p (target, op1))) 16018334Speter for (i = XVECLEN (seq, 0) - 2; i >= 0; i--) 16118334Speter if (reg_set_p (target, XVECEXP (seq, 0, i))) 16218334Speter return 0; 16318334Speter 16418334Speter if (GET_RTX_CLASS (code) == '1') 16550397Sobrien note = gen_rtx_fmt_e (code, GET_MODE (target), copy_rtx (op0)); 16618334Speter else 16750397Sobrien note = gen_rtx_fmt_ee (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1)); 16818334Speter 16952284Sobrien set_unique_reg_note (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1), REG_EQUAL, note); 17018334Speter 17118334Speter return 1; 17218334Speter} 17318334Speter 17418334Speter/* Widen OP to MODE and return the rtx for the widened operand. UNSIGNEDP 17518334Speter says whether OP is signed or unsigned. NO_EXTEND is nonzero if we need 17618334Speter not actually do a sign-extend or zero-extend, but can leave the 17718334Speter higher-order bits of the result rtx undefined, for example, in the case 17818334Speter of logical operations, but not right shifts. */ 17918334Speter 18018334Speterstatic rtx 18118334Speterwiden_operand (op, mode, oldmode, unsignedp, no_extend) 18218334Speter rtx op; 18318334Speter enum machine_mode mode, oldmode; 18418334Speter int unsignedp; 18518334Speter int no_extend; 18618334Speter{ 18718334Speter rtx result; 18818334Speter 18996263Sobrien /* If we don't have to extend and this is a constant, return it. */ 19096263Sobrien if (no_extend && GET_MODE (op) == VOIDmode) 19196263Sobrien return op; 19296263Sobrien 19396263Sobrien /* If we must extend do so. If OP is a SUBREG for a promoted object, also 19496263Sobrien extend since it will be more efficient to do so unless the signedness of 19596263Sobrien a promoted object differs from our extension. */ 19618334Speter if (! no_extend 19796263Sobrien || (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op) 19896263Sobrien && SUBREG_PROMOTED_UNSIGNED_P (op) == unsignedp)) 19918334Speter return convert_modes (mode, oldmode, op, unsignedp); 20018334Speter 20118334Speter /* If MODE is no wider than a single word, we return a paradoxical 20218334Speter SUBREG. */ 20318334Speter if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) 20450397Sobrien return gen_rtx_SUBREG (mode, force_reg (GET_MODE (op), op), 0); 20518334Speter 20618334Speter /* Otherwise, get an object of MODE, clobber it, and set the low-order 20718334Speter part to OP. */ 20818334Speter 20918334Speter result = gen_reg_rtx (mode); 21050397Sobrien emit_insn (gen_rtx_CLOBBER (VOIDmode, result)); 21118334Speter emit_move_insn (gen_lowpart (GET_MODE (op), result), op); 21218334Speter return result; 21318334Speter} 21418334Speter 21552284Sobrien/* Generate code to perform a straightforward complex divide. */ 21652284Sobrien 21752284Sobrienstatic int 21852284Sobrienexpand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode, 21952284Sobrien unsignedp, methods, class, binoptab) 22052284Sobrien rtx real0, real1, imag0, imag1, realr, imagr; 22152284Sobrien enum machine_mode submode; 22252284Sobrien int unsignedp; 22352284Sobrien enum optab_methods methods; 22452284Sobrien enum mode_class class; 22552284Sobrien optab binoptab; 22652284Sobrien{ 22752284Sobrien rtx divisor; 22852284Sobrien rtx real_t, imag_t; 22952284Sobrien rtx temp1, temp2; 23052284Sobrien rtx res; 23190075Sobrien optab this_add_optab = add_optab; 23290075Sobrien optab this_sub_optab = sub_optab; 23390075Sobrien optab this_neg_optab = neg_optab; 23490075Sobrien optab this_mul_optab = smul_optab; 23552284Sobrien 23690075Sobrien if (binoptab == sdivv_optab) 23790075Sobrien { 23890075Sobrien this_add_optab = addv_optab; 23990075Sobrien this_sub_optab = subv_optab; 24090075Sobrien this_neg_optab = negv_optab; 24190075Sobrien this_mul_optab = smulv_optab; 24290075Sobrien } 24390075Sobrien 24452284Sobrien /* Don't fetch these from memory more than once. */ 24552284Sobrien real0 = force_reg (submode, real0); 24652284Sobrien real1 = force_reg (submode, real1); 24752284Sobrien 24852284Sobrien if (imag0 != 0) 24952284Sobrien imag0 = force_reg (submode, imag0); 25052284Sobrien 25152284Sobrien imag1 = force_reg (submode, imag1); 25252284Sobrien 25352284Sobrien /* Divisor: c*c + d*d. */ 25490075Sobrien temp1 = expand_binop (submode, this_mul_optab, real1, real1, 25552284Sobrien NULL_RTX, unsignedp, methods); 25652284Sobrien 25790075Sobrien temp2 = expand_binop (submode, this_mul_optab, imag1, imag1, 25852284Sobrien NULL_RTX, unsignedp, methods); 25952284Sobrien 26052284Sobrien if (temp1 == 0 || temp2 == 0) 26152284Sobrien return 0; 26252284Sobrien 26390075Sobrien divisor = expand_binop (submode, this_add_optab, temp1, temp2, 26452284Sobrien NULL_RTX, unsignedp, methods); 26552284Sobrien if (divisor == 0) 26652284Sobrien return 0; 26752284Sobrien 26852284Sobrien if (imag0 == 0) 26952284Sobrien { 27052284Sobrien /* Mathematically, ((a)(c-id))/divisor. */ 27152284Sobrien /* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)). */ 27252284Sobrien 27352284Sobrien /* Calculate the dividend. */ 27490075Sobrien real_t = expand_binop (submode, this_mul_optab, real0, real1, 27552284Sobrien NULL_RTX, unsignedp, methods); 27652284Sobrien 27790075Sobrien imag_t = expand_binop (submode, this_mul_optab, real0, imag1, 27852284Sobrien NULL_RTX, unsignedp, methods); 27952284Sobrien 28052284Sobrien if (real_t == 0 || imag_t == 0) 28152284Sobrien return 0; 28252284Sobrien 28390075Sobrien imag_t = expand_unop (submode, this_neg_optab, imag_t, 28452284Sobrien NULL_RTX, unsignedp); 28552284Sobrien } 28652284Sobrien else 28752284Sobrien { 28852284Sobrien /* Mathematically, ((a+ib)(c-id))/divider. */ 28952284Sobrien /* Calculate the dividend. */ 29090075Sobrien temp1 = expand_binop (submode, this_mul_optab, real0, real1, 29152284Sobrien NULL_RTX, unsignedp, methods); 29252284Sobrien 29390075Sobrien temp2 = expand_binop (submode, this_mul_optab, imag0, imag1, 29452284Sobrien NULL_RTX, unsignedp, methods); 29552284Sobrien 29652284Sobrien if (temp1 == 0 || temp2 == 0) 29752284Sobrien return 0; 29852284Sobrien 29990075Sobrien real_t = expand_binop (submode, this_add_optab, temp1, temp2, 30052284Sobrien NULL_RTX, unsignedp, methods); 30152284Sobrien 30290075Sobrien temp1 = expand_binop (submode, this_mul_optab, imag0, real1, 30352284Sobrien NULL_RTX, unsignedp, methods); 30452284Sobrien 30590075Sobrien temp2 = expand_binop (submode, this_mul_optab, real0, imag1, 30652284Sobrien NULL_RTX, unsignedp, methods); 30752284Sobrien 30852284Sobrien if (temp1 == 0 || temp2 == 0) 30952284Sobrien return 0; 31052284Sobrien 31190075Sobrien imag_t = expand_binop (submode, this_sub_optab, temp1, temp2, 31252284Sobrien NULL_RTX, unsignedp, methods); 31352284Sobrien 31452284Sobrien if (real_t == 0 || imag_t == 0) 31552284Sobrien return 0; 31652284Sobrien } 31752284Sobrien 31852284Sobrien if (class == MODE_COMPLEX_FLOAT) 31952284Sobrien res = expand_binop (submode, binoptab, real_t, divisor, 32052284Sobrien realr, unsignedp, methods); 32152284Sobrien else 32252284Sobrien res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 32352284Sobrien real_t, divisor, realr, unsignedp); 32452284Sobrien 32552284Sobrien if (res == 0) 32652284Sobrien return 0; 32752284Sobrien 32852284Sobrien if (res != realr) 32952284Sobrien emit_move_insn (realr, res); 33052284Sobrien 33152284Sobrien if (class == MODE_COMPLEX_FLOAT) 33252284Sobrien res = expand_binop (submode, binoptab, imag_t, divisor, 33352284Sobrien imagr, unsignedp, methods); 33452284Sobrien else 33552284Sobrien res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 33652284Sobrien imag_t, divisor, imagr, unsignedp); 33752284Sobrien 33852284Sobrien if (res == 0) 33952284Sobrien return 0; 34052284Sobrien 34152284Sobrien if (res != imagr) 34252284Sobrien emit_move_insn (imagr, res); 34352284Sobrien 34452284Sobrien return 1; 34552284Sobrien} 34652284Sobrien 34752284Sobrien/* Generate code to perform a wide-input-range-acceptable complex divide. */ 34852284Sobrien 34952284Sobrienstatic int 35052284Sobrienexpand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode, 35152284Sobrien unsignedp, methods, class, binoptab) 35252284Sobrien rtx real0, real1, imag0, imag1, realr, imagr; 35352284Sobrien enum machine_mode submode; 35452284Sobrien int unsignedp; 35552284Sobrien enum optab_methods methods; 35652284Sobrien enum mode_class class; 35752284Sobrien optab binoptab; 35852284Sobrien{ 35952284Sobrien rtx ratio, divisor; 36052284Sobrien rtx real_t, imag_t; 36152284Sobrien rtx temp1, temp2, lab1, lab2; 36252284Sobrien enum machine_mode mode; 36352284Sobrien rtx res; 36490075Sobrien optab this_add_optab = add_optab; 36590075Sobrien optab this_sub_optab = sub_optab; 36690075Sobrien optab this_neg_optab = neg_optab; 36790075Sobrien optab this_mul_optab = smul_optab; 36890075Sobrien 36990075Sobrien if (binoptab == sdivv_optab) 37090075Sobrien { 37190075Sobrien this_add_optab = addv_optab; 37290075Sobrien this_sub_optab = subv_optab; 37390075Sobrien this_neg_optab = negv_optab; 37490075Sobrien this_mul_optab = smulv_optab; 37590075Sobrien } 37652284Sobrien 37752284Sobrien /* Don't fetch these from memory more than once. */ 37852284Sobrien real0 = force_reg (submode, real0); 37952284Sobrien real1 = force_reg (submode, real1); 38052284Sobrien 38152284Sobrien if (imag0 != 0) 38252284Sobrien imag0 = force_reg (submode, imag0); 38352284Sobrien 38452284Sobrien imag1 = force_reg (submode, imag1); 38552284Sobrien 38652284Sobrien /* XXX What's an "unsigned" complex number? */ 38752284Sobrien if (unsignedp) 38852284Sobrien { 38952284Sobrien temp1 = real1; 39052284Sobrien temp2 = imag1; 39152284Sobrien } 39252284Sobrien else 39352284Sobrien { 39490075Sobrien temp1 = expand_abs (submode, real1, NULL_RTX, unsignedp, 1); 39590075Sobrien temp2 = expand_abs (submode, imag1, NULL_RTX, unsignedp, 1); 39652284Sobrien } 39752284Sobrien 39852284Sobrien if (temp1 == 0 || temp2 == 0) 39952284Sobrien return 0; 40052284Sobrien 40152284Sobrien mode = GET_MODE (temp1); 40252284Sobrien lab1 = gen_label_rtx (); 40352284Sobrien emit_cmp_and_jump_insns (temp1, temp2, LT, NULL_RTX, 40490075Sobrien mode, unsignedp, lab1); 40552284Sobrien 40652284Sobrien /* |c| >= |d|; use ratio d/c to scale dividend and divisor. */ 40752284Sobrien 40852284Sobrien if (class == MODE_COMPLEX_FLOAT) 40952284Sobrien ratio = expand_binop (submode, binoptab, imag1, real1, 41052284Sobrien NULL_RTX, unsignedp, methods); 41152284Sobrien else 41252284Sobrien ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode, 41352284Sobrien imag1, real1, NULL_RTX, unsignedp); 41452284Sobrien 41552284Sobrien if (ratio == 0) 41652284Sobrien return 0; 41752284Sobrien 41852284Sobrien /* Calculate divisor. */ 41952284Sobrien 42090075Sobrien temp1 = expand_binop (submode, this_mul_optab, imag1, ratio, 42152284Sobrien NULL_RTX, unsignedp, methods); 42252284Sobrien 42352284Sobrien if (temp1 == 0) 42452284Sobrien return 0; 42552284Sobrien 42690075Sobrien divisor = expand_binop (submode, this_add_optab, temp1, real1, 42752284Sobrien NULL_RTX, unsignedp, methods); 42852284Sobrien 42952284Sobrien if (divisor == 0) 43052284Sobrien return 0; 43152284Sobrien 43252284Sobrien /* Calculate dividend. */ 43352284Sobrien 43452284Sobrien if (imag0 == 0) 43552284Sobrien { 43652284Sobrien real_t = real0; 43752284Sobrien 43852284Sobrien /* Compute a / (c+id) as a / (c+d(d/c)) + i (-a(d/c)) / (c+d(d/c)). */ 43952284Sobrien 44090075Sobrien imag_t = expand_binop (submode, this_mul_optab, real0, ratio, 44152284Sobrien NULL_RTX, unsignedp, methods); 44252284Sobrien 44352284Sobrien if (imag_t == 0) 44452284Sobrien return 0; 44552284Sobrien 44690075Sobrien imag_t = expand_unop (submode, this_neg_optab, imag_t, 44752284Sobrien NULL_RTX, unsignedp); 44852284Sobrien 44952284Sobrien if (real_t == 0 || imag_t == 0) 45052284Sobrien return 0; 45152284Sobrien } 45252284Sobrien else 45352284Sobrien { 45452284Sobrien /* Compute (a+ib)/(c+id) as 45552284Sobrien (a+b(d/c))/(c+d(d/c) + i(b-a(d/c))/(c+d(d/c)). */ 45652284Sobrien 45790075Sobrien temp1 = expand_binop (submode, this_mul_optab, imag0, ratio, 45852284Sobrien NULL_RTX, unsignedp, methods); 45952284Sobrien 46052284Sobrien if (temp1 == 0) 46152284Sobrien return 0; 46252284Sobrien 46390075Sobrien real_t = expand_binop (submode, this_add_optab, temp1, real0, 46452284Sobrien NULL_RTX, unsignedp, methods); 46552284Sobrien 46690075Sobrien temp1 = expand_binop (submode, this_mul_optab, real0, ratio, 46752284Sobrien NULL_RTX, unsignedp, methods); 46852284Sobrien 46952284Sobrien if (temp1 == 0) 47052284Sobrien return 0; 47152284Sobrien 47290075Sobrien imag_t = expand_binop (submode, this_sub_optab, imag0, temp1, 47352284Sobrien NULL_RTX, unsignedp, methods); 47452284Sobrien 47552284Sobrien if (real_t == 0 || imag_t == 0) 47652284Sobrien return 0; 47752284Sobrien } 47852284Sobrien 47952284Sobrien if (class == MODE_COMPLEX_FLOAT) 48052284Sobrien res = expand_binop (submode, binoptab, real_t, divisor, 48152284Sobrien realr, unsignedp, methods); 48252284Sobrien else 48352284Sobrien res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 48452284Sobrien real_t, divisor, realr, unsignedp); 48552284Sobrien 48652284Sobrien if (res == 0) 48752284Sobrien return 0; 48852284Sobrien 48952284Sobrien if (res != realr) 49052284Sobrien emit_move_insn (realr, res); 49152284Sobrien 49252284Sobrien if (class == MODE_COMPLEX_FLOAT) 49352284Sobrien res = expand_binop (submode, binoptab, imag_t, divisor, 49452284Sobrien imagr, unsignedp, methods); 49552284Sobrien else 49652284Sobrien res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 49752284Sobrien imag_t, divisor, imagr, unsignedp); 49852284Sobrien 49952284Sobrien if (res == 0) 50052284Sobrien return 0; 50152284Sobrien 50252284Sobrien if (res != imagr) 50352284Sobrien emit_move_insn (imagr, res); 50452284Sobrien 50552284Sobrien lab2 = gen_label_rtx (); 50652284Sobrien emit_jump_insn (gen_jump (lab2)); 50752284Sobrien emit_barrier (); 50852284Sobrien 50952284Sobrien emit_label (lab1); 51052284Sobrien 51152284Sobrien /* |d| > |c|; use ratio c/d to scale dividend and divisor. */ 51252284Sobrien 51352284Sobrien if (class == MODE_COMPLEX_FLOAT) 51452284Sobrien ratio = expand_binop (submode, binoptab, real1, imag1, 51552284Sobrien NULL_RTX, unsignedp, methods); 51652284Sobrien else 51752284Sobrien ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode, 51852284Sobrien real1, imag1, NULL_RTX, unsignedp); 51952284Sobrien 52052284Sobrien if (ratio == 0) 52152284Sobrien return 0; 52252284Sobrien 52352284Sobrien /* Calculate divisor. */ 52452284Sobrien 52590075Sobrien temp1 = expand_binop (submode, this_mul_optab, real1, ratio, 52652284Sobrien NULL_RTX, unsignedp, methods); 52752284Sobrien 52852284Sobrien if (temp1 == 0) 52952284Sobrien return 0; 53052284Sobrien 53190075Sobrien divisor = expand_binop (submode, this_add_optab, temp1, imag1, 53252284Sobrien NULL_RTX, unsignedp, methods); 53352284Sobrien 53452284Sobrien if (divisor == 0) 53552284Sobrien return 0; 53652284Sobrien 53752284Sobrien /* Calculate dividend. */ 53852284Sobrien 53952284Sobrien if (imag0 == 0) 54052284Sobrien { 54152284Sobrien /* Compute a / (c+id) as a(c/d) / (c(c/d)+d) + i (-a) / (c(c/d)+d). */ 54252284Sobrien 54390075Sobrien real_t = expand_binop (submode, this_mul_optab, real0, ratio, 54452284Sobrien NULL_RTX, unsignedp, methods); 54552284Sobrien 54690075Sobrien imag_t = expand_unop (submode, this_neg_optab, real0, 54752284Sobrien NULL_RTX, unsignedp); 54852284Sobrien 54952284Sobrien if (real_t == 0 || imag_t == 0) 55052284Sobrien return 0; 55152284Sobrien } 55252284Sobrien else 55352284Sobrien { 55452284Sobrien /* Compute (a+ib)/(c+id) as 55552284Sobrien (a(c/d)+b)/(c(c/d)+d) + i (b(c/d)-a)/(c(c/d)+d). */ 55652284Sobrien 55790075Sobrien temp1 = expand_binop (submode, this_mul_optab, real0, ratio, 55852284Sobrien NULL_RTX, unsignedp, methods); 55952284Sobrien 56052284Sobrien if (temp1 == 0) 56152284Sobrien return 0; 56252284Sobrien 56390075Sobrien real_t = expand_binop (submode, this_add_optab, temp1, imag0, 56452284Sobrien NULL_RTX, unsignedp, methods); 56552284Sobrien 56690075Sobrien temp1 = expand_binop (submode, this_mul_optab, imag0, ratio, 56752284Sobrien NULL_RTX, unsignedp, methods); 56852284Sobrien 56952284Sobrien if (temp1 == 0) 57052284Sobrien return 0; 57152284Sobrien 57290075Sobrien imag_t = expand_binop (submode, this_sub_optab, temp1, real0, 57352284Sobrien NULL_RTX, unsignedp, methods); 57452284Sobrien 57552284Sobrien if (real_t == 0 || imag_t == 0) 57652284Sobrien return 0; 57752284Sobrien } 57852284Sobrien 57952284Sobrien if (class == MODE_COMPLEX_FLOAT) 58052284Sobrien res = expand_binop (submode, binoptab, real_t, divisor, 58152284Sobrien realr, unsignedp, methods); 58252284Sobrien else 58352284Sobrien res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 58452284Sobrien real_t, divisor, realr, unsignedp); 58552284Sobrien 58652284Sobrien if (res == 0) 58752284Sobrien return 0; 58852284Sobrien 58952284Sobrien if (res != realr) 59052284Sobrien emit_move_insn (realr, res); 59152284Sobrien 59252284Sobrien if (class == MODE_COMPLEX_FLOAT) 59352284Sobrien res = expand_binop (submode, binoptab, imag_t, divisor, 59452284Sobrien imagr, unsignedp, methods); 59552284Sobrien else 59652284Sobrien res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 59752284Sobrien imag_t, divisor, imagr, unsignedp); 59852284Sobrien 59952284Sobrien if (res == 0) 60052284Sobrien return 0; 60152284Sobrien 60252284Sobrien if (res != imagr) 60352284Sobrien emit_move_insn (imagr, res); 60452284Sobrien 60552284Sobrien emit_label (lab2); 60652284Sobrien 60752284Sobrien return 1; 60852284Sobrien} 60952284Sobrien 61090075Sobrien/* Wrapper around expand_binop which takes an rtx code to specify 61190075Sobrien the operation to perform, not an optab pointer. All other 61290075Sobrien arguments are the same. */ 61390075Sobrienrtx 61490075Sobrienexpand_simple_binop (mode, code, op0, op1, target, unsignedp, methods) 61590075Sobrien enum machine_mode mode; 61690075Sobrien enum rtx_code code; 61790075Sobrien rtx op0, op1; 61890075Sobrien rtx target; 61990075Sobrien int unsignedp; 62090075Sobrien enum optab_methods methods; 62190075Sobrien{ 62290075Sobrien optab binop = code_to_optab [(int) code]; 62390075Sobrien if (binop == 0) 62490075Sobrien abort (); 62590075Sobrien 62690075Sobrien return expand_binop (mode, binop, op0, op1, target, unsignedp, methods); 62790075Sobrien} 62890075Sobrien 62918334Speter/* Generate code to perform an operation specified by BINOPTAB 63018334Speter on operands OP0 and OP1, with result having machine-mode MODE. 63118334Speter 63218334Speter UNSIGNEDP is for the case where we have to widen the operands 63318334Speter to perform the operation. It says to use zero-extension. 63418334Speter 63518334Speter If TARGET is nonzero, the value 63618334Speter is generated there, if it is convenient to do so. 63718334Speter In all cases an rtx is returned for the locus of the value; 63818334Speter this may or may not be TARGET. */ 63918334Speter 64018334Speterrtx 64118334Speterexpand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) 64218334Speter enum machine_mode mode; 64318334Speter optab binoptab; 64418334Speter rtx op0, op1; 64518334Speter rtx target; 64618334Speter int unsignedp; 64718334Speter enum optab_methods methods; 64818334Speter{ 64918334Speter enum optab_methods next_methods 65018334Speter = (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN 65118334Speter ? OPTAB_WIDEN : methods); 65218334Speter enum mode_class class; 65318334Speter enum machine_mode wider_mode; 65490075Sobrien rtx temp; 65518334Speter int commutative_op = 0; 65618334Speter int shift_op = (binoptab->code == ASHIFT 65718334Speter || binoptab->code == ASHIFTRT 65818334Speter || binoptab->code == LSHIFTRT 65918334Speter || binoptab->code == ROTATE 66018334Speter || binoptab->code == ROTATERT); 66118334Speter rtx entry_last = get_last_insn (); 66218334Speter rtx last; 66318334Speter 66418334Speter class = GET_MODE_CLASS (mode); 66518334Speter 66618334Speter op0 = protect_from_queue (op0, 0); 66718334Speter op1 = protect_from_queue (op1, 0); 66818334Speter if (target) 66918334Speter target = protect_from_queue (target, 1); 67018334Speter 67118334Speter if (flag_force_mem) 67218334Speter { 67318334Speter op0 = force_not_mem (op0); 67418334Speter op1 = force_not_mem (op1); 67518334Speter } 67618334Speter 67718334Speter /* If subtracting an integer constant, convert this into an addition of 67818334Speter the negated constant. */ 67918334Speter 68018334Speter if (binoptab == sub_optab && GET_CODE (op1) == CONST_INT) 68118334Speter { 68218334Speter op1 = negate_rtx (mode, op1); 68318334Speter binoptab = add_optab; 68418334Speter } 68518334Speter 68618334Speter /* If we are inside an appropriately-short loop and one operand is an 68718334Speter expensive constant, force it into a register. */ 68818334Speter if (CONSTANT_P (op0) && preserve_subexpressions_p () 68990075Sobrien && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1)) 69018334Speter op0 = force_reg (mode, op0); 69118334Speter 69218334Speter if (CONSTANT_P (op1) && preserve_subexpressions_p () 69390075Sobrien && ! shift_op && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1)) 69418334Speter op1 = force_reg (mode, op1); 69518334Speter 69618334Speter /* Record where to delete back to if we backtrack. */ 69718334Speter last = get_last_insn (); 69818334Speter 69918334Speter /* If operation is commutative, 70018334Speter try to make the first operand a register. 70118334Speter Even better, try to make it the same as the target. 70218334Speter Also try to make the last operand a constant. */ 70318334Speter if (GET_RTX_CLASS (binoptab->code) == 'c' 70418334Speter || binoptab == smul_widen_optab 70518334Speter || binoptab == umul_widen_optab 70618334Speter || binoptab == smul_highpart_optab 70718334Speter || binoptab == umul_highpart_optab) 70818334Speter { 70918334Speter commutative_op = 1; 71018334Speter 71118334Speter if (((target == 0 || GET_CODE (target) == REG) 71218334Speter ? ((GET_CODE (op1) == REG 71318334Speter && GET_CODE (op0) != REG) 71418334Speter || target == op1) 71518334Speter : rtx_equal_p (op1, target)) 71618334Speter || GET_CODE (op0) == CONST_INT) 71718334Speter { 71818334Speter temp = op1; 71918334Speter op1 = op0; 72018334Speter op0 = temp; 72118334Speter } 72218334Speter } 72318334Speter 72418334Speter /* If we can do it with a three-operand insn, do so. */ 72518334Speter 72618334Speter if (methods != OPTAB_MUST_WIDEN 72718334Speter && binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 72818334Speter { 72918334Speter int icode = (int) binoptab->handlers[(int) mode].insn_code; 73090075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 73190075Sobrien enum machine_mode mode1 = insn_data[icode].operand[2].mode; 73218334Speter rtx pat; 73318334Speter rtx xop0 = op0, xop1 = op1; 73418334Speter 73518334Speter if (target) 73618334Speter temp = target; 73718334Speter else 73818334Speter temp = gen_reg_rtx (mode); 73918334Speter 74018334Speter /* If it is a commutative operator and the modes would match 74150397Sobrien if we would swap the operands, we can save the conversions. */ 74218334Speter if (commutative_op) 74318334Speter { 74418334Speter if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1 74518334Speter && GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0) 74618334Speter { 74790075Sobrien rtx tmp; 74818334Speter 74918334Speter tmp = op0; op0 = op1; op1 = tmp; 75018334Speter tmp = xop0; xop0 = xop1; xop1 = tmp; 75118334Speter } 75218334Speter } 75318334Speter 75418334Speter /* In case the insn wants input operands in modes different from 755103445Skan those of the actual operands, convert the operands. It would 756103445Skan seem that we don't need to convert CONST_INTs, but we do, so 757103445Skan that they're properly zero-extended or sign-extended for their 758103445Skan modes; shift operations are an exception, because the second 759103445Skan operand needs not be extended to the mode of the result. */ 76018334Speter 76190075Sobrien if (GET_MODE (op0) != mode0 76218334Speter && mode0 != VOIDmode) 76390075Sobrien xop0 = convert_modes (mode0, 76490075Sobrien GET_MODE (op0) != VOIDmode 76590075Sobrien ? GET_MODE (op0) 766103445Skan : mode, 76790075Sobrien xop0, unsignedp); 76818334Speter 76990075Sobrien if (GET_MODE (xop1) != mode1 77018334Speter && mode1 != VOIDmode) 77190075Sobrien xop1 = convert_modes (mode1, 77290075Sobrien GET_MODE (op1) != VOIDmode 77390075Sobrien ? GET_MODE (op1) 774103445Skan : ! shift_op 77590075Sobrien ? mode 77690075Sobrien : mode1, 77790075Sobrien xop1, unsignedp); 77818334Speter 77918334Speter /* Now, if insn's predicates don't allow our operands, put them into 78018334Speter pseudo regs. */ 78118334Speter 78290075Sobrien if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0) 78318334Speter && mode0 != VOIDmode) 78418334Speter xop0 = copy_to_mode_reg (mode0, xop0); 78518334Speter 78690075Sobrien if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1) 78718334Speter && mode1 != VOIDmode) 78818334Speter xop1 = copy_to_mode_reg (mode1, xop1); 78918334Speter 79090075Sobrien if (! (*insn_data[icode].operand[0].predicate) (temp, mode)) 79118334Speter temp = gen_reg_rtx (mode); 79218334Speter 79318334Speter pat = GEN_FCN (icode) (temp, xop0, xop1); 79418334Speter if (pat) 79518334Speter { 79618334Speter /* If PAT is a multi-insn sequence, try to add an appropriate 79718334Speter REG_EQUAL note to it. If we can't because TEMP conflicts with an 79818334Speter operand, call ourselves again, this time without a target. */ 79918334Speter if (GET_CODE (pat) == SEQUENCE 80018334Speter && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1)) 80118334Speter { 80218334Speter delete_insns_since (last); 80318334Speter return expand_binop (mode, binoptab, op0, op1, NULL_RTX, 80418334Speter unsignedp, methods); 80518334Speter } 80618334Speter 80718334Speter emit_insn (pat); 80818334Speter return temp; 80918334Speter } 81018334Speter else 81118334Speter delete_insns_since (last); 81218334Speter } 81318334Speter 81418334Speter /* If this is a multiply, see if we can do a widening operation that 81518334Speter takes operands of this mode and makes a wider mode. */ 81618334Speter 81718334Speter if (binoptab == smul_optab && GET_MODE_WIDER_MODE (mode) != VOIDmode 81818334Speter && (((unsignedp ? umul_widen_optab : smul_widen_optab) 81918334Speter ->handlers[(int) GET_MODE_WIDER_MODE (mode)].insn_code) 82018334Speter != CODE_FOR_nothing)) 82118334Speter { 82218334Speter temp = expand_binop (GET_MODE_WIDER_MODE (mode), 82318334Speter unsignedp ? umul_widen_optab : smul_widen_optab, 82418334Speter op0, op1, NULL_RTX, unsignedp, OPTAB_DIRECT); 82518334Speter 82618334Speter if (temp != 0) 82718334Speter { 82818334Speter if (GET_MODE_CLASS (mode) == MODE_INT) 82918334Speter return gen_lowpart (mode, temp); 83018334Speter else 83118334Speter return convert_to_mode (mode, temp, unsignedp); 83218334Speter } 83318334Speter } 83418334Speter 83518334Speter /* Look for a wider mode of the same class for which we think we 83618334Speter can open-code the operation. Check for a widening multiply at the 83718334Speter wider mode as well. */ 83818334Speter 83918334Speter if ((class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) 84018334Speter && methods != OPTAB_DIRECT && methods != OPTAB_LIB) 84118334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 84218334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 84318334Speter { 84418334Speter if (binoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing 84518334Speter || (binoptab == smul_optab 84618334Speter && GET_MODE_WIDER_MODE (wider_mode) != VOIDmode 84718334Speter && (((unsignedp ? umul_widen_optab : smul_widen_optab) 84818334Speter ->handlers[(int) GET_MODE_WIDER_MODE (wider_mode)].insn_code) 84918334Speter != CODE_FOR_nothing))) 85018334Speter { 85118334Speter rtx xop0 = op0, xop1 = op1; 85218334Speter int no_extend = 0; 85318334Speter 85418334Speter /* For certain integer operations, we need not actually extend 85518334Speter the narrow operands, as long as we will truncate 85690075Sobrien the results to the same narrowness. */ 85718334Speter 85818334Speter if ((binoptab == ior_optab || binoptab == and_optab 85918334Speter || binoptab == xor_optab 86018334Speter || binoptab == add_optab || binoptab == sub_optab 86118334Speter || binoptab == smul_optab || binoptab == ashl_optab) 86218334Speter && class == MODE_INT) 86318334Speter no_extend = 1; 86418334Speter 86518334Speter xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, no_extend); 86618334Speter 86718334Speter /* The second operand of a shift must always be extended. */ 86818334Speter xop1 = widen_operand (xop1, wider_mode, mode, unsignedp, 86918334Speter no_extend && binoptab != ashl_optab); 87018334Speter 87118334Speter temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX, 87218334Speter unsignedp, OPTAB_DIRECT); 87318334Speter if (temp) 87418334Speter { 87518334Speter if (class != MODE_INT) 87618334Speter { 87718334Speter if (target == 0) 87818334Speter target = gen_reg_rtx (mode); 87918334Speter convert_move (target, temp, 0); 88018334Speter return target; 88118334Speter } 88218334Speter else 88318334Speter return gen_lowpart (mode, temp); 88418334Speter } 88518334Speter else 88618334Speter delete_insns_since (last); 88718334Speter } 88818334Speter } 88918334Speter 89018334Speter /* These can be done a word at a time. */ 89118334Speter if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab) 89218334Speter && class == MODE_INT 89318334Speter && GET_MODE_SIZE (mode) > UNITS_PER_WORD 89418334Speter && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 89518334Speter { 89618334Speter int i; 89718334Speter rtx insns; 89818334Speter rtx equiv_value; 89918334Speter 90018334Speter /* If TARGET is the same as one of the operands, the REG_EQUAL note 90118334Speter won't be accurate, so use a new target. */ 90218334Speter if (target == 0 || target == op0 || target == op1) 90318334Speter target = gen_reg_rtx (mode); 90418334Speter 90518334Speter start_sequence (); 90618334Speter 90718334Speter /* Do the actual arithmetic. */ 90818334Speter for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++) 90918334Speter { 91018334Speter rtx target_piece = operand_subword (target, i, 1, mode); 91118334Speter rtx x = expand_binop (word_mode, binoptab, 91218334Speter operand_subword_force (op0, i, mode), 91318334Speter operand_subword_force (op1, i, mode), 91418334Speter target_piece, unsignedp, next_methods); 91518334Speter 91618334Speter if (x == 0) 91718334Speter break; 91818334Speter 91918334Speter if (target_piece != x) 92018334Speter emit_move_insn (target_piece, x); 92118334Speter } 92218334Speter 92318334Speter insns = get_insns (); 92418334Speter end_sequence (); 92518334Speter 92618334Speter if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD) 92718334Speter { 92818334Speter if (binoptab->code != UNKNOWN) 92918334Speter equiv_value 93050397Sobrien = gen_rtx_fmt_ee (binoptab->code, mode, 93150397Sobrien copy_rtx (op0), copy_rtx (op1)); 93218334Speter else 93318334Speter equiv_value = 0; 93418334Speter 93518334Speter emit_no_conflict_block (insns, target, op0, op1, equiv_value); 93618334Speter return target; 93718334Speter } 93818334Speter } 93918334Speter 94018334Speter /* Synthesize double word shifts from single word shifts. */ 94118334Speter if ((binoptab == lshr_optab || binoptab == ashl_optab 94218334Speter || binoptab == ashr_optab) 94318334Speter && class == MODE_INT 94418334Speter && GET_CODE (op1) == CONST_INT 94518334Speter && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD 94618334Speter && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing 94718334Speter && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing 94818334Speter && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 94918334Speter { 95018334Speter rtx insns, inter, equiv_value; 95118334Speter rtx into_target, outof_target; 95218334Speter rtx into_input, outof_input; 95318334Speter int shift_count, left_shift, outof_word; 95418334Speter 95518334Speter /* If TARGET is the same as one of the operands, the REG_EQUAL note 95618334Speter won't be accurate, so use a new target. */ 95718334Speter if (target == 0 || target == op0 || target == op1) 95818334Speter target = gen_reg_rtx (mode); 95918334Speter 96018334Speter start_sequence (); 96118334Speter 96218334Speter shift_count = INTVAL (op1); 96318334Speter 96418334Speter /* OUTOF_* is the word we are shifting bits away from, and 96518334Speter INTO_* is the word that we are shifting bits towards, thus 96618334Speter they differ depending on the direction of the shift and 96718334Speter WORDS_BIG_ENDIAN. */ 96818334Speter 96918334Speter left_shift = binoptab == ashl_optab; 97018334Speter outof_word = left_shift ^ ! WORDS_BIG_ENDIAN; 97118334Speter 97218334Speter outof_target = operand_subword (target, outof_word, 1, mode); 97318334Speter into_target = operand_subword (target, 1 - outof_word, 1, mode); 97418334Speter 97518334Speter outof_input = operand_subword_force (op0, outof_word, mode); 97618334Speter into_input = operand_subword_force (op0, 1 - outof_word, mode); 97718334Speter 97818334Speter if (shift_count >= BITS_PER_WORD) 97918334Speter { 98018334Speter inter = expand_binop (word_mode, binoptab, 98118334Speter outof_input, 98218334Speter GEN_INT (shift_count - BITS_PER_WORD), 98318334Speter into_target, unsignedp, next_methods); 98418334Speter 98518334Speter if (inter != 0 && inter != into_target) 98618334Speter emit_move_insn (into_target, inter); 98718334Speter 98818334Speter /* For a signed right shift, we must fill the word we are shifting 98918334Speter out of with copies of the sign bit. Otherwise it is zeroed. */ 99018334Speter if (inter != 0 && binoptab != ashr_optab) 99118334Speter inter = CONST0_RTX (word_mode); 99218334Speter else if (inter != 0) 99318334Speter inter = expand_binop (word_mode, binoptab, 99418334Speter outof_input, 99518334Speter GEN_INT (BITS_PER_WORD - 1), 99618334Speter outof_target, unsignedp, next_methods); 99718334Speter 99818334Speter if (inter != 0 && inter != outof_target) 99918334Speter emit_move_insn (outof_target, inter); 100018334Speter } 100118334Speter else 100218334Speter { 100318334Speter rtx carries; 100418334Speter optab reverse_unsigned_shift, unsigned_shift; 100518334Speter 100618334Speter /* For a shift of less then BITS_PER_WORD, to compute the carry, 100718334Speter we must do a logical shift in the opposite direction of the 100818334Speter desired shift. */ 100918334Speter 101018334Speter reverse_unsigned_shift = (left_shift ? lshr_optab : ashl_optab); 101118334Speter 101218334Speter /* For a shift of less than BITS_PER_WORD, to compute the word 101318334Speter shifted towards, we need to unsigned shift the orig value of 101418334Speter that word. */ 101518334Speter 101618334Speter unsigned_shift = (left_shift ? ashl_optab : lshr_optab); 101718334Speter 101818334Speter carries = expand_binop (word_mode, reverse_unsigned_shift, 101918334Speter outof_input, 102018334Speter GEN_INT (BITS_PER_WORD - shift_count), 102118334Speter 0, unsignedp, next_methods); 102218334Speter 102318334Speter if (carries == 0) 102418334Speter inter = 0; 102518334Speter else 102618334Speter inter = expand_binop (word_mode, unsigned_shift, into_input, 102718334Speter op1, 0, unsignedp, next_methods); 102818334Speter 102918334Speter if (inter != 0) 103018334Speter inter = expand_binop (word_mode, ior_optab, carries, inter, 103118334Speter into_target, unsignedp, next_methods); 103218334Speter 103318334Speter if (inter != 0 && inter != into_target) 103418334Speter emit_move_insn (into_target, inter); 103518334Speter 103618334Speter if (inter != 0) 103718334Speter inter = expand_binop (word_mode, binoptab, outof_input, 103818334Speter op1, outof_target, unsignedp, next_methods); 103918334Speter 104018334Speter if (inter != 0 && inter != outof_target) 104118334Speter emit_move_insn (outof_target, inter); 104218334Speter } 104318334Speter 104418334Speter insns = get_insns (); 104518334Speter end_sequence (); 104618334Speter 104718334Speter if (inter != 0) 104818334Speter { 104918334Speter if (binoptab->code != UNKNOWN) 105050397Sobrien equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1); 105118334Speter else 105218334Speter equiv_value = 0; 105318334Speter 105418334Speter emit_no_conflict_block (insns, target, op0, op1, equiv_value); 105518334Speter return target; 105618334Speter } 105718334Speter } 105818334Speter 105918334Speter /* Synthesize double word rotates from single word shifts. */ 106018334Speter if ((binoptab == rotl_optab || binoptab == rotr_optab) 106118334Speter && class == MODE_INT 106218334Speter && GET_CODE (op1) == CONST_INT 106318334Speter && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD 106418334Speter && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing 106518334Speter && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 106618334Speter { 106718334Speter rtx insns, equiv_value; 106818334Speter rtx into_target, outof_target; 106918334Speter rtx into_input, outof_input; 107018334Speter rtx inter; 107118334Speter int shift_count, left_shift, outof_word; 107218334Speter 107318334Speter /* If TARGET is the same as one of the operands, the REG_EQUAL note 107418334Speter won't be accurate, so use a new target. */ 107518334Speter if (target == 0 || target == op0 || target == op1) 107618334Speter target = gen_reg_rtx (mode); 107718334Speter 107818334Speter start_sequence (); 107918334Speter 108018334Speter shift_count = INTVAL (op1); 108118334Speter 108218334Speter /* OUTOF_* is the word we are shifting bits away from, and 108318334Speter INTO_* is the word that we are shifting bits towards, thus 108418334Speter they differ depending on the direction of the shift and 108518334Speter WORDS_BIG_ENDIAN. */ 108618334Speter 108718334Speter left_shift = (binoptab == rotl_optab); 108818334Speter outof_word = left_shift ^ ! WORDS_BIG_ENDIAN; 108918334Speter 109018334Speter outof_target = operand_subword (target, outof_word, 1, mode); 109118334Speter into_target = operand_subword (target, 1 - outof_word, 1, mode); 109218334Speter 109318334Speter outof_input = operand_subword_force (op0, outof_word, mode); 109418334Speter into_input = operand_subword_force (op0, 1 - outof_word, mode); 109518334Speter 109618334Speter if (shift_count == BITS_PER_WORD) 109718334Speter { 109818334Speter /* This is just a word swap. */ 109918334Speter emit_move_insn (outof_target, into_input); 110018334Speter emit_move_insn (into_target, outof_input); 110118334Speter inter = const0_rtx; 110218334Speter } 110318334Speter else 110418334Speter { 110518334Speter rtx into_temp1, into_temp2, outof_temp1, outof_temp2; 110618334Speter rtx first_shift_count, second_shift_count; 110718334Speter optab reverse_unsigned_shift, unsigned_shift; 110818334Speter 110918334Speter reverse_unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD) 111018334Speter ? lshr_optab : ashl_optab); 111118334Speter 111218334Speter unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD) 111318334Speter ? ashl_optab : lshr_optab); 111418334Speter 111518334Speter if (shift_count > BITS_PER_WORD) 111618334Speter { 111718334Speter first_shift_count = GEN_INT (shift_count - BITS_PER_WORD); 111818334Speter second_shift_count = GEN_INT (2*BITS_PER_WORD - shift_count); 111918334Speter } 112018334Speter else 112118334Speter { 112218334Speter first_shift_count = GEN_INT (BITS_PER_WORD - shift_count); 112318334Speter second_shift_count = GEN_INT (shift_count); 112418334Speter } 112518334Speter 112618334Speter into_temp1 = expand_binop (word_mode, unsigned_shift, 112718334Speter outof_input, first_shift_count, 112818334Speter NULL_RTX, unsignedp, next_methods); 112918334Speter into_temp2 = expand_binop (word_mode, reverse_unsigned_shift, 113018334Speter into_input, second_shift_count, 113118334Speter into_target, unsignedp, next_methods); 113218334Speter 113318334Speter if (into_temp1 != 0 && into_temp2 != 0) 113418334Speter inter = expand_binop (word_mode, ior_optab, into_temp1, into_temp2, 113518334Speter into_target, unsignedp, next_methods); 113618334Speter else 113718334Speter inter = 0; 113818334Speter 113918334Speter if (inter != 0 && inter != into_target) 114018334Speter emit_move_insn (into_target, inter); 114118334Speter 114218334Speter outof_temp1 = expand_binop (word_mode, unsigned_shift, 114318334Speter into_input, first_shift_count, 114418334Speter NULL_RTX, unsignedp, next_methods); 114518334Speter outof_temp2 = expand_binop (word_mode, reverse_unsigned_shift, 114618334Speter outof_input, second_shift_count, 114718334Speter outof_target, unsignedp, next_methods); 114818334Speter 114918334Speter if (inter != 0 && outof_temp1 != 0 && outof_temp2 != 0) 115018334Speter inter = expand_binop (word_mode, ior_optab, 115118334Speter outof_temp1, outof_temp2, 115218334Speter outof_target, unsignedp, next_methods); 115318334Speter 115418334Speter if (inter != 0 && inter != outof_target) 115518334Speter emit_move_insn (outof_target, inter); 115618334Speter } 115718334Speter 115818334Speter insns = get_insns (); 115918334Speter end_sequence (); 116018334Speter 116118334Speter if (inter != 0) 116218334Speter { 116318334Speter if (binoptab->code != UNKNOWN) 116450397Sobrien equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1); 116518334Speter else 116618334Speter equiv_value = 0; 116718334Speter 116818334Speter /* We can't make this a no conflict block if this is a word swap, 116918334Speter because the word swap case fails if the input and output values 117018334Speter are in the same register. */ 117118334Speter if (shift_count != BITS_PER_WORD) 117218334Speter emit_no_conflict_block (insns, target, op0, op1, equiv_value); 117318334Speter else 117418334Speter emit_insns (insns); 117518334Speter 117618334Speter 117718334Speter return target; 117818334Speter } 117918334Speter } 118018334Speter 118118334Speter /* These can be done a word at a time by propagating carries. */ 118218334Speter if ((binoptab == add_optab || binoptab == sub_optab) 118318334Speter && class == MODE_INT 118418334Speter && GET_MODE_SIZE (mode) >= 2 * UNITS_PER_WORD 118518334Speter && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 118618334Speter { 118718334Speter int i; 118818334Speter optab otheroptab = binoptab == add_optab ? sub_optab : add_optab; 1189102780Skan int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD; 119052284Sobrien rtx carry_in = NULL_RTX, carry_out = NULL_RTX; 1191102780Skan rtx xop0, xop1, xtarget; 119218334Speter 119318334Speter /* We can handle either a 1 or -1 value for the carry. If STORE_FLAG 119418334Speter value is one of those, use it. Otherwise, use 1 since it is the 119518334Speter one easiest to get. */ 119618334Speter#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1 119718334Speter int normalizep = STORE_FLAG_VALUE; 119818334Speter#else 119918334Speter int normalizep = 1; 120018334Speter#endif 120118334Speter 120218334Speter /* Prepare the operands. */ 120318334Speter xop0 = force_reg (mode, op0); 120418334Speter xop1 = force_reg (mode, op1); 120518334Speter 1206102780Skan xtarget = gen_reg_rtx (mode); 120718334Speter 1208102780Skan if (target == 0 || GET_CODE (target) != REG) 1209102780Skan target = xtarget; 1210102780Skan 121118334Speter /* Indicate for flow that the entire target reg is being set. */ 121218334Speter if (GET_CODE (target) == REG) 1213102780Skan emit_insn (gen_rtx_CLOBBER (VOIDmode, xtarget)); 121418334Speter 121518334Speter /* Do the actual arithmetic. */ 121618334Speter for (i = 0; i < nwords; i++) 121718334Speter { 121818334Speter int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i); 1219102780Skan rtx target_piece = operand_subword (xtarget, index, 1, mode); 122018334Speter rtx op0_piece = operand_subword_force (xop0, index, mode); 122118334Speter rtx op1_piece = operand_subword_force (xop1, index, mode); 122218334Speter rtx x; 122318334Speter 122418334Speter /* Main add/subtract of the input operands. */ 122518334Speter x = expand_binop (word_mode, binoptab, 122618334Speter op0_piece, op1_piece, 122718334Speter target_piece, unsignedp, next_methods); 122818334Speter if (x == 0) 122918334Speter break; 123018334Speter 123118334Speter if (i + 1 < nwords) 123218334Speter { 123318334Speter /* Store carry from main add/subtract. */ 123418334Speter carry_out = gen_reg_rtx (word_mode); 123550397Sobrien carry_out = emit_store_flag_force (carry_out, 123650397Sobrien (binoptab == add_optab 123790075Sobrien ? LT : GT), 123850397Sobrien x, op0_piece, 123950397Sobrien word_mode, 1, normalizep); 124018334Speter } 124118334Speter 124218334Speter if (i > 0) 124318334Speter { 124490075Sobrien rtx newx; 124590075Sobrien 124618334Speter /* Add/subtract previous carry to main result. */ 124790075Sobrien newx = expand_binop (word_mode, 124890075Sobrien normalizep == 1 ? binoptab : otheroptab, 124990075Sobrien x, carry_in, 125090075Sobrien NULL_RTX, 1, next_methods); 125118334Speter 125218334Speter if (i + 1 < nwords) 125318334Speter { 125418334Speter /* Get out carry from adding/subtracting carry in. */ 125590075Sobrien rtx carry_tmp = gen_reg_rtx (word_mode); 125650397Sobrien carry_tmp = emit_store_flag_force (carry_tmp, 125790075Sobrien (binoptab == add_optab 125890075Sobrien ? LT : GT), 125990075Sobrien newx, x, 126050397Sobrien word_mode, 1, normalizep); 126118334Speter 126218334Speter /* Logical-ior the two poss. carry together. */ 126318334Speter carry_out = expand_binop (word_mode, ior_optab, 126418334Speter carry_out, carry_tmp, 126518334Speter carry_out, 0, next_methods); 126618334Speter if (carry_out == 0) 126718334Speter break; 126818334Speter } 126990075Sobrien emit_move_insn (target_piece, newx); 127018334Speter } 127118334Speter 127218334Speter carry_in = carry_out; 127318334Speter } 127418334Speter 127518334Speter if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD) 127618334Speter { 127750397Sobrien if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 127850397Sobrien { 1279102780Skan rtx temp = emit_move_insn (target, xtarget); 128018334Speter 128152284Sobrien set_unique_reg_note (temp, 128252284Sobrien REG_EQUAL, 128352284Sobrien gen_rtx_fmt_ee (binoptab->code, mode, 128452284Sobrien copy_rtx (xop0), 128552284Sobrien copy_rtx (xop1))); 128650397Sobrien } 128790075Sobrien 128818334Speter return target; 128918334Speter } 129090075Sobrien 129118334Speter else 129218334Speter delete_insns_since (last); 129318334Speter } 129418334Speter 129518334Speter /* If we want to multiply two two-word values and have normal and widening 129618334Speter multiplies of single-word values, we can do this with three smaller 129718334Speter multiplications. Note that we do not make a REG_NO_CONFLICT block here 129818334Speter because we are not operating on one word at a time. 129918334Speter 130018334Speter The multiplication proceeds as follows: 130118334Speter _______________________ 130218334Speter [__op0_high_|__op0_low__] 130318334Speter _______________________ 130418334Speter * [__op1_high_|__op1_low__] 130518334Speter _______________________________________________ 130618334Speter _______________________ 130718334Speter (1) [__op0_low__*__op1_low__] 130818334Speter _______________________ 130918334Speter (2a) [__op0_low__*__op1_high_] 131018334Speter _______________________ 131118334Speter (2b) [__op0_high_*__op1_low__] 131218334Speter _______________________ 131318334Speter (3) [__op0_high_*__op1_high_] 131418334Speter 131518334Speter 131618334Speter This gives a 4-word result. Since we are only interested in the 131718334Speter lower 2 words, partial result (3) and the upper words of (2a) and 131818334Speter (2b) don't need to be calculated. Hence (2a) and (2b) can be 131918334Speter calculated using non-widening multiplication. 132018334Speter 132118334Speter (1), however, needs to be calculated with an unsigned widening 132218334Speter multiplication. If this operation is not directly supported we 132318334Speter try using a signed widening multiplication and adjust the result. 132418334Speter This adjustment works as follows: 132518334Speter 132618334Speter If both operands are positive then no adjustment is needed. 132718334Speter 132818334Speter If the operands have different signs, for example op0_low < 0 and 132918334Speter op1_low >= 0, the instruction treats the most significant bit of 133018334Speter op0_low as a sign bit instead of a bit with significance 133118334Speter 2**(BITS_PER_WORD-1), i.e. the instruction multiplies op1_low 133218334Speter with 2**BITS_PER_WORD - op0_low, and two's complements the 133318334Speter result. Conclusion: We need to add op1_low * 2**BITS_PER_WORD to 133418334Speter the result. 133518334Speter 133618334Speter Similarly, if both operands are negative, we need to add 133718334Speter (op0_low + op1_low) * 2**BITS_PER_WORD. 133818334Speter 133918334Speter We use a trick to adjust quickly. We logically shift op0_low right 134018334Speter (op1_low) BITS_PER_WORD-1 steps to get 0 or 1, and add this to 134118334Speter op0_high (op1_high) before it is used to calculate 2b (2a). If no 134218334Speter logical shift exists, we do an arithmetic right shift and subtract 134318334Speter the 0 or -1. */ 134418334Speter 134518334Speter if (binoptab == smul_optab 134618334Speter && class == MODE_INT 134718334Speter && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD 134818334Speter && smul_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing 134918334Speter && add_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing 135018334Speter && ((umul_widen_optab->handlers[(int) mode].insn_code 135118334Speter != CODE_FOR_nothing) 135218334Speter || (smul_widen_optab->handlers[(int) mode].insn_code 135318334Speter != CODE_FOR_nothing))) 135418334Speter { 135518334Speter int low = (WORDS_BIG_ENDIAN ? 1 : 0); 135618334Speter int high = (WORDS_BIG_ENDIAN ? 0 : 1); 135718334Speter rtx op0_high = operand_subword_force (op0, high, mode); 135818334Speter rtx op0_low = operand_subword_force (op0, low, mode); 135918334Speter rtx op1_high = operand_subword_force (op1, high, mode); 136018334Speter rtx op1_low = operand_subword_force (op1, low, mode); 136118334Speter rtx product = 0; 136252284Sobrien rtx op0_xhigh = NULL_RTX; 136352284Sobrien rtx op1_xhigh = NULL_RTX; 136418334Speter 136518334Speter /* If the target is the same as one of the inputs, don't use it. This 136618334Speter prevents problems with the REG_EQUAL note. */ 136718334Speter if (target == op0 || target == op1 136818334Speter || (target != 0 && GET_CODE (target) != REG)) 136918334Speter target = 0; 137018334Speter 137118334Speter /* Multiply the two lower words to get a double-word product. 137218334Speter If unsigned widening multiplication is available, use that; 137318334Speter otherwise use the signed form and compensate. */ 137418334Speter 137518334Speter if (umul_widen_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 137618334Speter { 137718334Speter product = expand_binop (mode, umul_widen_optab, op0_low, op1_low, 137818334Speter target, 1, OPTAB_DIRECT); 137918334Speter 138018334Speter /* If we didn't succeed, delete everything we did so far. */ 138118334Speter if (product == 0) 138218334Speter delete_insns_since (last); 138318334Speter else 138418334Speter op0_xhigh = op0_high, op1_xhigh = op1_high; 138518334Speter } 138618334Speter 138718334Speter if (product == 0 138818334Speter && smul_widen_optab->handlers[(int) mode].insn_code 138918334Speter != CODE_FOR_nothing) 139018334Speter { 139118334Speter rtx wordm1 = GEN_INT (BITS_PER_WORD - 1); 139218334Speter product = expand_binop (mode, smul_widen_optab, op0_low, op1_low, 139318334Speter target, 1, OPTAB_DIRECT); 139418334Speter op0_xhigh = expand_binop (word_mode, lshr_optab, op0_low, wordm1, 139518334Speter NULL_RTX, 1, next_methods); 139618334Speter if (op0_xhigh) 139718334Speter op0_xhigh = expand_binop (word_mode, add_optab, op0_high, 139818334Speter op0_xhigh, op0_xhigh, 0, next_methods); 139918334Speter else 140018334Speter { 140118334Speter op0_xhigh = expand_binop (word_mode, ashr_optab, op0_low, wordm1, 140218334Speter NULL_RTX, 0, next_methods); 140318334Speter if (op0_xhigh) 140418334Speter op0_xhigh = expand_binop (word_mode, sub_optab, op0_high, 140518334Speter op0_xhigh, op0_xhigh, 0, 140618334Speter next_methods); 140718334Speter } 140818334Speter 140918334Speter op1_xhigh = expand_binop (word_mode, lshr_optab, op1_low, wordm1, 141018334Speter NULL_RTX, 1, next_methods); 141118334Speter if (op1_xhigh) 141218334Speter op1_xhigh = expand_binop (word_mode, add_optab, op1_high, 141318334Speter op1_xhigh, op1_xhigh, 0, next_methods); 141418334Speter else 141518334Speter { 141618334Speter op1_xhigh = expand_binop (word_mode, ashr_optab, op1_low, wordm1, 141718334Speter NULL_RTX, 0, next_methods); 141818334Speter if (op1_xhigh) 141918334Speter op1_xhigh = expand_binop (word_mode, sub_optab, op1_high, 142018334Speter op1_xhigh, op1_xhigh, 0, 142118334Speter next_methods); 142218334Speter } 142318334Speter } 142418334Speter 142518334Speter /* If we have been able to directly compute the product of the 142618334Speter low-order words of the operands and perform any required adjustments 142718334Speter of the operands, we proceed by trying two more multiplications 142818334Speter and then computing the appropriate sum. 142918334Speter 143018334Speter We have checked above that the required addition is provided. 143118334Speter Full-word addition will normally always succeed, especially if 143218334Speter it is provided at all, so we don't worry about its failure. The 143318334Speter multiplication may well fail, however, so we do handle that. */ 143418334Speter 143518334Speter if (product && op0_xhigh && op1_xhigh) 143618334Speter { 143718334Speter rtx product_high = operand_subword (product, high, 1, mode); 143818334Speter rtx temp = expand_binop (word_mode, binoptab, op0_low, op1_xhigh, 143918334Speter NULL_RTX, 0, OPTAB_DIRECT); 144018334Speter 1441102780Skan if (!REG_P (product_high)) 1442102780Skan product_high = force_reg (word_mode, product_high); 1443102780Skan 144418334Speter if (temp != 0) 144518334Speter temp = expand_binop (word_mode, add_optab, temp, product_high, 144618334Speter product_high, 0, next_methods); 144718334Speter 144818334Speter if (temp != 0 && temp != product_high) 144918334Speter emit_move_insn (product_high, temp); 145018334Speter 145118334Speter if (temp != 0) 145218334Speter temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh, 145318334Speter NULL_RTX, 0, OPTAB_DIRECT); 145418334Speter 145518334Speter if (temp != 0) 145618334Speter temp = expand_binop (word_mode, add_optab, temp, 145718334Speter product_high, product_high, 145818334Speter 0, next_methods); 145918334Speter 146018334Speter if (temp != 0 && temp != product_high) 146118334Speter emit_move_insn (product_high, temp); 146218334Speter 1463102780Skan emit_move_insn (operand_subword (product, high, 1, mode), product_high); 1464102780Skan 146518334Speter if (temp != 0) 146618334Speter { 146750397Sobrien if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 146850397Sobrien { 146950397Sobrien temp = emit_move_insn (product, product); 147052284Sobrien set_unique_reg_note (temp, 147152284Sobrien REG_EQUAL, 147252284Sobrien gen_rtx_fmt_ee (MULT, mode, 147352284Sobrien copy_rtx (op0), 147452284Sobrien copy_rtx (op1))); 147550397Sobrien } 147690075Sobrien 147718334Speter return product; 147818334Speter } 147918334Speter } 148018334Speter 148118334Speter /* If we get here, we couldn't do it for some reason even though we 148218334Speter originally thought we could. Delete anything we've emitted in 148318334Speter trying to do it. */ 148418334Speter 148518334Speter delete_insns_since (last); 148618334Speter } 148718334Speter 148818334Speter /* We need to open-code the complex type operations: '+, -, * and /' */ 148918334Speter 149018334Speter /* At this point we allow operations between two similar complex 149118334Speter numbers, and also if one of the operands is not a complex number 149218334Speter but rather of MODE_FLOAT or MODE_INT. However, the caller 149318334Speter must make sure that the MODE of the non-complex operand matches 149418334Speter the SUBMODE of the complex operand. */ 149518334Speter 149618334Speter if (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT) 149718334Speter { 149818334Speter rtx real0 = 0, imag0 = 0; 149918334Speter rtx real1 = 0, imag1 = 0; 150018334Speter rtx realr, imagr, res; 150118334Speter rtx seq; 150218334Speter rtx equiv_value; 150318334Speter int ok = 0; 150418334Speter 150518334Speter /* Find the correct mode for the real and imaginary parts */ 150618334Speter enum machine_mode submode 150718334Speter = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT, 150818334Speter class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT, 150918334Speter 0); 151018334Speter 151118334Speter if (submode == BLKmode) 151218334Speter abort (); 151318334Speter 151418334Speter if (! target) 151518334Speter target = gen_reg_rtx (mode); 151618334Speter 151718334Speter start_sequence (); 151818334Speter 151952284Sobrien realr = gen_realpart (submode, target); 152018334Speter imagr = gen_imagpart (submode, target); 152118334Speter 152218334Speter if (GET_MODE (op0) == mode) 152318334Speter { 152452284Sobrien real0 = gen_realpart (submode, op0); 152518334Speter imag0 = gen_imagpart (submode, op0); 152618334Speter } 152718334Speter else 152818334Speter real0 = op0; 152918334Speter 153018334Speter if (GET_MODE (op1) == mode) 153118334Speter { 153252284Sobrien real1 = gen_realpart (submode, op1); 153318334Speter imag1 = gen_imagpart (submode, op1); 153418334Speter } 153518334Speter else 153618334Speter real1 = op1; 153718334Speter 153818334Speter if (real0 == 0 || real1 == 0 || ! (imag0 != 0|| imag1 != 0)) 153918334Speter abort (); 154018334Speter 154118334Speter switch (binoptab->code) 154218334Speter { 154318334Speter case PLUS: 154418334Speter /* (a+ib) + (c+id) = (a+c) + i(b+d) */ 154518334Speter case MINUS: 154618334Speter /* (a+ib) - (c+id) = (a-c) + i(b-d) */ 154718334Speter res = expand_binop (submode, binoptab, real0, real1, 154818334Speter realr, unsignedp, methods); 154918334Speter 155018334Speter if (res == 0) 155118334Speter break; 155218334Speter else if (res != realr) 155318334Speter emit_move_insn (realr, res); 155418334Speter 155518334Speter if (imag0 && imag1) 155618334Speter res = expand_binop (submode, binoptab, imag0, imag1, 155718334Speter imagr, unsignedp, methods); 155818334Speter else if (imag0) 155918334Speter res = imag0; 156018334Speter else if (binoptab->code == MINUS) 156190075Sobrien res = expand_unop (submode, 156290075Sobrien binoptab == subv_optab ? negv_optab : neg_optab, 156390075Sobrien imag1, imagr, unsignedp); 156418334Speter else 156518334Speter res = imag1; 156618334Speter 156718334Speter if (res == 0) 156818334Speter break; 156918334Speter else if (res != imagr) 157018334Speter emit_move_insn (imagr, res); 157118334Speter 157218334Speter ok = 1; 157318334Speter break; 157418334Speter 157518334Speter case MULT: 157618334Speter /* (a+ib) * (c+id) = (ac-bd) + i(ad+cb) */ 157718334Speter 157818334Speter if (imag0 && imag1) 157918334Speter { 158018334Speter rtx temp1, temp2; 158118334Speter 158218334Speter /* Don't fetch these from memory more than once. */ 158318334Speter real0 = force_reg (submode, real0); 158418334Speter real1 = force_reg (submode, real1); 158518334Speter imag0 = force_reg (submode, imag0); 158618334Speter imag1 = force_reg (submode, imag1); 158718334Speter 158818334Speter temp1 = expand_binop (submode, binoptab, real0, real1, NULL_RTX, 158918334Speter unsignedp, methods); 159018334Speter 159118334Speter temp2 = expand_binop (submode, binoptab, imag0, imag1, NULL_RTX, 159218334Speter unsignedp, methods); 159318334Speter 159418334Speter if (temp1 == 0 || temp2 == 0) 159518334Speter break; 159618334Speter 159790075Sobrien res = (expand_binop 159890075Sobrien (submode, 159990075Sobrien binoptab == smulv_optab ? subv_optab : sub_optab, 160090075Sobrien temp1, temp2, realr, unsignedp, methods)); 160118334Speter 160218334Speter if (res == 0) 160318334Speter break; 160418334Speter else if (res != realr) 160518334Speter emit_move_insn (realr, res); 160618334Speter 160718334Speter temp1 = expand_binop (submode, binoptab, real0, imag1, 160818334Speter NULL_RTX, unsignedp, methods); 160918334Speter 161018334Speter temp2 = expand_binop (submode, binoptab, real1, imag0, 161118334Speter NULL_RTX, unsignedp, methods); 161218334Speter 161318334Speter if (temp1 == 0 || temp2 == 0) 161418334Speter break; 161518334Speter 161690075Sobrien res = (expand_binop 161790075Sobrien (submode, 161890075Sobrien binoptab == smulv_optab ? addv_optab : add_optab, 161990075Sobrien temp1, temp2, imagr, unsignedp, methods)); 162018334Speter 162118334Speter if (res == 0) 162218334Speter break; 162318334Speter else if (res != imagr) 162418334Speter emit_move_insn (imagr, res); 162518334Speter 162618334Speter ok = 1; 162718334Speter } 162818334Speter else 162918334Speter { 163018334Speter /* Don't fetch these from memory more than once. */ 163118334Speter real0 = force_reg (submode, real0); 163218334Speter real1 = force_reg (submode, real1); 163318334Speter 163418334Speter res = expand_binop (submode, binoptab, real0, real1, 163518334Speter realr, unsignedp, methods); 163618334Speter if (res == 0) 163718334Speter break; 163818334Speter else if (res != realr) 163918334Speter emit_move_insn (realr, res); 164018334Speter 164118334Speter if (imag0 != 0) 164218334Speter res = expand_binop (submode, binoptab, 164318334Speter real1, imag0, imagr, unsignedp, methods); 164418334Speter else 164518334Speter res = expand_binop (submode, binoptab, 164618334Speter real0, imag1, imagr, unsignedp, methods); 164718334Speter 164818334Speter if (res == 0) 164918334Speter break; 165018334Speter else if (res != imagr) 165118334Speter emit_move_insn (imagr, res); 165218334Speter 165318334Speter ok = 1; 165418334Speter } 165518334Speter break; 165618334Speter 165718334Speter case DIV: 165818334Speter /* (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) */ 165918334Speter 166018334Speter if (imag1 == 0) 166118334Speter { 166218334Speter /* (a+ib) / (c+i0) = (a/c) + i(b/c) */ 166318334Speter 166418334Speter /* Don't fetch these from memory more than once. */ 166518334Speter real1 = force_reg (submode, real1); 166618334Speter 166718334Speter /* Simply divide the real and imaginary parts by `c' */ 166818334Speter if (class == MODE_COMPLEX_FLOAT) 166918334Speter res = expand_binop (submode, binoptab, real0, real1, 167018334Speter realr, unsignedp, methods); 167118334Speter else 167218334Speter res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 167318334Speter real0, real1, realr, unsignedp); 167418334Speter 167518334Speter if (res == 0) 167618334Speter break; 167718334Speter else if (res != realr) 167818334Speter emit_move_insn (realr, res); 167918334Speter 168018334Speter if (class == MODE_COMPLEX_FLOAT) 168118334Speter res = expand_binop (submode, binoptab, imag0, real1, 168218334Speter imagr, unsignedp, methods); 168318334Speter else 168418334Speter res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 168518334Speter imag0, real1, imagr, unsignedp); 168618334Speter 168718334Speter if (res == 0) 168818334Speter break; 168918334Speter else if (res != imagr) 169018334Speter emit_move_insn (imagr, res); 169118334Speter 169218334Speter ok = 1; 169318334Speter } 169418334Speter else 169518334Speter { 169652284Sobrien switch (flag_complex_divide_method) 169718334Speter { 169852284Sobrien case 0: 169952284Sobrien ok = expand_cmplxdiv_straight (real0, real1, imag0, imag1, 170052284Sobrien realr, imagr, submode, 170152284Sobrien unsignedp, methods, 170252284Sobrien class, binoptab); 170352284Sobrien break; 170418334Speter 170552284Sobrien case 1: 170652284Sobrien ok = expand_cmplxdiv_wide (real0, real1, imag0, imag1, 170752284Sobrien realr, imagr, submode, 170852284Sobrien unsignedp, methods, 170952284Sobrien class, binoptab); 171052284Sobrien break; 171118334Speter 171252284Sobrien default: 171352284Sobrien abort (); 171418334Speter } 171518334Speter } 171618334Speter break; 171718334Speter 171818334Speter default: 171918334Speter abort (); 172018334Speter } 172118334Speter 172218334Speter seq = get_insns (); 172318334Speter end_sequence (); 172418334Speter 172518334Speter if (ok) 172618334Speter { 172718334Speter if (binoptab->code != UNKNOWN) 172818334Speter equiv_value 172950397Sobrien = gen_rtx_fmt_ee (binoptab->code, mode, 173050397Sobrien copy_rtx (op0), copy_rtx (op1)); 173118334Speter else 173218334Speter equiv_value = 0; 173318334Speter 173418334Speter emit_no_conflict_block (seq, target, op0, op1, equiv_value); 173518334Speter 173618334Speter return target; 173718334Speter } 173818334Speter } 173918334Speter 174018334Speter /* It can't be open-coded in this mode. 174118334Speter Use a library call if one is available and caller says that's ok. */ 174218334Speter 174318334Speter if (binoptab->handlers[(int) mode].libfunc 174418334Speter && (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN)) 174518334Speter { 174618334Speter rtx insns; 174718334Speter rtx op1x = op1; 174818334Speter enum machine_mode op1_mode = mode; 174918334Speter rtx value; 175018334Speter 175118334Speter start_sequence (); 175218334Speter 175318334Speter if (shift_op) 175418334Speter { 175518334Speter op1_mode = word_mode; 175618334Speter /* Specify unsigned here, 175718334Speter since negative shift counts are meaningless. */ 175818334Speter op1x = convert_to_mode (word_mode, op1, 1); 175918334Speter } 176018334Speter 176118334Speter if (GET_MODE (op0) != VOIDmode 176218334Speter && GET_MODE (op0) != mode) 176318334Speter op0 = convert_to_mode (mode, op0, unsignedp); 176418334Speter 176518334Speter /* Pass 1 for NO_QUEUE so we don't lose any increments 176618334Speter if the libcall is cse'd or moved. */ 176718334Speter value = emit_library_call_value (binoptab->handlers[(int) mode].libfunc, 176890075Sobrien NULL_RTX, LCT_CONST, mode, 2, 176918334Speter op0, mode, op1x, op1_mode); 177018334Speter 177118334Speter insns = get_insns (); 177218334Speter end_sequence (); 177318334Speter 177418334Speter target = gen_reg_rtx (mode); 177518334Speter emit_libcall_block (insns, target, value, 177650397Sobrien gen_rtx_fmt_ee (binoptab->code, mode, op0, op1)); 177718334Speter 177818334Speter return target; 177918334Speter } 178018334Speter 178118334Speter delete_insns_since (last); 178218334Speter 178318334Speter /* It can't be done in this mode. Can we do it in a wider mode? */ 178418334Speter 178518334Speter if (! (methods == OPTAB_WIDEN || methods == OPTAB_LIB_WIDEN 178618334Speter || methods == OPTAB_MUST_WIDEN)) 178718334Speter { 178818334Speter /* Caller says, don't even try. */ 178918334Speter delete_insns_since (entry_last); 179018334Speter return 0; 179118334Speter } 179218334Speter 179318334Speter /* Compute the value of METHODS to pass to recursive calls. 179418334Speter Don't allow widening to be tried recursively. */ 179518334Speter 179618334Speter methods = (methods == OPTAB_LIB_WIDEN ? OPTAB_LIB : OPTAB_DIRECT); 179718334Speter 179818334Speter /* Look for a wider mode of the same class for which it appears we can do 179918334Speter the operation. */ 180018334Speter 180118334Speter if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) 180218334Speter { 180318334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 180418334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 180518334Speter { 180618334Speter if ((binoptab->handlers[(int) wider_mode].insn_code 180718334Speter != CODE_FOR_nothing) 180818334Speter || (methods == OPTAB_LIB 180918334Speter && binoptab->handlers[(int) wider_mode].libfunc)) 181018334Speter { 181118334Speter rtx xop0 = op0, xop1 = op1; 181218334Speter int no_extend = 0; 181318334Speter 181418334Speter /* For certain integer operations, we need not actually extend 181518334Speter the narrow operands, as long as we will truncate 181618334Speter the results to the same narrowness. */ 181718334Speter 181818334Speter if ((binoptab == ior_optab || binoptab == and_optab 181918334Speter || binoptab == xor_optab 182018334Speter || binoptab == add_optab || binoptab == sub_optab 182118334Speter || binoptab == smul_optab || binoptab == ashl_optab) 182218334Speter && class == MODE_INT) 182318334Speter no_extend = 1; 182418334Speter 182518334Speter xop0 = widen_operand (xop0, wider_mode, mode, 182618334Speter unsignedp, no_extend); 182718334Speter 182818334Speter /* The second operand of a shift must always be extended. */ 182918334Speter xop1 = widen_operand (xop1, wider_mode, mode, unsignedp, 183018334Speter no_extend && binoptab != ashl_optab); 183118334Speter 183218334Speter temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX, 183318334Speter unsignedp, methods); 183418334Speter if (temp) 183518334Speter { 183618334Speter if (class != MODE_INT) 183718334Speter { 183818334Speter if (target == 0) 183918334Speter target = gen_reg_rtx (mode); 184018334Speter convert_move (target, temp, 0); 184118334Speter return target; 184218334Speter } 184318334Speter else 184418334Speter return gen_lowpart (mode, temp); 184518334Speter } 184618334Speter else 184718334Speter delete_insns_since (last); 184818334Speter } 184918334Speter } 185018334Speter } 185118334Speter 185218334Speter delete_insns_since (entry_last); 185318334Speter return 0; 185418334Speter} 185518334Speter 185618334Speter/* Expand a binary operator which has both signed and unsigned forms. 185718334Speter UOPTAB is the optab for unsigned operations, and SOPTAB is for 185818334Speter signed operations. 185918334Speter 186018334Speter If we widen unsigned operands, we may use a signed wider operation instead 186118334Speter of an unsigned wider operation, since the result would be the same. */ 186218334Speter 186318334Speterrtx 186418334Spetersign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods) 186518334Speter enum machine_mode mode; 186618334Speter optab uoptab, soptab; 186718334Speter rtx op0, op1, target; 186818334Speter int unsignedp; 186918334Speter enum optab_methods methods; 187018334Speter{ 187190075Sobrien rtx temp; 187218334Speter optab direct_optab = unsignedp ? uoptab : soptab; 187318334Speter struct optab wide_soptab; 187418334Speter 187518334Speter /* Do it without widening, if possible. */ 187618334Speter temp = expand_binop (mode, direct_optab, op0, op1, target, 187718334Speter unsignedp, OPTAB_DIRECT); 187818334Speter if (temp || methods == OPTAB_DIRECT) 187918334Speter return temp; 188018334Speter 188118334Speter /* Try widening to a signed int. Make a fake signed optab that 188218334Speter hides any signed insn for direct use. */ 188318334Speter wide_soptab = *soptab; 188418334Speter wide_soptab.handlers[(int) mode].insn_code = CODE_FOR_nothing; 188518334Speter wide_soptab.handlers[(int) mode].libfunc = 0; 188618334Speter 188718334Speter temp = expand_binop (mode, &wide_soptab, op0, op1, target, 188818334Speter unsignedp, OPTAB_WIDEN); 188918334Speter 189018334Speter /* For unsigned operands, try widening to an unsigned int. */ 189118334Speter if (temp == 0 && unsignedp) 189218334Speter temp = expand_binop (mode, uoptab, op0, op1, target, 189318334Speter unsignedp, OPTAB_WIDEN); 189418334Speter if (temp || methods == OPTAB_WIDEN) 189518334Speter return temp; 189618334Speter 189718334Speter /* Use the right width lib call if that exists. */ 189818334Speter temp = expand_binop (mode, direct_optab, op0, op1, target, unsignedp, OPTAB_LIB); 189918334Speter if (temp || methods == OPTAB_LIB) 190018334Speter return temp; 190118334Speter 190218334Speter /* Must widen and use a lib call, use either signed or unsigned. */ 190318334Speter temp = expand_binop (mode, &wide_soptab, op0, op1, target, 190418334Speter unsignedp, methods); 190518334Speter if (temp != 0) 190618334Speter return temp; 190718334Speter if (unsignedp) 190818334Speter return expand_binop (mode, uoptab, op0, op1, target, 190918334Speter unsignedp, methods); 191018334Speter return 0; 191118334Speter} 191218334Speter 191318334Speter/* Generate code to perform an operation specified by BINOPTAB 191418334Speter on operands OP0 and OP1, with two results to TARG1 and TARG2. 191518334Speter We assume that the order of the operands for the instruction 191618334Speter is TARG0, OP0, OP1, TARG1, which would fit a pattern like 191718334Speter [(set TARG0 (operate OP0 OP1)) (set TARG1 (operate ...))]. 191818334Speter 191918334Speter Either TARG0 or TARG1 may be zero, but what that means is that 192050397Sobrien the result is not actually wanted. We will generate it into 192118334Speter a dummy pseudo-reg and discard it. They may not both be zero. 192218334Speter 192318334Speter Returns 1 if this operation can be performed; 0 if not. */ 192418334Speter 192518334Speterint 192618334Speterexpand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp) 192718334Speter optab binoptab; 192818334Speter rtx op0, op1; 192918334Speter rtx targ0, targ1; 193018334Speter int unsignedp; 193118334Speter{ 193218334Speter enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1); 193318334Speter enum mode_class class; 193418334Speter enum machine_mode wider_mode; 193518334Speter rtx entry_last = get_last_insn (); 193618334Speter rtx last; 193718334Speter 193818334Speter class = GET_MODE_CLASS (mode); 193918334Speter 194018334Speter op0 = protect_from_queue (op0, 0); 194118334Speter op1 = protect_from_queue (op1, 0); 194218334Speter 194318334Speter if (flag_force_mem) 194418334Speter { 194518334Speter op0 = force_not_mem (op0); 194618334Speter op1 = force_not_mem (op1); 194718334Speter } 194818334Speter 194918334Speter /* If we are inside an appropriately-short loop and one operand is an 195018334Speter expensive constant, force it into a register. */ 195118334Speter if (CONSTANT_P (op0) && preserve_subexpressions_p () 195290075Sobrien && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1)) 195318334Speter op0 = force_reg (mode, op0); 195418334Speter 195518334Speter if (CONSTANT_P (op1) && preserve_subexpressions_p () 195690075Sobrien && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1)) 195718334Speter op1 = force_reg (mode, op1); 195818334Speter 195918334Speter if (targ0) 196018334Speter targ0 = protect_from_queue (targ0, 1); 196118334Speter else 196218334Speter targ0 = gen_reg_rtx (mode); 196318334Speter if (targ1) 196418334Speter targ1 = protect_from_queue (targ1, 1); 196518334Speter else 196618334Speter targ1 = gen_reg_rtx (mode); 196718334Speter 196818334Speter /* Record where to go back to if we fail. */ 196918334Speter last = get_last_insn (); 197018334Speter 197118334Speter if (binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 197218334Speter { 197318334Speter int icode = (int) binoptab->handlers[(int) mode].insn_code; 197490075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 197590075Sobrien enum machine_mode mode1 = insn_data[icode].operand[2].mode; 197618334Speter rtx pat; 197718334Speter rtx xop0 = op0, xop1 = op1; 197818334Speter 197918334Speter /* In case this insn wants input operands in modes different from the 198018334Speter result, convert the operands. */ 198118334Speter if (GET_MODE (op0) != VOIDmode && GET_MODE (op0) != mode0) 198218334Speter xop0 = convert_to_mode (mode0, xop0, unsignedp); 198318334Speter 198418334Speter if (GET_MODE (op1) != VOIDmode && GET_MODE (op1) != mode1) 198518334Speter xop1 = convert_to_mode (mode1, xop1, unsignedp); 198618334Speter 198718334Speter /* Now, if insn doesn't accept these operands, put them into pseudos. */ 198890075Sobrien if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)) 198918334Speter xop0 = copy_to_mode_reg (mode0, xop0); 199018334Speter 199190075Sobrien if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1)) 199218334Speter xop1 = copy_to_mode_reg (mode1, xop1); 199318334Speter 199418334Speter /* We could handle this, but we should always be called with a pseudo 199518334Speter for our targets and all insns should take them as outputs. */ 199690075Sobrien if (! (*insn_data[icode].operand[0].predicate) (targ0, mode) 199790075Sobrien || ! (*insn_data[icode].operand[3].predicate) (targ1, mode)) 199818334Speter abort (); 199918334Speter 200018334Speter pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1); 200118334Speter if (pat) 200218334Speter { 200318334Speter emit_insn (pat); 200418334Speter return 1; 200518334Speter } 200618334Speter else 200718334Speter delete_insns_since (last); 200818334Speter } 200918334Speter 201018334Speter /* It can't be done in this mode. Can we do it in a wider mode? */ 201118334Speter 201218334Speter if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) 201318334Speter { 201418334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 201518334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 201618334Speter { 201718334Speter if (binoptab->handlers[(int) wider_mode].insn_code 201818334Speter != CODE_FOR_nothing) 201918334Speter { 202090075Sobrien rtx t0 = gen_reg_rtx (wider_mode); 202190075Sobrien rtx t1 = gen_reg_rtx (wider_mode); 202290075Sobrien rtx cop0 = convert_modes (wider_mode, mode, op0, unsignedp); 202390075Sobrien rtx cop1 = convert_modes (wider_mode, mode, op1, unsignedp); 202418334Speter 202590075Sobrien if (expand_twoval_binop (binoptab, cop0, cop1, 202618334Speter t0, t1, unsignedp)) 202718334Speter { 202818334Speter convert_move (targ0, t0, unsignedp); 202918334Speter convert_move (targ1, t1, unsignedp); 203018334Speter return 1; 203118334Speter } 203218334Speter else 203318334Speter delete_insns_since (last); 203418334Speter } 203518334Speter } 203618334Speter } 203718334Speter 203818334Speter delete_insns_since (entry_last); 203918334Speter return 0; 204018334Speter} 204118334Speter 204290075Sobrien/* Wrapper around expand_unop which takes an rtx code to specify 204390075Sobrien the operation to perform, not an optab pointer. All other 204490075Sobrien arguments are the same. */ 204590075Sobrienrtx 204690075Sobrienexpand_simple_unop (mode, code, op0, target, unsignedp) 204790075Sobrien enum machine_mode mode; 204890075Sobrien enum rtx_code code; 204990075Sobrien rtx op0; 205090075Sobrien rtx target; 205190075Sobrien int unsignedp; 205290075Sobrien{ 205390075Sobrien optab unop = code_to_optab [(int) code]; 205490075Sobrien if (unop == 0) 205590075Sobrien abort (); 205690075Sobrien 205790075Sobrien return expand_unop (mode, unop, op0, target, unsignedp); 205890075Sobrien} 205990075Sobrien 206018334Speter/* Generate code to perform an operation specified by UNOPTAB 206118334Speter on operand OP0, with result having machine-mode MODE. 206218334Speter 206318334Speter UNSIGNEDP is for the case where we have to widen the operands 206418334Speter to perform the operation. It says to use zero-extension. 206518334Speter 206618334Speter If TARGET is nonzero, the value 206718334Speter is generated there, if it is convenient to do so. 206818334Speter In all cases an rtx is returned for the locus of the value; 206918334Speter this may or may not be TARGET. */ 207018334Speter 207118334Speterrtx 207218334Speterexpand_unop (mode, unoptab, op0, target, unsignedp) 207318334Speter enum machine_mode mode; 207418334Speter optab unoptab; 207518334Speter rtx op0; 207618334Speter rtx target; 207718334Speter int unsignedp; 207818334Speter{ 207918334Speter enum mode_class class; 208018334Speter enum machine_mode wider_mode; 208190075Sobrien rtx temp; 208218334Speter rtx last = get_last_insn (); 208318334Speter rtx pat; 208418334Speter 208518334Speter class = GET_MODE_CLASS (mode); 208618334Speter 208718334Speter op0 = protect_from_queue (op0, 0); 208818334Speter 208918334Speter if (flag_force_mem) 209018334Speter { 209118334Speter op0 = force_not_mem (op0); 209218334Speter } 209318334Speter 209418334Speter if (target) 209518334Speter target = protect_from_queue (target, 1); 209618334Speter 209718334Speter if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 209818334Speter { 209918334Speter int icode = (int) unoptab->handlers[(int) mode].insn_code; 210090075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 210118334Speter rtx xop0 = op0; 210218334Speter 210318334Speter if (target) 210418334Speter temp = target; 210518334Speter else 210618334Speter temp = gen_reg_rtx (mode); 210718334Speter 210818334Speter if (GET_MODE (xop0) != VOIDmode 210918334Speter && GET_MODE (xop0) != mode0) 211018334Speter xop0 = convert_to_mode (mode0, xop0, unsignedp); 211118334Speter 211218334Speter /* Now, if insn doesn't accept our operand, put it into a pseudo. */ 211318334Speter 211490075Sobrien if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)) 211518334Speter xop0 = copy_to_mode_reg (mode0, xop0); 211618334Speter 211790075Sobrien if (! (*insn_data[icode].operand[0].predicate) (temp, mode)) 211818334Speter temp = gen_reg_rtx (mode); 211918334Speter 212018334Speter pat = GEN_FCN (icode) (temp, xop0); 212118334Speter if (pat) 212218334Speter { 212318334Speter if (GET_CODE (pat) == SEQUENCE 212418334Speter && ! add_equal_note (pat, temp, unoptab->code, xop0, NULL_RTX)) 212518334Speter { 212618334Speter delete_insns_since (last); 212718334Speter return expand_unop (mode, unoptab, op0, NULL_RTX, unsignedp); 212818334Speter } 212918334Speter 213018334Speter emit_insn (pat); 213118334Speter 213218334Speter return temp; 213318334Speter } 213418334Speter else 213518334Speter delete_insns_since (last); 213618334Speter } 213718334Speter 213818334Speter /* It can't be done in this mode. Can we open-code it in a wider mode? */ 213918334Speter 214018334Speter if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) 214118334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 214218334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 214318334Speter { 214418334Speter if (unoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing) 214518334Speter { 214618334Speter rtx xop0 = op0; 214718334Speter 214818334Speter /* For certain operations, we need not actually extend 214918334Speter the narrow operand, as long as we will truncate the 215018334Speter results to the same narrowness. */ 215118334Speter 215218334Speter xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, 215318334Speter (unoptab == neg_optab 215418334Speter || unoptab == one_cmpl_optab) 215518334Speter && class == MODE_INT); 215618334Speter 215718334Speter temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX, 215818334Speter unsignedp); 215918334Speter 216018334Speter if (temp) 216118334Speter { 216218334Speter if (class != MODE_INT) 216318334Speter { 216418334Speter if (target == 0) 216518334Speter target = gen_reg_rtx (mode); 216618334Speter convert_move (target, temp, 0); 216718334Speter return target; 216818334Speter } 216918334Speter else 217018334Speter return gen_lowpart (mode, temp); 217118334Speter } 217218334Speter else 217318334Speter delete_insns_since (last); 217418334Speter } 217518334Speter } 217618334Speter 217718334Speter /* These can be done a word at a time. */ 217818334Speter if (unoptab == one_cmpl_optab 217918334Speter && class == MODE_INT 218018334Speter && GET_MODE_SIZE (mode) > UNITS_PER_WORD 218118334Speter && unoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 218218334Speter { 218318334Speter int i; 218418334Speter rtx insns; 218518334Speter 218618334Speter if (target == 0 || target == op0) 218718334Speter target = gen_reg_rtx (mode); 218818334Speter 218918334Speter start_sequence (); 219018334Speter 219118334Speter /* Do the actual arithmetic. */ 219218334Speter for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++) 219318334Speter { 219418334Speter rtx target_piece = operand_subword (target, i, 1, mode); 219518334Speter rtx x = expand_unop (word_mode, unoptab, 219618334Speter operand_subword_force (op0, i, mode), 219718334Speter target_piece, unsignedp); 219890075Sobrien 219918334Speter if (target_piece != x) 220018334Speter emit_move_insn (target_piece, x); 220118334Speter } 220218334Speter 220318334Speter insns = get_insns (); 220418334Speter end_sequence (); 220518334Speter 220618334Speter emit_no_conflict_block (insns, target, op0, NULL_RTX, 220750397Sobrien gen_rtx_fmt_e (unoptab->code, mode, 220850397Sobrien copy_rtx (op0))); 220918334Speter return target; 221018334Speter } 221118334Speter 221218334Speter /* Open-code the complex negation operation. */ 221390075Sobrien else if (unoptab->code == NEG 221418334Speter && (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)) 221518334Speter { 221618334Speter rtx target_piece; 221718334Speter rtx x; 221818334Speter rtx seq; 221918334Speter 222018334Speter /* Find the correct mode for the real and imaginary parts */ 222118334Speter enum machine_mode submode 222218334Speter = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT, 222318334Speter class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT, 222418334Speter 0); 222518334Speter 222618334Speter if (submode == BLKmode) 222718334Speter abort (); 222818334Speter 222918334Speter if (target == 0) 223018334Speter target = gen_reg_rtx (mode); 223118334Speter 223218334Speter start_sequence (); 223318334Speter 223418334Speter target_piece = gen_imagpart (submode, target); 223518334Speter x = expand_unop (submode, unoptab, 223618334Speter gen_imagpart (submode, op0), 223718334Speter target_piece, unsignedp); 223818334Speter if (target_piece != x) 223918334Speter emit_move_insn (target_piece, x); 224018334Speter 224118334Speter target_piece = gen_realpart (submode, target); 224218334Speter x = expand_unop (submode, unoptab, 224318334Speter gen_realpart (submode, op0), 224418334Speter target_piece, unsignedp); 224518334Speter if (target_piece != x) 224618334Speter emit_move_insn (target_piece, x); 224718334Speter 224818334Speter seq = get_insns (); 224918334Speter end_sequence (); 225018334Speter 225118334Speter emit_no_conflict_block (seq, target, op0, 0, 225250397Sobrien gen_rtx_fmt_e (unoptab->code, mode, 225350397Sobrien copy_rtx (op0))); 225418334Speter return target; 225518334Speter } 225618334Speter 225718334Speter /* Now try a library call in this mode. */ 225818334Speter if (unoptab->handlers[(int) mode].libfunc) 225918334Speter { 226018334Speter rtx insns; 226118334Speter rtx value; 226218334Speter 226318334Speter start_sequence (); 226418334Speter 226518334Speter /* Pass 1 for NO_QUEUE so we don't lose any increments 226618334Speter if the libcall is cse'd or moved. */ 226718334Speter value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc, 226890075Sobrien NULL_RTX, LCT_CONST, mode, 1, op0, mode); 226918334Speter insns = get_insns (); 227018334Speter end_sequence (); 227118334Speter 227218334Speter target = gen_reg_rtx (mode); 227318334Speter emit_libcall_block (insns, target, value, 227450397Sobrien gen_rtx_fmt_e (unoptab->code, mode, op0)); 227518334Speter 227618334Speter return target; 227718334Speter } 227818334Speter 227918334Speter /* It can't be done in this mode. Can we do it in a wider mode? */ 228018334Speter 228118334Speter if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) 228218334Speter { 228318334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 228418334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 228518334Speter { 228618334Speter if ((unoptab->handlers[(int) wider_mode].insn_code 228718334Speter != CODE_FOR_nothing) 228818334Speter || unoptab->handlers[(int) wider_mode].libfunc) 228918334Speter { 229018334Speter rtx xop0 = op0; 229118334Speter 229218334Speter /* For certain operations, we need not actually extend 229318334Speter the narrow operand, as long as we will truncate the 229418334Speter results to the same narrowness. */ 229518334Speter 229618334Speter xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, 229718334Speter (unoptab == neg_optab 229818334Speter || unoptab == one_cmpl_optab) 229918334Speter && class == MODE_INT); 230018334Speter 230118334Speter temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX, 230218334Speter unsignedp); 230318334Speter 230418334Speter if (temp) 230518334Speter { 230618334Speter if (class != MODE_INT) 230718334Speter { 230818334Speter if (target == 0) 230918334Speter target = gen_reg_rtx (mode); 231018334Speter convert_move (target, temp, 0); 231118334Speter return target; 231218334Speter } 231318334Speter else 231418334Speter return gen_lowpart (mode, temp); 231518334Speter } 231618334Speter else 231718334Speter delete_insns_since (last); 231818334Speter } 231918334Speter } 232018334Speter } 232118334Speter 232218334Speter /* If there is no negate operation, try doing a subtract from zero. 232318334Speter The US Software GOFAST library needs this. */ 232490075Sobrien if (unoptab->code == NEG) 232518334Speter { 232618334Speter rtx temp; 232790075Sobrien temp = expand_binop (mode, 232890075Sobrien unoptab == negv_optab ? subv_optab : sub_optab, 232990075Sobrien CONST0_RTX (mode), op0, 233090075Sobrien target, unsignedp, OPTAB_LIB_WIDEN); 233118334Speter if (temp) 233218334Speter return temp; 233318334Speter } 233418334Speter 233518334Speter return 0; 233618334Speter} 233718334Speter 233818334Speter/* Emit code to compute the absolute value of OP0, with result to 233918334Speter TARGET if convenient. (TARGET may be 0.) The return value says 234018334Speter where the result actually is to be found. 234118334Speter 234218334Speter MODE is the mode of the operand; the mode of the result is 234318334Speter different but can be deduced from MODE. 234418334Speter 234552284Sobrien */ 234618334Speter 234718334Speterrtx 234890075Sobrienexpand_abs (mode, op0, target, result_unsignedp, safe) 234918334Speter enum machine_mode mode; 235018334Speter rtx op0; 235118334Speter rtx target; 235290075Sobrien int result_unsignedp; 235318334Speter int safe; 235418334Speter{ 235518334Speter rtx temp, op1; 235618334Speter 235790075Sobrien if (! flag_trapv) 235890075Sobrien result_unsignedp = 1; 235990075Sobrien 236018334Speter /* First try to do it with a special abs instruction. */ 236190075Sobrien temp = expand_unop (mode, result_unsignedp ? abs_optab : absv_optab, 236290075Sobrien op0, target, 0); 236318334Speter if (temp != 0) 236418334Speter return temp; 236518334Speter 236690075Sobrien /* If we have a MAX insn, we can do this as MAX (x, -x). */ 236790075Sobrien if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 236890075Sobrien { 236990075Sobrien rtx last = get_last_insn (); 237090075Sobrien 237190075Sobrien temp = expand_unop (mode, neg_optab, op0, NULL_RTX, 0); 237290075Sobrien if (temp != 0) 237390075Sobrien temp = expand_binop (mode, smax_optab, op0, temp, target, 0, 237490075Sobrien OPTAB_WIDEN); 237590075Sobrien 237690075Sobrien if (temp != 0) 237790075Sobrien return temp; 237890075Sobrien 237990075Sobrien delete_insns_since (last); 238090075Sobrien } 238190075Sobrien 238218334Speter /* If this machine has expensive jumps, we can do integer absolute 238318334Speter value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)), 238418334Speter where W is the width of MODE. */ 238518334Speter 238618334Speter if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2) 238718334Speter { 238818334Speter rtx extended = expand_shift (RSHIFT_EXPR, mode, op0, 238918334Speter size_int (GET_MODE_BITSIZE (mode) - 1), 239018334Speter NULL_RTX, 0); 239118334Speter 239218334Speter temp = expand_binop (mode, xor_optab, extended, op0, target, 0, 239318334Speter OPTAB_LIB_WIDEN); 239418334Speter if (temp != 0) 239590075Sobrien temp = expand_binop (mode, result_unsignedp ? sub_optab : subv_optab, 239690075Sobrien temp, extended, target, 0, OPTAB_LIB_WIDEN); 239718334Speter 239818334Speter if (temp != 0) 239918334Speter return temp; 240018334Speter } 240118334Speter 240218334Speter /* If that does not win, use conditional jump and negate. */ 240350397Sobrien 240450397Sobrien /* It is safe to use the target if it is the same 240550397Sobrien as the source if this is also a pseudo register */ 240650397Sobrien if (op0 == target && GET_CODE (op0) == REG 240750397Sobrien && REGNO (op0) >= FIRST_PSEUDO_REGISTER) 240850397Sobrien safe = 1; 240950397Sobrien 241018334Speter op1 = gen_label_rtx (); 241118334Speter if (target == 0 || ! safe 241218334Speter || GET_MODE (target) != mode 241318334Speter || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target)) 241418334Speter || (GET_CODE (target) == REG 241518334Speter && REGNO (target) < FIRST_PSEUDO_REGISTER)) 241618334Speter target = gen_reg_rtx (mode); 241718334Speter 241818334Speter emit_move_insn (target, op0); 241918334Speter NO_DEFER_POP; 242018334Speter 242118334Speter /* If this mode is an integer too wide to compare properly, 242218334Speter compare word by word. Rely on CSE to optimize constant cases. */ 242390075Sobrien if (GET_MODE_CLASS (mode) == MODE_INT 242490075Sobrien && ! can_compare_p (GE, mode, ccp_jump)) 242518334Speter do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx, 242618334Speter NULL_RTX, op1); 242718334Speter else 242890075Sobrien do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode, 242990075Sobrien NULL_RTX, NULL_RTX, op1); 243018334Speter 243190075Sobrien op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab, 243290075Sobrien target, target, 0); 243318334Speter if (op0 != target) 243418334Speter emit_move_insn (target, op0); 243518334Speter emit_label (op1); 243618334Speter OK_DEFER_POP; 243718334Speter return target; 243818334Speter} 243918334Speter 244018334Speter/* Emit code to compute the absolute value of OP0, with result to 244118334Speter TARGET if convenient. (TARGET may be 0.) The return value says 244218334Speter where the result actually is to be found. 244318334Speter 244418334Speter MODE is the mode of the operand; the mode of the result is 244518334Speter different but can be deduced from MODE. 244618334Speter 244718334Speter UNSIGNEDP is relevant for complex integer modes. */ 244818334Speter 244918334Speterrtx 245018334Speterexpand_complex_abs (mode, op0, target, unsignedp) 245118334Speter enum machine_mode mode; 245218334Speter rtx op0; 245318334Speter rtx target; 245418334Speter int unsignedp; 245518334Speter{ 245618334Speter enum mode_class class = GET_MODE_CLASS (mode); 245718334Speter enum machine_mode wider_mode; 245890075Sobrien rtx temp; 245918334Speter rtx entry_last = get_last_insn (); 246018334Speter rtx last; 246118334Speter rtx pat; 246290075Sobrien optab this_abs_optab; 246318334Speter 246418334Speter /* Find the correct mode for the real and imaginary parts. */ 246518334Speter enum machine_mode submode 246618334Speter = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT, 246718334Speter class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT, 246818334Speter 0); 246918334Speter 247018334Speter if (submode == BLKmode) 247118334Speter abort (); 247218334Speter 247318334Speter op0 = protect_from_queue (op0, 0); 247418334Speter 247518334Speter if (flag_force_mem) 247618334Speter { 247718334Speter op0 = force_not_mem (op0); 247818334Speter } 247918334Speter 248018334Speter last = get_last_insn (); 248118334Speter 248218334Speter if (target) 248318334Speter target = protect_from_queue (target, 1); 248418334Speter 248590075Sobrien this_abs_optab = ! unsignedp && flag_trapv 248690075Sobrien && (GET_MODE_CLASS(mode) == MODE_INT) 248790075Sobrien ? absv_optab : abs_optab; 248890075Sobrien 248990075Sobrien if (this_abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 249018334Speter { 249190075Sobrien int icode = (int) this_abs_optab->handlers[(int) mode].insn_code; 249290075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 249318334Speter rtx xop0 = op0; 249418334Speter 249518334Speter if (target) 249618334Speter temp = target; 249718334Speter else 249818334Speter temp = gen_reg_rtx (submode); 249918334Speter 250018334Speter if (GET_MODE (xop0) != VOIDmode 250118334Speter && GET_MODE (xop0) != mode0) 250218334Speter xop0 = convert_to_mode (mode0, xop0, unsignedp); 250318334Speter 250418334Speter /* Now, if insn doesn't accept our operand, put it into a pseudo. */ 250518334Speter 250690075Sobrien if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)) 250718334Speter xop0 = copy_to_mode_reg (mode0, xop0); 250818334Speter 250990075Sobrien if (! (*insn_data[icode].operand[0].predicate) (temp, submode)) 251018334Speter temp = gen_reg_rtx (submode); 251118334Speter 251218334Speter pat = GEN_FCN (icode) (temp, xop0); 251318334Speter if (pat) 251418334Speter { 251518334Speter if (GET_CODE (pat) == SEQUENCE 251690075Sobrien && ! add_equal_note (pat, temp, this_abs_optab->code, xop0, 251790075Sobrien NULL_RTX)) 251818334Speter { 251918334Speter delete_insns_since (last); 252090075Sobrien return expand_unop (mode, this_abs_optab, op0, NULL_RTX, 252190075Sobrien unsignedp); 252218334Speter } 252318334Speter 252418334Speter emit_insn (pat); 252518334Speter 252618334Speter return temp; 252718334Speter } 252818334Speter else 252918334Speter delete_insns_since (last); 253018334Speter } 253118334Speter 253218334Speter /* It can't be done in this mode. Can we open-code it in a wider mode? */ 253318334Speter 253418334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 253518334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 253618334Speter { 253790075Sobrien if (this_abs_optab->handlers[(int) wider_mode].insn_code 253890075Sobrien != CODE_FOR_nothing) 253918334Speter { 254018334Speter rtx xop0 = op0; 254118334Speter 254218334Speter xop0 = convert_modes (wider_mode, mode, xop0, unsignedp); 254318334Speter temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp); 254418334Speter 254518334Speter if (temp) 254618334Speter { 254718334Speter if (class != MODE_COMPLEX_INT) 254818334Speter { 254918334Speter if (target == 0) 255018334Speter target = gen_reg_rtx (submode); 255118334Speter convert_move (target, temp, 0); 255218334Speter return target; 255318334Speter } 255418334Speter else 255518334Speter return gen_lowpart (submode, temp); 255618334Speter } 255718334Speter else 255818334Speter delete_insns_since (last); 255918334Speter } 256018334Speter } 256118334Speter 256218334Speter /* Open-code the complex absolute-value operation 256318334Speter if we can open-code sqrt. Otherwise it's not worth while. */ 256490075Sobrien if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing 256590075Sobrien && ! flag_trapv) 256618334Speter { 256718334Speter rtx real, imag, total; 256818334Speter 256918334Speter real = gen_realpart (submode, op0); 257018334Speter imag = gen_imagpart (submode, op0); 257118334Speter 257218334Speter /* Square both parts. */ 257318334Speter real = expand_mult (submode, real, real, NULL_RTX, 0); 257418334Speter imag = expand_mult (submode, imag, imag, NULL_RTX, 0); 257518334Speter 257618334Speter /* Sum the parts. */ 257718334Speter total = expand_binop (submode, add_optab, real, imag, NULL_RTX, 257818334Speter 0, OPTAB_LIB_WIDEN); 257918334Speter 258018334Speter /* Get sqrt in TARGET. Set TARGET to where the result is. */ 258118334Speter target = expand_unop (submode, sqrt_optab, total, target, 0); 258218334Speter if (target == 0) 258318334Speter delete_insns_since (last); 258418334Speter else 258518334Speter return target; 258618334Speter } 258718334Speter 258818334Speter /* Now try a library call in this mode. */ 258990075Sobrien if (this_abs_optab->handlers[(int) mode].libfunc) 259018334Speter { 259118334Speter rtx insns; 259218334Speter rtx value; 259318334Speter 259418334Speter start_sequence (); 259518334Speter 259618334Speter /* Pass 1 for NO_QUEUE so we don't lose any increments 259718334Speter if the libcall is cse'd or moved. */ 259818334Speter value = emit_library_call_value (abs_optab->handlers[(int) mode].libfunc, 259990075Sobrien NULL_RTX, LCT_CONST, submode, 1, op0, mode); 260018334Speter insns = get_insns (); 260118334Speter end_sequence (); 260218334Speter 260318334Speter target = gen_reg_rtx (submode); 260418334Speter emit_libcall_block (insns, target, value, 260590075Sobrien gen_rtx_fmt_e (this_abs_optab->code, mode, op0)); 260618334Speter 260718334Speter return target; 260818334Speter } 260918334Speter 261018334Speter /* It can't be done in this mode. Can we do it in a wider mode? */ 261118334Speter 261218334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 261318334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 261418334Speter { 261590075Sobrien if ((this_abs_optab->handlers[(int) wider_mode].insn_code 261618334Speter != CODE_FOR_nothing) 261790075Sobrien || this_abs_optab->handlers[(int) wider_mode].libfunc) 261818334Speter { 261918334Speter rtx xop0 = op0; 262018334Speter 262118334Speter xop0 = convert_modes (wider_mode, mode, xop0, unsignedp); 262218334Speter 262318334Speter temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp); 262418334Speter 262518334Speter if (temp) 262618334Speter { 262718334Speter if (class != MODE_COMPLEX_INT) 262818334Speter { 262918334Speter if (target == 0) 263018334Speter target = gen_reg_rtx (submode); 263118334Speter convert_move (target, temp, 0); 263218334Speter return target; 263318334Speter } 263418334Speter else 263518334Speter return gen_lowpart (submode, temp); 263618334Speter } 263718334Speter else 263818334Speter delete_insns_since (last); 263918334Speter } 264018334Speter } 264118334Speter 264218334Speter delete_insns_since (entry_last); 264318334Speter return 0; 264418334Speter} 264518334Speter 264618334Speter/* Generate an instruction whose insn-code is INSN_CODE, 264718334Speter with two operands: an output TARGET and an input OP0. 264818334Speter TARGET *must* be nonzero, and the output is always stored there. 264918334Speter CODE is an rtx code such that (CODE OP0) is an rtx that describes 265018334Speter the value that is stored into TARGET. */ 265118334Speter 265218334Spetervoid 265318334Speteremit_unop_insn (icode, target, op0, code) 265418334Speter int icode; 265518334Speter rtx target; 265618334Speter rtx op0; 265718334Speter enum rtx_code code; 265818334Speter{ 265990075Sobrien rtx temp; 266090075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 266118334Speter rtx pat; 266218334Speter 266318334Speter temp = target = protect_from_queue (target, 1); 266418334Speter 266518334Speter op0 = protect_from_queue (op0, 0); 266618334Speter 266750397Sobrien /* Sign and zero extension from memory is often done specially on 266850397Sobrien RISC machines, so forcing into a register here can pessimize 266950397Sobrien code. */ 267050397Sobrien if (flag_force_mem && code != SIGN_EXTEND && code != ZERO_EXTEND) 267118334Speter op0 = force_not_mem (op0); 267218334Speter 267318334Speter /* Now, if insn does not accept our operands, put them into pseudos. */ 267418334Speter 267590075Sobrien if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) 267618334Speter op0 = copy_to_mode_reg (mode0, op0); 267718334Speter 267890075Sobrien if (! (*insn_data[icode].operand[0].predicate) (temp, GET_MODE (temp)) 267918334Speter || (flag_force_mem && GET_CODE (temp) == MEM)) 268018334Speter temp = gen_reg_rtx (GET_MODE (temp)); 268118334Speter 268218334Speter pat = GEN_FCN (icode) (temp, op0); 268318334Speter 268418334Speter if (GET_CODE (pat) == SEQUENCE && code != UNKNOWN) 268518334Speter add_equal_note (pat, temp, code, op0, NULL_RTX); 268618334Speter 268718334Speter emit_insn (pat); 268818334Speter 268918334Speter if (temp != target) 269018334Speter emit_move_insn (target, temp); 269118334Speter} 269218334Speter 269318334Speter/* Emit code to perform a series of operations on a multi-word quantity, one 269418334Speter word at a time. 269518334Speter 269618334Speter Such a block is preceded by a CLOBBER of the output, consists of multiple 269718334Speter insns, each setting one word of the output, and followed by a SET copying 269818334Speter the output to itself. 269918334Speter 270018334Speter Each of the insns setting words of the output receives a REG_NO_CONFLICT 270118334Speter note indicating that it doesn't conflict with the (also multi-word) 270218334Speter inputs. The entire block is surrounded by REG_LIBCALL and REG_RETVAL 270318334Speter notes. 270418334Speter 270518334Speter INSNS is a block of code generated to perform the operation, not including 270618334Speter the CLOBBER and final copy. All insns that compute intermediate values 270718334Speter are first emitted, followed by the block as described above. 270818334Speter 270918334Speter TARGET, OP0, and OP1 are the output and inputs of the operations, 271018334Speter respectively. OP1 may be zero for a unary operation. 271118334Speter 271218334Speter EQUIV, if non-zero, is an expression to be placed into a REG_EQUAL note 271318334Speter on the last insn. 271418334Speter 271518334Speter If TARGET is not a register, INSNS is simply emitted with no special 271618334Speter processing. Likewise if anything in INSNS is not an INSN or if 271718334Speter there is a libcall block inside INSNS. 271818334Speter 271918334Speter The final insn emitted is returned. */ 272018334Speter 272118334Speterrtx 272218334Speteremit_no_conflict_block (insns, target, op0, op1, equiv) 272318334Speter rtx insns; 272418334Speter rtx target; 272518334Speter rtx op0, op1; 272618334Speter rtx equiv; 272718334Speter{ 272818334Speter rtx prev, next, first, last, insn; 272918334Speter 273018334Speter if (GET_CODE (target) != REG || reload_in_progress) 273118334Speter return emit_insns (insns); 273218334Speter else 273318334Speter for (insn = insns; insn; insn = NEXT_INSN (insn)) 273418334Speter if (GET_CODE (insn) != INSN 273518334Speter || find_reg_note (insn, REG_LIBCALL, NULL_RTX)) 273618334Speter return emit_insns (insns); 273718334Speter 273818334Speter /* First emit all insns that do not store into words of the output and remove 273918334Speter these from the list. */ 274018334Speter for (insn = insns; insn; insn = next) 274118334Speter { 274296263Sobrien rtx set = 0, note; 274318334Speter int i; 274418334Speter 274518334Speter next = NEXT_INSN (insn); 274618334Speter 274796263Sobrien /* Some ports (cris) create an libcall regions at their own. We must 274896263Sobrien avoid any potential nesting of LIBCALLs. */ 274996263Sobrien if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL) 275096263Sobrien remove_note (insn, note); 275196263Sobrien if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL) 275296263Sobrien remove_note (insn, note); 275396263Sobrien 275490075Sobrien if (GET_CODE (PATTERN (insn)) == SET || GET_CODE (PATTERN (insn)) == USE 275590075Sobrien || GET_CODE (PATTERN (insn)) == CLOBBER) 275618334Speter set = PATTERN (insn); 275718334Speter else if (GET_CODE (PATTERN (insn)) == PARALLEL) 275818334Speter { 275918334Speter for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) 276018334Speter if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET) 276118334Speter { 276218334Speter set = XVECEXP (PATTERN (insn), 0, i); 276318334Speter break; 276418334Speter } 276518334Speter } 276618334Speter 276718334Speter if (set == 0) 276818334Speter abort (); 276918334Speter 277018334Speter if (! reg_overlap_mentioned_p (target, SET_DEST (set))) 277118334Speter { 277218334Speter if (PREV_INSN (insn)) 277318334Speter NEXT_INSN (PREV_INSN (insn)) = next; 277418334Speter else 277518334Speter insns = next; 277618334Speter 277718334Speter if (next) 277818334Speter PREV_INSN (next) = PREV_INSN (insn); 277918334Speter 278018334Speter add_insn (insn); 278118334Speter } 278218334Speter } 278318334Speter 278418334Speter prev = get_last_insn (); 278518334Speter 278618334Speter /* Now write the CLOBBER of the output, followed by the setting of each 278718334Speter of the words, followed by the final copy. */ 278818334Speter if (target != op0 && target != op1) 278950397Sobrien emit_insn (gen_rtx_CLOBBER (VOIDmode, target)); 279018334Speter 279118334Speter for (insn = insns; insn; insn = next) 279218334Speter { 279318334Speter next = NEXT_INSN (insn); 279418334Speter add_insn (insn); 279518334Speter 279618334Speter if (op1 && GET_CODE (op1) == REG) 279750397Sobrien REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op1, 279850397Sobrien REG_NOTES (insn)); 279918334Speter 280018334Speter if (op0 && GET_CODE (op0) == REG) 280150397Sobrien REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op0, 280250397Sobrien REG_NOTES (insn)); 280318334Speter } 280418334Speter 280518334Speter if (mov_optab->handlers[(int) GET_MODE (target)].insn_code 280618334Speter != CODE_FOR_nothing) 280718334Speter { 280818334Speter last = emit_move_insn (target, target); 280918334Speter if (equiv) 281052284Sobrien set_unique_reg_note (last, REG_EQUAL, equiv); 281118334Speter } 281218334Speter else 281390075Sobrien { 281490075Sobrien last = get_last_insn (); 281518334Speter 281690075Sobrien /* Remove any existing REG_EQUAL note from "last", or else it will 281790075Sobrien be mistaken for a note referring to the full contents of the 281890075Sobrien alleged libcall value when found together with the REG_RETVAL 281990075Sobrien note added below. An existing note can come from an insn 282090075Sobrien expansion at "last". */ 282190075Sobrien remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX)); 282290075Sobrien } 282390075Sobrien 282418334Speter if (prev == 0) 282518334Speter first = get_insns (); 282618334Speter else 282718334Speter first = NEXT_INSN (prev); 282818334Speter 282918334Speter /* Encapsulate the block so it gets manipulated as a unit. */ 283050397Sobrien REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, 283150397Sobrien REG_NOTES (first)); 283250397Sobrien REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last)); 283318334Speter 283418334Speter return last; 283518334Speter} 283618334Speter 283718334Speter/* Emit code to make a call to a constant function or a library call. 283818334Speter 283918334Speter INSNS is a list containing all insns emitted in the call. 284018334Speter These insns leave the result in RESULT. Our block is to copy RESULT 284118334Speter to TARGET, which is logically equivalent to EQUIV. 284218334Speter 284318334Speter We first emit any insns that set a pseudo on the assumption that these are 284418334Speter loading constants into registers; doing so allows them to be safely cse'ed 284518334Speter between blocks. Then we emit all the other insns in the block, followed by 284618334Speter an insn to move RESULT to TARGET. This last insn will have a REQ_EQUAL 284718334Speter note with an operand of EQUIV. 284818334Speter 284918334Speter Moving assignments to pseudos outside of the block is done to improve 285018334Speter the generated code, but is not required to generate correct code, 285118334Speter hence being unable to move an assignment is not grounds for not making 285218334Speter a libcall block. There are two reasons why it is safe to leave these 285318334Speter insns inside the block: First, we know that these pseudos cannot be 285418334Speter used in generated RTL outside the block since they are created for 285518334Speter temporary purposes within the block. Second, CSE will not record the 285618334Speter values of anything set inside a libcall block, so we know they must 285718334Speter be dead at the end of the block. 285818334Speter 285918334Speter Except for the first group of insns (the ones setting pseudos), the 286018334Speter block is delimited by REG_RETVAL and REG_LIBCALL notes. */ 286118334Speter 286218334Spetervoid 286318334Speteremit_libcall_block (insns, target, result, equiv) 286418334Speter rtx insns; 286518334Speter rtx target; 286618334Speter rtx result; 286718334Speter rtx equiv; 286818334Speter{ 286970635Sobrien rtx final_dest = target; 287018334Speter rtx prev, next, first, last, insn; 287118334Speter 287270635Sobrien /* If this is a reg with REG_USERVAR_P set, then it could possibly turn 287370635Sobrien into a MEM later. Protect the libcall block from this change. */ 287470635Sobrien if (! REG_P (target) || REG_USERVAR_P (target)) 287570635Sobrien target = gen_reg_rtx (GET_MODE (target)); 287690075Sobrien 287790075Sobrien /* If we're using non-call exceptions, a libcall corresponding to an 287890075Sobrien operation that may trap may also trap. */ 287990075Sobrien if (flag_non_call_exceptions && may_trap_p (equiv)) 288090075Sobrien { 288190075Sobrien for (insn = insns; insn; insn = NEXT_INSN (insn)) 288290075Sobrien if (GET_CODE (insn) == CALL_INSN) 288390075Sobrien { 288490075Sobrien rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 288590075Sobrien 288690075Sobrien if (note != 0 && INTVAL (XEXP (note, 0)) <= 0) 288790075Sobrien remove_note (insn, note); 288890075Sobrien } 288990075Sobrien } 289090075Sobrien else 289152284Sobrien /* look for any CALL_INSNs in this sequence, and attach a REG_EH_REGION 289290075Sobrien reg note to indicate that this call cannot throw or execute a nonlocal 289390075Sobrien goto (unless there is already a REG_EH_REGION note, in which case 289490075Sobrien we update it). */ 289590075Sobrien for (insn = insns; insn; insn = NEXT_INSN (insn)) 289652284Sobrien if (GET_CODE (insn) == CALL_INSN) 289790075Sobrien { 289890075Sobrien rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 289990075Sobrien 290090075Sobrien if (note != 0) 290190075Sobrien XEXP (note, 0) = GEN_INT (-1); 290290075Sobrien else 290390075Sobrien REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, GEN_INT (-1), 290490075Sobrien REG_NOTES (insn)); 290590075Sobrien } 290652284Sobrien 290718334Speter /* First emit all insns that set pseudos. Remove them from the list as 290818334Speter we go. Avoid insns that set pseudos which were referenced in previous 290918334Speter insns. These can be generated by move_by_pieces, for example, 291018334Speter to update an address. Similarly, avoid insns that reference things 291118334Speter set in previous insns. */ 291218334Speter 291318334Speter for (insn = insns; insn; insn = next) 291418334Speter { 291518334Speter rtx set = single_set (insn); 291696263Sobrien rtx note; 291718334Speter 291896263Sobrien /* Some ports (cris) create an libcall regions at their own. We must 291996263Sobrien avoid any potential nesting of LIBCALLs. */ 292096263Sobrien if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL) 292196263Sobrien remove_note (insn, note); 292296263Sobrien if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL) 292396263Sobrien remove_note (insn, note); 292496263Sobrien 292518334Speter next = NEXT_INSN (insn); 292618334Speter 292718334Speter if (set != 0 && GET_CODE (SET_DEST (set)) == REG 292818334Speter && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER 292918334Speter && (insn == insns 293090075Sobrien || ((! INSN_P(insns) 293190075Sobrien || ! reg_mentioned_p (SET_DEST (set), PATTERN (insns))) 293218334Speter && ! reg_used_between_p (SET_DEST (set), insns, insn) 293318334Speter && ! modified_in_p (SET_SRC (set), insns) 293418334Speter && ! modified_between_p (SET_SRC (set), insns, insn)))) 293518334Speter { 293618334Speter if (PREV_INSN (insn)) 293718334Speter NEXT_INSN (PREV_INSN (insn)) = next; 293818334Speter else 293918334Speter insns = next; 294018334Speter 294118334Speter if (next) 294218334Speter PREV_INSN (next) = PREV_INSN (insn); 294318334Speter 294418334Speter add_insn (insn); 294518334Speter } 294618334Speter } 294718334Speter 294818334Speter prev = get_last_insn (); 294918334Speter 295018334Speter /* Write the remaining insns followed by the final copy. */ 295118334Speter 295218334Speter for (insn = insns; insn; insn = next) 295318334Speter { 295418334Speter next = NEXT_INSN (insn); 295518334Speter 295618334Speter add_insn (insn); 295718334Speter } 295818334Speter 295918334Speter last = emit_move_insn (target, result); 296050397Sobrien if (mov_optab->handlers[(int) GET_MODE (target)].insn_code 296150397Sobrien != CODE_FOR_nothing) 296252284Sobrien set_unique_reg_note (last, REG_EQUAL, copy_rtx (equiv)); 296390075Sobrien else 296490075Sobrien { 296590075Sobrien /* Remove any existing REG_EQUAL note from "last", or else it will 296690075Sobrien be mistaken for a note referring to the full contents of the 296790075Sobrien libcall value when found together with the REG_RETVAL note added 296890075Sobrien below. An existing note can come from an insn expansion at 296990075Sobrien "last". */ 297090075Sobrien remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX)); 297190075Sobrien } 297218334Speter 297370635Sobrien if (final_dest != target) 297470635Sobrien emit_move_insn (final_dest, target); 297570635Sobrien 297618334Speter if (prev == 0) 297718334Speter first = get_insns (); 297818334Speter else 297918334Speter first = NEXT_INSN (prev); 298018334Speter 298118334Speter /* Encapsulate the block so it gets manipulated as a unit. */ 298290075Sobrien if (!flag_non_call_exceptions || !may_trap_p (equiv)) 298390075Sobrien { 298490075Sobrien REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, 298590075Sobrien REG_NOTES (first)); 298690075Sobrien REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, 298790075Sobrien REG_NOTES (last)); 298890075Sobrien } 298918334Speter} 299018334Speter 299118334Speter/* Generate code to store zero in X. */ 299218334Speter 299318334Spetervoid 299418334Speteremit_clr_insn (x) 299518334Speter rtx x; 299618334Speter{ 299718334Speter emit_move_insn (x, const0_rtx); 299818334Speter} 299918334Speter 300018334Speter/* Generate code to store 1 in X 300118334Speter assuming it contains zero beforehand. */ 300218334Speter 300318334Spetervoid 300418334Speteremit_0_to_1_insn (x) 300518334Speter rtx x; 300618334Speter{ 300718334Speter emit_move_insn (x, const1_rtx); 300818334Speter} 300918334Speter 301090075Sobrien/* Nonzero if we can perform a comparison of mode MODE straightforwardly. 301190075Sobrien PURPOSE describes how this comparison will be used. CODE is the rtx 301290075Sobrien comparison code we will be using. 301318334Speter 301490075Sobrien ??? Actually, CODE is slightly weaker than that. A target is still 301590075Sobrien required to implement all of the normal bcc operations, but not 301690075Sobrien required to implement all (or any) of the unordered bcc operations. */ 301790075Sobrien 301890075Sobrienint 301990075Sobriencan_compare_p (code, mode, purpose) 302090075Sobrien enum rtx_code code; 302190075Sobrien enum machine_mode mode; 302290075Sobrien enum can_compare_purpose purpose; 302390075Sobrien{ 302490075Sobrien do 302590075Sobrien { 302690075Sobrien if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing) 302790075Sobrien { 302890075Sobrien if (purpose == ccp_jump) 302990075Sobrien return bcc_gen_fctn[(int)code] != NULL; 303090075Sobrien else if (purpose == ccp_store_flag) 303190075Sobrien return setcc_gen_code[(int)code] != CODE_FOR_nothing; 303290075Sobrien else 303390075Sobrien /* There's only one cmov entry point, and it's allowed to fail. */ 303490075Sobrien return 1; 303590075Sobrien } 303690075Sobrien if (purpose == ccp_jump 303790075Sobrien && cbranch_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing) 303890075Sobrien return 1; 303990075Sobrien if (purpose == ccp_cmov 304090075Sobrien && cmov_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing) 304190075Sobrien return 1; 304290075Sobrien if (purpose == ccp_store_flag 304390075Sobrien && cstore_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing) 304490075Sobrien return 1; 304590075Sobrien 304690075Sobrien mode = GET_MODE_WIDER_MODE (mode); 304790075Sobrien } 304890075Sobrien while (mode != VOIDmode); 304990075Sobrien 305090075Sobrien return 0; 305190075Sobrien} 305290075Sobrien 305390075Sobrien/* This function is called when we are going to emit a compare instruction that 305490075Sobrien compares the values found in *PX and *PY, using the rtl operator COMPARISON. 305590075Sobrien 305690075Sobrien *PMODE is the mode of the inputs (in case they are const_int). 305790075Sobrien *PUNSIGNEDP nonzero says that the operands are unsigned; 305818334Speter this matters if they need to be widened. 305918334Speter 306090075Sobrien If they have mode BLKmode, then SIZE specifies the size of both operands. 306118334Speter 306290075Sobrien This function performs all the setup necessary so that the caller only has 306390075Sobrien to emit a single comparison insn. This setup can involve doing a BLKmode 306490075Sobrien comparison or emitting a library call to perform the comparison if no insn 306590075Sobrien is available to handle it. 306690075Sobrien The values which are passed in through pointers can be modified; the caller 306790075Sobrien should perform the comparison on the modified values. */ 306818334Speter 306990075Sobrienstatic void 307090075Sobrienprepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose) 307190075Sobrien rtx *px, *py; 307290075Sobrien enum rtx_code *pcomparison; 307318334Speter rtx size; 307490075Sobrien enum machine_mode *pmode; 307590075Sobrien int *punsignedp; 307690075Sobrien enum can_compare_purpose purpose; 307718334Speter{ 307890075Sobrien enum machine_mode mode = *pmode; 307990075Sobrien rtx x = *px, y = *py; 308090075Sobrien int unsignedp = *punsignedp; 308118334Speter enum mode_class class; 308218334Speter 308318334Speter class = GET_MODE_CLASS (mode); 308418334Speter 308518334Speter /* They could both be VOIDmode if both args are immediate constants, 308618334Speter but we should fold that at an earlier stage. 308718334Speter With no special code here, this will call abort, 308818334Speter reminding the programmer to implement such folding. */ 308918334Speter 309018334Speter if (mode != BLKmode && flag_force_mem) 309118334Speter { 309218334Speter x = force_not_mem (x); 309318334Speter y = force_not_mem (y); 309418334Speter } 309518334Speter 309618334Speter /* If we are inside an appropriately-short loop and one operand is an 309718334Speter expensive constant, force it into a register. */ 309890075Sobrien if (CONSTANT_P (x) && preserve_subexpressions_p () 309990075Sobrien && rtx_cost (x, COMPARE) > COSTS_N_INSNS (1)) 310018334Speter x = force_reg (mode, x); 310118334Speter 310290075Sobrien if (CONSTANT_P (y) && preserve_subexpressions_p () 310390075Sobrien && rtx_cost (y, COMPARE) > COSTS_N_INSNS (1)) 310418334Speter y = force_reg (mode, y); 310518334Speter 310652284Sobrien#ifdef HAVE_cc0 310752284Sobrien /* Abort if we have a non-canonical comparison. The RTL documentation 310852284Sobrien states that canonical comparisons are required only for targets which 310952284Sobrien have cc0. */ 311052284Sobrien if (CONSTANT_P (x) && ! CONSTANT_P (y)) 311152284Sobrien abort(); 311252284Sobrien#endif 311352284Sobrien 311418334Speter /* Don't let both operands fail to indicate the mode. */ 311518334Speter if (GET_MODE (x) == VOIDmode && GET_MODE (y) == VOIDmode) 311618334Speter x = force_reg (mode, x); 311718334Speter 311818334Speter /* Handle all BLKmode compares. */ 311918334Speter 312018334Speter if (mode == BLKmode) 312118334Speter { 312290075Sobrien rtx result; 312390075Sobrien enum machine_mode result_mode; 312490075Sobrien rtx opalign ATTRIBUTE_UNUSED 312590075Sobrien = GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT); 312690075Sobrien 312718334Speter emit_queue (); 312818334Speter x = protect_from_queue (x, 0); 312918334Speter y = protect_from_queue (y, 0); 313018334Speter 313118334Speter if (size == 0) 313218334Speter abort (); 313318334Speter#ifdef HAVE_cmpstrqi 313418334Speter if (HAVE_cmpstrqi 313518334Speter && GET_CODE (size) == CONST_INT 313618334Speter && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode))) 313718334Speter { 313890075Sobrien result_mode = insn_data[(int) CODE_FOR_cmpstrqi].operand[0].mode; 313990075Sobrien result = gen_reg_rtx (result_mode); 314090075Sobrien emit_insn (gen_cmpstrqi (result, x, y, size, opalign)); 314118334Speter } 314218334Speter else 314318334Speter#endif 314418334Speter#ifdef HAVE_cmpstrhi 314518334Speter if (HAVE_cmpstrhi 314618334Speter && GET_CODE (size) == CONST_INT 314718334Speter && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode))) 314818334Speter { 314990075Sobrien result_mode = insn_data[(int) CODE_FOR_cmpstrhi].operand[0].mode; 315090075Sobrien result = gen_reg_rtx (result_mode); 315190075Sobrien emit_insn (gen_cmpstrhi (result, x, y, size, opalign)); 315218334Speter } 315318334Speter else 315418334Speter#endif 315518334Speter#ifdef HAVE_cmpstrsi 315618334Speter if (HAVE_cmpstrsi) 315718334Speter { 315890075Sobrien result_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; 315990075Sobrien result = gen_reg_rtx (result_mode); 316018334Speter size = protect_from_queue (size, 0); 316118334Speter emit_insn (gen_cmpstrsi (result, x, y, 316218334Speter convert_to_mode (SImode, size, 1), 316390075Sobrien opalign)); 316418334Speter } 316518334Speter else 316618334Speter#endif 316718334Speter { 316818334Speter#ifdef TARGET_MEM_FUNCTIONS 316990075Sobrien emit_library_call (memcmp_libfunc, LCT_PURE_MAKE_BLOCK, 317018334Speter TYPE_MODE (integer_type_node), 3, 317118334Speter XEXP (x, 0), Pmode, XEXP (y, 0), Pmode, 317250397Sobrien convert_to_mode (TYPE_MODE (sizetype), size, 317350397Sobrien TREE_UNSIGNED (sizetype)), 317450397Sobrien TYPE_MODE (sizetype)); 317518334Speter#else 317690075Sobrien emit_library_call (bcmp_libfunc, LCT_PURE_MAKE_BLOCK, 317718334Speter TYPE_MODE (integer_type_node), 3, 317818334Speter XEXP (x, 0), Pmode, XEXP (y, 0), Pmode, 317950397Sobrien convert_to_mode (TYPE_MODE (integer_type_node), 318050397Sobrien size, 318150397Sobrien TREE_UNSIGNED (integer_type_node)), 318250397Sobrien TYPE_MODE (integer_type_node)); 318318334Speter#endif 318450397Sobrien 318550397Sobrien /* Immediately move the result of the libcall into a pseudo 318650397Sobrien register so reload doesn't clobber the value if it needs 318750397Sobrien the return register for a spill reg. */ 318850397Sobrien result = gen_reg_rtx (TYPE_MODE (integer_type_node)); 318990075Sobrien result_mode = TYPE_MODE (integer_type_node); 319050397Sobrien emit_move_insn (result, 319190075Sobrien hard_libcall_value (result_mode)); 319218334Speter } 319390075Sobrien *px = result; 319490075Sobrien *py = const0_rtx; 319590075Sobrien *pmode = result_mode; 319618334Speter return; 319718334Speter } 319818334Speter 319990075Sobrien *px = x; 320090075Sobrien *py = y; 320190075Sobrien if (can_compare_p (*pcomparison, mode, purpose)) 320290075Sobrien return; 320318334Speter 320418334Speter /* Handle a lib call just for the mode we are using. */ 320518334Speter 320690075Sobrien if (cmp_optab->handlers[(int) mode].libfunc && class != MODE_FLOAT) 320718334Speter { 320818334Speter rtx libfunc = cmp_optab->handlers[(int) mode].libfunc; 320950397Sobrien rtx result; 321050397Sobrien 321118334Speter /* If we want unsigned, and this mode has a distinct unsigned 321218334Speter comparison routine, use that. */ 321318334Speter if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc) 321418334Speter libfunc = ucmp_optab->handlers[(int) mode].libfunc; 321518334Speter 321690075Sobrien emit_library_call (libfunc, LCT_CONST_MAKE_BLOCK, word_mode, 2, x, mode, 321790075Sobrien y, mode); 321818334Speter 321950397Sobrien /* Immediately move the result of the libcall into a pseudo 322050397Sobrien register so reload doesn't clobber the value if it needs 322150397Sobrien the return register for a spill reg. */ 322250397Sobrien result = gen_reg_rtx (word_mode); 322350397Sobrien emit_move_insn (result, hard_libcall_value (word_mode)); 322450397Sobrien 322518334Speter /* Integer comparison returns a result that must be compared against 1, 322618334Speter so that even if we do an unsigned compare afterward, 322718334Speter there is still a value that can represent the result "less than". */ 322890075Sobrien *px = result; 322990075Sobrien *py = const1_rtx; 323090075Sobrien *pmode = word_mode; 323118334Speter return; 323218334Speter } 323318334Speter 323418334Speter if (class == MODE_FLOAT) 323590075Sobrien prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp); 323618334Speter 323718334Speter else 323818334Speter abort (); 323918334Speter} 324018334Speter 324190075Sobrien/* Before emitting an insn with code ICODE, make sure that X, which is going 324290075Sobrien to be used for operand OPNUM of the insn, is converted from mode MODE to 324390075Sobrien WIDER_MODE (UNSIGNEDP determines whether it is an unsigned conversion), and 324490075Sobrien that it is accepted by the operand predicate. Return the new value. */ 324590075Sobrien 324690075Sobrienrtx 324790075Sobrienprepare_operand (icode, x, opnum, mode, wider_mode, unsignedp) 324890075Sobrien int icode; 324990075Sobrien rtx x; 325090075Sobrien int opnum; 325190075Sobrien enum machine_mode mode, wider_mode; 325290075Sobrien int unsignedp; 325390075Sobrien{ 325490075Sobrien x = protect_from_queue (x, 0); 325590075Sobrien 325690075Sobrien if (mode != wider_mode) 325790075Sobrien x = convert_modes (wider_mode, mode, x, unsignedp); 325890075Sobrien 325990075Sobrien if (! (*insn_data[icode].operand[opnum].predicate) 326090075Sobrien (x, insn_data[icode].operand[opnum].mode)) 326190075Sobrien x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x); 326290075Sobrien return x; 326390075Sobrien} 326490075Sobrien 326590075Sobrien/* Subroutine of emit_cmp_and_jump_insns; this function is called when we know 326690075Sobrien we can do the comparison. 326790075Sobrien The arguments are the same as for emit_cmp_and_jump_insns; but LABEL may 326890075Sobrien be NULL_RTX which indicates that only a comparison is to be generated. */ 326990075Sobrien 327090075Sobrienstatic void 327190075Sobrienemit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label) 327290075Sobrien rtx x, y; 327390075Sobrien enum machine_mode mode; 327490075Sobrien enum rtx_code comparison; 327590075Sobrien int unsignedp; 327690075Sobrien rtx label; 327790075Sobrien{ 327890075Sobrien rtx test = gen_rtx_fmt_ee (comparison, mode, x, y); 327990075Sobrien enum mode_class class = GET_MODE_CLASS (mode); 328090075Sobrien enum machine_mode wider_mode = mode; 328190075Sobrien 328290075Sobrien /* Try combined insns first. */ 328390075Sobrien do 328490075Sobrien { 328590075Sobrien enum insn_code icode; 328690075Sobrien PUT_MODE (test, wider_mode); 328790075Sobrien 328890075Sobrien if (label) 328990075Sobrien { 329090075Sobrien icode = cbranch_optab->handlers[(int)wider_mode].insn_code; 329190075Sobrien 329290075Sobrien if (icode != CODE_FOR_nothing 329390075Sobrien && (*insn_data[icode].operand[0].predicate) (test, wider_mode)) 329490075Sobrien { 329590075Sobrien x = prepare_operand (icode, x, 1, mode, wider_mode, unsignedp); 329690075Sobrien y = prepare_operand (icode, y, 2, mode, wider_mode, unsignedp); 329790075Sobrien emit_jump_insn (GEN_FCN (icode) (test, x, y, label)); 329890075Sobrien return; 329990075Sobrien } 330090075Sobrien } 330190075Sobrien 330290075Sobrien /* Handle some compares against zero. */ 330390075Sobrien icode = (int) tst_optab->handlers[(int) wider_mode].insn_code; 330490075Sobrien if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing) 330590075Sobrien { 330690075Sobrien x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp); 330790075Sobrien emit_insn (GEN_FCN (icode) (x)); 330890075Sobrien if (label) 330990075Sobrien emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label)); 331090075Sobrien return; 331190075Sobrien } 331290075Sobrien 331390075Sobrien /* Handle compares for which there is a directly suitable insn. */ 331490075Sobrien 331590075Sobrien icode = (int) cmp_optab->handlers[(int) wider_mode].insn_code; 331690075Sobrien if (icode != CODE_FOR_nothing) 331790075Sobrien { 331890075Sobrien x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp); 331990075Sobrien y = prepare_operand (icode, y, 1, mode, wider_mode, unsignedp); 332090075Sobrien emit_insn (GEN_FCN (icode) (x, y)); 332190075Sobrien if (label) 332290075Sobrien emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label)); 332390075Sobrien return; 332490075Sobrien } 332590075Sobrien 332690075Sobrien if (class != MODE_INT && class != MODE_FLOAT 332790075Sobrien && class != MODE_COMPLEX_FLOAT) 332890075Sobrien break; 332990075Sobrien 333090075Sobrien wider_mode = GET_MODE_WIDER_MODE (wider_mode); 333190075Sobrien } while (wider_mode != VOIDmode); 333290075Sobrien 333390075Sobrien abort (); 333490075Sobrien} 333590075Sobrien 333652284Sobrien/* Generate code to compare X with Y so that the condition codes are 333752284Sobrien set and to jump to LABEL if the condition is true. If X is a 333852284Sobrien constant and Y is not a constant, then the comparison is swapped to 333952284Sobrien ensure that the comparison RTL has the canonical form. 334052284Sobrien 334152284Sobrien UNSIGNEDP nonzero says that X and Y are unsigned; this matters if they 334252284Sobrien need to be widened by emit_cmp_insn. UNSIGNEDP is also used to select 334352284Sobrien the proper branch condition code. 334452284Sobrien 334590075Sobrien If X and Y have mode BLKmode, then SIZE specifies the size of both X and Y. 334652284Sobrien 334752284Sobrien MODE is the mode of the inputs (in case they are const_int). 334852284Sobrien 334952284Sobrien COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). It will 335052284Sobrien be passed unchanged to emit_cmp_insn, then potentially converted into an 335152284Sobrien unsigned variant based on UNSIGNEDP to select a proper jump instruction. */ 335252284Sobrien 335352284Sobrienvoid 335490075Sobrienemit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, label) 335552284Sobrien rtx x, y; 335652284Sobrien enum rtx_code comparison; 335752284Sobrien rtx size; 335852284Sobrien enum machine_mode mode; 335952284Sobrien int unsignedp; 336052284Sobrien rtx label; 336152284Sobrien{ 336290075Sobrien rtx op0 = x, op1 = y; 336390075Sobrien 336490075Sobrien /* Swap operands and condition to ensure canonical RTL. */ 336590075Sobrien if (swap_commutative_operands_p (x, y)) 336652284Sobrien { 336790075Sobrien /* If we're not emitting a branch, this means some caller 336890075Sobrien is out of sync. */ 336990075Sobrien if (! label) 337090075Sobrien abort (); 337190075Sobrien 337290075Sobrien op0 = y, op1 = x; 337352284Sobrien comparison = swap_condition (comparison); 337452284Sobrien } 337552284Sobrien 337652284Sobrien#ifdef HAVE_cc0 337752284Sobrien /* If OP0 is still a constant, then both X and Y must be constants. Force 337852284Sobrien X into a register to avoid aborting in emit_cmp_insn due to non-canonical 337952284Sobrien RTL. */ 338052284Sobrien if (CONSTANT_P (op0)) 338152284Sobrien op0 = force_reg (mode, op0); 338252284Sobrien#endif 338352284Sobrien 338490075Sobrien emit_queue (); 338552284Sobrien if (unsignedp) 338652284Sobrien comparison = unsigned_condition (comparison); 338790075Sobrien 338890075Sobrien prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp, 338990075Sobrien ccp_jump); 339090075Sobrien emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label); 339152284Sobrien} 339252284Sobrien 339390075Sobrien/* Like emit_cmp_and_jump_insns, but generate only the comparison. */ 339452284Sobrien 339590075Sobrienvoid 339690075Sobrienemit_cmp_insn (x, y, comparison, size, mode, unsignedp) 339790075Sobrien rtx x, y; 339890075Sobrien enum rtx_code comparison; 339990075Sobrien rtx size; 340018334Speter enum machine_mode mode; 340190075Sobrien int unsignedp; 340218334Speter{ 340390075Sobrien emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, 0); 340418334Speter} 340518334Speter 340618334Speter/* Emit a library call comparison between floating point X and Y. 340718334Speter COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). */ 340818334Speter 340990075Sobrienstatic void 341090075Sobrienprepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp) 341190075Sobrien rtx *px, *py; 341290075Sobrien enum rtx_code *pcomparison; 341390075Sobrien enum machine_mode *pmode; 341490075Sobrien int *punsignedp; 341518334Speter{ 341690075Sobrien enum rtx_code comparison = *pcomparison; 341790075Sobrien rtx x = *px = protect_from_queue (*px, 0); 341890075Sobrien rtx y = *py = protect_from_queue (*py, 0); 341918334Speter enum machine_mode mode = GET_MODE (x); 342018334Speter rtx libfunc = 0; 342150397Sobrien rtx result; 342218334Speter 342318334Speter if (mode == HFmode) 342418334Speter switch (comparison) 342518334Speter { 342618334Speter case EQ: 342718334Speter libfunc = eqhf2_libfunc; 342818334Speter break; 342918334Speter 343018334Speter case NE: 343118334Speter libfunc = nehf2_libfunc; 343218334Speter break; 343318334Speter 343418334Speter case GT: 343518334Speter libfunc = gthf2_libfunc; 343618334Speter break; 343718334Speter 343818334Speter case GE: 343918334Speter libfunc = gehf2_libfunc; 344018334Speter break; 344118334Speter 344218334Speter case LT: 344318334Speter libfunc = lthf2_libfunc; 344418334Speter break; 344518334Speter 344618334Speter case LE: 344718334Speter libfunc = lehf2_libfunc; 344818334Speter break; 344950397Sobrien 345090075Sobrien case UNORDERED: 345190075Sobrien libfunc = unordhf2_libfunc; 345290075Sobrien break; 345390075Sobrien 345450397Sobrien default: 345550397Sobrien break; 345618334Speter } 345718334Speter else if (mode == SFmode) 345818334Speter switch (comparison) 345918334Speter { 346018334Speter case EQ: 346118334Speter libfunc = eqsf2_libfunc; 346218334Speter break; 346318334Speter 346418334Speter case NE: 346518334Speter libfunc = nesf2_libfunc; 346618334Speter break; 346718334Speter 346818334Speter case GT: 346918334Speter libfunc = gtsf2_libfunc; 347018334Speter break; 347118334Speter 347218334Speter case GE: 347318334Speter libfunc = gesf2_libfunc; 347418334Speter break; 347518334Speter 347618334Speter case LT: 347718334Speter libfunc = ltsf2_libfunc; 347818334Speter break; 347918334Speter 348018334Speter case LE: 348118334Speter libfunc = lesf2_libfunc; 348218334Speter break; 348350397Sobrien 348490075Sobrien case UNORDERED: 348590075Sobrien libfunc = unordsf2_libfunc; 348690075Sobrien break; 348790075Sobrien 348850397Sobrien default: 348950397Sobrien break; 349018334Speter } 349118334Speter else if (mode == DFmode) 349218334Speter switch (comparison) 349318334Speter { 349418334Speter case EQ: 349518334Speter libfunc = eqdf2_libfunc; 349618334Speter break; 349718334Speter 349818334Speter case NE: 349918334Speter libfunc = nedf2_libfunc; 350018334Speter break; 350118334Speter 350218334Speter case GT: 350318334Speter libfunc = gtdf2_libfunc; 350418334Speter break; 350518334Speter 350618334Speter case GE: 350718334Speter libfunc = gedf2_libfunc; 350818334Speter break; 350918334Speter 351018334Speter case LT: 351118334Speter libfunc = ltdf2_libfunc; 351218334Speter break; 351318334Speter 351418334Speter case LE: 351518334Speter libfunc = ledf2_libfunc; 351618334Speter break; 351750397Sobrien 351890075Sobrien case UNORDERED: 351990075Sobrien libfunc = unorddf2_libfunc; 352090075Sobrien break; 352190075Sobrien 352250397Sobrien default: 352350397Sobrien break; 352418334Speter } 352518334Speter else if (mode == XFmode) 352618334Speter switch (comparison) 352718334Speter { 352818334Speter case EQ: 352918334Speter libfunc = eqxf2_libfunc; 353018334Speter break; 353118334Speter 353218334Speter case NE: 353318334Speter libfunc = nexf2_libfunc; 353418334Speter break; 353518334Speter 353618334Speter case GT: 353718334Speter libfunc = gtxf2_libfunc; 353818334Speter break; 353918334Speter 354018334Speter case GE: 354118334Speter libfunc = gexf2_libfunc; 354218334Speter break; 354318334Speter 354418334Speter case LT: 354518334Speter libfunc = ltxf2_libfunc; 354618334Speter break; 354718334Speter 354818334Speter case LE: 354918334Speter libfunc = lexf2_libfunc; 355018334Speter break; 355150397Sobrien 355290075Sobrien case UNORDERED: 355390075Sobrien libfunc = unordxf2_libfunc; 355490075Sobrien break; 355590075Sobrien 355650397Sobrien default: 355750397Sobrien break; 355818334Speter } 355918334Speter else if (mode == TFmode) 356018334Speter switch (comparison) 356118334Speter { 356218334Speter case EQ: 356318334Speter libfunc = eqtf2_libfunc; 356418334Speter break; 356518334Speter 356618334Speter case NE: 356718334Speter libfunc = netf2_libfunc; 356818334Speter break; 356918334Speter 357018334Speter case GT: 357118334Speter libfunc = gttf2_libfunc; 357218334Speter break; 357318334Speter 357418334Speter case GE: 357518334Speter libfunc = getf2_libfunc; 357618334Speter break; 357718334Speter 357818334Speter case LT: 357918334Speter libfunc = lttf2_libfunc; 358018334Speter break; 358118334Speter 358218334Speter case LE: 358318334Speter libfunc = letf2_libfunc; 358418334Speter break; 358550397Sobrien 358690075Sobrien case UNORDERED: 358790075Sobrien libfunc = unordtf2_libfunc; 358890075Sobrien break; 358990075Sobrien 359050397Sobrien default: 359150397Sobrien break; 359218334Speter } 359318334Speter else 359418334Speter { 359518334Speter enum machine_mode wider_mode; 359618334Speter 359718334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 359818334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 359918334Speter { 360018334Speter if ((cmp_optab->handlers[(int) wider_mode].insn_code 360118334Speter != CODE_FOR_nothing) 360218334Speter || (cmp_optab->handlers[(int) wider_mode].libfunc != 0)) 360318334Speter { 360418334Speter x = protect_from_queue (x, 0); 360518334Speter y = protect_from_queue (y, 0); 360690075Sobrien *px = convert_to_mode (wider_mode, x, 0); 360790075Sobrien *py = convert_to_mode (wider_mode, y, 0); 360890075Sobrien prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp); 360918334Speter return; 361018334Speter } 361118334Speter } 361218334Speter abort (); 361318334Speter } 361418334Speter 361518334Speter if (libfunc == 0) 361618334Speter abort (); 361718334Speter 361890075Sobrien emit_library_call (libfunc, LCT_CONST_MAKE_BLOCK, word_mode, 2, x, mode, y, 361990075Sobrien mode); 362018334Speter 362150397Sobrien /* Immediately move the result of the libcall into a pseudo 362250397Sobrien register so reload doesn't clobber the value if it needs 362350397Sobrien the return register for a spill reg. */ 362450397Sobrien result = gen_reg_rtx (word_mode); 362550397Sobrien emit_move_insn (result, hard_libcall_value (word_mode)); 362690075Sobrien *px = result; 362790075Sobrien *py = const0_rtx; 362890075Sobrien *pmode = word_mode; 362990075Sobrien if (comparison == UNORDERED) 363090075Sobrien *pcomparison = NE; 363190075Sobrien#ifdef FLOAT_LIB_COMPARE_RETURNS_BOOL 363290075Sobrien else if (FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison)) 363390075Sobrien *pcomparison = NE; 363490075Sobrien#endif 363590075Sobrien *punsignedp = 0; 363618334Speter} 363718334Speter 363818334Speter/* Generate code to indirectly jump to a location given in the rtx LOC. */ 363918334Speter 364018334Spetervoid 364118334Speteremit_indirect_jump (loc) 364218334Speter rtx loc; 364318334Speter{ 364490075Sobrien if (! ((*insn_data[(int)CODE_FOR_indirect_jump].operand[0].predicate) 364518334Speter (loc, Pmode))) 364618334Speter loc = copy_to_mode_reg (Pmode, loc); 364718334Speter 364818334Speter emit_jump_insn (gen_indirect_jump (loc)); 364918334Speter emit_barrier (); 365018334Speter} 365118334Speter 365218334Speter#ifdef HAVE_conditional_move 365318334Speter 365418334Speter/* Emit a conditional move instruction if the machine supports one for that 365518334Speter condition and machine mode. 365618334Speter 365718334Speter OP0 and OP1 are the operands that should be compared using CODE. CMODE is 365818334Speter the mode to use should they be constants. If it is VOIDmode, they cannot 365918334Speter both be constants. 366018334Speter 366118334Speter OP2 should be stored in TARGET if the comparison is true, otherwise OP3 366218334Speter should be stored there. MODE is the mode to use should they be constants. 366318334Speter If it is VOIDmode, they cannot both be constants. 366418334Speter 366518334Speter The result is either TARGET (perhaps modified) or NULL_RTX if the operation 366618334Speter is not supported. */ 366718334Speter 366818334Speterrtx 366918334Speteremit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode, 367018334Speter unsignedp) 367118334Speter rtx target; 367218334Speter enum rtx_code code; 367318334Speter rtx op0, op1; 367418334Speter enum machine_mode cmode; 367518334Speter rtx op2, op3; 367618334Speter enum machine_mode mode; 367718334Speter int unsignedp; 367818334Speter{ 367918334Speter rtx tem, subtarget, comparison, insn; 368018334Speter enum insn_code icode; 368190075Sobrien enum rtx_code reversed; 368218334Speter 368318334Speter /* If one operand is constant, make it the second one. Only do this 368418334Speter if the other operand is not constant as well. */ 368518334Speter 368690075Sobrien if (swap_commutative_operands_p (op0, op1)) 368718334Speter { 368818334Speter tem = op0; 368918334Speter op0 = op1; 369018334Speter op1 = tem; 369118334Speter code = swap_condition (code); 369218334Speter } 369318334Speter 369490075Sobrien /* get_condition will prefer to generate LT and GT even if the old 369590075Sobrien comparison was against zero, so undo that canonicalization here since 369690075Sobrien comparisons against zero are cheaper. */ 369790075Sobrien if (code == LT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == 1) 369890075Sobrien code = LE, op1 = const0_rtx; 369990075Sobrien else if (code == GT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == -1) 370090075Sobrien code = GE, op1 = const0_rtx; 370190075Sobrien 370218334Speter if (cmode == VOIDmode) 370318334Speter cmode = GET_MODE (op0); 370418334Speter 370590075Sobrien if (swap_commutative_operands_p (op2, op3) 370690075Sobrien && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL)) 370790075Sobrien != UNKNOWN)) 370818334Speter { 370918334Speter tem = op2; 371018334Speter op2 = op3; 371118334Speter op3 = tem; 371290075Sobrien code = reversed; 371318334Speter } 371418334Speter 371518334Speter if (mode == VOIDmode) 371618334Speter mode = GET_MODE (op2); 371718334Speter 371818334Speter icode = movcc_gen_code[mode]; 371918334Speter 372018334Speter if (icode == CODE_FOR_nothing) 372118334Speter return 0; 372218334Speter 372318334Speter if (flag_force_mem) 372418334Speter { 372518334Speter op2 = force_not_mem (op2); 372618334Speter op3 = force_not_mem (op3); 372718334Speter } 372818334Speter 372918334Speter if (target) 373018334Speter target = protect_from_queue (target, 1); 373118334Speter else 373218334Speter target = gen_reg_rtx (mode); 373318334Speter 373418334Speter subtarget = target; 373518334Speter 373618334Speter emit_queue (); 373718334Speter 373818334Speter op2 = protect_from_queue (op2, 0); 373918334Speter op3 = protect_from_queue (op3, 0); 374018334Speter 374118334Speter /* If the insn doesn't accept these operands, put them in pseudos. */ 374218334Speter 374390075Sobrien if (! (*insn_data[icode].operand[0].predicate) 374490075Sobrien (subtarget, insn_data[icode].operand[0].mode)) 374590075Sobrien subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode); 374618334Speter 374790075Sobrien if (! (*insn_data[icode].operand[2].predicate) 374890075Sobrien (op2, insn_data[icode].operand[2].mode)) 374990075Sobrien op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2); 375018334Speter 375190075Sobrien if (! (*insn_data[icode].operand[3].predicate) 375290075Sobrien (op3, insn_data[icode].operand[3].mode)) 375390075Sobrien op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3); 375418334Speter 375518334Speter /* Everything should now be in the suitable form, so emit the compare insn 375618334Speter and then the conditional move. */ 375718334Speter 375818334Speter comparison 375990075Sobrien = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX); 376018334Speter 376118334Speter /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)? */ 376290075Sobrien /* We can get const0_rtx or const_true_rtx in some circumstances. Just 376390075Sobrien return NULL and let the caller figure out how best to deal with this 376490075Sobrien situation. */ 376518334Speter if (GET_CODE (comparison) != code) 376690075Sobrien return NULL_RTX; 376718334Speter 376818334Speter insn = GEN_FCN (icode) (subtarget, comparison, op2, op3); 376918334Speter 377018334Speter /* If that failed, then give up. */ 377118334Speter if (insn == 0) 377218334Speter return 0; 377318334Speter 377418334Speter emit_insn (insn); 377518334Speter 377618334Speter if (subtarget != target) 377718334Speter convert_move (target, subtarget, 0); 377818334Speter 377918334Speter return target; 378018334Speter} 378118334Speter 378218334Speter/* Return non-zero if a conditional move of mode MODE is supported. 378318334Speter 378418334Speter This function is for combine so it can tell whether an insn that looks 378518334Speter like a conditional move is actually supported by the hardware. If we 378618334Speter guess wrong we lose a bit on optimization, but that's it. */ 378718334Speter/* ??? sparc64 supports conditionally moving integers values based on fp 378818334Speter comparisons, and vice versa. How do we handle them? */ 378918334Speter 379018334Speterint 379118334Spetercan_conditionally_move_p (mode) 379218334Speter enum machine_mode mode; 379318334Speter{ 379418334Speter if (movcc_gen_code[mode] != CODE_FOR_nothing) 379518334Speter return 1; 379618334Speter 379718334Speter return 0; 379818334Speter} 379918334Speter 380018334Speter#endif /* HAVE_conditional_move */ 380118334Speter 380290075Sobrien/* These functions generate an insn body and return it 380318334Speter rather than emitting the insn. 380418334Speter 380518334Speter They do not protect from queued increments, 380618334Speter because they may be used 1) in protect_from_queue itself 380718334Speter and 2) in other passes where there is no queue. */ 380818334Speter 380918334Speter/* Generate and return an insn body to add Y to X. */ 381018334Speter 381118334Speterrtx 381218334Spetergen_add2_insn (x, y) 381318334Speter rtx x, y; 381418334Speter{ 381518334Speter int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code; 381618334Speter 381790075Sobrien if (! ((*insn_data[icode].operand[0].predicate) 381890075Sobrien (x, insn_data[icode].operand[0].mode)) 381990075Sobrien || ! ((*insn_data[icode].operand[1].predicate) 382090075Sobrien (x, insn_data[icode].operand[1].mode)) 382190075Sobrien || ! ((*insn_data[icode].operand[2].predicate) 382290075Sobrien (y, insn_data[icode].operand[2].mode))) 382318334Speter abort (); 382418334Speter 382518334Speter return (GEN_FCN (icode) (x, x, y)); 382618334Speter} 382718334Speter 382890075Sobrien/* Generate and return an insn body to add r1 and c, 382990075Sobrien storing the result in r0. */ 383090075Sobrienrtx 383190075Sobriengen_add3_insn (r0, r1, c) 383290075Sobrien rtx r0, r1, c; 383390075Sobrien{ 383490075Sobrien int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code; 383590075Sobrien 383690075Sobrien if (icode == CODE_FOR_nothing 383790075Sobrien || ! ((*insn_data[icode].operand[0].predicate) 383890075Sobrien (r0, insn_data[icode].operand[0].mode)) 383990075Sobrien || ! ((*insn_data[icode].operand[1].predicate) 384090075Sobrien (r1, insn_data[icode].operand[1].mode)) 384190075Sobrien || ! ((*insn_data[icode].operand[2].predicate) 384290075Sobrien (c, insn_data[icode].operand[2].mode))) 384390075Sobrien return NULL_RTX; 384490075Sobrien 384590075Sobrien return (GEN_FCN (icode) (r0, r1, c)); 384690075Sobrien} 384790075Sobrien 384818334Speterint 384990075Sobrienhave_add2_insn (x, y) 385090075Sobrien rtx x, y; 385118334Speter{ 385290075Sobrien int icode; 385390075Sobrien 385490075Sobrien if (GET_MODE (x) == VOIDmode) 385590075Sobrien abort (); 385690075Sobrien 385790075Sobrien icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code; 385890075Sobrien 385990075Sobrien if (icode == CODE_FOR_nothing) 386090075Sobrien return 0; 386190075Sobrien 386290075Sobrien if (! ((*insn_data[icode].operand[0].predicate) 386390075Sobrien (x, insn_data[icode].operand[0].mode)) 386490075Sobrien || ! ((*insn_data[icode].operand[1].predicate) 386590075Sobrien (x, insn_data[icode].operand[1].mode)) 386690075Sobrien || ! ((*insn_data[icode].operand[2].predicate) 386790075Sobrien (y, insn_data[icode].operand[2].mode))) 386890075Sobrien return 0; 386990075Sobrien 387090075Sobrien return 1; 387118334Speter} 387218334Speter 387318334Speter/* Generate and return an insn body to subtract Y from X. */ 387418334Speter 387518334Speterrtx 387618334Spetergen_sub2_insn (x, y) 387718334Speter rtx x, y; 387818334Speter{ 387918334Speter int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code; 388018334Speter 388190075Sobrien if (! ((*insn_data[icode].operand[0].predicate) 388290075Sobrien (x, insn_data[icode].operand[0].mode)) 388390075Sobrien || ! ((*insn_data[icode].operand[1].predicate) 388490075Sobrien (x, insn_data[icode].operand[1].mode)) 388590075Sobrien || ! ((*insn_data[icode].operand[2].predicate) 388690075Sobrien (y, insn_data[icode].operand[2].mode))) 388718334Speter abort (); 388818334Speter 388918334Speter return (GEN_FCN (icode) (x, x, y)); 389018334Speter} 389118334Speter 389290075Sobrien/* Generate and return an insn body to subtract r1 and c, 389390075Sobrien storing the result in r0. */ 389490075Sobrienrtx 389590075Sobriengen_sub3_insn (r0, r1, c) 389690075Sobrien rtx r0, r1, c; 389790075Sobrien{ 389890075Sobrien int icode = (int) sub_optab->handlers[(int) GET_MODE (r0)].insn_code; 389990075Sobrien 390090075Sobrien if (icode == CODE_FOR_nothing 390190075Sobrien || ! ((*insn_data[icode].operand[0].predicate) 390290075Sobrien (r0, insn_data[icode].operand[0].mode)) 390390075Sobrien || ! ((*insn_data[icode].operand[1].predicate) 390490075Sobrien (r1, insn_data[icode].operand[1].mode)) 390590075Sobrien || ! ((*insn_data[icode].operand[2].predicate) 390690075Sobrien (c, insn_data[icode].operand[2].mode))) 390790075Sobrien return NULL_RTX; 390890075Sobrien 390990075Sobrien return (GEN_FCN (icode) (r0, r1, c)); 391090075Sobrien} 391190075Sobrien 391218334Speterint 391390075Sobrienhave_sub2_insn (x, y) 391490075Sobrien rtx x, y; 391518334Speter{ 391690075Sobrien int icode; 391790075Sobrien 391890075Sobrien if (GET_MODE (x) == VOIDmode) 391990075Sobrien abort (); 392090075Sobrien 392190075Sobrien icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code; 392290075Sobrien 392390075Sobrien if (icode == CODE_FOR_nothing) 392490075Sobrien return 0; 392590075Sobrien 392690075Sobrien if (! ((*insn_data[icode].operand[0].predicate) 392790075Sobrien (x, insn_data[icode].operand[0].mode)) 392890075Sobrien || ! ((*insn_data[icode].operand[1].predicate) 392990075Sobrien (x, insn_data[icode].operand[1].mode)) 393090075Sobrien || ! ((*insn_data[icode].operand[2].predicate) 393190075Sobrien (y, insn_data[icode].operand[2].mode))) 393290075Sobrien return 0; 393390075Sobrien 393490075Sobrien return 1; 393518334Speter} 393618334Speter 393718334Speter/* Generate the body of an instruction to copy Y into X. 393818334Speter It may be a SEQUENCE, if one insn isn't enough. */ 393918334Speter 394018334Speterrtx 394118334Spetergen_move_insn (x, y) 394218334Speter rtx x, y; 394318334Speter{ 394490075Sobrien enum machine_mode mode = GET_MODE (x); 394518334Speter enum insn_code insn_code; 394618334Speter rtx seq; 394718334Speter 394818334Speter if (mode == VOIDmode) 394918334Speter mode = GET_MODE (y); 395018334Speter 395118334Speter insn_code = mov_optab->handlers[(int) mode].insn_code; 395218334Speter 395318334Speter /* Handle MODE_CC modes: If we don't have a special move insn for this mode, 395418334Speter find a mode to do it in. If we have a movcc, use it. Otherwise, 395518334Speter find the MODE_INT mode of the same width. */ 395618334Speter 395718334Speter if (GET_MODE_CLASS (mode) == MODE_CC && insn_code == CODE_FOR_nothing) 395818334Speter { 395918334Speter enum machine_mode tmode = VOIDmode; 396018334Speter rtx x1 = x, y1 = y; 396118334Speter 396218334Speter if (mode != CCmode 396318334Speter && mov_optab->handlers[(int) CCmode].insn_code != CODE_FOR_nothing) 396418334Speter tmode = CCmode; 396518334Speter else 396618334Speter for (tmode = QImode; tmode != VOIDmode; 396718334Speter tmode = GET_MODE_WIDER_MODE (tmode)) 396818334Speter if (GET_MODE_SIZE (tmode) == GET_MODE_SIZE (mode)) 396918334Speter break; 397018334Speter 397118334Speter if (tmode == VOIDmode) 397218334Speter abort (); 397318334Speter 397418334Speter /* Get X and Y in TMODE. We can't use gen_lowpart here because it 397518334Speter may call change_address which is not appropriate if we were 397618334Speter called when a reload was in progress. We don't have to worry 397718334Speter about changing the address since the size in bytes is supposed to 397818334Speter be the same. Copy the MEM to change the mode and move any 397918334Speter substitutions from the old MEM to the new one. */ 398018334Speter 398118334Speter if (reload_in_progress) 398218334Speter { 398318334Speter x = gen_lowpart_common (tmode, x1); 398418334Speter if (x == 0 && GET_CODE (x1) == MEM) 398518334Speter { 398690075Sobrien x = adjust_address_nv (x1, tmode, 0); 398718334Speter copy_replacements (x1, x); 398818334Speter } 398918334Speter 399018334Speter y = gen_lowpart_common (tmode, y1); 399118334Speter if (y == 0 && GET_CODE (y1) == MEM) 399218334Speter { 399390075Sobrien y = adjust_address_nv (y1, tmode, 0); 399418334Speter copy_replacements (y1, y); 399518334Speter } 399618334Speter } 399718334Speter else 399818334Speter { 399918334Speter x = gen_lowpart (tmode, x); 400018334Speter y = gen_lowpart (tmode, y); 400118334Speter } 400218334Speter 400318334Speter insn_code = mov_optab->handlers[(int) tmode].insn_code; 400418334Speter return (GEN_FCN (insn_code) (x, y)); 400518334Speter } 400618334Speter 400718334Speter start_sequence (); 400818334Speter emit_move_insn_1 (x, y); 400918334Speter seq = gen_sequence (); 401018334Speter end_sequence (); 401118334Speter return seq; 401218334Speter} 401318334Speter 401418334Speter/* Return the insn code used to extend FROM_MODE to TO_MODE. 401518334Speter UNSIGNEDP specifies zero-extension instead of sign-extension. If 401618334Speter no such operation exists, CODE_FOR_nothing will be returned. */ 401718334Speter 401818334Speterenum insn_code 401918334Spetercan_extend_p (to_mode, from_mode, unsignedp) 402018334Speter enum machine_mode to_mode, from_mode; 402118334Speter int unsignedp; 402218334Speter{ 402390075Sobrien#ifdef HAVE_ptr_extend 402490075Sobrien if (unsignedp < 0) 402590075Sobrien return CODE_FOR_ptr_extend; 402690075Sobrien else 402790075Sobrien#endif 402890075Sobrien return extendtab[(int) to_mode][(int) from_mode][unsignedp != 0]; 402918334Speter} 403018334Speter 403118334Speter/* Generate the body of an insn to extend Y (with mode MFROM) 403218334Speter into X (with mode MTO). Do zero-extension if UNSIGNEDP is nonzero. */ 403318334Speter 403418334Speterrtx 403518334Spetergen_extend_insn (x, y, mto, mfrom, unsignedp) 403618334Speter rtx x, y; 403718334Speter enum machine_mode mto, mfrom; 403818334Speter int unsignedp; 403918334Speter{ 404090075Sobrien return (GEN_FCN (extendtab[(int) mto][(int) mfrom][unsignedp != 0]) (x, y)); 404118334Speter} 404218334Speter 404318334Speter/* can_fix_p and can_float_p say whether the target machine 404418334Speter can directly convert a given fixed point type to 404518334Speter a given floating point type, or vice versa. 404618334Speter The returned value is the CODE_FOR_... value to use, 404718334Speter or CODE_FOR_nothing if these modes cannot be directly converted. 404818334Speter 404918334Speter *TRUNCP_PTR is set to 1 if it is necessary to output 405018334Speter an explicit FTRUNC insn before the fix insn; otherwise 0. */ 405118334Speter 405218334Speterstatic enum insn_code 405318334Spetercan_fix_p (fixmode, fltmode, unsignedp, truncp_ptr) 405418334Speter enum machine_mode fltmode, fixmode; 405518334Speter int unsignedp; 405618334Speter int *truncp_ptr; 405718334Speter{ 405818334Speter *truncp_ptr = 0; 405990075Sobrien if (fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0] 406090075Sobrien != CODE_FOR_nothing) 406190075Sobrien return fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0]; 406218334Speter 406318334Speter if (ftrunc_optab->handlers[(int) fltmode].insn_code != CODE_FOR_nothing) 406418334Speter { 406518334Speter *truncp_ptr = 1; 406690075Sobrien return fixtab[(int) fltmode][(int) fixmode][unsignedp != 0]; 406718334Speter } 406818334Speter return CODE_FOR_nothing; 406918334Speter} 407018334Speter 407118334Speterstatic enum insn_code 407218334Spetercan_float_p (fltmode, fixmode, unsignedp) 407318334Speter enum machine_mode fixmode, fltmode; 407418334Speter int unsignedp; 407518334Speter{ 407690075Sobrien return floattab[(int) fltmode][(int) fixmode][unsignedp != 0]; 407718334Speter} 407818334Speter 407918334Speter/* Generate code to convert FROM to floating point 408018334Speter and store in TO. FROM must be fixed point and not VOIDmode. 408118334Speter UNSIGNEDP nonzero means regard FROM as unsigned. 408218334Speter Normally this is done by correcting the final value 408318334Speter if it is negative. */ 408418334Speter 408518334Spetervoid 408618334Speterexpand_float (to, from, unsignedp) 408718334Speter rtx to, from; 408818334Speter int unsignedp; 408918334Speter{ 409018334Speter enum insn_code icode; 409190075Sobrien rtx target = to; 409218334Speter enum machine_mode fmode, imode; 409318334Speter 409418334Speter /* Crash now, because we won't be able to decide which mode to use. */ 409518334Speter if (GET_MODE (from) == VOIDmode) 409618334Speter abort (); 409718334Speter 409818334Speter /* Look for an insn to do the conversion. Do it in the specified 409918334Speter modes if possible; otherwise convert either input, output or both to 410018334Speter wider mode. If the integer mode is wider than the mode of FROM, 410118334Speter we can do the conversion signed even if the input is unsigned. */ 410218334Speter 410318334Speter for (imode = GET_MODE (from); imode != VOIDmode; 410418334Speter imode = GET_MODE_WIDER_MODE (imode)) 410518334Speter for (fmode = GET_MODE (to); fmode != VOIDmode; 410618334Speter fmode = GET_MODE_WIDER_MODE (fmode)) 410718334Speter { 410818334Speter int doing_unsigned = unsignedp; 410918334Speter 411090075Sobrien if (fmode != GET_MODE (to) 411190075Sobrien && significand_size (fmode) < GET_MODE_BITSIZE (GET_MODE (from))) 411290075Sobrien continue; 411390075Sobrien 411418334Speter icode = can_float_p (fmode, imode, unsignedp); 411518334Speter if (icode == CODE_FOR_nothing && imode != GET_MODE (from) && unsignedp) 411618334Speter icode = can_float_p (fmode, imode, 0), doing_unsigned = 0; 411718334Speter 411818334Speter if (icode != CODE_FOR_nothing) 411918334Speter { 412018334Speter to = protect_from_queue (to, 1); 412118334Speter from = protect_from_queue (from, 0); 412218334Speter 412318334Speter if (imode != GET_MODE (from)) 412418334Speter from = convert_to_mode (imode, from, unsignedp); 412518334Speter 412618334Speter if (fmode != GET_MODE (to)) 412718334Speter target = gen_reg_rtx (fmode); 412818334Speter 412918334Speter emit_unop_insn (icode, target, from, 413018334Speter doing_unsigned ? UNSIGNED_FLOAT : FLOAT); 413118334Speter 413218334Speter if (target != to) 413318334Speter convert_move (to, target, 0); 413418334Speter return; 413518334Speter } 413618334Speter } 413718334Speter 413818334Speter#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) 413918334Speter 414018334Speter /* Unsigned integer, and no way to convert directly. 414118334Speter Convert as signed, then conditionally adjust the result. */ 414218334Speter if (unsignedp) 414318334Speter { 414418334Speter rtx label = gen_label_rtx (); 414518334Speter rtx temp; 414618334Speter REAL_VALUE_TYPE offset; 414718334Speter 414818334Speter emit_queue (); 414918334Speter 415018334Speter to = protect_from_queue (to, 1); 415118334Speter from = protect_from_queue (from, 0); 415218334Speter 415318334Speter if (flag_force_mem) 415418334Speter from = force_not_mem (from); 415518334Speter 415618334Speter /* Look for a usable floating mode FMODE wider than the source and at 415718334Speter least as wide as the target. Using FMODE will avoid rounding woes 415818334Speter with unsigned values greater than the signed maximum value. */ 415918334Speter 416018334Speter for (fmode = GET_MODE (to); fmode != VOIDmode; 416118334Speter fmode = GET_MODE_WIDER_MODE (fmode)) 416218334Speter if (GET_MODE_BITSIZE (GET_MODE (from)) < GET_MODE_BITSIZE (fmode) 416318334Speter && can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing) 416418334Speter break; 416518334Speter 416618334Speter if (fmode == VOIDmode) 416718334Speter { 416818334Speter /* There is no such mode. Pretend the target is wide enough. */ 416918334Speter fmode = GET_MODE (to); 417018334Speter 417150397Sobrien /* Avoid double-rounding when TO is narrower than FROM. */ 417218334Speter if ((significand_size (fmode) + 1) 417318334Speter < GET_MODE_BITSIZE (GET_MODE (from))) 417418334Speter { 417518334Speter rtx temp1; 417618334Speter rtx neglabel = gen_label_rtx (); 417718334Speter 417818334Speter /* Don't use TARGET if it isn't a register, is a hard register, 417918334Speter or is the wrong mode. */ 418018334Speter if (GET_CODE (target) != REG 418118334Speter || REGNO (target) < FIRST_PSEUDO_REGISTER 418218334Speter || GET_MODE (target) != fmode) 418318334Speter target = gen_reg_rtx (fmode); 418418334Speter 418518334Speter imode = GET_MODE (from); 418618334Speter do_pending_stack_adjust (); 418718334Speter 418818334Speter /* Test whether the sign bit is set. */ 418990075Sobrien emit_cmp_and_jump_insns (from, const0_rtx, LT, NULL_RTX, imode, 419090075Sobrien 0, neglabel); 419118334Speter 419218334Speter /* The sign bit is not set. Convert as signed. */ 419318334Speter expand_float (target, from, 0); 419418334Speter emit_jump_insn (gen_jump (label)); 419518334Speter emit_barrier (); 419618334Speter 419718334Speter /* The sign bit is set. 419818334Speter Convert to a usable (positive signed) value by shifting right 419918334Speter one bit, while remembering if a nonzero bit was shifted 420018334Speter out; i.e., compute (from & 1) | (from >> 1). */ 420118334Speter 420218334Speter emit_label (neglabel); 420318334Speter temp = expand_binop (imode, and_optab, from, const1_rtx, 420418334Speter NULL_RTX, 1, OPTAB_LIB_WIDEN); 420518334Speter temp1 = expand_shift (RSHIFT_EXPR, imode, from, integer_one_node, 420618334Speter NULL_RTX, 1); 420718334Speter temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1, 420818334Speter OPTAB_LIB_WIDEN); 420918334Speter expand_float (target, temp, 0); 421018334Speter 421118334Speter /* Multiply by 2 to undo the shift above. */ 421218334Speter temp = expand_binop (fmode, add_optab, target, target, 421318334Speter target, 0, OPTAB_LIB_WIDEN); 421418334Speter if (temp != target) 421518334Speter emit_move_insn (target, temp); 421618334Speter 421718334Speter do_pending_stack_adjust (); 421818334Speter emit_label (label); 421918334Speter goto done; 422018334Speter } 422118334Speter } 422218334Speter 422318334Speter /* If we are about to do some arithmetic to correct for an 422418334Speter unsigned operand, do it in a pseudo-register. */ 422518334Speter 422618334Speter if (GET_MODE (to) != fmode 422718334Speter || GET_CODE (to) != REG || REGNO (to) < FIRST_PSEUDO_REGISTER) 422818334Speter target = gen_reg_rtx (fmode); 422918334Speter 423018334Speter /* Convert as signed integer to floating. */ 423118334Speter expand_float (target, from, 0); 423218334Speter 423318334Speter /* If FROM is negative (and therefore TO is negative), 423418334Speter correct its value by 2**bitwidth. */ 423518334Speter 423618334Speter do_pending_stack_adjust (); 423752284Sobrien emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from), 423890075Sobrien 0, label); 423918334Speter 424018334Speter /* On SCO 3.2.1, ldexp rejects values outside [0.5, 1). 424118334Speter Rather than setting up a dconst_dot_5, let's hope SCO 424218334Speter fixes the bug. */ 424318334Speter offset = REAL_VALUE_LDEXP (dconst1, GET_MODE_BITSIZE (GET_MODE (from))); 424418334Speter temp = expand_binop (fmode, add_optab, target, 424518334Speter CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode), 424618334Speter target, 0, OPTAB_LIB_WIDEN); 424718334Speter if (temp != target) 424818334Speter emit_move_insn (target, temp); 424918334Speter 425018334Speter do_pending_stack_adjust (); 425118334Speter emit_label (label); 425218334Speter goto done; 425318334Speter } 425418334Speter#endif 425518334Speter 425618334Speter /* No hardware instruction available; call a library routine to convert from 425718334Speter SImode, DImode, or TImode into SFmode, DFmode, XFmode, or TFmode. */ 425818334Speter { 425918334Speter rtx libfcn; 426018334Speter rtx insns; 426118334Speter rtx value; 426218334Speter 426318334Speter to = protect_from_queue (to, 1); 426418334Speter from = protect_from_queue (from, 0); 426518334Speter 426618334Speter if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode)) 426718334Speter from = convert_to_mode (SImode, from, unsignedp); 426818334Speter 426918334Speter if (flag_force_mem) 427018334Speter from = force_not_mem (from); 427118334Speter 427218334Speter if (GET_MODE (to) == SFmode) 427318334Speter { 427418334Speter if (GET_MODE (from) == SImode) 427518334Speter libfcn = floatsisf_libfunc; 427618334Speter else if (GET_MODE (from) == DImode) 427718334Speter libfcn = floatdisf_libfunc; 427818334Speter else if (GET_MODE (from) == TImode) 427918334Speter libfcn = floattisf_libfunc; 428018334Speter else 428118334Speter abort (); 428218334Speter } 428318334Speter else if (GET_MODE (to) == DFmode) 428418334Speter { 428518334Speter if (GET_MODE (from) == SImode) 428618334Speter libfcn = floatsidf_libfunc; 428718334Speter else if (GET_MODE (from) == DImode) 428818334Speter libfcn = floatdidf_libfunc; 428918334Speter else if (GET_MODE (from) == TImode) 429018334Speter libfcn = floattidf_libfunc; 429118334Speter else 429218334Speter abort (); 429318334Speter } 429418334Speter else if (GET_MODE (to) == XFmode) 429518334Speter { 429618334Speter if (GET_MODE (from) == SImode) 429718334Speter libfcn = floatsixf_libfunc; 429818334Speter else if (GET_MODE (from) == DImode) 429918334Speter libfcn = floatdixf_libfunc; 430018334Speter else if (GET_MODE (from) == TImode) 430118334Speter libfcn = floattixf_libfunc; 430218334Speter else 430318334Speter abort (); 430418334Speter } 430518334Speter else if (GET_MODE (to) == TFmode) 430618334Speter { 430718334Speter if (GET_MODE (from) == SImode) 430818334Speter libfcn = floatsitf_libfunc; 430918334Speter else if (GET_MODE (from) == DImode) 431018334Speter libfcn = floatditf_libfunc; 431118334Speter else if (GET_MODE (from) == TImode) 431218334Speter libfcn = floattitf_libfunc; 431318334Speter else 431418334Speter abort (); 431518334Speter } 431618334Speter else 431718334Speter abort (); 431818334Speter 431918334Speter start_sequence (); 432018334Speter 432190075Sobrien value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST, 432290075Sobrien GET_MODE (to), 1, from, 432390075Sobrien GET_MODE (from)); 432418334Speter insns = get_insns (); 432518334Speter end_sequence (); 432618334Speter 432718334Speter emit_libcall_block (insns, target, value, 432850397Sobrien gen_rtx_FLOAT (GET_MODE (to), from)); 432918334Speter } 433018334Speter 433118334Speter done: 433218334Speter 433318334Speter /* Copy result to requested destination 433418334Speter if we have been computing in a temp location. */ 433518334Speter 433618334Speter if (target != to) 433718334Speter { 433818334Speter if (GET_MODE (target) == GET_MODE (to)) 433918334Speter emit_move_insn (to, target); 434018334Speter else 434118334Speter convert_move (to, target, 0); 434218334Speter } 434318334Speter} 434418334Speter 434518334Speter/* expand_fix: generate code to convert FROM to fixed point 434618334Speter and store in TO. FROM must be floating point. */ 434718334Speter 434818334Speterstatic rtx 434918334Speterftruncify (x) 435018334Speter rtx x; 435118334Speter{ 435218334Speter rtx temp = gen_reg_rtx (GET_MODE (x)); 435318334Speter return expand_unop (GET_MODE (x), ftrunc_optab, x, temp, 0); 435418334Speter} 435518334Speter 435618334Spetervoid 435718334Speterexpand_fix (to, from, unsignedp) 435890075Sobrien rtx to, from; 435918334Speter int unsignedp; 436018334Speter{ 436118334Speter enum insn_code icode; 436290075Sobrien rtx target = to; 436318334Speter enum machine_mode fmode, imode; 436418334Speter int must_trunc = 0; 436518334Speter rtx libfcn = 0; 436618334Speter 436718334Speter /* We first try to find a pair of modes, one real and one integer, at 436818334Speter least as wide as FROM and TO, respectively, in which we can open-code 436918334Speter this conversion. If the integer mode is wider than the mode of TO, 437018334Speter we can do the conversion either signed or unsigned. */ 437118334Speter 437290075Sobrien for (fmode = GET_MODE (from); fmode != VOIDmode; 437390075Sobrien fmode = GET_MODE_WIDER_MODE (fmode)) 437490075Sobrien for (imode = GET_MODE (to); imode != VOIDmode; 437590075Sobrien imode = GET_MODE_WIDER_MODE (imode)) 437618334Speter { 437718334Speter int doing_unsigned = unsignedp; 437818334Speter 437918334Speter icode = can_fix_p (imode, fmode, unsignedp, &must_trunc); 438018334Speter if (icode == CODE_FOR_nothing && imode != GET_MODE (to) && unsignedp) 438118334Speter icode = can_fix_p (imode, fmode, 0, &must_trunc), doing_unsigned = 0; 438218334Speter 438318334Speter if (icode != CODE_FOR_nothing) 438418334Speter { 438518334Speter to = protect_from_queue (to, 1); 438618334Speter from = protect_from_queue (from, 0); 438718334Speter 438818334Speter if (fmode != GET_MODE (from)) 438918334Speter from = convert_to_mode (fmode, from, 0); 439018334Speter 439118334Speter if (must_trunc) 439218334Speter from = ftruncify (from); 439318334Speter 439418334Speter if (imode != GET_MODE (to)) 439518334Speter target = gen_reg_rtx (imode); 439618334Speter 439718334Speter emit_unop_insn (icode, target, from, 439818334Speter doing_unsigned ? UNSIGNED_FIX : FIX); 439918334Speter if (target != to) 440018334Speter convert_move (to, target, unsignedp); 440118334Speter return; 440218334Speter } 440318334Speter } 440418334Speter 440518334Speter#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) 440618334Speter /* For an unsigned conversion, there is one more way to do it. 440718334Speter If we have a signed conversion, we generate code that compares 440818334Speter the real value to the largest representable positive number. If if 440918334Speter is smaller, the conversion is done normally. Otherwise, subtract 441018334Speter one plus the highest signed number, convert, and add it back. 441118334Speter 441218334Speter We only need to check all real modes, since we know we didn't find 441318334Speter anything with a wider integer mode. */ 441418334Speter 441518334Speter if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT) 441618334Speter for (fmode = GET_MODE (from); fmode != VOIDmode; 441718334Speter fmode = GET_MODE_WIDER_MODE (fmode)) 441818334Speter /* Make sure we won't lose significant bits doing this. */ 441918334Speter if (GET_MODE_BITSIZE (fmode) > GET_MODE_BITSIZE (GET_MODE (to)) 442018334Speter && CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0, 442118334Speter &must_trunc)) 442218334Speter { 442318334Speter int bitsize; 442418334Speter REAL_VALUE_TYPE offset; 442518334Speter rtx limit, lab1, lab2, insn; 442618334Speter 442718334Speter bitsize = GET_MODE_BITSIZE (GET_MODE (to)); 442818334Speter offset = REAL_VALUE_LDEXP (dconst1, bitsize - 1); 442918334Speter limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode); 443018334Speter lab1 = gen_label_rtx (); 443118334Speter lab2 = gen_label_rtx (); 443218334Speter 443318334Speter emit_queue (); 443418334Speter to = protect_from_queue (to, 1); 443518334Speter from = protect_from_queue (from, 0); 443618334Speter 443718334Speter if (flag_force_mem) 443818334Speter from = force_not_mem (from); 443918334Speter 444018334Speter if (fmode != GET_MODE (from)) 444118334Speter from = convert_to_mode (fmode, from, 0); 444218334Speter 444318334Speter /* See if we need to do the subtraction. */ 444418334Speter do_pending_stack_adjust (); 444552284Sobrien emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, GET_MODE (from), 444690075Sobrien 0, lab1); 444718334Speter 444818334Speter /* If not, do the signed "fix" and branch around fixup code. */ 444918334Speter expand_fix (to, from, 0); 445018334Speter emit_jump_insn (gen_jump (lab2)); 445118334Speter emit_barrier (); 445218334Speter 445318334Speter /* Otherwise, subtract 2**(N-1), convert to signed number, 445418334Speter then add 2**(N-1). Do the addition using XOR since this 445518334Speter will often generate better code. */ 445618334Speter emit_label (lab1); 445718334Speter target = expand_binop (GET_MODE (from), sub_optab, from, limit, 445818334Speter NULL_RTX, 0, OPTAB_LIB_WIDEN); 445918334Speter expand_fix (to, target, 0); 446018334Speter target = expand_binop (GET_MODE (to), xor_optab, to, 446190075Sobrien GEN_INT (trunc_int_for_mode 446290075Sobrien ((HOST_WIDE_INT) 1 << (bitsize - 1), 446390075Sobrien GET_MODE (to))), 446418334Speter to, 1, OPTAB_LIB_WIDEN); 446518334Speter 446618334Speter if (target != to) 446718334Speter emit_move_insn (to, target); 446818334Speter 446918334Speter emit_label (lab2); 447018334Speter 447150397Sobrien if (mov_optab->handlers[(int) GET_MODE (to)].insn_code 447250397Sobrien != CODE_FOR_nothing) 447350397Sobrien { 447450397Sobrien /* Make a place for a REG_NOTE and add it. */ 447550397Sobrien insn = emit_move_insn (to, to); 447652284Sobrien set_unique_reg_note (insn, 447752284Sobrien REG_EQUAL, 447852284Sobrien gen_rtx_fmt_e (UNSIGNED_FIX, 447952284Sobrien GET_MODE (to), 448052284Sobrien copy_rtx (from))); 448150397Sobrien } 448290075Sobrien 448318334Speter return; 448418334Speter } 448518334Speter#endif 448618334Speter 448718334Speter /* We can't do it with an insn, so use a library call. But first ensure 448818334Speter that the mode of TO is at least as wide as SImode, since those are the 448918334Speter only library calls we know about. */ 449018334Speter 449118334Speter if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode)) 449218334Speter { 449318334Speter target = gen_reg_rtx (SImode); 449418334Speter 449518334Speter expand_fix (target, from, unsignedp); 449618334Speter } 449718334Speter else if (GET_MODE (from) == SFmode) 449818334Speter { 449918334Speter if (GET_MODE (to) == SImode) 450018334Speter libfcn = unsignedp ? fixunssfsi_libfunc : fixsfsi_libfunc; 450118334Speter else if (GET_MODE (to) == DImode) 450218334Speter libfcn = unsignedp ? fixunssfdi_libfunc : fixsfdi_libfunc; 450318334Speter else if (GET_MODE (to) == TImode) 450418334Speter libfcn = unsignedp ? fixunssfti_libfunc : fixsfti_libfunc; 450518334Speter else 450618334Speter abort (); 450718334Speter } 450818334Speter else if (GET_MODE (from) == DFmode) 450918334Speter { 451018334Speter if (GET_MODE (to) == SImode) 451118334Speter libfcn = unsignedp ? fixunsdfsi_libfunc : fixdfsi_libfunc; 451218334Speter else if (GET_MODE (to) == DImode) 451318334Speter libfcn = unsignedp ? fixunsdfdi_libfunc : fixdfdi_libfunc; 451418334Speter else if (GET_MODE (to) == TImode) 451518334Speter libfcn = unsignedp ? fixunsdfti_libfunc : fixdfti_libfunc; 451618334Speter else 451718334Speter abort (); 451818334Speter } 451918334Speter else if (GET_MODE (from) == XFmode) 452018334Speter { 452118334Speter if (GET_MODE (to) == SImode) 452218334Speter libfcn = unsignedp ? fixunsxfsi_libfunc : fixxfsi_libfunc; 452318334Speter else if (GET_MODE (to) == DImode) 452418334Speter libfcn = unsignedp ? fixunsxfdi_libfunc : fixxfdi_libfunc; 452518334Speter else if (GET_MODE (to) == TImode) 452618334Speter libfcn = unsignedp ? fixunsxfti_libfunc : fixxfti_libfunc; 452718334Speter else 452818334Speter abort (); 452918334Speter } 453018334Speter else if (GET_MODE (from) == TFmode) 453118334Speter { 453218334Speter if (GET_MODE (to) == SImode) 453318334Speter libfcn = unsignedp ? fixunstfsi_libfunc : fixtfsi_libfunc; 453418334Speter else if (GET_MODE (to) == DImode) 453518334Speter libfcn = unsignedp ? fixunstfdi_libfunc : fixtfdi_libfunc; 453618334Speter else if (GET_MODE (to) == TImode) 453718334Speter libfcn = unsignedp ? fixunstfti_libfunc : fixtfti_libfunc; 453818334Speter else 453918334Speter abort (); 454018334Speter } 454118334Speter else 454218334Speter abort (); 454318334Speter 454418334Speter if (libfcn) 454518334Speter { 454618334Speter rtx insns; 454718334Speter rtx value; 454818334Speter 454918334Speter to = protect_from_queue (to, 1); 455018334Speter from = protect_from_queue (from, 0); 455118334Speter 455218334Speter if (flag_force_mem) 455318334Speter from = force_not_mem (from); 455418334Speter 455518334Speter start_sequence (); 455618334Speter 455790075Sobrien value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST, 455890075Sobrien GET_MODE (to), 1, from, 455990075Sobrien GET_MODE (from)); 456018334Speter insns = get_insns (); 456118334Speter end_sequence (); 456218334Speter 456318334Speter emit_libcall_block (insns, target, value, 456450397Sobrien gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX, 456550397Sobrien GET_MODE (to), from)); 456618334Speter } 456718334Speter 456850397Sobrien if (target != to) 456950397Sobrien { 457050397Sobrien if (GET_MODE (to) == GET_MODE (target)) 457150397Sobrien emit_move_insn (to, target); 457250397Sobrien else 457350397Sobrien convert_move (to, target, 0); 457450397Sobrien } 457518334Speter} 457618334Speter 457790075Sobrien/* Report whether we have an instruction to perform the operation 457890075Sobrien specified by CODE on operands of mode MODE. */ 457990075Sobrienint 458090075Sobrienhave_insn_for (code, mode) 458118334Speter enum rtx_code code; 458290075Sobrien enum machine_mode mode; 458318334Speter{ 458490075Sobrien return (code_to_optab[(int) code] != 0 458590075Sobrien && (code_to_optab[(int) code]->handlers[(int) mode].insn_code 458690075Sobrien != CODE_FOR_nothing)); 458790075Sobrien} 458890075Sobrien 458990075Sobrien/* Create a blank optab. */ 459090075Sobrienstatic optab 459190075Sobriennew_optab () 459290075Sobrien{ 459318334Speter int i; 459418334Speter optab op = (optab) xmalloc (sizeof (struct optab)); 459518334Speter for (i = 0; i < NUM_MACHINE_MODES; i++) 459618334Speter { 459718334Speter op->handlers[i].insn_code = CODE_FOR_nothing; 459818334Speter op->handlers[i].libfunc = 0; 459918334Speter } 460018334Speter 460190075Sobrien return op; 460290075Sobrien} 460318334Speter 460490075Sobrien/* Same, but fill in its code as CODE, and write it into the 460590075Sobrien code_to_optab table. */ 460690075Sobrienstatic inline optab 460790075Sobrieninit_optab (code) 460890075Sobrien enum rtx_code code; 460990075Sobrien{ 461090075Sobrien optab op = new_optab (); 461190075Sobrien op->code = code; 461290075Sobrien code_to_optab[(int) code] = op; 461318334Speter return op; 461418334Speter} 461518334Speter 461690075Sobrien/* Same, but fill in its code as CODE, and do _not_ write it into 461790075Sobrien the code_to_optab table. */ 461890075Sobrienstatic inline optab 461990075Sobrieninit_optabv (code) 462090075Sobrien enum rtx_code code; 462190075Sobrien{ 462290075Sobrien optab op = new_optab (); 462390075Sobrien op->code = code; 462490075Sobrien return op; 462590075Sobrien} 462690075Sobrien 462718334Speter/* Initialize the libfunc fields of an entire group of entries in some 462818334Speter optab. Each entry is set equal to a string consisting of a leading 462918334Speter pair of underscores followed by a generic operation name followed by 463018334Speter a mode name (downshifted to lower case) followed by a single character 463118334Speter representing the number of operands for the given operation (which is 463218334Speter usually one of the characters '2', '3', or '4'). 463318334Speter 463418334Speter OPTABLE is the table in which libfunc fields are to be initialized. 463518334Speter FIRST_MODE is the first machine mode index in the given optab to 463618334Speter initialize. 463718334Speter LAST_MODE is the last machine mode index in the given optab to 463818334Speter initialize. 463918334Speter OPNAME is the generic (string) name of the operation. 464018334Speter SUFFIX is the character which specifies the number of operands for 464118334Speter the given generic operation. 464218334Speter*/ 464318334Speter 464418334Speterstatic void 464518334Speterinit_libfuncs (optable, first_mode, last_mode, opname, suffix) 464690075Sobrien optab optable; 464790075Sobrien int first_mode; 464890075Sobrien int last_mode; 464990075Sobrien const char *opname; 465090075Sobrien int suffix; 465118334Speter{ 465290075Sobrien int mode; 465390075Sobrien unsigned opname_len = strlen (opname); 465418334Speter 465518334Speter for (mode = first_mode; (int) mode <= (int) last_mode; 465618334Speter mode = (enum machine_mode) ((int) mode + 1)) 465718334Speter { 465890075Sobrien const char *mname = GET_MODE_NAME(mode); 465990075Sobrien unsigned mname_len = strlen (mname); 466090075Sobrien char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1); 466190075Sobrien char *p; 466290075Sobrien const char *q; 466318334Speter 466418334Speter p = libfunc_name; 466518334Speter *p++ = '_'; 466618334Speter *p++ = '_'; 466718334Speter for (q = opname; *q; ) 466818334Speter *p++ = *q++; 466918334Speter for (q = mname; *q; q++) 467090075Sobrien *p++ = TOLOWER (*q); 467118334Speter *p++ = suffix; 467290075Sobrien *p = '\0'; 467390075Sobrien 467418334Speter optable->handlers[(int) mode].libfunc 467590075Sobrien = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (libfunc_name, 467690075Sobrien p - libfunc_name)); 467718334Speter } 467818334Speter} 467918334Speter 468018334Speter/* Initialize the libfunc fields of an entire group of entries in some 468118334Speter optab which correspond to all integer mode operations. The parameters 468218334Speter have the same meaning as similarly named ones for the `init_libfuncs' 468318334Speter routine. (See above). */ 468418334Speter 468518334Speterstatic void 468618334Speterinit_integral_libfuncs (optable, opname, suffix) 468790075Sobrien optab optable; 468890075Sobrien const char *opname; 468990075Sobrien int suffix; 469018334Speter{ 469118334Speter init_libfuncs (optable, SImode, TImode, opname, suffix); 469218334Speter} 469318334Speter 469418334Speter/* Initialize the libfunc fields of an entire group of entries in some 469518334Speter optab which correspond to all real mode operations. The parameters 469618334Speter have the same meaning as similarly named ones for the `init_libfuncs' 469718334Speter routine. (See above). */ 469818334Speter 469918334Speterstatic void 470018334Speterinit_floating_libfuncs (optable, opname, suffix) 470190075Sobrien optab optable; 470290075Sobrien const char *opname; 470390075Sobrien int suffix; 470418334Speter{ 470518334Speter init_libfuncs (optable, SFmode, TFmode, opname, suffix); 470618334Speter} 470718334Speter 470890075Sobrienrtx 470990075Sobrieninit_one_libfunc (name) 471090075Sobrien const char *name; 471190075Sobrien{ 471290075Sobrien /* Create a FUNCTION_DECL that can be passed to ENCODE_SECTION_INFO. */ 471390075Sobrien /* ??? We don't have any type information except for this is 471490075Sobrien a function. Pretend this is "int foo()". */ 471590075Sobrien tree decl = build_decl (FUNCTION_DECL, get_identifier (name), 471690075Sobrien build_function_type (integer_type_node, NULL_TREE)); 471790075Sobrien DECL_ARTIFICIAL (decl) = 1; 471890075Sobrien DECL_EXTERNAL (decl) = 1; 471990075Sobrien TREE_PUBLIC (decl) = 1; 472018334Speter 472190075Sobrien /* Return the symbol_ref from the mem rtx. */ 472290075Sobrien return XEXP (DECL_RTL (decl), 0); 472390075Sobrien} 472490075Sobrien 472590075Sobrien/* Mark ARG (which is really an OPTAB *) for GC. */ 472690075Sobrien 472790075Sobrienvoid 472890075Sobrienmark_optab (arg) 472990075Sobrien void *arg; 473090075Sobrien{ 473190075Sobrien optab o = *(optab *) arg; 473290075Sobrien int i; 473390075Sobrien 473490075Sobrien for (i = 0; i < NUM_MACHINE_MODES; ++i) 473590075Sobrien ggc_mark_rtx (o->handlers[i].libfunc); 473690075Sobrien} 473790075Sobrien 473818334Speter/* Call this once to initialize the contents of the optabs 473918334Speter appropriately for the current target machine. */ 474018334Speter 474118334Spetervoid 474218334Speterinit_optabs () 474318334Speter{ 474490075Sobrien unsigned int i, j, k; 474550397Sobrien 474618334Speter /* Start by initializing all tables to contain CODE_FOR_nothing. */ 474718334Speter 474890075Sobrien for (i = 0; i < ARRAY_SIZE (fixtab); i++) 474990075Sobrien for (j = 0; j < ARRAY_SIZE (fixtab[0]); j++) 475090075Sobrien for (k = 0; k < ARRAY_SIZE (fixtab[0][0]); k++) 475190075Sobrien fixtab[i][j][k] = CODE_FOR_nothing; 475218334Speter 475390075Sobrien for (i = 0; i < ARRAY_SIZE (fixtrunctab); i++) 475490075Sobrien for (j = 0; j < ARRAY_SIZE (fixtrunctab[0]); j++) 475590075Sobrien for (k = 0; k < ARRAY_SIZE (fixtrunctab[0][0]); k++) 475690075Sobrien fixtrunctab[i][j][k] = CODE_FOR_nothing; 475718334Speter 475890075Sobrien for (i = 0; i < ARRAY_SIZE (floattab); i++) 475990075Sobrien for (j = 0; j < ARRAY_SIZE (floattab[0]); j++) 476090075Sobrien for (k = 0; k < ARRAY_SIZE (floattab[0][0]); k++) 476190075Sobrien floattab[i][j][k] = CODE_FOR_nothing; 476218334Speter 476390075Sobrien for (i = 0; i < ARRAY_SIZE (extendtab); i++) 476490075Sobrien for (j = 0; j < ARRAY_SIZE (extendtab[0]); j++) 476590075Sobrien for (k = 0; k < ARRAY_SIZE (extendtab[0][0]); k++) 476690075Sobrien extendtab[i][j][k] = CODE_FOR_nothing; 476718334Speter 476818334Speter for (i = 0; i < NUM_RTX_CODE; i++) 476918334Speter setcc_gen_code[i] = CODE_FOR_nothing; 477018334Speter 477118334Speter#ifdef HAVE_conditional_move 477218334Speter for (i = 0; i < NUM_MACHINE_MODES; i++) 477318334Speter movcc_gen_code[i] = CODE_FOR_nothing; 477418334Speter#endif 477518334Speter 477618334Speter add_optab = init_optab (PLUS); 477790075Sobrien addv_optab = init_optabv (PLUS); 477818334Speter sub_optab = init_optab (MINUS); 477990075Sobrien subv_optab = init_optabv (MINUS); 478018334Speter smul_optab = init_optab (MULT); 478190075Sobrien smulv_optab = init_optabv (MULT); 478218334Speter smul_highpart_optab = init_optab (UNKNOWN); 478318334Speter umul_highpart_optab = init_optab (UNKNOWN); 478418334Speter smul_widen_optab = init_optab (UNKNOWN); 478518334Speter umul_widen_optab = init_optab (UNKNOWN); 478618334Speter sdiv_optab = init_optab (DIV); 478790075Sobrien sdivv_optab = init_optabv (DIV); 478818334Speter sdivmod_optab = init_optab (UNKNOWN); 478918334Speter udiv_optab = init_optab (UDIV); 479018334Speter udivmod_optab = init_optab (UNKNOWN); 479118334Speter smod_optab = init_optab (MOD); 479218334Speter umod_optab = init_optab (UMOD); 479318334Speter ftrunc_optab = init_optab (UNKNOWN); 479418334Speter and_optab = init_optab (AND); 479518334Speter ior_optab = init_optab (IOR); 479618334Speter xor_optab = init_optab (XOR); 479718334Speter ashl_optab = init_optab (ASHIFT); 479818334Speter ashr_optab = init_optab (ASHIFTRT); 479918334Speter lshr_optab = init_optab (LSHIFTRT); 480018334Speter rotl_optab = init_optab (ROTATE); 480118334Speter rotr_optab = init_optab (ROTATERT); 480218334Speter smin_optab = init_optab (SMIN); 480318334Speter smax_optab = init_optab (SMAX); 480418334Speter umin_optab = init_optab (UMIN); 480518334Speter umax_optab = init_optab (UMAX); 480690075Sobrien 480790075Sobrien /* These three have codes assigned exclusively for the sake of 480890075Sobrien have_insn_for. */ 480990075Sobrien mov_optab = init_optab (SET); 481090075Sobrien movstrict_optab = init_optab (STRICT_LOW_PART); 481190075Sobrien cmp_optab = init_optab (COMPARE); 481290075Sobrien 481318334Speter ucmp_optab = init_optab (UNKNOWN); 481418334Speter tst_optab = init_optab (UNKNOWN); 481518334Speter neg_optab = init_optab (NEG); 481690075Sobrien negv_optab = init_optabv (NEG); 481718334Speter abs_optab = init_optab (ABS); 481890075Sobrien absv_optab = init_optabv (ABS); 481918334Speter one_cmpl_optab = init_optab (NOT); 482018334Speter ffs_optab = init_optab (FFS); 482118334Speter sqrt_optab = init_optab (SQRT); 482218334Speter sin_optab = init_optab (UNKNOWN); 482318334Speter cos_optab = init_optab (UNKNOWN); 482418334Speter strlen_optab = init_optab (UNKNOWN); 482590075Sobrien cbranch_optab = init_optab (UNKNOWN); 482690075Sobrien cmov_optab = init_optab (UNKNOWN); 482790075Sobrien cstore_optab = init_optab (UNKNOWN); 482890075Sobrien push_optab = init_optab (UNKNOWN); 482918334Speter 483018334Speter for (i = 0; i < NUM_MACHINE_MODES; i++) 483118334Speter { 483218334Speter movstr_optab[i] = CODE_FOR_nothing; 483350397Sobrien clrstr_optab[i] = CODE_FOR_nothing; 483418334Speter 483518334Speter#ifdef HAVE_SECONDARY_RELOADS 483618334Speter reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing; 483718334Speter#endif 483818334Speter } 483918334Speter 484018334Speter /* Fill in the optabs with the insns we support. */ 484118334Speter init_all_optabs (); 484218334Speter 484318334Speter#ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC 484418334Speter /* This flag says the same insns that convert to a signed fixnum 484518334Speter also convert validly to an unsigned one. */ 484618334Speter for (i = 0; i < NUM_MACHINE_MODES; i++) 484718334Speter for (j = 0; j < NUM_MACHINE_MODES; j++) 484818334Speter fixtrunctab[i][j][1] = fixtrunctab[i][j][0]; 484918334Speter#endif 485018334Speter 485118334Speter /* Initialize the optabs with the names of the library functions. */ 485218334Speter init_integral_libfuncs (add_optab, "add", '3'); 485318334Speter init_floating_libfuncs (add_optab, "add", '3'); 485490075Sobrien init_integral_libfuncs (addv_optab, "addv", '3'); 485590075Sobrien init_floating_libfuncs (addv_optab, "add", '3'); 485618334Speter init_integral_libfuncs (sub_optab, "sub", '3'); 485718334Speter init_floating_libfuncs (sub_optab, "sub", '3'); 485890075Sobrien init_integral_libfuncs (subv_optab, "subv", '3'); 485990075Sobrien init_floating_libfuncs (subv_optab, "sub", '3'); 486018334Speter init_integral_libfuncs (smul_optab, "mul", '3'); 486118334Speter init_floating_libfuncs (smul_optab, "mul", '3'); 486290075Sobrien init_integral_libfuncs (smulv_optab, "mulv", '3'); 486390075Sobrien init_floating_libfuncs (smulv_optab, "mul", '3'); 486418334Speter init_integral_libfuncs (sdiv_optab, "div", '3'); 486590075Sobrien init_floating_libfuncs (sdiv_optab, "div", '3'); 486690075Sobrien init_integral_libfuncs (sdivv_optab, "divv", '3'); 486718334Speter init_integral_libfuncs (udiv_optab, "udiv", '3'); 486818334Speter init_integral_libfuncs (sdivmod_optab, "divmod", '4'); 486918334Speter init_integral_libfuncs (udivmod_optab, "udivmod", '4'); 487018334Speter init_integral_libfuncs (smod_optab, "mod", '3'); 487118334Speter init_integral_libfuncs (umod_optab, "umod", '3'); 487218334Speter init_floating_libfuncs (ftrunc_optab, "ftrunc", '2'); 487318334Speter init_integral_libfuncs (and_optab, "and", '3'); 487418334Speter init_integral_libfuncs (ior_optab, "ior", '3'); 487518334Speter init_integral_libfuncs (xor_optab, "xor", '3'); 487618334Speter init_integral_libfuncs (ashl_optab, "ashl", '3'); 487718334Speter init_integral_libfuncs (ashr_optab, "ashr", '3'); 487818334Speter init_integral_libfuncs (lshr_optab, "lshr", '3'); 487918334Speter init_integral_libfuncs (smin_optab, "min", '3'); 488018334Speter init_floating_libfuncs (smin_optab, "min", '3'); 488118334Speter init_integral_libfuncs (smax_optab, "max", '3'); 488218334Speter init_floating_libfuncs (smax_optab, "max", '3'); 488318334Speter init_integral_libfuncs (umin_optab, "umin", '3'); 488418334Speter init_integral_libfuncs (umax_optab, "umax", '3'); 488518334Speter init_integral_libfuncs (neg_optab, "neg", '2'); 488618334Speter init_floating_libfuncs (neg_optab, "neg", '2'); 488790075Sobrien init_integral_libfuncs (negv_optab, "negv", '2'); 488890075Sobrien init_floating_libfuncs (negv_optab, "neg", '2'); 488918334Speter init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2'); 489018334Speter init_integral_libfuncs (ffs_optab, "ffs", '2'); 489118334Speter 489218334Speter /* Comparison libcalls for integers MUST come in pairs, signed/unsigned. */ 489318334Speter init_integral_libfuncs (cmp_optab, "cmp", '2'); 489418334Speter init_integral_libfuncs (ucmp_optab, "ucmp", '2'); 489518334Speter init_floating_libfuncs (cmp_optab, "cmp", '2'); 489618334Speter 489718334Speter#ifdef MULSI3_LIBCALL 489818334Speter smul_optab->handlers[(int) SImode].libfunc 489990075Sobrien = init_one_libfunc (MULSI3_LIBCALL); 490018334Speter#endif 490118334Speter#ifdef MULDI3_LIBCALL 490218334Speter smul_optab->handlers[(int) DImode].libfunc 490390075Sobrien = init_one_libfunc (MULDI3_LIBCALL); 490418334Speter#endif 490518334Speter 490618334Speter#ifdef DIVSI3_LIBCALL 490718334Speter sdiv_optab->handlers[(int) SImode].libfunc 490890075Sobrien = init_one_libfunc (DIVSI3_LIBCALL); 490918334Speter#endif 491018334Speter#ifdef DIVDI3_LIBCALL 491118334Speter sdiv_optab->handlers[(int) DImode].libfunc 491290075Sobrien = init_one_libfunc (DIVDI3_LIBCALL); 491318334Speter#endif 491418334Speter 491518334Speter#ifdef UDIVSI3_LIBCALL 491618334Speter udiv_optab->handlers[(int) SImode].libfunc 491790075Sobrien = init_one_libfunc (UDIVSI3_LIBCALL); 491818334Speter#endif 491918334Speter#ifdef UDIVDI3_LIBCALL 492018334Speter udiv_optab->handlers[(int) DImode].libfunc 492190075Sobrien = init_one_libfunc (UDIVDI3_LIBCALL); 492218334Speter#endif 492318334Speter 492418334Speter#ifdef MODSI3_LIBCALL 492518334Speter smod_optab->handlers[(int) SImode].libfunc 492690075Sobrien = init_one_libfunc (MODSI3_LIBCALL); 492718334Speter#endif 492818334Speter#ifdef MODDI3_LIBCALL 492918334Speter smod_optab->handlers[(int) DImode].libfunc 493090075Sobrien = init_one_libfunc (MODDI3_LIBCALL); 493118334Speter#endif 493218334Speter 493318334Speter#ifdef UMODSI3_LIBCALL 493418334Speter umod_optab->handlers[(int) SImode].libfunc 493590075Sobrien = init_one_libfunc (UMODSI3_LIBCALL); 493618334Speter#endif 493718334Speter#ifdef UMODDI3_LIBCALL 493818334Speter umod_optab->handlers[(int) DImode].libfunc 493990075Sobrien = init_one_libfunc (UMODDI3_LIBCALL); 494018334Speter#endif 494118334Speter 494218334Speter /* Use cabs for DC complex abs, since systems generally have cabs. 494318334Speter Don't define any libcall for SCmode, so that cabs will be used. */ 494418334Speter abs_optab->handlers[(int) DCmode].libfunc 494590075Sobrien = init_one_libfunc ("cabs"); 494618334Speter 494718334Speter /* The ffs function operates on `int'. */ 494890075Sobrien ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc 494990075Sobrien = init_one_libfunc ("ffs"); 495018334Speter 495190075Sobrien extendsfdf2_libfunc = init_one_libfunc ("__extendsfdf2"); 495290075Sobrien extendsfxf2_libfunc = init_one_libfunc ("__extendsfxf2"); 495390075Sobrien extendsftf2_libfunc = init_one_libfunc ("__extendsftf2"); 495490075Sobrien extenddfxf2_libfunc = init_one_libfunc ("__extenddfxf2"); 495590075Sobrien extenddftf2_libfunc = init_one_libfunc ("__extenddftf2"); 495618334Speter 495790075Sobrien truncdfsf2_libfunc = init_one_libfunc ("__truncdfsf2"); 495890075Sobrien truncxfsf2_libfunc = init_one_libfunc ("__truncxfsf2"); 495990075Sobrien trunctfsf2_libfunc = init_one_libfunc ("__trunctfsf2"); 496090075Sobrien truncxfdf2_libfunc = init_one_libfunc ("__truncxfdf2"); 496190075Sobrien trunctfdf2_libfunc = init_one_libfunc ("__trunctfdf2"); 496218334Speter 496396263Sobrien abort_libfunc = init_one_libfunc ("abort"); 496490075Sobrien memcpy_libfunc = init_one_libfunc ("memcpy"); 496590075Sobrien memmove_libfunc = init_one_libfunc ("memmove"); 496690075Sobrien bcopy_libfunc = init_one_libfunc ("bcopy"); 496790075Sobrien memcmp_libfunc = init_one_libfunc ("memcmp"); 496890075Sobrien bcmp_libfunc = init_one_libfunc ("__gcc_bcmp"); 496990075Sobrien memset_libfunc = init_one_libfunc ("memset"); 497090075Sobrien bzero_libfunc = init_one_libfunc ("bzero"); 497118334Speter 497290075Sobrien unwind_resume_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS 497390075Sobrien ? "_Unwind_SjLj_Resume" 497490075Sobrien : "_Unwind_Resume"); 497550397Sobrien#ifndef DONT_USE_BUILTIN_SETJMP 497690075Sobrien setjmp_libfunc = init_one_libfunc ("__builtin_setjmp"); 497790075Sobrien longjmp_libfunc = init_one_libfunc ("__builtin_longjmp"); 497850397Sobrien#else 497990075Sobrien setjmp_libfunc = init_one_libfunc ("setjmp"); 498090075Sobrien longjmp_libfunc = init_one_libfunc ("longjmp"); 498150397Sobrien#endif 498290075Sobrien unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register"); 498390075Sobrien unwind_sjlj_unregister_libfunc 498490075Sobrien = init_one_libfunc ("_Unwind_SjLj_Unregister"); 498518334Speter 498690075Sobrien eqhf2_libfunc = init_one_libfunc ("__eqhf2"); 498790075Sobrien nehf2_libfunc = init_one_libfunc ("__nehf2"); 498890075Sobrien gthf2_libfunc = init_one_libfunc ("__gthf2"); 498990075Sobrien gehf2_libfunc = init_one_libfunc ("__gehf2"); 499090075Sobrien lthf2_libfunc = init_one_libfunc ("__lthf2"); 499190075Sobrien lehf2_libfunc = init_one_libfunc ("__lehf2"); 499290075Sobrien unordhf2_libfunc = init_one_libfunc ("__unordhf2"); 499318334Speter 499490075Sobrien eqsf2_libfunc = init_one_libfunc ("__eqsf2"); 499590075Sobrien nesf2_libfunc = init_one_libfunc ("__nesf2"); 499690075Sobrien gtsf2_libfunc = init_one_libfunc ("__gtsf2"); 499790075Sobrien gesf2_libfunc = init_one_libfunc ("__gesf2"); 499890075Sobrien ltsf2_libfunc = init_one_libfunc ("__ltsf2"); 499990075Sobrien lesf2_libfunc = init_one_libfunc ("__lesf2"); 500090075Sobrien unordsf2_libfunc = init_one_libfunc ("__unordsf2"); 500118334Speter 500290075Sobrien eqdf2_libfunc = init_one_libfunc ("__eqdf2"); 500390075Sobrien nedf2_libfunc = init_one_libfunc ("__nedf2"); 500490075Sobrien gtdf2_libfunc = init_one_libfunc ("__gtdf2"); 500590075Sobrien gedf2_libfunc = init_one_libfunc ("__gedf2"); 500690075Sobrien ltdf2_libfunc = init_one_libfunc ("__ltdf2"); 500790075Sobrien ledf2_libfunc = init_one_libfunc ("__ledf2"); 500890075Sobrien unorddf2_libfunc = init_one_libfunc ("__unorddf2"); 500918334Speter 501090075Sobrien eqxf2_libfunc = init_one_libfunc ("__eqxf2"); 501190075Sobrien nexf2_libfunc = init_one_libfunc ("__nexf2"); 501290075Sobrien gtxf2_libfunc = init_one_libfunc ("__gtxf2"); 501390075Sobrien gexf2_libfunc = init_one_libfunc ("__gexf2"); 501490075Sobrien ltxf2_libfunc = init_one_libfunc ("__ltxf2"); 501590075Sobrien lexf2_libfunc = init_one_libfunc ("__lexf2"); 501690075Sobrien unordxf2_libfunc = init_one_libfunc ("__unordxf2"); 501718334Speter 501890075Sobrien eqtf2_libfunc = init_one_libfunc ("__eqtf2"); 501990075Sobrien netf2_libfunc = init_one_libfunc ("__netf2"); 502090075Sobrien gttf2_libfunc = init_one_libfunc ("__gttf2"); 502190075Sobrien getf2_libfunc = init_one_libfunc ("__getf2"); 502290075Sobrien lttf2_libfunc = init_one_libfunc ("__lttf2"); 502390075Sobrien letf2_libfunc = init_one_libfunc ("__letf2"); 502490075Sobrien unordtf2_libfunc = init_one_libfunc ("__unordtf2"); 502518334Speter 502690075Sobrien floatsisf_libfunc = init_one_libfunc ("__floatsisf"); 502790075Sobrien floatdisf_libfunc = init_one_libfunc ("__floatdisf"); 502890075Sobrien floattisf_libfunc = init_one_libfunc ("__floattisf"); 502918334Speter 503090075Sobrien floatsidf_libfunc = init_one_libfunc ("__floatsidf"); 503190075Sobrien floatdidf_libfunc = init_one_libfunc ("__floatdidf"); 503290075Sobrien floattidf_libfunc = init_one_libfunc ("__floattidf"); 503318334Speter 503490075Sobrien floatsixf_libfunc = init_one_libfunc ("__floatsixf"); 503590075Sobrien floatdixf_libfunc = init_one_libfunc ("__floatdixf"); 503690075Sobrien floattixf_libfunc = init_one_libfunc ("__floattixf"); 503718334Speter 503890075Sobrien floatsitf_libfunc = init_one_libfunc ("__floatsitf"); 503990075Sobrien floatditf_libfunc = init_one_libfunc ("__floatditf"); 504090075Sobrien floattitf_libfunc = init_one_libfunc ("__floattitf"); 504118334Speter 504290075Sobrien fixsfsi_libfunc = init_one_libfunc ("__fixsfsi"); 504390075Sobrien fixsfdi_libfunc = init_one_libfunc ("__fixsfdi"); 504490075Sobrien fixsfti_libfunc = init_one_libfunc ("__fixsfti"); 504518334Speter 504690075Sobrien fixdfsi_libfunc = init_one_libfunc ("__fixdfsi"); 504790075Sobrien fixdfdi_libfunc = init_one_libfunc ("__fixdfdi"); 504890075Sobrien fixdfti_libfunc = init_one_libfunc ("__fixdfti"); 504918334Speter 505090075Sobrien fixxfsi_libfunc = init_one_libfunc ("__fixxfsi"); 505190075Sobrien fixxfdi_libfunc = init_one_libfunc ("__fixxfdi"); 505290075Sobrien fixxfti_libfunc = init_one_libfunc ("__fixxfti"); 505318334Speter 505490075Sobrien fixtfsi_libfunc = init_one_libfunc ("__fixtfsi"); 505590075Sobrien fixtfdi_libfunc = init_one_libfunc ("__fixtfdi"); 505690075Sobrien fixtfti_libfunc = init_one_libfunc ("__fixtfti"); 505718334Speter 505890075Sobrien fixunssfsi_libfunc = init_one_libfunc ("__fixunssfsi"); 505990075Sobrien fixunssfdi_libfunc = init_one_libfunc ("__fixunssfdi"); 506090075Sobrien fixunssfti_libfunc = init_one_libfunc ("__fixunssfti"); 506118334Speter 506290075Sobrien fixunsdfsi_libfunc = init_one_libfunc ("__fixunsdfsi"); 506390075Sobrien fixunsdfdi_libfunc = init_one_libfunc ("__fixunsdfdi"); 506490075Sobrien fixunsdfti_libfunc = init_one_libfunc ("__fixunsdfti"); 506518334Speter 506690075Sobrien fixunsxfsi_libfunc = init_one_libfunc ("__fixunsxfsi"); 506790075Sobrien fixunsxfdi_libfunc = init_one_libfunc ("__fixunsxfdi"); 506890075Sobrien fixunsxfti_libfunc = init_one_libfunc ("__fixunsxfti"); 506918334Speter 507090075Sobrien fixunstfsi_libfunc = init_one_libfunc ("__fixunstfsi"); 507190075Sobrien fixunstfdi_libfunc = init_one_libfunc ("__fixunstfdi"); 507290075Sobrien fixunstfti_libfunc = init_one_libfunc ("__fixunstfti"); 507350397Sobrien 507452284Sobrien /* For function entry/exit instrumentation. */ 507552284Sobrien profile_function_entry_libfunc 507690075Sobrien = init_one_libfunc ("__cyg_profile_func_enter"); 507752284Sobrien profile_function_exit_libfunc 507890075Sobrien = init_one_libfunc ("__cyg_profile_func_exit"); 507952284Sobrien 508050397Sobrien#ifdef HAVE_conditional_trap 508150397Sobrien init_traps (); 508250397Sobrien#endif 508350397Sobrien 508418334Speter#ifdef INIT_TARGET_OPTABS 508518334Speter /* Allow the target to add more libcalls or rename some, etc. */ 508618334Speter INIT_TARGET_OPTABS; 508718334Speter#endif 508818334Speter 508990075Sobrien /* Add these GC roots. */ 509090075Sobrien ggc_add_root (optab_table, OTI_MAX, sizeof(optab), mark_optab); 509190075Sobrien ggc_add_rtx_root (libfunc_table, LTI_MAX); 509218334Speter} 509350397Sobrien 509450397Sobrien#ifdef HAVE_conditional_trap 509550397Sobrien/* The insn generating function can not take an rtx_code argument. 509650397Sobrien TRAP_RTX is used as an rtx argument. Its code is replaced with 509750397Sobrien the code to be used in the trap insn and all other fields are 509890075Sobrien ignored. */ 509950397Sobrienstatic rtx trap_rtx; 510050397Sobrien 510150397Sobrienstatic void 510250397Sobrieninit_traps () 510350397Sobrien{ 510450397Sobrien if (HAVE_conditional_trap) 510590075Sobrien { 510690075Sobrien trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX); 510790075Sobrien ggc_add_rtx_root (&trap_rtx, 1); 510890075Sobrien } 510950397Sobrien} 511050397Sobrien#endif 511150397Sobrien 511250397Sobrien/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition 511350397Sobrien CODE. Return 0 on failure. */ 511450397Sobrien 511550397Sobrienrtx 511650397Sobriengen_cond_trap (code, op1, op2, tcode) 511752284Sobrien enum rtx_code code ATTRIBUTE_UNUSED; 511852284Sobrien rtx op1, op2 ATTRIBUTE_UNUSED, tcode ATTRIBUTE_UNUSED; 511950397Sobrien{ 512050397Sobrien enum machine_mode mode = GET_MODE (op1); 512150397Sobrien 512250397Sobrien if (mode == VOIDmode) 512350397Sobrien return 0; 512450397Sobrien 512550397Sobrien#ifdef HAVE_conditional_trap 512650397Sobrien if (HAVE_conditional_trap 512750397Sobrien && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 512850397Sobrien { 512950397Sobrien rtx insn; 513090075Sobrien start_sequence(); 513150397Sobrien emit_insn (GEN_FCN (cmp_optab->handlers[(int) mode].insn_code) (op1, op2)); 513250397Sobrien PUT_CODE (trap_rtx, code); 513350397Sobrien insn = gen_conditional_trap (trap_rtx, tcode); 513450397Sobrien if (insn) 513590075Sobrien { 513690075Sobrien emit_insn (insn); 513790075Sobrien insn = gen_sequence (); 513890075Sobrien } 513990075Sobrien end_sequence(); 514090075Sobrien return insn; 514150397Sobrien } 514250397Sobrien#endif 514350397Sobrien 514450397Sobrien return 0; 514550397Sobrien} 5146