optabs.c revision 119256
118334Speter/* Expand the basic unary and binary arithmetic operations, for GNU compiler. 290075Sobrien Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 3117395Skan 1999, 2000, 2001, 2002, 2003 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" 43110611Skan#include "basic-block.h" 4418334Speter 4518334Speter/* Each optab contains info on how this target machine 4618334Speter can perform a particular operation 4718334Speter for all sizes and kinds of operands. 4818334Speter 4918334Speter The operation to be performed is often specified 5018334Speter by passing one of these optabs as an argument. 5118334Speter 5218334Speter See expr.h for documentation of these optabs. */ 5318334Speter 5490075Sobrienoptab optab_table[OTI_MAX]; 5518334Speter 5690075Sobrienrtx libfunc_table[LTI_MAX]; 5718334Speter 5818334Speter/* Tables of patterns for extending one integer mode to another. */ 5918334Speterenum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2]; 6018334Speter 6150397Sobrien/* Tables of patterns for converting between fixed and floating point. */ 6218334Speterenum insn_code fixtab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2]; 6318334Speterenum insn_code fixtrunctab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2]; 6418334Speterenum insn_code floattab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2]; 6518334Speter 6618334Speter/* Contains the optab used for each rtx code. */ 6718334Speteroptab code_to_optab[NUM_RTX_CODE + 1]; 6818334Speter 6918334Speter/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...) 7018334Speter gives the gen_function to make a branch to test that condition. */ 7118334Speter 7218334Speterrtxfun bcc_gen_fctn[NUM_RTX_CODE]; 7318334Speter 7418334Speter/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...) 7518334Speter gives the insn code to make a store-condition insn 7618334Speter to test that condition. */ 7718334Speter 7818334Speterenum insn_code setcc_gen_code[NUM_RTX_CODE]; 7918334Speter 8018334Speter#ifdef HAVE_conditional_move 8118334Speter/* Indexed by the machine mode, gives the insn code to make a conditional 8218334Speter move insn. This is not indexed by the rtx-code like bcc_gen_fctn and 8318334Speter setcc_gen_code to cut down on the number of named patterns. Consider a day 8418334Speter when a lot more rtx codes are conditional (eg: for the ARM). */ 8518334Speter 8618334Speterenum insn_code movcc_gen_code[NUM_MACHINE_MODES]; 8718334Speter#endif 8818334Speter 89117395Skan/* The insn generating function can not take an rtx_code argument. 90117395Skan TRAP_RTX is used as an rtx argument. Its code is replaced with 91117395Skan the code to be used in the trap insn and all other fields are ignored. */ 92117395Skanstatic GTY(()) rtx trap_rtx; 93117395Skan 9490075Sobrienstatic int add_equal_note PARAMS ((rtx, rtx, enum rtx_code, rtx, rtx)); 9590075Sobrienstatic rtx widen_operand PARAMS ((rtx, enum machine_mode, 9618334Speter enum machine_mode, int, int)); 9790075Sobrienstatic int expand_cmplxdiv_straight PARAMS ((rtx, rtx, rtx, rtx, 9852284Sobrien rtx, rtx, enum machine_mode, 9952284Sobrien int, enum optab_methods, 10052284Sobrien enum mode_class, optab)); 10190075Sobrienstatic int expand_cmplxdiv_wide PARAMS ((rtx, rtx, rtx, rtx, 10252284Sobrien rtx, rtx, enum machine_mode, 10352284Sobrien int, enum optab_methods, 10452284Sobrien enum mode_class, optab)); 10590075Sobrienstatic void prepare_cmp_insn PARAMS ((rtx *, rtx *, enum rtx_code *, rtx, 10690075Sobrien enum machine_mode *, int *, 10790075Sobrien enum can_compare_purpose)); 10890075Sobrienstatic enum insn_code can_fix_p PARAMS ((enum machine_mode, enum machine_mode, 10918334Speter int, int *)); 11090075Sobrienstatic enum insn_code can_float_p PARAMS ((enum machine_mode, 11190075Sobrien enum machine_mode, 11290075Sobrien int)); 11390075Sobrienstatic rtx ftruncify PARAMS ((rtx)); 11490075Sobrienstatic optab new_optab PARAMS ((void)); 11590075Sobrienstatic inline optab init_optab PARAMS ((enum rtx_code)); 11690075Sobrienstatic inline optab init_optabv PARAMS ((enum rtx_code)); 11790075Sobrienstatic void init_libfuncs PARAMS ((optab, int, int, const char *, int)); 11890075Sobrienstatic void init_integral_libfuncs PARAMS ((optab, const char *, int)); 11990075Sobrienstatic void init_floating_libfuncs PARAMS ((optab, const char *, int)); 12090075Sobrienstatic void emit_cmp_and_jump_insn_1 PARAMS ((rtx, rtx, enum machine_mode, 12190075Sobrien enum rtx_code, int, rtx)); 12290075Sobrienstatic void prepare_float_lib_cmp PARAMS ((rtx *, rtx *, enum rtx_code *, 12390075Sobrien enum machine_mode *, int *)); 124117395Skanstatic rtx expand_vector_binop PARAMS ((enum machine_mode, optab, 125117395Skan rtx, rtx, rtx, int, 126117395Skan enum optab_methods)); 127117395Skanstatic rtx expand_vector_unop PARAMS ((enum machine_mode, optab, rtx, rtx, 128117395Skan int)); 129117395Skan 130117395Skan#ifndef HAVE_conditional_trap 131117395Skan#define HAVE_conditional_trap 0 132117395Skan#define gen_conditional_trap(a,b) (abort (), NULL_RTX) 133117395Skan#endif 13418334Speter 135117395Skan/* Add a REG_EQUAL note to the last insn in INSNS. TARGET is being set to 13618334Speter the result of operation CODE applied to OP0 (and OP1 if it is a binary 13718334Speter operation). 13818334Speter 13918334Speter If the last insn does not set TARGET, don't do anything, but return 1. 14018334Speter 14118334Speter If a previous insn sets TARGET and TARGET is one of OP0 or OP1, 14218334Speter don't add the REG_EQUAL note but return 0. Our caller can then try 14318334Speter again, ensuring that TARGET is not one of the operands. */ 14418334Speter 14518334Speterstatic int 146117395Skanadd_equal_note (insns, target, code, op0, op1) 147117395Skan rtx insns; 14818334Speter rtx target; 14918334Speter enum rtx_code code; 15018334Speter rtx op0, op1; 15118334Speter{ 152117395Skan rtx last_insn, insn, set; 15318334Speter rtx note; 15418334Speter 155117395Skan if (! insns 156117395Skan || ! INSN_P (insns) 157117395Skan || NEXT_INSN (insns) == NULL_RTX) 158117395Skan abort (); 159117395Skan 160117395Skan if (GET_RTX_CLASS (code) != '1' && GET_RTX_CLASS (code) != '2' 161117395Skan && GET_RTX_CLASS (code) != 'c' && GET_RTX_CLASS (code) != '<') 16218334Speter return 1; 16318334Speter 164117395Skan if (GET_CODE (target) == ZERO_EXTRACT) 165117395Skan return 1; 166117395Skan 167117395Skan for (last_insn = insns; 168117395Skan NEXT_INSN (last_insn) != NULL_RTX; 169117395Skan last_insn = NEXT_INSN (last_insn)) 170117395Skan ; 171117395Skan 172117395Skan set = single_set (last_insn); 173117395Skan if (set == NULL_RTX) 174117395Skan return 1; 175117395Skan 176117395Skan if (! rtx_equal_p (SET_DEST (set), target) 177117395Skan /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside the 178117395Skan SUBREG. */ 179117395Skan && (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART 180117395Skan || ! rtx_equal_p (SUBREG_REG (XEXP (SET_DEST (set), 0)), 181117395Skan target))) 182117395Skan return 1; 183117395Skan 18418334Speter /* If TARGET is in OP0 or OP1, check if anything in SEQ sets TARGET 18518334Speter besides the last insn. */ 18618334Speter if (reg_overlap_mentioned_p (target, op0) 18718334Speter || (op1 && reg_overlap_mentioned_p (target, op1))) 188117395Skan { 189117395Skan insn = PREV_INSN (last_insn); 190117395Skan while (insn != NULL_RTX) 191117395Skan { 192117395Skan if (reg_set_p (target, insn)) 193117395Skan return 0; 19418334Speter 195117395Skan insn = PREV_INSN (insn); 196117395Skan } 197117395Skan } 198117395Skan 19918334Speter if (GET_RTX_CLASS (code) == '1') 20050397Sobrien note = gen_rtx_fmt_e (code, GET_MODE (target), copy_rtx (op0)); 20118334Speter else 20250397Sobrien note = gen_rtx_fmt_ee (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1)); 20318334Speter 204117395Skan set_unique_reg_note (last_insn, REG_EQUAL, note); 20518334Speter 20618334Speter return 1; 20718334Speter} 20818334Speter 20918334Speter/* Widen OP to MODE and return the rtx for the widened operand. UNSIGNEDP 21018334Speter says whether OP is signed or unsigned. NO_EXTEND is nonzero if we need 21118334Speter not actually do a sign-extend or zero-extend, but can leave the 21218334Speter higher-order bits of the result rtx undefined, for example, in the case 21318334Speter of logical operations, but not right shifts. */ 21418334Speter 21518334Speterstatic rtx 21618334Speterwiden_operand (op, mode, oldmode, unsignedp, no_extend) 21718334Speter rtx op; 21818334Speter enum machine_mode mode, oldmode; 21918334Speter int unsignedp; 22018334Speter int no_extend; 22118334Speter{ 22218334Speter rtx result; 22318334Speter 22496263Sobrien /* If we don't have to extend and this is a constant, return it. */ 22596263Sobrien if (no_extend && GET_MODE (op) == VOIDmode) 22696263Sobrien return op; 22796263Sobrien 22896263Sobrien /* If we must extend do so. If OP is a SUBREG for a promoted object, also 22996263Sobrien extend since it will be more efficient to do so unless the signedness of 23096263Sobrien a promoted object differs from our extension. */ 23118334Speter if (! no_extend 23296263Sobrien || (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op) 23396263Sobrien && SUBREG_PROMOTED_UNSIGNED_P (op) == unsignedp)) 23418334Speter return convert_modes (mode, oldmode, op, unsignedp); 23518334Speter 23618334Speter /* If MODE is no wider than a single word, we return a paradoxical 23718334Speter SUBREG. */ 23818334Speter if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) 23950397Sobrien return gen_rtx_SUBREG (mode, force_reg (GET_MODE (op), op), 0); 24018334Speter 24118334Speter /* Otherwise, get an object of MODE, clobber it, and set the low-order 24218334Speter part to OP. */ 24318334Speter 24418334Speter result = gen_reg_rtx (mode); 24550397Sobrien emit_insn (gen_rtx_CLOBBER (VOIDmode, result)); 24618334Speter emit_move_insn (gen_lowpart (GET_MODE (op), result), op); 24718334Speter return result; 24818334Speter} 24918334Speter 25052284Sobrien/* Generate code to perform a straightforward complex divide. */ 25152284Sobrien 25252284Sobrienstatic int 25352284Sobrienexpand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode, 25452284Sobrien unsignedp, methods, class, binoptab) 255117395Skan rtx real0, real1, imag0, imag1, realr, imagr; 256117395Skan enum machine_mode submode; 257117395Skan int unsignedp; 258117395Skan enum optab_methods methods; 259117395Skan enum mode_class class; 260117395Skan optab binoptab; 26152284Sobrien{ 26252284Sobrien rtx divisor; 26352284Sobrien rtx real_t, imag_t; 26452284Sobrien rtx temp1, temp2; 26552284Sobrien rtx res; 26690075Sobrien optab this_add_optab = add_optab; 26790075Sobrien optab this_sub_optab = sub_optab; 26890075Sobrien optab this_neg_optab = neg_optab; 26990075Sobrien optab this_mul_optab = smul_optab; 27052284Sobrien 27190075Sobrien if (binoptab == sdivv_optab) 27290075Sobrien { 27390075Sobrien this_add_optab = addv_optab; 27490075Sobrien this_sub_optab = subv_optab; 27590075Sobrien this_neg_optab = negv_optab; 27690075Sobrien this_mul_optab = smulv_optab; 27790075Sobrien } 27890075Sobrien 27952284Sobrien /* Don't fetch these from memory more than once. */ 28052284Sobrien real0 = force_reg (submode, real0); 28152284Sobrien real1 = force_reg (submode, real1); 28252284Sobrien 28352284Sobrien if (imag0 != 0) 28452284Sobrien imag0 = force_reg (submode, imag0); 28552284Sobrien 28652284Sobrien imag1 = force_reg (submode, imag1); 28752284Sobrien 28852284Sobrien /* Divisor: c*c + d*d. */ 28990075Sobrien temp1 = expand_binop (submode, this_mul_optab, real1, real1, 29052284Sobrien NULL_RTX, unsignedp, methods); 29152284Sobrien 29290075Sobrien temp2 = expand_binop (submode, this_mul_optab, imag1, imag1, 29352284Sobrien NULL_RTX, unsignedp, methods); 29452284Sobrien 29552284Sobrien if (temp1 == 0 || temp2 == 0) 29652284Sobrien return 0; 29752284Sobrien 29890075Sobrien divisor = expand_binop (submode, this_add_optab, temp1, temp2, 29952284Sobrien NULL_RTX, unsignedp, methods); 30052284Sobrien if (divisor == 0) 30152284Sobrien return 0; 30252284Sobrien 30352284Sobrien if (imag0 == 0) 30452284Sobrien { 30552284Sobrien /* Mathematically, ((a)(c-id))/divisor. */ 30652284Sobrien /* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)). */ 30752284Sobrien 30852284Sobrien /* Calculate the dividend. */ 30990075Sobrien real_t = expand_binop (submode, this_mul_optab, real0, real1, 31052284Sobrien NULL_RTX, unsignedp, methods); 31152284Sobrien 31290075Sobrien imag_t = expand_binop (submode, this_mul_optab, real0, imag1, 31352284Sobrien NULL_RTX, unsignedp, methods); 31452284Sobrien 31552284Sobrien if (real_t == 0 || imag_t == 0) 31652284Sobrien return 0; 31752284Sobrien 31890075Sobrien imag_t = expand_unop (submode, this_neg_optab, imag_t, 31952284Sobrien NULL_RTX, unsignedp); 32052284Sobrien } 32152284Sobrien else 32252284Sobrien { 32352284Sobrien /* Mathematically, ((a+ib)(c-id))/divider. */ 32452284Sobrien /* Calculate the dividend. */ 32590075Sobrien temp1 = expand_binop (submode, this_mul_optab, real0, real1, 32652284Sobrien NULL_RTX, unsignedp, methods); 32752284Sobrien 32890075Sobrien temp2 = expand_binop (submode, this_mul_optab, imag0, imag1, 32952284Sobrien NULL_RTX, unsignedp, methods); 33052284Sobrien 33152284Sobrien if (temp1 == 0 || temp2 == 0) 33252284Sobrien return 0; 33352284Sobrien 33490075Sobrien real_t = expand_binop (submode, this_add_optab, temp1, temp2, 33552284Sobrien NULL_RTX, unsignedp, methods); 33652284Sobrien 33790075Sobrien temp1 = expand_binop (submode, this_mul_optab, imag0, real1, 33852284Sobrien NULL_RTX, unsignedp, methods); 33952284Sobrien 34090075Sobrien temp2 = expand_binop (submode, this_mul_optab, real0, imag1, 34152284Sobrien NULL_RTX, unsignedp, methods); 34252284Sobrien 34352284Sobrien if (temp1 == 0 || temp2 == 0) 34452284Sobrien return 0; 34552284Sobrien 34690075Sobrien imag_t = expand_binop (submode, this_sub_optab, temp1, temp2, 34752284Sobrien NULL_RTX, unsignedp, methods); 34852284Sobrien 34952284Sobrien if (real_t == 0 || imag_t == 0) 35052284Sobrien return 0; 35152284Sobrien } 35252284Sobrien 35352284Sobrien if (class == MODE_COMPLEX_FLOAT) 35452284Sobrien res = expand_binop (submode, binoptab, real_t, divisor, 35552284Sobrien realr, unsignedp, methods); 35652284Sobrien else 35752284Sobrien res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 35852284Sobrien real_t, divisor, realr, unsignedp); 35952284Sobrien 36052284Sobrien if (res == 0) 36152284Sobrien return 0; 36252284Sobrien 36352284Sobrien if (res != realr) 36452284Sobrien emit_move_insn (realr, res); 36552284Sobrien 36652284Sobrien if (class == MODE_COMPLEX_FLOAT) 36752284Sobrien res = expand_binop (submode, binoptab, imag_t, divisor, 36852284Sobrien imagr, unsignedp, methods); 36952284Sobrien else 37052284Sobrien res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 37152284Sobrien imag_t, divisor, imagr, unsignedp); 37252284Sobrien 37352284Sobrien if (res == 0) 37452284Sobrien return 0; 37552284Sobrien 37652284Sobrien if (res != imagr) 37752284Sobrien emit_move_insn (imagr, res); 37852284Sobrien 37952284Sobrien return 1; 38052284Sobrien} 38152284Sobrien 38252284Sobrien/* Generate code to perform a wide-input-range-acceptable complex divide. */ 38352284Sobrien 38452284Sobrienstatic int 38552284Sobrienexpand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode, 38652284Sobrien unsignedp, methods, class, binoptab) 387117395Skan rtx real0, real1, imag0, imag1, realr, imagr; 388117395Skan enum machine_mode submode; 389117395Skan int unsignedp; 390117395Skan enum optab_methods methods; 391117395Skan enum mode_class class; 392117395Skan optab binoptab; 39352284Sobrien{ 39452284Sobrien rtx ratio, divisor; 39552284Sobrien rtx real_t, imag_t; 39652284Sobrien rtx temp1, temp2, lab1, lab2; 39752284Sobrien enum machine_mode mode; 39852284Sobrien rtx res; 39990075Sobrien optab this_add_optab = add_optab; 40090075Sobrien optab this_sub_optab = sub_optab; 40190075Sobrien optab this_neg_optab = neg_optab; 40290075Sobrien optab this_mul_optab = smul_optab; 40390075Sobrien 40490075Sobrien if (binoptab == sdivv_optab) 40590075Sobrien { 40690075Sobrien this_add_optab = addv_optab; 40790075Sobrien this_sub_optab = subv_optab; 40890075Sobrien this_neg_optab = negv_optab; 40990075Sobrien this_mul_optab = smulv_optab; 41090075Sobrien } 41152284Sobrien 41252284Sobrien /* Don't fetch these from memory more than once. */ 41352284Sobrien real0 = force_reg (submode, real0); 41452284Sobrien real1 = force_reg (submode, real1); 41552284Sobrien 41652284Sobrien if (imag0 != 0) 41752284Sobrien imag0 = force_reg (submode, imag0); 41852284Sobrien 41952284Sobrien imag1 = force_reg (submode, imag1); 42052284Sobrien 42152284Sobrien /* XXX What's an "unsigned" complex number? */ 42252284Sobrien if (unsignedp) 42352284Sobrien { 42452284Sobrien temp1 = real1; 42552284Sobrien temp2 = imag1; 42652284Sobrien } 42752284Sobrien else 42852284Sobrien { 42990075Sobrien temp1 = expand_abs (submode, real1, NULL_RTX, unsignedp, 1); 43090075Sobrien temp2 = expand_abs (submode, imag1, NULL_RTX, unsignedp, 1); 43152284Sobrien } 43252284Sobrien 43352284Sobrien if (temp1 == 0 || temp2 == 0) 43452284Sobrien return 0; 43552284Sobrien 43652284Sobrien mode = GET_MODE (temp1); 43752284Sobrien lab1 = gen_label_rtx (); 43852284Sobrien emit_cmp_and_jump_insns (temp1, temp2, LT, NULL_RTX, 43990075Sobrien mode, unsignedp, lab1); 44052284Sobrien 44152284Sobrien /* |c| >= |d|; use ratio d/c to scale dividend and divisor. */ 44252284Sobrien 44352284Sobrien if (class == MODE_COMPLEX_FLOAT) 44452284Sobrien ratio = expand_binop (submode, binoptab, imag1, real1, 44552284Sobrien NULL_RTX, unsignedp, methods); 44652284Sobrien else 44752284Sobrien ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode, 44852284Sobrien imag1, real1, NULL_RTX, unsignedp); 44952284Sobrien 45052284Sobrien if (ratio == 0) 45152284Sobrien return 0; 45252284Sobrien 45352284Sobrien /* Calculate divisor. */ 45452284Sobrien 45590075Sobrien temp1 = expand_binop (submode, this_mul_optab, imag1, ratio, 45652284Sobrien NULL_RTX, unsignedp, methods); 45752284Sobrien 45852284Sobrien if (temp1 == 0) 45952284Sobrien return 0; 46052284Sobrien 46190075Sobrien divisor = expand_binop (submode, this_add_optab, temp1, real1, 46252284Sobrien NULL_RTX, unsignedp, methods); 46352284Sobrien 46452284Sobrien if (divisor == 0) 46552284Sobrien return 0; 46652284Sobrien 46752284Sobrien /* Calculate dividend. */ 46852284Sobrien 46952284Sobrien if (imag0 == 0) 47052284Sobrien { 47152284Sobrien real_t = real0; 47252284Sobrien 47352284Sobrien /* Compute a / (c+id) as a / (c+d(d/c)) + i (-a(d/c)) / (c+d(d/c)). */ 47452284Sobrien 47590075Sobrien imag_t = expand_binop (submode, this_mul_optab, real0, ratio, 47652284Sobrien NULL_RTX, unsignedp, methods); 47752284Sobrien 47852284Sobrien if (imag_t == 0) 47952284Sobrien return 0; 48052284Sobrien 48190075Sobrien imag_t = expand_unop (submode, this_neg_optab, imag_t, 48252284Sobrien NULL_RTX, unsignedp); 48352284Sobrien 48452284Sobrien if (real_t == 0 || imag_t == 0) 48552284Sobrien return 0; 48652284Sobrien } 48752284Sobrien else 48852284Sobrien { 48952284Sobrien /* Compute (a+ib)/(c+id) as 49052284Sobrien (a+b(d/c))/(c+d(d/c) + i(b-a(d/c))/(c+d(d/c)). */ 49152284Sobrien 49290075Sobrien temp1 = expand_binop (submode, this_mul_optab, imag0, ratio, 49352284Sobrien NULL_RTX, unsignedp, methods); 49452284Sobrien 49552284Sobrien if (temp1 == 0) 49652284Sobrien return 0; 49752284Sobrien 49890075Sobrien real_t = expand_binop (submode, this_add_optab, temp1, real0, 49952284Sobrien NULL_RTX, unsignedp, methods); 50052284Sobrien 50190075Sobrien temp1 = expand_binop (submode, this_mul_optab, real0, ratio, 50252284Sobrien NULL_RTX, unsignedp, methods); 50352284Sobrien 50452284Sobrien if (temp1 == 0) 50552284Sobrien return 0; 50652284Sobrien 50790075Sobrien imag_t = expand_binop (submode, this_sub_optab, imag0, temp1, 50852284Sobrien NULL_RTX, unsignedp, methods); 50952284Sobrien 51052284Sobrien if (real_t == 0 || imag_t == 0) 51152284Sobrien return 0; 51252284Sobrien } 51352284Sobrien 51452284Sobrien if (class == MODE_COMPLEX_FLOAT) 51552284Sobrien res = expand_binop (submode, binoptab, real_t, divisor, 51652284Sobrien realr, unsignedp, methods); 51752284Sobrien else 51852284Sobrien res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 51952284Sobrien real_t, divisor, realr, unsignedp); 52052284Sobrien 52152284Sobrien if (res == 0) 52252284Sobrien return 0; 52352284Sobrien 52452284Sobrien if (res != realr) 52552284Sobrien emit_move_insn (realr, res); 52652284Sobrien 52752284Sobrien if (class == MODE_COMPLEX_FLOAT) 52852284Sobrien res = expand_binop (submode, binoptab, imag_t, divisor, 52952284Sobrien imagr, unsignedp, methods); 53052284Sobrien else 53152284Sobrien res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 53252284Sobrien imag_t, divisor, imagr, unsignedp); 53352284Sobrien 53452284Sobrien if (res == 0) 53552284Sobrien return 0; 53652284Sobrien 53752284Sobrien if (res != imagr) 53852284Sobrien emit_move_insn (imagr, res); 53952284Sobrien 54052284Sobrien lab2 = gen_label_rtx (); 54152284Sobrien emit_jump_insn (gen_jump (lab2)); 54252284Sobrien emit_barrier (); 54352284Sobrien 54452284Sobrien emit_label (lab1); 54552284Sobrien 54652284Sobrien /* |d| > |c|; use ratio c/d to scale dividend and divisor. */ 54752284Sobrien 54852284Sobrien if (class == MODE_COMPLEX_FLOAT) 54952284Sobrien ratio = expand_binop (submode, binoptab, real1, imag1, 55052284Sobrien NULL_RTX, unsignedp, methods); 55152284Sobrien else 55252284Sobrien ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode, 55352284Sobrien real1, imag1, NULL_RTX, unsignedp); 55452284Sobrien 55552284Sobrien if (ratio == 0) 55652284Sobrien return 0; 55752284Sobrien 55852284Sobrien /* Calculate divisor. */ 55952284Sobrien 56090075Sobrien temp1 = expand_binop (submode, this_mul_optab, real1, ratio, 56152284Sobrien NULL_RTX, unsignedp, methods); 56252284Sobrien 56352284Sobrien if (temp1 == 0) 56452284Sobrien return 0; 56552284Sobrien 56690075Sobrien divisor = expand_binop (submode, this_add_optab, temp1, imag1, 56752284Sobrien NULL_RTX, unsignedp, methods); 56852284Sobrien 56952284Sobrien if (divisor == 0) 57052284Sobrien return 0; 57152284Sobrien 57252284Sobrien /* Calculate dividend. */ 57352284Sobrien 57452284Sobrien if (imag0 == 0) 57552284Sobrien { 57652284Sobrien /* Compute a / (c+id) as a(c/d) / (c(c/d)+d) + i (-a) / (c(c/d)+d). */ 57752284Sobrien 57890075Sobrien real_t = expand_binop (submode, this_mul_optab, real0, ratio, 57952284Sobrien NULL_RTX, unsignedp, methods); 58052284Sobrien 58190075Sobrien imag_t = expand_unop (submode, this_neg_optab, real0, 58252284Sobrien NULL_RTX, unsignedp); 58352284Sobrien 58452284Sobrien if (real_t == 0 || imag_t == 0) 58552284Sobrien return 0; 58652284Sobrien } 58752284Sobrien else 58852284Sobrien { 58952284Sobrien /* Compute (a+ib)/(c+id) as 59052284Sobrien (a(c/d)+b)/(c(c/d)+d) + i (b(c/d)-a)/(c(c/d)+d). */ 59152284Sobrien 59290075Sobrien temp1 = expand_binop (submode, this_mul_optab, real0, ratio, 59352284Sobrien NULL_RTX, unsignedp, methods); 59452284Sobrien 59552284Sobrien if (temp1 == 0) 59652284Sobrien return 0; 59752284Sobrien 59890075Sobrien real_t = expand_binop (submode, this_add_optab, temp1, imag0, 59952284Sobrien NULL_RTX, unsignedp, methods); 60052284Sobrien 60190075Sobrien temp1 = expand_binop (submode, this_mul_optab, imag0, ratio, 60252284Sobrien NULL_RTX, unsignedp, methods); 60352284Sobrien 60452284Sobrien if (temp1 == 0) 60552284Sobrien return 0; 60652284Sobrien 60790075Sobrien imag_t = expand_binop (submode, this_sub_optab, temp1, real0, 60852284Sobrien NULL_RTX, unsignedp, methods); 60952284Sobrien 61052284Sobrien if (real_t == 0 || imag_t == 0) 61152284Sobrien return 0; 61252284Sobrien } 61352284Sobrien 61452284Sobrien if (class == MODE_COMPLEX_FLOAT) 61552284Sobrien res = expand_binop (submode, binoptab, real_t, divisor, 61652284Sobrien realr, unsignedp, methods); 61752284Sobrien else 61852284Sobrien res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 61952284Sobrien real_t, divisor, realr, unsignedp); 62052284Sobrien 62152284Sobrien if (res == 0) 62252284Sobrien return 0; 62352284Sobrien 62452284Sobrien if (res != realr) 62552284Sobrien emit_move_insn (realr, res); 62652284Sobrien 62752284Sobrien if (class == MODE_COMPLEX_FLOAT) 62852284Sobrien res = expand_binop (submode, binoptab, imag_t, divisor, 62952284Sobrien imagr, unsignedp, methods); 63052284Sobrien else 63152284Sobrien res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 63252284Sobrien imag_t, divisor, imagr, unsignedp); 63352284Sobrien 63452284Sobrien if (res == 0) 63552284Sobrien return 0; 63652284Sobrien 63752284Sobrien if (res != imagr) 63852284Sobrien emit_move_insn (imagr, res); 63952284Sobrien 64052284Sobrien emit_label (lab2); 64152284Sobrien 64252284Sobrien return 1; 64352284Sobrien} 64452284Sobrien 64590075Sobrien/* Wrapper around expand_binop which takes an rtx code to specify 64690075Sobrien the operation to perform, not an optab pointer. All other 64790075Sobrien arguments are the same. */ 64890075Sobrienrtx 64990075Sobrienexpand_simple_binop (mode, code, op0, op1, target, unsignedp, methods) 65090075Sobrien enum machine_mode mode; 65190075Sobrien enum rtx_code code; 65290075Sobrien rtx op0, op1; 65390075Sobrien rtx target; 65490075Sobrien int unsignedp; 65590075Sobrien enum optab_methods methods; 65690075Sobrien{ 657117395Skan optab binop = code_to_optab[(int) code]; 65890075Sobrien if (binop == 0) 65990075Sobrien abort (); 66090075Sobrien 66190075Sobrien return expand_binop (mode, binop, op0, op1, target, unsignedp, methods); 66290075Sobrien} 66390075Sobrien 66418334Speter/* Generate code to perform an operation specified by BINOPTAB 66518334Speter on operands OP0 and OP1, with result having machine-mode MODE. 66618334Speter 66718334Speter UNSIGNEDP is for the case where we have to widen the operands 66818334Speter to perform the operation. It says to use zero-extension. 66918334Speter 67018334Speter If TARGET is nonzero, the value 67118334Speter is generated there, if it is convenient to do so. 67218334Speter In all cases an rtx is returned for the locus of the value; 67318334Speter this may or may not be TARGET. */ 67418334Speter 67518334Speterrtx 67618334Speterexpand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) 67718334Speter enum machine_mode mode; 67818334Speter optab binoptab; 67918334Speter rtx op0, op1; 68018334Speter rtx target; 68118334Speter int unsignedp; 68218334Speter enum optab_methods methods; 68318334Speter{ 68418334Speter enum optab_methods next_methods 68518334Speter = (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN 68618334Speter ? OPTAB_WIDEN : methods); 68718334Speter enum mode_class class; 68818334Speter enum machine_mode wider_mode; 68990075Sobrien rtx temp; 69018334Speter int commutative_op = 0; 691117395Skan int shift_op = (binoptab->code == ASHIFT 69218334Speter || binoptab->code == ASHIFTRT 69318334Speter || binoptab->code == LSHIFTRT 69418334Speter || binoptab->code == ROTATE 69518334Speter || binoptab->code == ROTATERT); 69618334Speter rtx entry_last = get_last_insn (); 69718334Speter rtx last; 69818334Speter 69918334Speter class = GET_MODE_CLASS (mode); 70018334Speter 70118334Speter op0 = protect_from_queue (op0, 0); 70218334Speter op1 = protect_from_queue (op1, 0); 70318334Speter if (target) 70418334Speter target = protect_from_queue (target, 1); 70518334Speter 70618334Speter if (flag_force_mem) 70718334Speter { 70818334Speter op0 = force_not_mem (op0); 70918334Speter op1 = force_not_mem (op1); 71018334Speter } 71118334Speter 71218334Speter /* If subtracting an integer constant, convert this into an addition of 71318334Speter the negated constant. */ 71418334Speter 71518334Speter if (binoptab == sub_optab && GET_CODE (op1) == CONST_INT) 71618334Speter { 71718334Speter op1 = negate_rtx (mode, op1); 71818334Speter binoptab = add_optab; 71918334Speter } 72018334Speter 72118334Speter /* If we are inside an appropriately-short loop and one operand is an 72218334Speter expensive constant, force it into a register. */ 72318334Speter if (CONSTANT_P (op0) && preserve_subexpressions_p () 72490075Sobrien && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1)) 72518334Speter op0 = force_reg (mode, op0); 72618334Speter 72718334Speter if (CONSTANT_P (op1) && preserve_subexpressions_p () 72890075Sobrien && ! shift_op && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1)) 72918334Speter op1 = force_reg (mode, op1); 73018334Speter 73118334Speter /* Record where to delete back to if we backtrack. */ 73218334Speter last = get_last_insn (); 73318334Speter 73418334Speter /* If operation is commutative, 73518334Speter try to make the first operand a register. 73618334Speter Even better, try to make it the same as the target. 73718334Speter Also try to make the last operand a constant. */ 73818334Speter if (GET_RTX_CLASS (binoptab->code) == 'c' 73918334Speter || binoptab == smul_widen_optab 74018334Speter || binoptab == umul_widen_optab 74118334Speter || binoptab == smul_highpart_optab 74218334Speter || binoptab == umul_highpart_optab) 74318334Speter { 74418334Speter commutative_op = 1; 74518334Speter 74618334Speter if (((target == 0 || GET_CODE (target) == REG) 74718334Speter ? ((GET_CODE (op1) == REG 74818334Speter && GET_CODE (op0) != REG) 74918334Speter || target == op1) 75018334Speter : rtx_equal_p (op1, target)) 75118334Speter || GET_CODE (op0) == CONST_INT) 75218334Speter { 75318334Speter temp = op1; 75418334Speter op1 = op0; 75518334Speter op0 = temp; 75618334Speter } 75718334Speter } 75818334Speter 75918334Speter /* If we can do it with a three-operand insn, do so. */ 76018334Speter 76118334Speter if (methods != OPTAB_MUST_WIDEN 76218334Speter && binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 76318334Speter { 76418334Speter int icode = (int) binoptab->handlers[(int) mode].insn_code; 76590075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 76690075Sobrien enum machine_mode mode1 = insn_data[icode].operand[2].mode; 76718334Speter rtx pat; 76818334Speter rtx xop0 = op0, xop1 = op1; 76918334Speter 77018334Speter if (target) 77118334Speter temp = target; 77218334Speter else 77318334Speter temp = gen_reg_rtx (mode); 77418334Speter 77518334Speter /* If it is a commutative operator and the modes would match 77650397Sobrien if we would swap the operands, we can save the conversions. */ 77718334Speter if (commutative_op) 77818334Speter { 77918334Speter if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1 78018334Speter && GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0) 78118334Speter { 78290075Sobrien rtx tmp; 78318334Speter 78418334Speter tmp = op0; op0 = op1; op1 = tmp; 78518334Speter tmp = xop0; xop0 = xop1; xop1 = tmp; 78618334Speter } 78718334Speter } 78818334Speter 78918334Speter /* In case the insn wants input operands in modes different from 790103445Skan those of the actual operands, convert the operands. It would 791103445Skan seem that we don't need to convert CONST_INTs, but we do, so 792110611Skan that they're properly zero-extended, sign-extended or truncated 793110611Skan for their mode. */ 79418334Speter 795117395Skan if (GET_MODE (op0) != mode0 && mode0 != VOIDmode) 79690075Sobrien xop0 = convert_modes (mode0, 79790075Sobrien GET_MODE (op0) != VOIDmode 79890075Sobrien ? GET_MODE (op0) 799103445Skan : mode, 80090075Sobrien xop0, unsignedp); 80118334Speter 802117395Skan if (GET_MODE (op1) != mode1 && mode1 != VOIDmode) 80390075Sobrien xop1 = convert_modes (mode1, 80490075Sobrien GET_MODE (op1) != VOIDmode 80590075Sobrien ? GET_MODE (op1) 806110611Skan : mode, 80790075Sobrien xop1, unsignedp); 80818334Speter 80918334Speter /* Now, if insn's predicates don't allow our operands, put them into 81018334Speter pseudo regs. */ 81118334Speter 81290075Sobrien if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0) 81318334Speter && mode0 != VOIDmode) 81418334Speter xop0 = copy_to_mode_reg (mode0, xop0); 81518334Speter 81690075Sobrien if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1) 81718334Speter && mode1 != VOIDmode) 81818334Speter xop1 = copy_to_mode_reg (mode1, xop1); 81918334Speter 82090075Sobrien if (! (*insn_data[icode].operand[0].predicate) (temp, mode)) 82118334Speter temp = gen_reg_rtx (mode); 82218334Speter 82318334Speter pat = GEN_FCN (icode) (temp, xop0, xop1); 82418334Speter if (pat) 82518334Speter { 826117395Skan /* If PAT is composed of more than one insn, try to add an appropriate 82718334Speter REG_EQUAL note to it. If we can't because TEMP conflicts with an 82818334Speter operand, call ourselves again, this time without a target. */ 829117395Skan if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX 83018334Speter && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1)) 83118334Speter { 83218334Speter delete_insns_since (last); 83318334Speter return expand_binop (mode, binoptab, op0, op1, NULL_RTX, 83418334Speter unsignedp, methods); 83518334Speter } 83618334Speter 83718334Speter emit_insn (pat); 83818334Speter return temp; 83918334Speter } 84018334Speter else 84118334Speter delete_insns_since (last); 84218334Speter } 84318334Speter 84418334Speter /* If this is a multiply, see if we can do a widening operation that 84518334Speter takes operands of this mode and makes a wider mode. */ 84618334Speter 84718334Speter if (binoptab == smul_optab && GET_MODE_WIDER_MODE (mode) != VOIDmode 84818334Speter && (((unsignedp ? umul_widen_optab : smul_widen_optab) 84918334Speter ->handlers[(int) GET_MODE_WIDER_MODE (mode)].insn_code) 85018334Speter != CODE_FOR_nothing)) 85118334Speter { 85218334Speter temp = expand_binop (GET_MODE_WIDER_MODE (mode), 85318334Speter unsignedp ? umul_widen_optab : smul_widen_optab, 85418334Speter op0, op1, NULL_RTX, unsignedp, OPTAB_DIRECT); 85518334Speter 85618334Speter if (temp != 0) 85718334Speter { 85818334Speter if (GET_MODE_CLASS (mode) == MODE_INT) 85918334Speter return gen_lowpart (mode, temp); 86018334Speter else 86118334Speter return convert_to_mode (mode, temp, unsignedp); 86218334Speter } 86318334Speter } 86418334Speter 86518334Speter /* Look for a wider mode of the same class for which we think we 86618334Speter can open-code the operation. Check for a widening multiply at the 86718334Speter wider mode as well. */ 86818334Speter 86918334Speter if ((class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) 87018334Speter && methods != OPTAB_DIRECT && methods != OPTAB_LIB) 87118334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 87218334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 87318334Speter { 87418334Speter if (binoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing 87518334Speter || (binoptab == smul_optab 87618334Speter && GET_MODE_WIDER_MODE (wider_mode) != VOIDmode 87718334Speter && (((unsignedp ? umul_widen_optab : smul_widen_optab) 87818334Speter ->handlers[(int) GET_MODE_WIDER_MODE (wider_mode)].insn_code) 87918334Speter != CODE_FOR_nothing))) 88018334Speter { 88118334Speter rtx xop0 = op0, xop1 = op1; 88218334Speter int no_extend = 0; 88318334Speter 88418334Speter /* For certain integer operations, we need not actually extend 88518334Speter the narrow operands, as long as we will truncate 88690075Sobrien the results to the same narrowness. */ 88718334Speter 88818334Speter if ((binoptab == ior_optab || binoptab == and_optab 88918334Speter || binoptab == xor_optab 89018334Speter || binoptab == add_optab || binoptab == sub_optab 89118334Speter || binoptab == smul_optab || binoptab == ashl_optab) 89218334Speter && class == MODE_INT) 89318334Speter no_extend = 1; 89418334Speter 89518334Speter xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, no_extend); 89618334Speter 89718334Speter /* The second operand of a shift must always be extended. */ 89818334Speter xop1 = widen_operand (xop1, wider_mode, mode, unsignedp, 89918334Speter no_extend && binoptab != ashl_optab); 90018334Speter 90118334Speter temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX, 90218334Speter unsignedp, OPTAB_DIRECT); 90318334Speter if (temp) 90418334Speter { 90518334Speter if (class != MODE_INT) 90618334Speter { 90718334Speter if (target == 0) 90818334Speter target = gen_reg_rtx (mode); 90918334Speter convert_move (target, temp, 0); 91018334Speter return target; 91118334Speter } 91218334Speter else 91318334Speter return gen_lowpart (mode, temp); 91418334Speter } 91518334Speter else 91618334Speter delete_insns_since (last); 91718334Speter } 91818334Speter } 91918334Speter 92018334Speter /* These can be done a word at a time. */ 92118334Speter if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab) 92218334Speter && class == MODE_INT 92318334Speter && GET_MODE_SIZE (mode) > UNITS_PER_WORD 92418334Speter && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 92518334Speter { 92618334Speter int i; 92718334Speter rtx insns; 92818334Speter rtx equiv_value; 92918334Speter 93018334Speter /* If TARGET is the same as one of the operands, the REG_EQUAL note 93118334Speter won't be accurate, so use a new target. */ 93218334Speter if (target == 0 || target == op0 || target == op1) 93318334Speter target = gen_reg_rtx (mode); 93418334Speter 93518334Speter start_sequence (); 93618334Speter 93718334Speter /* Do the actual arithmetic. */ 93818334Speter for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++) 93918334Speter { 94018334Speter rtx target_piece = operand_subword (target, i, 1, mode); 94118334Speter rtx x = expand_binop (word_mode, binoptab, 94218334Speter operand_subword_force (op0, i, mode), 94318334Speter operand_subword_force (op1, i, mode), 94418334Speter target_piece, unsignedp, next_methods); 94518334Speter 94618334Speter if (x == 0) 94718334Speter break; 94818334Speter 94918334Speter if (target_piece != x) 95018334Speter emit_move_insn (target_piece, x); 95118334Speter } 95218334Speter 95318334Speter insns = get_insns (); 95418334Speter end_sequence (); 95518334Speter 95618334Speter if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD) 95718334Speter { 95818334Speter if (binoptab->code != UNKNOWN) 95918334Speter equiv_value 96050397Sobrien = gen_rtx_fmt_ee (binoptab->code, mode, 96150397Sobrien copy_rtx (op0), copy_rtx (op1)); 96218334Speter else 96318334Speter equiv_value = 0; 96418334Speter 96518334Speter emit_no_conflict_block (insns, target, op0, op1, equiv_value); 96618334Speter return target; 96718334Speter } 96818334Speter } 96918334Speter 97018334Speter /* Synthesize double word shifts from single word shifts. */ 97118334Speter if ((binoptab == lshr_optab || binoptab == ashl_optab 97218334Speter || binoptab == ashr_optab) 97318334Speter && class == MODE_INT 97418334Speter && GET_CODE (op1) == CONST_INT 97518334Speter && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD 97618334Speter && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing 97718334Speter && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing 97818334Speter && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 97918334Speter { 98018334Speter rtx insns, inter, equiv_value; 98118334Speter rtx into_target, outof_target; 98218334Speter rtx into_input, outof_input; 98318334Speter int shift_count, left_shift, outof_word; 98418334Speter 98518334Speter /* If TARGET is the same as one of the operands, the REG_EQUAL note 98618334Speter won't be accurate, so use a new target. */ 98718334Speter if (target == 0 || target == op0 || target == op1) 98818334Speter target = gen_reg_rtx (mode); 98918334Speter 99018334Speter start_sequence (); 99118334Speter 99218334Speter shift_count = INTVAL (op1); 99318334Speter 99418334Speter /* OUTOF_* is the word we are shifting bits away from, and 99518334Speter INTO_* is the word that we are shifting bits towards, thus 99618334Speter they differ depending on the direction of the shift and 99718334Speter WORDS_BIG_ENDIAN. */ 99818334Speter 99918334Speter left_shift = binoptab == ashl_optab; 100018334Speter outof_word = left_shift ^ ! WORDS_BIG_ENDIAN; 100118334Speter 100218334Speter outof_target = operand_subword (target, outof_word, 1, mode); 100318334Speter into_target = operand_subword (target, 1 - outof_word, 1, mode); 100418334Speter 100518334Speter outof_input = operand_subword_force (op0, outof_word, mode); 100618334Speter into_input = operand_subword_force (op0, 1 - outof_word, mode); 100718334Speter 100818334Speter if (shift_count >= BITS_PER_WORD) 100918334Speter { 101018334Speter inter = expand_binop (word_mode, binoptab, 101118334Speter outof_input, 101218334Speter GEN_INT (shift_count - BITS_PER_WORD), 101318334Speter into_target, unsignedp, next_methods); 101418334Speter 101518334Speter if (inter != 0 && inter != into_target) 101618334Speter emit_move_insn (into_target, inter); 101718334Speter 101818334Speter /* For a signed right shift, we must fill the word we are shifting 101918334Speter out of with copies of the sign bit. Otherwise it is zeroed. */ 102018334Speter if (inter != 0 && binoptab != ashr_optab) 102118334Speter inter = CONST0_RTX (word_mode); 102218334Speter else if (inter != 0) 102318334Speter inter = expand_binop (word_mode, binoptab, 102418334Speter outof_input, 102518334Speter GEN_INT (BITS_PER_WORD - 1), 102618334Speter outof_target, unsignedp, next_methods); 102718334Speter 102818334Speter if (inter != 0 && inter != outof_target) 102918334Speter emit_move_insn (outof_target, inter); 103018334Speter } 103118334Speter else 103218334Speter { 103318334Speter rtx carries; 103418334Speter optab reverse_unsigned_shift, unsigned_shift; 103518334Speter 103618334Speter /* For a shift of less then BITS_PER_WORD, to compute the carry, 103718334Speter we must do a logical shift in the opposite direction of the 103818334Speter desired shift. */ 103918334Speter 104018334Speter reverse_unsigned_shift = (left_shift ? lshr_optab : ashl_optab); 104118334Speter 104218334Speter /* For a shift of less than BITS_PER_WORD, to compute the word 104318334Speter shifted towards, we need to unsigned shift the orig value of 104418334Speter that word. */ 104518334Speter 104618334Speter unsigned_shift = (left_shift ? ashl_optab : lshr_optab); 104718334Speter 104818334Speter carries = expand_binop (word_mode, reverse_unsigned_shift, 104918334Speter outof_input, 105018334Speter GEN_INT (BITS_PER_WORD - shift_count), 105118334Speter 0, unsignedp, next_methods); 105218334Speter 105318334Speter if (carries == 0) 105418334Speter inter = 0; 105518334Speter else 105618334Speter inter = expand_binop (word_mode, unsigned_shift, into_input, 105718334Speter op1, 0, unsignedp, next_methods); 105818334Speter 105918334Speter if (inter != 0) 106018334Speter inter = expand_binop (word_mode, ior_optab, carries, inter, 106118334Speter into_target, unsignedp, next_methods); 106218334Speter 106318334Speter if (inter != 0 && inter != into_target) 106418334Speter emit_move_insn (into_target, inter); 106518334Speter 106618334Speter if (inter != 0) 106718334Speter inter = expand_binop (word_mode, binoptab, outof_input, 106818334Speter op1, outof_target, unsignedp, next_methods); 106918334Speter 107018334Speter if (inter != 0 && inter != outof_target) 107118334Speter emit_move_insn (outof_target, inter); 107218334Speter } 107318334Speter 107418334Speter insns = get_insns (); 107518334Speter end_sequence (); 107618334Speter 107718334Speter if (inter != 0) 107818334Speter { 107918334Speter if (binoptab->code != UNKNOWN) 108050397Sobrien equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1); 108118334Speter else 108218334Speter equiv_value = 0; 108318334Speter 108418334Speter emit_no_conflict_block (insns, target, op0, op1, equiv_value); 108518334Speter return target; 108618334Speter } 108718334Speter } 108818334Speter 108918334Speter /* Synthesize double word rotates from single word shifts. */ 109018334Speter if ((binoptab == rotl_optab || binoptab == rotr_optab) 109118334Speter && class == MODE_INT 109218334Speter && GET_CODE (op1) == CONST_INT 109318334Speter && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD 109418334Speter && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing 109518334Speter && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 109618334Speter { 109718334Speter rtx insns, equiv_value; 109818334Speter rtx into_target, outof_target; 109918334Speter rtx into_input, outof_input; 110018334Speter rtx inter; 110118334Speter int shift_count, left_shift, outof_word; 110218334Speter 110318334Speter /* If TARGET is the same as one of the operands, the REG_EQUAL note 110418334Speter won't be accurate, so use a new target. */ 110518334Speter if (target == 0 || target == op0 || target == op1) 110618334Speter target = gen_reg_rtx (mode); 110718334Speter 110818334Speter start_sequence (); 110918334Speter 111018334Speter shift_count = INTVAL (op1); 111118334Speter 111218334Speter /* OUTOF_* is the word we are shifting bits away from, and 111318334Speter INTO_* is the word that we are shifting bits towards, thus 111418334Speter they differ depending on the direction of the shift and 111518334Speter WORDS_BIG_ENDIAN. */ 111618334Speter 111718334Speter left_shift = (binoptab == rotl_optab); 111818334Speter outof_word = left_shift ^ ! WORDS_BIG_ENDIAN; 111918334Speter 112018334Speter outof_target = operand_subword (target, outof_word, 1, mode); 112118334Speter into_target = operand_subword (target, 1 - outof_word, 1, mode); 112218334Speter 112318334Speter outof_input = operand_subword_force (op0, outof_word, mode); 112418334Speter into_input = operand_subword_force (op0, 1 - outof_word, mode); 112518334Speter 112618334Speter if (shift_count == BITS_PER_WORD) 112718334Speter { 112818334Speter /* This is just a word swap. */ 112918334Speter emit_move_insn (outof_target, into_input); 113018334Speter emit_move_insn (into_target, outof_input); 113118334Speter inter = const0_rtx; 113218334Speter } 113318334Speter else 113418334Speter { 113518334Speter rtx into_temp1, into_temp2, outof_temp1, outof_temp2; 113618334Speter rtx first_shift_count, second_shift_count; 113718334Speter optab reverse_unsigned_shift, unsigned_shift; 113818334Speter 113918334Speter reverse_unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD) 114018334Speter ? lshr_optab : ashl_optab); 114118334Speter 114218334Speter unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD) 114318334Speter ? ashl_optab : lshr_optab); 114418334Speter 114518334Speter if (shift_count > BITS_PER_WORD) 114618334Speter { 114718334Speter first_shift_count = GEN_INT (shift_count - BITS_PER_WORD); 1148117395Skan second_shift_count = GEN_INT (2 * BITS_PER_WORD - shift_count); 114918334Speter } 115018334Speter else 115118334Speter { 115218334Speter first_shift_count = GEN_INT (BITS_PER_WORD - shift_count); 115318334Speter second_shift_count = GEN_INT (shift_count); 115418334Speter } 115518334Speter 115618334Speter into_temp1 = expand_binop (word_mode, unsigned_shift, 115718334Speter outof_input, first_shift_count, 115818334Speter NULL_RTX, unsignedp, next_methods); 115918334Speter into_temp2 = expand_binop (word_mode, reverse_unsigned_shift, 116018334Speter into_input, second_shift_count, 1161117395Skan NULL_RTX, unsignedp, next_methods); 116218334Speter 116318334Speter if (into_temp1 != 0 && into_temp2 != 0) 116418334Speter inter = expand_binop (word_mode, ior_optab, into_temp1, into_temp2, 116518334Speter into_target, unsignedp, next_methods); 116618334Speter else 116718334Speter inter = 0; 116818334Speter 116918334Speter if (inter != 0 && inter != into_target) 117018334Speter emit_move_insn (into_target, inter); 117118334Speter 117218334Speter outof_temp1 = expand_binop (word_mode, unsigned_shift, 117318334Speter into_input, first_shift_count, 117418334Speter NULL_RTX, unsignedp, next_methods); 117518334Speter outof_temp2 = expand_binop (word_mode, reverse_unsigned_shift, 117618334Speter outof_input, second_shift_count, 1177117395Skan NULL_RTX, unsignedp, next_methods); 117818334Speter 117918334Speter if (inter != 0 && outof_temp1 != 0 && outof_temp2 != 0) 118018334Speter inter = expand_binop (word_mode, ior_optab, 118118334Speter outof_temp1, outof_temp2, 118218334Speter outof_target, unsignedp, next_methods); 118318334Speter 118418334Speter if (inter != 0 && inter != outof_target) 118518334Speter emit_move_insn (outof_target, inter); 118618334Speter } 118718334Speter 118818334Speter insns = get_insns (); 118918334Speter end_sequence (); 119018334Speter 119118334Speter if (inter != 0) 119218334Speter { 119318334Speter if (binoptab->code != UNKNOWN) 119450397Sobrien equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1); 119518334Speter else 119618334Speter equiv_value = 0; 119718334Speter 119818334Speter /* We can't make this a no conflict block if this is a word swap, 119918334Speter because the word swap case fails if the input and output values 120018334Speter are in the same register. */ 120118334Speter if (shift_count != BITS_PER_WORD) 120218334Speter emit_no_conflict_block (insns, target, op0, op1, equiv_value); 120318334Speter else 1204117395Skan emit_insn (insns); 120518334Speter 120618334Speter 120718334Speter return target; 120818334Speter } 120918334Speter } 121018334Speter 121118334Speter /* These can be done a word at a time by propagating carries. */ 121218334Speter if ((binoptab == add_optab || binoptab == sub_optab) 121318334Speter && class == MODE_INT 121418334Speter && GET_MODE_SIZE (mode) >= 2 * UNITS_PER_WORD 121518334Speter && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 121618334Speter { 1217117395Skan unsigned int i; 121818334Speter optab otheroptab = binoptab == add_optab ? sub_optab : add_optab; 1219117395Skan const unsigned int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD; 122052284Sobrien rtx carry_in = NULL_RTX, carry_out = NULL_RTX; 1221102780Skan rtx xop0, xop1, xtarget; 122218334Speter 122318334Speter /* We can handle either a 1 or -1 value for the carry. If STORE_FLAG 122418334Speter value is one of those, use it. Otherwise, use 1 since it is the 122518334Speter one easiest to get. */ 122618334Speter#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1 122718334Speter int normalizep = STORE_FLAG_VALUE; 122818334Speter#else 122918334Speter int normalizep = 1; 123018334Speter#endif 123118334Speter 123218334Speter /* Prepare the operands. */ 123318334Speter xop0 = force_reg (mode, op0); 123418334Speter xop1 = force_reg (mode, op1); 123518334Speter 1236102780Skan xtarget = gen_reg_rtx (mode); 123718334Speter 1238102780Skan if (target == 0 || GET_CODE (target) != REG) 1239102780Skan target = xtarget; 1240102780Skan 124118334Speter /* Indicate for flow that the entire target reg is being set. */ 124218334Speter if (GET_CODE (target) == REG) 1243102780Skan emit_insn (gen_rtx_CLOBBER (VOIDmode, xtarget)); 124418334Speter 124518334Speter /* Do the actual arithmetic. */ 124618334Speter for (i = 0; i < nwords; i++) 124718334Speter { 124818334Speter int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i); 1249102780Skan rtx target_piece = operand_subword (xtarget, index, 1, mode); 125018334Speter rtx op0_piece = operand_subword_force (xop0, index, mode); 125118334Speter rtx op1_piece = operand_subword_force (xop1, index, mode); 125218334Speter rtx x; 125318334Speter 125418334Speter /* Main add/subtract of the input operands. */ 125518334Speter x = expand_binop (word_mode, binoptab, 125618334Speter op0_piece, op1_piece, 125718334Speter target_piece, unsignedp, next_methods); 125818334Speter if (x == 0) 125918334Speter break; 126018334Speter 126118334Speter if (i + 1 < nwords) 126218334Speter { 126318334Speter /* Store carry from main add/subtract. */ 126418334Speter carry_out = gen_reg_rtx (word_mode); 126550397Sobrien carry_out = emit_store_flag_force (carry_out, 126650397Sobrien (binoptab == add_optab 126790075Sobrien ? LT : GT), 126850397Sobrien x, op0_piece, 126950397Sobrien word_mode, 1, normalizep); 127018334Speter } 127118334Speter 127218334Speter if (i > 0) 127318334Speter { 127490075Sobrien rtx newx; 127590075Sobrien 127618334Speter /* Add/subtract previous carry to main result. */ 127790075Sobrien newx = expand_binop (word_mode, 127890075Sobrien normalizep == 1 ? binoptab : otheroptab, 127990075Sobrien x, carry_in, 128090075Sobrien NULL_RTX, 1, next_methods); 128118334Speter 128218334Speter if (i + 1 < nwords) 128318334Speter { 128418334Speter /* Get out carry from adding/subtracting carry in. */ 128590075Sobrien rtx carry_tmp = gen_reg_rtx (word_mode); 128650397Sobrien carry_tmp = emit_store_flag_force (carry_tmp, 128790075Sobrien (binoptab == add_optab 128890075Sobrien ? LT : GT), 128990075Sobrien newx, x, 129050397Sobrien word_mode, 1, normalizep); 129118334Speter 129218334Speter /* Logical-ior the two poss. carry together. */ 129318334Speter carry_out = expand_binop (word_mode, ior_optab, 129418334Speter carry_out, carry_tmp, 129518334Speter carry_out, 0, next_methods); 129618334Speter if (carry_out == 0) 129718334Speter break; 129818334Speter } 129990075Sobrien emit_move_insn (target_piece, newx); 130018334Speter } 130118334Speter 130218334Speter carry_in = carry_out; 130318334Speter } 130418334Speter 1305117395Skan if (i == GET_MODE_BITSIZE (mode) / (unsigned) BITS_PER_WORD) 130618334Speter { 130750397Sobrien if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 130850397Sobrien { 1309102780Skan rtx temp = emit_move_insn (target, xtarget); 131018334Speter 131152284Sobrien set_unique_reg_note (temp, 131252284Sobrien REG_EQUAL, 131352284Sobrien gen_rtx_fmt_ee (binoptab->code, mode, 131452284Sobrien copy_rtx (xop0), 131552284Sobrien copy_rtx (xop1))); 131650397Sobrien } 1317117395Skan else 1318117395Skan target = xtarget; 131990075Sobrien 132018334Speter return target; 132118334Speter } 132290075Sobrien 132318334Speter else 132418334Speter delete_insns_since (last); 132518334Speter } 132618334Speter 132718334Speter /* If we want to multiply two two-word values and have normal and widening 132818334Speter multiplies of single-word values, we can do this with three smaller 132918334Speter multiplications. Note that we do not make a REG_NO_CONFLICT block here 133018334Speter because we are not operating on one word at a time. 133118334Speter 133218334Speter The multiplication proceeds as follows: 133318334Speter _______________________ 133418334Speter [__op0_high_|__op0_low__] 133518334Speter _______________________ 133618334Speter * [__op1_high_|__op1_low__] 133718334Speter _______________________________________________ 133818334Speter _______________________ 133918334Speter (1) [__op0_low__*__op1_low__] 134018334Speter _______________________ 134118334Speter (2a) [__op0_low__*__op1_high_] 134218334Speter _______________________ 134318334Speter (2b) [__op0_high_*__op1_low__] 134418334Speter _______________________ 134518334Speter (3) [__op0_high_*__op1_high_] 134618334Speter 134718334Speter 134818334Speter This gives a 4-word result. Since we are only interested in the 134918334Speter lower 2 words, partial result (3) and the upper words of (2a) and 135018334Speter (2b) don't need to be calculated. Hence (2a) and (2b) can be 135118334Speter calculated using non-widening multiplication. 135218334Speter 135318334Speter (1), however, needs to be calculated with an unsigned widening 135418334Speter multiplication. If this operation is not directly supported we 135518334Speter try using a signed widening multiplication and adjust the result. 135618334Speter This adjustment works as follows: 135718334Speter 135818334Speter If both operands are positive then no adjustment is needed. 135918334Speter 136018334Speter If the operands have different signs, for example op0_low < 0 and 136118334Speter op1_low >= 0, the instruction treats the most significant bit of 136218334Speter op0_low as a sign bit instead of a bit with significance 136318334Speter 2**(BITS_PER_WORD-1), i.e. the instruction multiplies op1_low 136418334Speter with 2**BITS_PER_WORD - op0_low, and two's complements the 136518334Speter result. Conclusion: We need to add op1_low * 2**BITS_PER_WORD to 136618334Speter the result. 136718334Speter 136818334Speter Similarly, if both operands are negative, we need to add 136918334Speter (op0_low + op1_low) * 2**BITS_PER_WORD. 137018334Speter 137118334Speter We use a trick to adjust quickly. We logically shift op0_low right 137218334Speter (op1_low) BITS_PER_WORD-1 steps to get 0 or 1, and add this to 137318334Speter op0_high (op1_high) before it is used to calculate 2b (2a). If no 137418334Speter logical shift exists, we do an arithmetic right shift and subtract 137518334Speter the 0 or -1. */ 137618334Speter 137718334Speter if (binoptab == smul_optab 137818334Speter && class == MODE_INT 137918334Speter && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD 138018334Speter && smul_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing 138118334Speter && add_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing 138218334Speter && ((umul_widen_optab->handlers[(int) mode].insn_code 138318334Speter != CODE_FOR_nothing) 138418334Speter || (smul_widen_optab->handlers[(int) mode].insn_code 138518334Speter != CODE_FOR_nothing))) 138618334Speter { 138718334Speter int low = (WORDS_BIG_ENDIAN ? 1 : 0); 138818334Speter int high = (WORDS_BIG_ENDIAN ? 0 : 1); 138918334Speter rtx op0_high = operand_subword_force (op0, high, mode); 139018334Speter rtx op0_low = operand_subword_force (op0, low, mode); 139118334Speter rtx op1_high = operand_subword_force (op1, high, mode); 139218334Speter rtx op1_low = operand_subword_force (op1, low, mode); 139318334Speter rtx product = 0; 139452284Sobrien rtx op0_xhigh = NULL_RTX; 139552284Sobrien rtx op1_xhigh = NULL_RTX; 139618334Speter 139718334Speter /* If the target is the same as one of the inputs, don't use it. This 139818334Speter prevents problems with the REG_EQUAL note. */ 139918334Speter if (target == op0 || target == op1 140018334Speter || (target != 0 && GET_CODE (target) != REG)) 140118334Speter target = 0; 140218334Speter 140318334Speter /* Multiply the two lower words to get a double-word product. 140418334Speter If unsigned widening multiplication is available, use that; 140518334Speter otherwise use the signed form and compensate. */ 140618334Speter 140718334Speter if (umul_widen_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 140818334Speter { 140918334Speter product = expand_binop (mode, umul_widen_optab, op0_low, op1_low, 141018334Speter target, 1, OPTAB_DIRECT); 141118334Speter 141218334Speter /* If we didn't succeed, delete everything we did so far. */ 141318334Speter if (product == 0) 141418334Speter delete_insns_since (last); 141518334Speter else 141618334Speter op0_xhigh = op0_high, op1_xhigh = op1_high; 141718334Speter } 141818334Speter 141918334Speter if (product == 0 142018334Speter && smul_widen_optab->handlers[(int) mode].insn_code 142118334Speter != CODE_FOR_nothing) 142218334Speter { 142318334Speter rtx wordm1 = GEN_INT (BITS_PER_WORD - 1); 142418334Speter product = expand_binop (mode, smul_widen_optab, op0_low, op1_low, 142518334Speter target, 1, OPTAB_DIRECT); 142618334Speter op0_xhigh = expand_binop (word_mode, lshr_optab, op0_low, wordm1, 142718334Speter NULL_RTX, 1, next_methods); 142818334Speter if (op0_xhigh) 142918334Speter op0_xhigh = expand_binop (word_mode, add_optab, op0_high, 143018334Speter op0_xhigh, op0_xhigh, 0, next_methods); 143118334Speter else 143218334Speter { 143318334Speter op0_xhigh = expand_binop (word_mode, ashr_optab, op0_low, wordm1, 143418334Speter NULL_RTX, 0, next_methods); 143518334Speter if (op0_xhigh) 143618334Speter op0_xhigh = expand_binop (word_mode, sub_optab, op0_high, 143718334Speter op0_xhigh, op0_xhigh, 0, 143818334Speter next_methods); 143918334Speter } 144018334Speter 144118334Speter op1_xhigh = expand_binop (word_mode, lshr_optab, op1_low, wordm1, 144218334Speter NULL_RTX, 1, next_methods); 144318334Speter if (op1_xhigh) 144418334Speter op1_xhigh = expand_binop (word_mode, add_optab, op1_high, 144518334Speter op1_xhigh, op1_xhigh, 0, next_methods); 144618334Speter else 144718334Speter { 144818334Speter op1_xhigh = expand_binop (word_mode, ashr_optab, op1_low, wordm1, 144918334Speter NULL_RTX, 0, next_methods); 145018334Speter if (op1_xhigh) 145118334Speter op1_xhigh = expand_binop (word_mode, sub_optab, op1_high, 145218334Speter op1_xhigh, op1_xhigh, 0, 145318334Speter next_methods); 145418334Speter } 145518334Speter } 145618334Speter 145718334Speter /* If we have been able to directly compute the product of the 145818334Speter low-order words of the operands and perform any required adjustments 145918334Speter of the operands, we proceed by trying two more multiplications 146018334Speter and then computing the appropriate sum. 146118334Speter 146218334Speter We have checked above that the required addition is provided. 146318334Speter Full-word addition will normally always succeed, especially if 146418334Speter it is provided at all, so we don't worry about its failure. The 146518334Speter multiplication may well fail, however, so we do handle that. */ 146618334Speter 146718334Speter if (product && op0_xhigh && op1_xhigh) 146818334Speter { 146918334Speter rtx product_high = operand_subword (product, high, 1, mode); 147018334Speter rtx temp = expand_binop (word_mode, binoptab, op0_low, op1_xhigh, 147118334Speter NULL_RTX, 0, OPTAB_DIRECT); 147218334Speter 1473102780Skan if (!REG_P (product_high)) 1474102780Skan product_high = force_reg (word_mode, product_high); 1475102780Skan 147618334Speter if (temp != 0) 147718334Speter temp = expand_binop (word_mode, add_optab, temp, product_high, 147818334Speter product_high, 0, next_methods); 147918334Speter 148018334Speter if (temp != 0 && temp != product_high) 148118334Speter emit_move_insn (product_high, temp); 148218334Speter 148318334Speter if (temp != 0) 148418334Speter temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh, 148518334Speter NULL_RTX, 0, OPTAB_DIRECT); 148618334Speter 148718334Speter if (temp != 0) 148818334Speter temp = expand_binop (word_mode, add_optab, temp, 148918334Speter product_high, product_high, 149018334Speter 0, next_methods); 149118334Speter 149218334Speter if (temp != 0 && temp != product_high) 149318334Speter emit_move_insn (product_high, temp); 149418334Speter 1495102780Skan emit_move_insn (operand_subword (product, high, 1, mode), product_high); 1496102780Skan 149718334Speter if (temp != 0) 149818334Speter { 149950397Sobrien if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 150050397Sobrien { 150150397Sobrien temp = emit_move_insn (product, product); 150252284Sobrien set_unique_reg_note (temp, 150352284Sobrien REG_EQUAL, 150452284Sobrien gen_rtx_fmt_ee (MULT, mode, 150552284Sobrien copy_rtx (op0), 150652284Sobrien copy_rtx (op1))); 150750397Sobrien } 150890075Sobrien 150918334Speter return product; 151018334Speter } 151118334Speter } 151218334Speter 151318334Speter /* If we get here, we couldn't do it for some reason even though we 151418334Speter originally thought we could. Delete anything we've emitted in 151518334Speter trying to do it. */ 151618334Speter 151718334Speter delete_insns_since (last); 151818334Speter } 151918334Speter 1520117395Skan /* Open-code the vector operations if we have no hardware support 1521117395Skan for them. */ 1522117395Skan if (class == MODE_VECTOR_INT || class == MODE_VECTOR_FLOAT) 1523117395Skan return expand_vector_binop (mode, binoptab, op0, op1, target, 1524117395Skan unsignedp, methods); 1525117395Skan 152618334Speter /* We need to open-code the complex type operations: '+, -, * and /' */ 152718334Speter 152818334Speter /* At this point we allow operations between two similar complex 152918334Speter numbers, and also if one of the operands is not a complex number 153018334Speter but rather of MODE_FLOAT or MODE_INT. However, the caller 153118334Speter must make sure that the MODE of the non-complex operand matches 153218334Speter the SUBMODE of the complex operand. */ 153318334Speter 153418334Speter if (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT) 153518334Speter { 153618334Speter rtx real0 = 0, imag0 = 0; 153718334Speter rtx real1 = 0, imag1 = 0; 153818334Speter rtx realr, imagr, res; 153918334Speter rtx seq; 154018334Speter rtx equiv_value; 154118334Speter int ok = 0; 154218334Speter 154318334Speter /* Find the correct mode for the real and imaginary parts */ 1544117395Skan enum machine_mode submode = GET_MODE_INNER(mode); 154518334Speter 154618334Speter if (submode == BLKmode) 154718334Speter abort (); 154818334Speter 154918334Speter if (! target) 155018334Speter target = gen_reg_rtx (mode); 155118334Speter 155218334Speter start_sequence (); 155318334Speter 155452284Sobrien realr = gen_realpart (submode, target); 155518334Speter imagr = gen_imagpart (submode, target); 155618334Speter 155718334Speter if (GET_MODE (op0) == mode) 155818334Speter { 155952284Sobrien real0 = gen_realpart (submode, op0); 156018334Speter imag0 = gen_imagpart (submode, op0); 156118334Speter } 156218334Speter else 156318334Speter real0 = op0; 156418334Speter 156518334Speter if (GET_MODE (op1) == mode) 156618334Speter { 156752284Sobrien real1 = gen_realpart (submode, op1); 156818334Speter imag1 = gen_imagpart (submode, op1); 156918334Speter } 157018334Speter else 157118334Speter real1 = op1; 157218334Speter 1573117395Skan if (real0 == 0 || real1 == 0 || ! (imag0 != 0 || imag1 != 0)) 157418334Speter abort (); 157518334Speter 157618334Speter switch (binoptab->code) 157718334Speter { 157818334Speter case PLUS: 157918334Speter /* (a+ib) + (c+id) = (a+c) + i(b+d) */ 158018334Speter case MINUS: 158118334Speter /* (a+ib) - (c+id) = (a-c) + i(b-d) */ 158218334Speter res = expand_binop (submode, binoptab, real0, real1, 158318334Speter realr, unsignedp, methods); 158418334Speter 158518334Speter if (res == 0) 158618334Speter break; 158718334Speter else if (res != realr) 158818334Speter emit_move_insn (realr, res); 158918334Speter 1590117395Skan if (imag0 != 0 && imag1 != 0) 159118334Speter res = expand_binop (submode, binoptab, imag0, imag1, 159218334Speter imagr, unsignedp, methods); 1593117395Skan else if (imag0 != 0) 159418334Speter res = imag0; 159518334Speter else if (binoptab->code == MINUS) 159690075Sobrien res = expand_unop (submode, 159790075Sobrien binoptab == subv_optab ? negv_optab : neg_optab, 159890075Sobrien imag1, imagr, unsignedp); 159918334Speter else 160018334Speter res = imag1; 160118334Speter 160218334Speter if (res == 0) 160318334Speter break; 160418334Speter else if (res != imagr) 160518334Speter emit_move_insn (imagr, res); 160618334Speter 160718334Speter ok = 1; 160818334Speter break; 160918334Speter 161018334Speter case MULT: 161118334Speter /* (a+ib) * (c+id) = (ac-bd) + i(ad+cb) */ 161218334Speter 1613117395Skan if (imag0 != 0 && imag1 != 0) 161418334Speter { 161518334Speter rtx temp1, temp2; 161618334Speter 161718334Speter /* Don't fetch these from memory more than once. */ 161818334Speter real0 = force_reg (submode, real0); 161918334Speter real1 = force_reg (submode, real1); 162018334Speter imag0 = force_reg (submode, imag0); 162118334Speter imag1 = force_reg (submode, imag1); 162218334Speter 162318334Speter temp1 = expand_binop (submode, binoptab, real0, real1, NULL_RTX, 162418334Speter unsignedp, methods); 162518334Speter 162618334Speter temp2 = expand_binop (submode, binoptab, imag0, imag1, NULL_RTX, 162718334Speter unsignedp, methods); 162818334Speter 162918334Speter if (temp1 == 0 || temp2 == 0) 163018334Speter break; 163118334Speter 163290075Sobrien res = (expand_binop 163390075Sobrien (submode, 163490075Sobrien binoptab == smulv_optab ? subv_optab : sub_optab, 163590075Sobrien temp1, temp2, realr, unsignedp, methods)); 163618334Speter 163718334Speter if (res == 0) 163818334Speter break; 163918334Speter else if (res != realr) 164018334Speter emit_move_insn (realr, res); 164118334Speter 164218334Speter temp1 = expand_binop (submode, binoptab, real0, imag1, 164318334Speter NULL_RTX, unsignedp, methods); 164418334Speter 164518334Speter temp2 = expand_binop (submode, binoptab, real1, imag0, 164618334Speter NULL_RTX, unsignedp, methods); 164718334Speter 164818334Speter if (temp1 == 0 || temp2 == 0) 1649117395Skan break; 165018334Speter 165190075Sobrien res = (expand_binop 165290075Sobrien (submode, 165390075Sobrien binoptab == smulv_optab ? addv_optab : add_optab, 165490075Sobrien temp1, temp2, imagr, unsignedp, methods)); 165518334Speter 165618334Speter if (res == 0) 165718334Speter break; 165818334Speter else if (res != imagr) 165918334Speter emit_move_insn (imagr, res); 166018334Speter 166118334Speter ok = 1; 166218334Speter } 166318334Speter else 166418334Speter { 166518334Speter /* Don't fetch these from memory more than once. */ 166618334Speter real0 = force_reg (submode, real0); 166718334Speter real1 = force_reg (submode, real1); 166818334Speter 166918334Speter res = expand_binop (submode, binoptab, real0, real1, 167018334Speter realr, unsignedp, methods); 167118334Speter if (res == 0) 167218334Speter break; 167318334Speter else if (res != realr) 167418334Speter emit_move_insn (realr, res); 167518334Speter 167618334Speter if (imag0 != 0) 167718334Speter res = expand_binop (submode, binoptab, 167818334Speter real1, imag0, imagr, unsignedp, methods); 167918334Speter else 168018334Speter res = expand_binop (submode, binoptab, 168118334Speter real0, imag1, imagr, unsignedp, methods); 168218334Speter 168318334Speter if (res == 0) 168418334Speter break; 168518334Speter else if (res != imagr) 168618334Speter emit_move_insn (imagr, res); 168718334Speter 168818334Speter ok = 1; 168918334Speter } 169018334Speter break; 169118334Speter 169218334Speter case DIV: 169318334Speter /* (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) */ 169418334Speter 169518334Speter if (imag1 == 0) 169618334Speter { 169718334Speter /* (a+ib) / (c+i0) = (a/c) + i(b/c) */ 169818334Speter 169918334Speter /* Don't fetch these from memory more than once. */ 170018334Speter real1 = force_reg (submode, real1); 170118334Speter 170218334Speter /* Simply divide the real and imaginary parts by `c' */ 170318334Speter if (class == MODE_COMPLEX_FLOAT) 170418334Speter res = expand_binop (submode, binoptab, real0, real1, 170518334Speter realr, unsignedp, methods); 170618334Speter else 170718334Speter res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 170818334Speter real0, real1, realr, unsignedp); 170918334Speter 171018334Speter if (res == 0) 171118334Speter break; 171218334Speter else if (res != realr) 171318334Speter emit_move_insn (realr, res); 171418334Speter 171518334Speter if (class == MODE_COMPLEX_FLOAT) 171618334Speter res = expand_binop (submode, binoptab, imag0, real1, 171718334Speter imagr, unsignedp, methods); 171818334Speter else 171918334Speter res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 172018334Speter imag0, real1, imagr, unsignedp); 172118334Speter 172218334Speter if (res == 0) 172318334Speter break; 172418334Speter else if (res != imagr) 172518334Speter emit_move_insn (imagr, res); 172618334Speter 172718334Speter ok = 1; 172818334Speter } 172918334Speter else 173018334Speter { 173152284Sobrien switch (flag_complex_divide_method) 173218334Speter { 173352284Sobrien case 0: 173452284Sobrien ok = expand_cmplxdiv_straight (real0, real1, imag0, imag1, 173552284Sobrien realr, imagr, submode, 173652284Sobrien unsignedp, methods, 173752284Sobrien class, binoptab); 173852284Sobrien break; 173918334Speter 174052284Sobrien case 1: 174152284Sobrien ok = expand_cmplxdiv_wide (real0, real1, imag0, imag1, 174252284Sobrien realr, imagr, submode, 174352284Sobrien unsignedp, methods, 174452284Sobrien class, binoptab); 174552284Sobrien break; 174618334Speter 174752284Sobrien default: 174852284Sobrien abort (); 174918334Speter } 175018334Speter } 175118334Speter break; 175218334Speter 175318334Speter default: 175418334Speter abort (); 175518334Speter } 175618334Speter 175718334Speter seq = get_insns (); 175818334Speter end_sequence (); 175918334Speter 176018334Speter if (ok) 176118334Speter { 176218334Speter if (binoptab->code != UNKNOWN) 176318334Speter equiv_value 176450397Sobrien = gen_rtx_fmt_ee (binoptab->code, mode, 176550397Sobrien copy_rtx (op0), copy_rtx (op1)); 176618334Speter else 176718334Speter equiv_value = 0; 176818334Speter 176918334Speter emit_no_conflict_block (seq, target, op0, op1, equiv_value); 177018334Speter 177118334Speter return target; 177218334Speter } 177318334Speter } 177418334Speter 177518334Speter /* It can't be open-coded in this mode. 177618334Speter Use a library call if one is available and caller says that's ok. */ 177718334Speter 177818334Speter if (binoptab->handlers[(int) mode].libfunc 177918334Speter && (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN)) 178018334Speter { 178118334Speter rtx insns; 178218334Speter rtx op1x = op1; 178318334Speter enum machine_mode op1_mode = mode; 178418334Speter rtx value; 178518334Speter 178618334Speter start_sequence (); 178718334Speter 178818334Speter if (shift_op) 178918334Speter { 179018334Speter op1_mode = word_mode; 179118334Speter /* Specify unsigned here, 179218334Speter since negative shift counts are meaningless. */ 179318334Speter op1x = convert_to_mode (word_mode, op1, 1); 179418334Speter } 179518334Speter 179618334Speter if (GET_MODE (op0) != VOIDmode 179718334Speter && GET_MODE (op0) != mode) 179818334Speter op0 = convert_to_mode (mode, op0, unsignedp); 179918334Speter 180018334Speter /* Pass 1 for NO_QUEUE so we don't lose any increments 180118334Speter if the libcall is cse'd or moved. */ 180218334Speter value = emit_library_call_value (binoptab->handlers[(int) mode].libfunc, 180390075Sobrien NULL_RTX, LCT_CONST, mode, 2, 180418334Speter op0, mode, op1x, op1_mode); 180518334Speter 180618334Speter insns = get_insns (); 180718334Speter end_sequence (); 180818334Speter 180918334Speter target = gen_reg_rtx (mode); 181018334Speter emit_libcall_block (insns, target, value, 181150397Sobrien gen_rtx_fmt_ee (binoptab->code, mode, op0, op1)); 181218334Speter 181318334Speter return target; 181418334Speter } 181518334Speter 181618334Speter delete_insns_since (last); 181718334Speter 181818334Speter /* It can't be done in this mode. Can we do it in a wider mode? */ 181918334Speter 182018334Speter if (! (methods == OPTAB_WIDEN || methods == OPTAB_LIB_WIDEN 182118334Speter || methods == OPTAB_MUST_WIDEN)) 182218334Speter { 182318334Speter /* Caller says, don't even try. */ 182418334Speter delete_insns_since (entry_last); 182518334Speter return 0; 182618334Speter } 182718334Speter 182818334Speter /* Compute the value of METHODS to pass to recursive calls. 182918334Speter Don't allow widening to be tried recursively. */ 183018334Speter 183118334Speter methods = (methods == OPTAB_LIB_WIDEN ? OPTAB_LIB : OPTAB_DIRECT); 183218334Speter 183318334Speter /* Look for a wider mode of the same class for which it appears we can do 183418334Speter the operation. */ 183518334Speter 183618334Speter if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) 183718334Speter { 183818334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 183918334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 184018334Speter { 184118334Speter if ((binoptab->handlers[(int) wider_mode].insn_code 184218334Speter != CODE_FOR_nothing) 184318334Speter || (methods == OPTAB_LIB 184418334Speter && binoptab->handlers[(int) wider_mode].libfunc)) 184518334Speter { 184618334Speter rtx xop0 = op0, xop1 = op1; 184718334Speter int no_extend = 0; 184818334Speter 184918334Speter /* For certain integer operations, we need not actually extend 185018334Speter the narrow operands, as long as we will truncate 185118334Speter the results to the same narrowness. */ 185218334Speter 185318334Speter if ((binoptab == ior_optab || binoptab == and_optab 185418334Speter || binoptab == xor_optab 185518334Speter || binoptab == add_optab || binoptab == sub_optab 185618334Speter || binoptab == smul_optab || binoptab == ashl_optab) 185718334Speter && class == MODE_INT) 185818334Speter no_extend = 1; 185918334Speter 186018334Speter xop0 = widen_operand (xop0, wider_mode, mode, 186118334Speter unsignedp, no_extend); 186218334Speter 186318334Speter /* The second operand of a shift must always be extended. */ 186418334Speter xop1 = widen_operand (xop1, wider_mode, mode, unsignedp, 186518334Speter no_extend && binoptab != ashl_optab); 186618334Speter 186718334Speter temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX, 186818334Speter unsignedp, methods); 186918334Speter if (temp) 187018334Speter { 187118334Speter if (class != MODE_INT) 187218334Speter { 187318334Speter if (target == 0) 187418334Speter target = gen_reg_rtx (mode); 187518334Speter convert_move (target, temp, 0); 187618334Speter return target; 187718334Speter } 187818334Speter else 187918334Speter return gen_lowpart (mode, temp); 188018334Speter } 188118334Speter else 188218334Speter delete_insns_since (last); 188318334Speter } 188418334Speter } 188518334Speter } 188618334Speter 188718334Speter delete_insns_since (entry_last); 188818334Speter return 0; 188918334Speter} 1890117395Skan 1891117395Skan/* Like expand_binop, but for open-coding vectors binops. */ 1892117395Skan 1893117395Skanstatic rtx 1894117395Skanexpand_vector_binop (mode, binoptab, op0, op1, target, unsignedp, methods) 1895117395Skan enum machine_mode mode; 1896117395Skan optab binoptab; 1897117395Skan rtx op0, op1; 1898117395Skan rtx target; 1899117395Skan int unsignedp; 1900117395Skan enum optab_methods methods; 1901117395Skan{ 1902117395Skan enum machine_mode submode, tmode; 1903117395Skan int size, elts, subsize, subbitsize, i; 1904117395Skan rtx t, a, b, res, seq; 1905117395Skan enum mode_class class; 1906117395Skan 1907117395Skan class = GET_MODE_CLASS (mode); 1908117395Skan 1909117395Skan size = GET_MODE_SIZE (mode); 1910117395Skan submode = GET_MODE_INNER (mode); 1911117395Skan 1912117395Skan /* Search for the widest vector mode with the same inner mode that is 1913117395Skan still narrower than MODE and that allows to open-code this operator. 1914117395Skan Note, if we find such a mode and the handler later decides it can't 1915117395Skan do the expansion, we'll be called recursively with the narrower mode. */ 1916117395Skan for (tmode = GET_CLASS_NARROWEST_MODE (class); 1917117395Skan GET_MODE_SIZE (tmode) < GET_MODE_SIZE (mode); 1918117395Skan tmode = GET_MODE_WIDER_MODE (tmode)) 1919117395Skan { 1920117395Skan if (GET_MODE_INNER (tmode) == GET_MODE_INNER (mode) 1921117395Skan && binoptab->handlers[(int) tmode].insn_code != CODE_FOR_nothing) 1922117395Skan submode = tmode; 1923117395Skan } 1924117395Skan 1925117395Skan switch (binoptab->code) 1926117395Skan { 1927117395Skan case AND: 1928117395Skan case IOR: 1929117395Skan case XOR: 1930117395Skan tmode = int_mode_for_mode (mode); 1931117395Skan if (tmode != BLKmode) 1932117395Skan submode = tmode; 1933117395Skan case PLUS: 1934117395Skan case MINUS: 1935117395Skan case MULT: 1936117395Skan case DIV: 1937117395Skan subsize = GET_MODE_SIZE (submode); 1938117395Skan subbitsize = GET_MODE_BITSIZE (submode); 1939117395Skan elts = size / subsize; 1940117395Skan 1941117395Skan /* If METHODS is OPTAB_DIRECT, we don't insist on the exact mode, 1942117395Skan but that we operate on more than one element at a time. */ 1943117395Skan if (subsize == GET_MODE_UNIT_SIZE (mode) && methods == OPTAB_DIRECT) 1944117395Skan return 0; 1945117395Skan 1946117395Skan start_sequence (); 1947117395Skan 1948117395Skan /* Errors can leave us with a const0_rtx as operand. */ 1949117395Skan if (GET_MODE (op0) != mode) 1950117395Skan op0 = copy_to_mode_reg (mode, op0); 1951117395Skan if (GET_MODE (op1) != mode) 1952117395Skan op1 = copy_to_mode_reg (mode, op1); 1953117395Skan 1954117395Skan if (!target) 1955117395Skan target = gen_reg_rtx (mode); 1956117395Skan 1957117395Skan for (i = 0; i < elts; ++i) 1958117395Skan { 1959117395Skan /* If this is part of a register, and not the first item in the 1960117395Skan word, we can't store using a SUBREG - that would clobber 1961117395Skan previous results. 1962117395Skan And storing with a SUBREG is only possible for the least 1963117395Skan significant part, hence we can't do it for big endian 1964117395Skan (unless we want to permute the evaluation order. */ 1965117395Skan if (GET_CODE (target) == REG 1966117395Skan && (BYTES_BIG_ENDIAN 1967117395Skan ? subsize < UNITS_PER_WORD 1968117395Skan : ((i * subsize) % UNITS_PER_WORD) != 0)) 1969117395Skan t = NULL_RTX; 1970117395Skan else 1971117395Skan t = simplify_gen_subreg (submode, target, mode, i * subsize); 1972117395Skan if (CONSTANT_P (op0)) 1973117395Skan a = simplify_gen_subreg (submode, op0, mode, i * subsize); 1974117395Skan else 1975117395Skan a = extract_bit_field (op0, subbitsize, i * subbitsize, unsignedp, 1976117395Skan NULL_RTX, submode, submode, size); 1977117395Skan if (CONSTANT_P (op1)) 1978117395Skan b = simplify_gen_subreg (submode, op1, mode, i * subsize); 1979117395Skan else 1980117395Skan b = extract_bit_field (op1, subbitsize, i * subbitsize, unsignedp, 1981117395Skan NULL_RTX, submode, submode, size); 1982117395Skan 1983117395Skan if (binoptab->code == DIV) 1984117395Skan { 1985117395Skan if (class == MODE_VECTOR_FLOAT) 1986117395Skan res = expand_binop (submode, binoptab, a, b, t, 1987117395Skan unsignedp, methods); 1988117395Skan else 1989117395Skan res = expand_divmod (0, TRUNC_DIV_EXPR, submode, 1990117395Skan a, b, t, unsignedp); 1991117395Skan } 1992117395Skan else 1993117395Skan res = expand_binop (submode, binoptab, a, b, t, 1994117395Skan unsignedp, methods); 1995117395Skan 1996117395Skan if (res == 0) 1997117395Skan break; 1998117395Skan 1999117395Skan if (t) 2000117395Skan emit_move_insn (t, res); 2001117395Skan else 2002117395Skan store_bit_field (target, subbitsize, i * subbitsize, submode, res, 2003117395Skan size); 2004117395Skan } 2005117395Skan break; 2006117395Skan 2007117395Skan default: 2008117395Skan abort (); 2009117395Skan } 2010117395Skan 2011117395Skan seq = get_insns (); 2012117395Skan end_sequence (); 2013117395Skan emit_insn (seq); 2014117395Skan 2015117395Skan return target; 2016117395Skan} 2017117395Skan 2018117395Skan/* Like expand_unop but for open-coding vector unops. */ 2019117395Skan 2020117395Skanstatic rtx 2021117395Skanexpand_vector_unop (mode, unoptab, op0, target, unsignedp) 2022117395Skan enum machine_mode mode; 2023117395Skan optab unoptab; 2024117395Skan rtx op0; 2025117395Skan rtx target; 2026117395Skan int unsignedp; 2027117395Skan{ 2028117395Skan enum machine_mode submode, tmode; 2029117395Skan int size, elts, subsize, subbitsize, i; 2030117395Skan rtx t, a, res, seq; 2031117395Skan 2032117395Skan size = GET_MODE_SIZE (mode); 2033117395Skan submode = GET_MODE_INNER (mode); 2034117395Skan 2035117395Skan /* Search for the widest vector mode with the same inner mode that is 2036117395Skan still narrower than MODE and that allows to open-code this operator. 2037117395Skan Note, if we find such a mode and the handler later decides it can't 2038117395Skan do the expansion, we'll be called recursively with the narrower mode. */ 2039117395Skan for (tmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (mode)); 2040117395Skan GET_MODE_SIZE (tmode) < GET_MODE_SIZE (mode); 2041117395Skan tmode = GET_MODE_WIDER_MODE (tmode)) 2042117395Skan { 2043117395Skan if (GET_MODE_INNER (tmode) == GET_MODE_INNER (mode) 2044117395Skan && unoptab->handlers[(int) tmode].insn_code != CODE_FOR_nothing) 2045117395Skan submode = tmode; 2046117395Skan } 2047117395Skan /* If there is no negate operation, try doing a subtract from zero. */ 2048117395Skan if (unoptab == neg_optab && GET_MODE_CLASS (submode) == MODE_INT 2049117395Skan /* Avoid infinite recursion when an 2050117395Skan error has left us with the wrong mode. */ 2051117395Skan && GET_MODE (op0) == mode) 2052117395Skan { 2053117395Skan rtx temp; 2054117395Skan temp = expand_binop (mode, sub_optab, CONST0_RTX (mode), op0, 2055117395Skan target, unsignedp, OPTAB_DIRECT); 2056117395Skan if (temp) 2057117395Skan return temp; 2058117395Skan } 2059117395Skan 2060117395Skan if (unoptab == one_cmpl_optab) 2061117395Skan { 2062117395Skan tmode = int_mode_for_mode (mode); 2063117395Skan if (tmode != BLKmode) 2064117395Skan submode = tmode; 2065117395Skan } 2066117395Skan 2067117395Skan subsize = GET_MODE_SIZE (submode); 2068117395Skan subbitsize = GET_MODE_BITSIZE (submode); 2069117395Skan elts = size / subsize; 2070117395Skan 2071117395Skan /* Errors can leave us with a const0_rtx as operand. */ 2072117395Skan if (GET_MODE (op0) != mode) 2073117395Skan op0 = copy_to_mode_reg (mode, op0); 2074117395Skan 2075117395Skan if (!target) 2076117395Skan target = gen_reg_rtx (mode); 2077117395Skan 2078117395Skan start_sequence (); 2079117395Skan 2080117395Skan for (i = 0; i < elts; ++i) 2081117395Skan { 2082117395Skan /* If this is part of a register, and not the first item in the 2083117395Skan word, we can't store using a SUBREG - that would clobber 2084117395Skan previous results. 2085117395Skan And storing with a SUBREG is only possible for the least 2086117395Skan significant part, hence we can't do it for big endian 2087117395Skan (unless we want to permute the evaluation order. */ 2088117395Skan if (GET_CODE (target) == REG 2089117395Skan && (BYTES_BIG_ENDIAN 2090117395Skan ? subsize < UNITS_PER_WORD 2091117395Skan : ((i * subsize) % UNITS_PER_WORD) != 0)) 2092117395Skan t = NULL_RTX; 2093117395Skan else 2094117395Skan t = simplify_gen_subreg (submode, target, mode, i * subsize); 2095117395Skan if (CONSTANT_P (op0)) 2096117395Skan a = simplify_gen_subreg (submode, op0, mode, i * subsize); 2097117395Skan else 2098117395Skan a = extract_bit_field (op0, subbitsize, i * subbitsize, unsignedp, 2099117395Skan t, submode, submode, size); 2100117395Skan 2101117395Skan res = expand_unop (submode, unoptab, a, t, unsignedp); 2102117395Skan 2103117395Skan if (t) 2104117395Skan emit_move_insn (t, res); 2105117395Skan else 2106117395Skan store_bit_field (target, subbitsize, i * subbitsize, submode, res, 2107117395Skan size); 2108117395Skan } 2109117395Skan 2110117395Skan seq = get_insns (); 2111117395Skan end_sequence (); 2112117395Skan emit_insn (seq); 2113117395Skan 2114117395Skan return target; 2115117395Skan} 211618334Speter 211718334Speter/* Expand a binary operator which has both signed and unsigned forms. 211818334Speter UOPTAB is the optab for unsigned operations, and SOPTAB is for 211918334Speter signed operations. 212018334Speter 212118334Speter If we widen unsigned operands, we may use a signed wider operation instead 212218334Speter of an unsigned wider operation, since the result would be the same. */ 212318334Speter 212418334Speterrtx 212518334Spetersign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods) 2126117395Skan enum machine_mode mode; 2127117395Skan optab uoptab, soptab; 2128117395Skan rtx op0, op1, target; 2129117395Skan int unsignedp; 2130117395Skan enum optab_methods methods; 213118334Speter{ 213290075Sobrien rtx temp; 213318334Speter optab direct_optab = unsignedp ? uoptab : soptab; 213418334Speter struct optab wide_soptab; 213518334Speter 213618334Speter /* Do it without widening, if possible. */ 213718334Speter temp = expand_binop (mode, direct_optab, op0, op1, target, 213818334Speter unsignedp, OPTAB_DIRECT); 213918334Speter if (temp || methods == OPTAB_DIRECT) 214018334Speter return temp; 214118334Speter 214218334Speter /* Try widening to a signed int. Make a fake signed optab that 214318334Speter hides any signed insn for direct use. */ 214418334Speter wide_soptab = *soptab; 214518334Speter wide_soptab.handlers[(int) mode].insn_code = CODE_FOR_nothing; 214618334Speter wide_soptab.handlers[(int) mode].libfunc = 0; 214718334Speter 214818334Speter temp = expand_binop (mode, &wide_soptab, op0, op1, target, 214918334Speter unsignedp, OPTAB_WIDEN); 215018334Speter 215118334Speter /* For unsigned operands, try widening to an unsigned int. */ 215218334Speter if (temp == 0 && unsignedp) 215318334Speter temp = expand_binop (mode, uoptab, op0, op1, target, 215418334Speter unsignedp, OPTAB_WIDEN); 215518334Speter if (temp || methods == OPTAB_WIDEN) 215618334Speter return temp; 215718334Speter 215818334Speter /* Use the right width lib call if that exists. */ 215918334Speter temp = expand_binop (mode, direct_optab, op0, op1, target, unsignedp, OPTAB_LIB); 216018334Speter if (temp || methods == OPTAB_LIB) 216118334Speter return temp; 216218334Speter 216318334Speter /* Must widen and use a lib call, use either signed or unsigned. */ 216418334Speter temp = expand_binop (mode, &wide_soptab, op0, op1, target, 216518334Speter unsignedp, methods); 216618334Speter if (temp != 0) 216718334Speter return temp; 216818334Speter if (unsignedp) 216918334Speter return expand_binop (mode, uoptab, op0, op1, target, 217018334Speter unsignedp, methods); 217118334Speter return 0; 217218334Speter} 217318334Speter 217418334Speter/* Generate code to perform an operation specified by BINOPTAB 217518334Speter on operands OP0 and OP1, with two results to TARG1 and TARG2. 217618334Speter We assume that the order of the operands for the instruction 217718334Speter is TARG0, OP0, OP1, TARG1, which would fit a pattern like 217818334Speter [(set TARG0 (operate OP0 OP1)) (set TARG1 (operate ...))]. 217918334Speter 218018334Speter Either TARG0 or TARG1 may be zero, but what that means is that 218150397Sobrien the result is not actually wanted. We will generate it into 218218334Speter a dummy pseudo-reg and discard it. They may not both be zero. 218318334Speter 218418334Speter Returns 1 if this operation can be performed; 0 if not. */ 218518334Speter 218618334Speterint 218718334Speterexpand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp) 218818334Speter optab binoptab; 218918334Speter rtx op0, op1; 219018334Speter rtx targ0, targ1; 219118334Speter int unsignedp; 219218334Speter{ 219318334Speter enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1); 219418334Speter enum mode_class class; 219518334Speter enum machine_mode wider_mode; 219618334Speter rtx entry_last = get_last_insn (); 219718334Speter rtx last; 219818334Speter 219918334Speter class = GET_MODE_CLASS (mode); 220018334Speter 220118334Speter op0 = protect_from_queue (op0, 0); 220218334Speter op1 = protect_from_queue (op1, 0); 220318334Speter 220418334Speter if (flag_force_mem) 220518334Speter { 220618334Speter op0 = force_not_mem (op0); 220718334Speter op1 = force_not_mem (op1); 220818334Speter } 220918334Speter 221018334Speter /* If we are inside an appropriately-short loop and one operand is an 221118334Speter expensive constant, force it into a register. */ 221218334Speter if (CONSTANT_P (op0) && preserve_subexpressions_p () 221390075Sobrien && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1)) 221418334Speter op0 = force_reg (mode, op0); 221518334Speter 221618334Speter if (CONSTANT_P (op1) && preserve_subexpressions_p () 221790075Sobrien && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1)) 221818334Speter op1 = force_reg (mode, op1); 221918334Speter 222018334Speter if (targ0) 222118334Speter targ0 = protect_from_queue (targ0, 1); 222218334Speter else 222318334Speter targ0 = gen_reg_rtx (mode); 222418334Speter if (targ1) 222518334Speter targ1 = protect_from_queue (targ1, 1); 222618334Speter else 222718334Speter targ1 = gen_reg_rtx (mode); 222818334Speter 222918334Speter /* Record where to go back to if we fail. */ 223018334Speter last = get_last_insn (); 223118334Speter 223218334Speter if (binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 223318334Speter { 223418334Speter int icode = (int) binoptab->handlers[(int) mode].insn_code; 223590075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 223690075Sobrien enum machine_mode mode1 = insn_data[icode].operand[2].mode; 223718334Speter rtx pat; 223818334Speter rtx xop0 = op0, xop1 = op1; 223918334Speter 2240117395Skan /* In case the insn wants input operands in modes different from 2241117395Skan those of the actual operands, convert the operands. It would 2242117395Skan seem that we don't need to convert CONST_INTs, but we do, so 2243117395Skan that they're properly zero-extended, sign-extended or truncated 2244117395Skan for their mode. */ 224518334Speter 2246117395Skan if (GET_MODE (op0) != mode0 && mode0 != VOIDmode) 2247117395Skan xop0 = convert_modes (mode0, 2248117395Skan GET_MODE (op0) != VOIDmode 2249117395Skan ? GET_MODE (op0) 2250117395Skan : mode, 2251117395Skan xop0, unsignedp); 225218334Speter 2253117395Skan if (GET_MODE (op1) != mode1 && mode1 != VOIDmode) 2254117395Skan xop1 = convert_modes (mode1, 2255117395Skan GET_MODE (op1) != VOIDmode 2256117395Skan ? GET_MODE (op1) 2257117395Skan : mode, 2258117395Skan xop1, unsignedp); 2259117395Skan 226018334Speter /* Now, if insn doesn't accept these operands, put them into pseudos. */ 226190075Sobrien if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)) 226218334Speter xop0 = copy_to_mode_reg (mode0, xop0); 226318334Speter 226490075Sobrien if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1)) 226518334Speter xop1 = copy_to_mode_reg (mode1, xop1); 226618334Speter 226718334Speter /* We could handle this, but we should always be called with a pseudo 226818334Speter for our targets and all insns should take them as outputs. */ 226990075Sobrien if (! (*insn_data[icode].operand[0].predicate) (targ0, mode) 227090075Sobrien || ! (*insn_data[icode].operand[3].predicate) (targ1, mode)) 227118334Speter abort (); 227218334Speter 227318334Speter pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1); 227418334Speter if (pat) 227518334Speter { 227618334Speter emit_insn (pat); 227718334Speter return 1; 227818334Speter } 227918334Speter else 228018334Speter delete_insns_since (last); 228118334Speter } 228218334Speter 228318334Speter /* It can't be done in this mode. Can we do it in a wider mode? */ 228418334Speter 228518334Speter if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) 228618334Speter { 228718334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 228818334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 228918334Speter { 229018334Speter if (binoptab->handlers[(int) wider_mode].insn_code 229118334Speter != CODE_FOR_nothing) 229218334Speter { 229390075Sobrien rtx t0 = gen_reg_rtx (wider_mode); 229490075Sobrien rtx t1 = gen_reg_rtx (wider_mode); 229590075Sobrien rtx cop0 = convert_modes (wider_mode, mode, op0, unsignedp); 229690075Sobrien rtx cop1 = convert_modes (wider_mode, mode, op1, unsignedp); 229718334Speter 229890075Sobrien if (expand_twoval_binop (binoptab, cop0, cop1, 229918334Speter t0, t1, unsignedp)) 230018334Speter { 230118334Speter convert_move (targ0, t0, unsignedp); 230218334Speter convert_move (targ1, t1, unsignedp); 230318334Speter return 1; 230418334Speter } 230518334Speter else 230618334Speter delete_insns_since (last); 230718334Speter } 230818334Speter } 230918334Speter } 231018334Speter 231118334Speter delete_insns_since (entry_last); 231218334Speter return 0; 231318334Speter} 231418334Speter 231590075Sobrien/* Wrapper around expand_unop which takes an rtx code to specify 231690075Sobrien the operation to perform, not an optab pointer. All other 231790075Sobrien arguments are the same. */ 231890075Sobrienrtx 231990075Sobrienexpand_simple_unop (mode, code, op0, target, unsignedp) 232090075Sobrien enum machine_mode mode; 232190075Sobrien enum rtx_code code; 232290075Sobrien rtx op0; 232390075Sobrien rtx target; 232490075Sobrien int unsignedp; 232590075Sobrien{ 2326117395Skan optab unop = code_to_optab[(int) code]; 232790075Sobrien if (unop == 0) 232890075Sobrien abort (); 232990075Sobrien 233090075Sobrien return expand_unop (mode, unop, op0, target, unsignedp); 233190075Sobrien} 233290075Sobrien 233318334Speter/* Generate code to perform an operation specified by UNOPTAB 233418334Speter on operand OP0, with result having machine-mode MODE. 233518334Speter 233618334Speter UNSIGNEDP is for the case where we have to widen the operands 233718334Speter to perform the operation. It says to use zero-extension. 233818334Speter 233918334Speter If TARGET is nonzero, the value 234018334Speter is generated there, if it is convenient to do so. 234118334Speter In all cases an rtx is returned for the locus of the value; 234218334Speter this may or may not be TARGET. */ 234318334Speter 234418334Speterrtx 234518334Speterexpand_unop (mode, unoptab, op0, target, unsignedp) 234618334Speter enum machine_mode mode; 234718334Speter optab unoptab; 234818334Speter rtx op0; 234918334Speter rtx target; 235018334Speter int unsignedp; 235118334Speter{ 235218334Speter enum mode_class class; 235318334Speter enum machine_mode wider_mode; 235490075Sobrien rtx temp; 235518334Speter rtx last = get_last_insn (); 235618334Speter rtx pat; 235718334Speter 235818334Speter class = GET_MODE_CLASS (mode); 235918334Speter 236018334Speter op0 = protect_from_queue (op0, 0); 236118334Speter 236218334Speter if (flag_force_mem) 236318334Speter { 236418334Speter op0 = force_not_mem (op0); 236518334Speter } 236618334Speter 236718334Speter if (target) 236818334Speter target = protect_from_queue (target, 1); 236918334Speter 237018334Speter if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 237118334Speter { 237218334Speter int icode = (int) unoptab->handlers[(int) mode].insn_code; 237390075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 237418334Speter rtx xop0 = op0; 237518334Speter 237618334Speter if (target) 237718334Speter temp = target; 237818334Speter else 237918334Speter temp = gen_reg_rtx (mode); 238018334Speter 238118334Speter if (GET_MODE (xop0) != VOIDmode 238218334Speter && GET_MODE (xop0) != mode0) 238318334Speter xop0 = convert_to_mode (mode0, xop0, unsignedp); 238418334Speter 238518334Speter /* Now, if insn doesn't accept our operand, put it into a pseudo. */ 238618334Speter 238790075Sobrien if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)) 238818334Speter xop0 = copy_to_mode_reg (mode0, xop0); 238918334Speter 239090075Sobrien if (! (*insn_data[icode].operand[0].predicate) (temp, mode)) 239118334Speter temp = gen_reg_rtx (mode); 239218334Speter 239318334Speter pat = GEN_FCN (icode) (temp, xop0); 239418334Speter if (pat) 239518334Speter { 2396117395Skan if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX 239718334Speter && ! add_equal_note (pat, temp, unoptab->code, xop0, NULL_RTX)) 239818334Speter { 239918334Speter delete_insns_since (last); 240018334Speter return expand_unop (mode, unoptab, op0, NULL_RTX, unsignedp); 240118334Speter } 240218334Speter 240318334Speter emit_insn (pat); 240418334Speter 240518334Speter return temp; 240618334Speter } 240718334Speter else 240818334Speter delete_insns_since (last); 240918334Speter } 241018334Speter 241118334Speter /* It can't be done in this mode. Can we open-code it in a wider mode? */ 241218334Speter 241318334Speter if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) 241418334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 241518334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 241618334Speter { 241718334Speter if (unoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing) 241818334Speter { 241918334Speter rtx xop0 = op0; 242018334Speter 242118334Speter /* For certain operations, we need not actually extend 242218334Speter the narrow operand, as long as we will truncate the 242318334Speter results to the same narrowness. */ 242418334Speter 242518334Speter xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, 242618334Speter (unoptab == neg_optab 242718334Speter || unoptab == one_cmpl_optab) 242818334Speter && class == MODE_INT); 242918334Speter 243018334Speter temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX, 243118334Speter unsignedp); 243218334Speter 243318334Speter if (temp) 243418334Speter { 243518334Speter if (class != MODE_INT) 243618334Speter { 243718334Speter if (target == 0) 243818334Speter target = gen_reg_rtx (mode); 243918334Speter convert_move (target, temp, 0); 244018334Speter return target; 244118334Speter } 244218334Speter else 244318334Speter return gen_lowpart (mode, temp); 244418334Speter } 244518334Speter else 244618334Speter delete_insns_since (last); 244718334Speter } 244818334Speter } 244918334Speter 245018334Speter /* These can be done a word at a time. */ 245118334Speter if (unoptab == one_cmpl_optab 245218334Speter && class == MODE_INT 245318334Speter && GET_MODE_SIZE (mode) > UNITS_PER_WORD 245418334Speter && unoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 245518334Speter { 245618334Speter int i; 245718334Speter rtx insns; 245818334Speter 245918334Speter if (target == 0 || target == op0) 246018334Speter target = gen_reg_rtx (mode); 246118334Speter 246218334Speter start_sequence (); 246318334Speter 246418334Speter /* Do the actual arithmetic. */ 246518334Speter for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++) 246618334Speter { 246718334Speter rtx target_piece = operand_subword (target, i, 1, mode); 246818334Speter rtx x = expand_unop (word_mode, unoptab, 246918334Speter operand_subword_force (op0, i, mode), 247018334Speter target_piece, unsignedp); 247190075Sobrien 247218334Speter if (target_piece != x) 247318334Speter emit_move_insn (target_piece, x); 247418334Speter } 247518334Speter 247618334Speter insns = get_insns (); 247718334Speter end_sequence (); 247818334Speter 247918334Speter emit_no_conflict_block (insns, target, op0, NULL_RTX, 248050397Sobrien gen_rtx_fmt_e (unoptab->code, mode, 248150397Sobrien copy_rtx (op0))); 248218334Speter return target; 248318334Speter } 248418334Speter 248518334Speter /* Open-code the complex negation operation. */ 248690075Sobrien else if (unoptab->code == NEG 248718334Speter && (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)) 248818334Speter { 248918334Speter rtx target_piece; 249018334Speter rtx x; 249118334Speter rtx seq; 249218334Speter 249318334Speter /* Find the correct mode for the real and imaginary parts */ 2494117395Skan enum machine_mode submode = GET_MODE_INNER (mode); 249518334Speter 249618334Speter if (submode == BLKmode) 249718334Speter abort (); 249818334Speter 249918334Speter if (target == 0) 250018334Speter target = gen_reg_rtx (mode); 250118334Speter 250218334Speter start_sequence (); 250318334Speter 250418334Speter target_piece = gen_imagpart (submode, target); 250518334Speter x = expand_unop (submode, unoptab, 250618334Speter gen_imagpart (submode, op0), 250718334Speter target_piece, unsignedp); 250818334Speter if (target_piece != x) 250918334Speter emit_move_insn (target_piece, x); 251018334Speter 251118334Speter target_piece = gen_realpart (submode, target); 251218334Speter x = expand_unop (submode, unoptab, 251318334Speter gen_realpart (submode, op0), 251418334Speter target_piece, unsignedp); 251518334Speter if (target_piece != x) 251618334Speter emit_move_insn (target_piece, x); 251718334Speter 251818334Speter seq = get_insns (); 251918334Speter end_sequence (); 252018334Speter 252118334Speter emit_no_conflict_block (seq, target, op0, 0, 252250397Sobrien gen_rtx_fmt_e (unoptab->code, mode, 252350397Sobrien copy_rtx (op0))); 252418334Speter return target; 252518334Speter } 252618334Speter 252718334Speter /* Now try a library call in this mode. */ 252818334Speter if (unoptab->handlers[(int) mode].libfunc) 252918334Speter { 253018334Speter rtx insns; 253118334Speter rtx value; 253218334Speter 253318334Speter start_sequence (); 253418334Speter 253518334Speter /* Pass 1 for NO_QUEUE so we don't lose any increments 253618334Speter if the libcall is cse'd or moved. */ 253718334Speter value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc, 253890075Sobrien NULL_RTX, LCT_CONST, mode, 1, op0, mode); 253918334Speter insns = get_insns (); 254018334Speter end_sequence (); 254118334Speter 254218334Speter target = gen_reg_rtx (mode); 254318334Speter emit_libcall_block (insns, target, value, 254450397Sobrien gen_rtx_fmt_e (unoptab->code, mode, op0)); 254518334Speter 254618334Speter return target; 254718334Speter } 254818334Speter 2549117395Skan if (class == MODE_VECTOR_FLOAT || class == MODE_VECTOR_INT) 2550117395Skan return expand_vector_unop (mode, unoptab, op0, target, unsignedp); 2551117395Skan 255218334Speter /* It can't be done in this mode. Can we do it in a wider mode? */ 255318334Speter 255418334Speter if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) 255518334Speter { 255618334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 255718334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 255818334Speter { 255918334Speter if ((unoptab->handlers[(int) wider_mode].insn_code 256018334Speter != CODE_FOR_nothing) 256118334Speter || unoptab->handlers[(int) wider_mode].libfunc) 256218334Speter { 256318334Speter rtx xop0 = op0; 256418334Speter 256518334Speter /* For certain operations, we need not actually extend 256618334Speter the narrow operand, as long as we will truncate the 256718334Speter results to the same narrowness. */ 256818334Speter 256918334Speter xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, 257018334Speter (unoptab == neg_optab 257118334Speter || unoptab == one_cmpl_optab) 257218334Speter && class == MODE_INT); 257318334Speter 257418334Speter temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX, 257518334Speter unsignedp); 257618334Speter 257718334Speter if (temp) 257818334Speter { 257918334Speter if (class != MODE_INT) 258018334Speter { 258118334Speter if (target == 0) 258218334Speter target = gen_reg_rtx (mode); 258318334Speter convert_move (target, temp, 0); 258418334Speter return target; 258518334Speter } 258618334Speter else 258718334Speter return gen_lowpart (mode, temp); 258818334Speter } 258918334Speter else 259018334Speter delete_insns_since (last); 259118334Speter } 259218334Speter } 259318334Speter } 259418334Speter 259518334Speter /* If there is no negate operation, try doing a subtract from zero. 259618334Speter The US Software GOFAST library needs this. */ 259790075Sobrien if (unoptab->code == NEG) 259818334Speter { 259918334Speter rtx temp; 260090075Sobrien temp = expand_binop (mode, 260190075Sobrien unoptab == negv_optab ? subv_optab : sub_optab, 260290075Sobrien CONST0_RTX (mode), op0, 260390075Sobrien target, unsignedp, OPTAB_LIB_WIDEN); 260418334Speter if (temp) 260518334Speter return temp; 260618334Speter } 260718334Speter 260818334Speter return 0; 260918334Speter} 261018334Speter 261118334Speter/* Emit code to compute the absolute value of OP0, with result to 261218334Speter TARGET if convenient. (TARGET may be 0.) The return value says 261318334Speter where the result actually is to be found. 261418334Speter 261518334Speter MODE is the mode of the operand; the mode of the result is 261618334Speter different but can be deduced from MODE. 261718334Speter 261852284Sobrien */ 261918334Speter 262018334Speterrtx 262190075Sobrienexpand_abs (mode, op0, target, result_unsignedp, safe) 262218334Speter enum machine_mode mode; 262318334Speter rtx op0; 262418334Speter rtx target; 262590075Sobrien int result_unsignedp; 262618334Speter int safe; 262718334Speter{ 262818334Speter rtx temp, op1; 262918334Speter 263090075Sobrien if (! flag_trapv) 263190075Sobrien result_unsignedp = 1; 263290075Sobrien 263318334Speter /* First try to do it with a special abs instruction. */ 263490075Sobrien temp = expand_unop (mode, result_unsignedp ? abs_optab : absv_optab, 263590075Sobrien op0, target, 0); 263618334Speter if (temp != 0) 263718334Speter return temp; 263818334Speter 263990075Sobrien /* If we have a MAX insn, we can do this as MAX (x, -x). */ 264090075Sobrien if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 264190075Sobrien { 264290075Sobrien rtx last = get_last_insn (); 264390075Sobrien 264490075Sobrien temp = expand_unop (mode, neg_optab, op0, NULL_RTX, 0); 264590075Sobrien if (temp != 0) 264690075Sobrien temp = expand_binop (mode, smax_optab, op0, temp, target, 0, 264790075Sobrien OPTAB_WIDEN); 264890075Sobrien 264990075Sobrien if (temp != 0) 265090075Sobrien return temp; 265190075Sobrien 265290075Sobrien delete_insns_since (last); 265390075Sobrien } 265490075Sobrien 265518334Speter /* If this machine has expensive jumps, we can do integer absolute 265618334Speter value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)), 265718334Speter where W is the width of MODE. */ 265818334Speter 265918334Speter if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2) 266018334Speter { 266118334Speter rtx extended = expand_shift (RSHIFT_EXPR, mode, op0, 266218334Speter size_int (GET_MODE_BITSIZE (mode) - 1), 266318334Speter NULL_RTX, 0); 266418334Speter 266518334Speter temp = expand_binop (mode, xor_optab, extended, op0, target, 0, 266618334Speter OPTAB_LIB_WIDEN); 266718334Speter if (temp != 0) 266890075Sobrien temp = expand_binop (mode, result_unsignedp ? sub_optab : subv_optab, 266990075Sobrien temp, extended, target, 0, OPTAB_LIB_WIDEN); 267018334Speter 267118334Speter if (temp != 0) 267218334Speter return temp; 267318334Speter } 267418334Speter 267518334Speter /* If that does not win, use conditional jump and negate. */ 267650397Sobrien 267750397Sobrien /* It is safe to use the target if it is the same 267850397Sobrien as the source if this is also a pseudo register */ 267950397Sobrien if (op0 == target && GET_CODE (op0) == REG 268050397Sobrien && REGNO (op0) >= FIRST_PSEUDO_REGISTER) 268150397Sobrien safe = 1; 268250397Sobrien 268318334Speter op1 = gen_label_rtx (); 268418334Speter if (target == 0 || ! safe 268518334Speter || GET_MODE (target) != mode 268618334Speter || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target)) 268718334Speter || (GET_CODE (target) == REG 268818334Speter && REGNO (target) < FIRST_PSEUDO_REGISTER)) 268918334Speter target = gen_reg_rtx (mode); 269018334Speter 269118334Speter emit_move_insn (target, op0); 269218334Speter NO_DEFER_POP; 269318334Speter 269418334Speter /* If this mode is an integer too wide to compare properly, 269518334Speter compare word by word. Rely on CSE to optimize constant cases. */ 269690075Sobrien if (GET_MODE_CLASS (mode) == MODE_INT 269790075Sobrien && ! can_compare_p (GE, mode, ccp_jump)) 269818334Speter do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx, 269918334Speter NULL_RTX, op1); 270018334Speter else 270190075Sobrien do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode, 270290075Sobrien NULL_RTX, NULL_RTX, op1); 270318334Speter 270490075Sobrien op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab, 270590075Sobrien target, target, 0); 270618334Speter if (op0 != target) 270718334Speter emit_move_insn (target, op0); 270818334Speter emit_label (op1); 270918334Speter OK_DEFER_POP; 271018334Speter return target; 271118334Speter} 271218334Speter 271318334Speter/* Emit code to compute the absolute value of OP0, with result to 271418334Speter TARGET if convenient. (TARGET may be 0.) The return value says 271518334Speter where the result actually is to be found. 271618334Speter 271718334Speter MODE is the mode of the operand; the mode of the result is 271818334Speter different but can be deduced from MODE. 271918334Speter 272018334Speter UNSIGNEDP is relevant for complex integer modes. */ 272118334Speter 272218334Speterrtx 272318334Speterexpand_complex_abs (mode, op0, target, unsignedp) 272418334Speter enum machine_mode mode; 272518334Speter rtx op0; 272618334Speter rtx target; 272718334Speter int unsignedp; 272818334Speter{ 272918334Speter enum mode_class class = GET_MODE_CLASS (mode); 273018334Speter enum machine_mode wider_mode; 273190075Sobrien rtx temp; 273218334Speter rtx entry_last = get_last_insn (); 273318334Speter rtx last; 273418334Speter rtx pat; 273590075Sobrien optab this_abs_optab; 273618334Speter 273718334Speter /* Find the correct mode for the real and imaginary parts. */ 2738117395Skan enum machine_mode submode = GET_MODE_INNER (mode); 273918334Speter 274018334Speter if (submode == BLKmode) 274118334Speter abort (); 274218334Speter 274318334Speter op0 = protect_from_queue (op0, 0); 274418334Speter 274518334Speter if (flag_force_mem) 274618334Speter { 274718334Speter op0 = force_not_mem (op0); 274818334Speter } 274918334Speter 275018334Speter last = get_last_insn (); 275118334Speter 275218334Speter if (target) 275318334Speter target = protect_from_queue (target, 1); 275418334Speter 275590075Sobrien this_abs_optab = ! unsignedp && flag_trapv 275690075Sobrien && (GET_MODE_CLASS(mode) == MODE_INT) 275790075Sobrien ? absv_optab : abs_optab; 275890075Sobrien 275990075Sobrien if (this_abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 276018334Speter { 276190075Sobrien int icode = (int) this_abs_optab->handlers[(int) mode].insn_code; 276290075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 276318334Speter rtx xop0 = op0; 276418334Speter 276518334Speter if (target) 276618334Speter temp = target; 276718334Speter else 276818334Speter temp = gen_reg_rtx (submode); 276918334Speter 277018334Speter if (GET_MODE (xop0) != VOIDmode 277118334Speter && GET_MODE (xop0) != mode0) 277218334Speter xop0 = convert_to_mode (mode0, xop0, unsignedp); 277318334Speter 277418334Speter /* Now, if insn doesn't accept our operand, put it into a pseudo. */ 277518334Speter 277690075Sobrien if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)) 277718334Speter xop0 = copy_to_mode_reg (mode0, xop0); 277818334Speter 277990075Sobrien if (! (*insn_data[icode].operand[0].predicate) (temp, submode)) 278018334Speter temp = gen_reg_rtx (submode); 278118334Speter 278218334Speter pat = GEN_FCN (icode) (temp, xop0); 278318334Speter if (pat) 278418334Speter { 2785117395Skan if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX 278690075Sobrien && ! add_equal_note (pat, temp, this_abs_optab->code, xop0, 278790075Sobrien NULL_RTX)) 278818334Speter { 278918334Speter delete_insns_since (last); 279090075Sobrien return expand_unop (mode, this_abs_optab, op0, NULL_RTX, 279190075Sobrien unsignedp); 279218334Speter } 279318334Speter 279418334Speter emit_insn (pat); 279518334Speter 279618334Speter return temp; 279718334Speter } 279818334Speter else 279918334Speter delete_insns_since (last); 280018334Speter } 280118334Speter 280218334Speter /* It can't be done in this mode. Can we open-code it in a wider mode? */ 280318334Speter 280418334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 280518334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 280618334Speter { 280790075Sobrien if (this_abs_optab->handlers[(int) wider_mode].insn_code 280890075Sobrien != CODE_FOR_nothing) 280918334Speter { 281018334Speter rtx xop0 = op0; 281118334Speter 281218334Speter xop0 = convert_modes (wider_mode, mode, xop0, unsignedp); 281318334Speter temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp); 281418334Speter 281518334Speter if (temp) 281618334Speter { 281718334Speter if (class != MODE_COMPLEX_INT) 281818334Speter { 281918334Speter if (target == 0) 282018334Speter target = gen_reg_rtx (submode); 282118334Speter convert_move (target, temp, 0); 282218334Speter return target; 282318334Speter } 282418334Speter else 282518334Speter return gen_lowpart (submode, temp); 282618334Speter } 282718334Speter else 282818334Speter delete_insns_since (last); 282918334Speter } 283018334Speter } 283118334Speter 283218334Speter /* Open-code the complex absolute-value operation 283318334Speter if we can open-code sqrt. Otherwise it's not worth while. */ 283490075Sobrien if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing 283590075Sobrien && ! flag_trapv) 283618334Speter { 283718334Speter rtx real, imag, total; 283818334Speter 283918334Speter real = gen_realpart (submode, op0); 284018334Speter imag = gen_imagpart (submode, op0); 284118334Speter 284218334Speter /* Square both parts. */ 284318334Speter real = expand_mult (submode, real, real, NULL_RTX, 0); 284418334Speter imag = expand_mult (submode, imag, imag, NULL_RTX, 0); 284518334Speter 284618334Speter /* Sum the parts. */ 284718334Speter total = expand_binop (submode, add_optab, real, imag, NULL_RTX, 284818334Speter 0, OPTAB_LIB_WIDEN); 284918334Speter 285018334Speter /* Get sqrt in TARGET. Set TARGET to where the result is. */ 285118334Speter target = expand_unop (submode, sqrt_optab, total, target, 0); 285218334Speter if (target == 0) 285318334Speter delete_insns_since (last); 285418334Speter else 285518334Speter return target; 285618334Speter } 285718334Speter 285818334Speter /* Now try a library call in this mode. */ 285990075Sobrien if (this_abs_optab->handlers[(int) mode].libfunc) 286018334Speter { 286118334Speter rtx insns; 286218334Speter rtx value; 286318334Speter 286418334Speter start_sequence (); 286518334Speter 286618334Speter /* Pass 1 for NO_QUEUE so we don't lose any increments 286718334Speter if the libcall is cse'd or moved. */ 286818334Speter value = emit_library_call_value (abs_optab->handlers[(int) mode].libfunc, 286990075Sobrien NULL_RTX, LCT_CONST, submode, 1, op0, mode); 287018334Speter insns = get_insns (); 287118334Speter end_sequence (); 287218334Speter 287318334Speter target = gen_reg_rtx (submode); 287418334Speter emit_libcall_block (insns, target, value, 287590075Sobrien gen_rtx_fmt_e (this_abs_optab->code, mode, op0)); 287618334Speter 287718334Speter return target; 287818334Speter } 287918334Speter 288018334Speter /* It can't be done in this mode. Can we do it in a wider mode? */ 288118334Speter 288218334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 288318334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 288418334Speter { 288590075Sobrien if ((this_abs_optab->handlers[(int) wider_mode].insn_code 288618334Speter != CODE_FOR_nothing) 288790075Sobrien || this_abs_optab->handlers[(int) wider_mode].libfunc) 288818334Speter { 288918334Speter rtx xop0 = op0; 289018334Speter 289118334Speter xop0 = convert_modes (wider_mode, mode, xop0, unsignedp); 289218334Speter 289318334Speter temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp); 289418334Speter 289518334Speter if (temp) 289618334Speter { 289718334Speter if (class != MODE_COMPLEX_INT) 289818334Speter { 289918334Speter if (target == 0) 290018334Speter target = gen_reg_rtx (submode); 290118334Speter convert_move (target, temp, 0); 290218334Speter return target; 290318334Speter } 290418334Speter else 290518334Speter return gen_lowpart (submode, temp); 290618334Speter } 290718334Speter else 290818334Speter delete_insns_since (last); 290918334Speter } 291018334Speter } 291118334Speter 291218334Speter delete_insns_since (entry_last); 291318334Speter return 0; 291418334Speter} 291518334Speter 291618334Speter/* Generate an instruction whose insn-code is INSN_CODE, 291718334Speter with two operands: an output TARGET and an input OP0. 291818334Speter TARGET *must* be nonzero, and the output is always stored there. 291918334Speter CODE is an rtx code such that (CODE OP0) is an rtx that describes 292018334Speter the value that is stored into TARGET. */ 292118334Speter 292218334Spetervoid 292318334Speteremit_unop_insn (icode, target, op0, code) 292418334Speter int icode; 292518334Speter rtx target; 292618334Speter rtx op0; 292718334Speter enum rtx_code code; 292818334Speter{ 292990075Sobrien rtx temp; 293090075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 293118334Speter rtx pat; 293218334Speter 293318334Speter temp = target = protect_from_queue (target, 1); 293418334Speter 293518334Speter op0 = protect_from_queue (op0, 0); 293618334Speter 293750397Sobrien /* Sign and zero extension from memory is often done specially on 293850397Sobrien RISC machines, so forcing into a register here can pessimize 293950397Sobrien code. */ 294050397Sobrien if (flag_force_mem && code != SIGN_EXTEND && code != ZERO_EXTEND) 294118334Speter op0 = force_not_mem (op0); 294218334Speter 294318334Speter /* Now, if insn does not accept our operands, put them into pseudos. */ 294418334Speter 294590075Sobrien if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) 294618334Speter op0 = copy_to_mode_reg (mode0, op0); 294718334Speter 294890075Sobrien if (! (*insn_data[icode].operand[0].predicate) (temp, GET_MODE (temp)) 294918334Speter || (flag_force_mem && GET_CODE (temp) == MEM)) 295018334Speter temp = gen_reg_rtx (GET_MODE (temp)); 295118334Speter 295218334Speter pat = GEN_FCN (icode) (temp, op0); 295318334Speter 2954117395Skan if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX && code != UNKNOWN) 295518334Speter add_equal_note (pat, temp, code, op0, NULL_RTX); 295618334Speter 295718334Speter emit_insn (pat); 295818334Speter 295918334Speter if (temp != target) 296018334Speter emit_move_insn (target, temp); 296118334Speter} 296218334Speter 296318334Speter/* Emit code to perform a series of operations on a multi-word quantity, one 296418334Speter word at a time. 296518334Speter 296618334Speter Such a block is preceded by a CLOBBER of the output, consists of multiple 296718334Speter insns, each setting one word of the output, and followed by a SET copying 296818334Speter the output to itself. 296918334Speter 297018334Speter Each of the insns setting words of the output receives a REG_NO_CONFLICT 297118334Speter note indicating that it doesn't conflict with the (also multi-word) 297218334Speter inputs. The entire block is surrounded by REG_LIBCALL and REG_RETVAL 297318334Speter notes. 297418334Speter 297518334Speter INSNS is a block of code generated to perform the operation, not including 297618334Speter the CLOBBER and final copy. All insns that compute intermediate values 297718334Speter are first emitted, followed by the block as described above. 297818334Speter 297918334Speter TARGET, OP0, and OP1 are the output and inputs of the operations, 298018334Speter respectively. OP1 may be zero for a unary operation. 298118334Speter 2982117395Skan EQUIV, if nonzero, is an expression to be placed into a REG_EQUAL note 298318334Speter on the last insn. 298418334Speter 298518334Speter If TARGET is not a register, INSNS is simply emitted with no special 298618334Speter processing. Likewise if anything in INSNS is not an INSN or if 298718334Speter there is a libcall block inside INSNS. 298818334Speter 298918334Speter The final insn emitted is returned. */ 299018334Speter 299118334Speterrtx 299218334Speteremit_no_conflict_block (insns, target, op0, op1, equiv) 299318334Speter rtx insns; 299418334Speter rtx target; 299518334Speter rtx op0, op1; 299618334Speter rtx equiv; 299718334Speter{ 299818334Speter rtx prev, next, first, last, insn; 299918334Speter 300018334Speter if (GET_CODE (target) != REG || reload_in_progress) 3001117395Skan return emit_insn (insns); 300218334Speter else 300318334Speter for (insn = insns; insn; insn = NEXT_INSN (insn)) 300418334Speter if (GET_CODE (insn) != INSN 300518334Speter || find_reg_note (insn, REG_LIBCALL, NULL_RTX)) 3006117395Skan return emit_insn (insns); 300718334Speter 300818334Speter /* First emit all insns that do not store into words of the output and remove 300918334Speter these from the list. */ 301018334Speter for (insn = insns; insn; insn = next) 301118334Speter { 301296263Sobrien rtx set = 0, note; 301318334Speter int i; 301418334Speter 301518334Speter next = NEXT_INSN (insn); 301618334Speter 301796263Sobrien /* Some ports (cris) create an libcall regions at their own. We must 301896263Sobrien avoid any potential nesting of LIBCALLs. */ 301996263Sobrien if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL) 302096263Sobrien remove_note (insn, note); 302196263Sobrien if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL) 302296263Sobrien remove_note (insn, note); 302396263Sobrien 302490075Sobrien if (GET_CODE (PATTERN (insn)) == SET || GET_CODE (PATTERN (insn)) == USE 302590075Sobrien || GET_CODE (PATTERN (insn)) == CLOBBER) 302618334Speter set = PATTERN (insn); 302718334Speter else if (GET_CODE (PATTERN (insn)) == PARALLEL) 302818334Speter { 302918334Speter for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) 303018334Speter if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET) 303118334Speter { 303218334Speter set = XVECEXP (PATTERN (insn), 0, i); 303318334Speter break; 303418334Speter } 303518334Speter } 303618334Speter 303718334Speter if (set == 0) 303818334Speter abort (); 303918334Speter 304018334Speter if (! reg_overlap_mentioned_p (target, SET_DEST (set))) 304118334Speter { 304218334Speter if (PREV_INSN (insn)) 304318334Speter NEXT_INSN (PREV_INSN (insn)) = next; 304418334Speter else 304518334Speter insns = next; 304618334Speter 304718334Speter if (next) 304818334Speter PREV_INSN (next) = PREV_INSN (insn); 304918334Speter 305018334Speter add_insn (insn); 305118334Speter } 305218334Speter } 305318334Speter 305418334Speter prev = get_last_insn (); 305518334Speter 305618334Speter /* Now write the CLOBBER of the output, followed by the setting of each 305718334Speter of the words, followed by the final copy. */ 305818334Speter if (target != op0 && target != op1) 305950397Sobrien emit_insn (gen_rtx_CLOBBER (VOIDmode, target)); 306018334Speter 306118334Speter for (insn = insns; insn; insn = next) 306218334Speter { 306318334Speter next = NEXT_INSN (insn); 306418334Speter add_insn (insn); 306518334Speter 306618334Speter if (op1 && GET_CODE (op1) == REG) 306750397Sobrien REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op1, 306850397Sobrien REG_NOTES (insn)); 306918334Speter 307018334Speter if (op0 && GET_CODE (op0) == REG) 307150397Sobrien REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op0, 307250397Sobrien REG_NOTES (insn)); 307318334Speter } 307418334Speter 307518334Speter if (mov_optab->handlers[(int) GET_MODE (target)].insn_code 307618334Speter != CODE_FOR_nothing) 307718334Speter { 307818334Speter last = emit_move_insn (target, target); 307918334Speter if (equiv) 308052284Sobrien set_unique_reg_note (last, REG_EQUAL, equiv); 308118334Speter } 308218334Speter else 308390075Sobrien { 308490075Sobrien last = get_last_insn (); 308518334Speter 308690075Sobrien /* Remove any existing REG_EQUAL note from "last", or else it will 308790075Sobrien be mistaken for a note referring to the full contents of the 308890075Sobrien alleged libcall value when found together with the REG_RETVAL 308990075Sobrien note added below. An existing note can come from an insn 309090075Sobrien expansion at "last". */ 309190075Sobrien remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX)); 309290075Sobrien } 309390075Sobrien 309418334Speter if (prev == 0) 309518334Speter first = get_insns (); 309618334Speter else 309718334Speter first = NEXT_INSN (prev); 309818334Speter 309918334Speter /* Encapsulate the block so it gets manipulated as a unit. */ 310050397Sobrien REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, 310150397Sobrien REG_NOTES (first)); 310250397Sobrien REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last)); 310318334Speter 310418334Speter return last; 310518334Speter} 310618334Speter 310718334Speter/* Emit code to make a call to a constant function or a library call. 310818334Speter 310918334Speter INSNS is a list containing all insns emitted in the call. 311018334Speter These insns leave the result in RESULT. Our block is to copy RESULT 311118334Speter to TARGET, which is logically equivalent to EQUIV. 311218334Speter 311318334Speter We first emit any insns that set a pseudo on the assumption that these are 311418334Speter loading constants into registers; doing so allows them to be safely cse'ed 311518334Speter between blocks. Then we emit all the other insns in the block, followed by 311618334Speter an insn to move RESULT to TARGET. This last insn will have a REQ_EQUAL 311718334Speter note with an operand of EQUIV. 311818334Speter 311918334Speter Moving assignments to pseudos outside of the block is done to improve 312018334Speter the generated code, but is not required to generate correct code, 312118334Speter hence being unable to move an assignment is not grounds for not making 312218334Speter a libcall block. There are two reasons why it is safe to leave these 312318334Speter insns inside the block: First, we know that these pseudos cannot be 312418334Speter used in generated RTL outside the block since they are created for 312518334Speter temporary purposes within the block. Second, CSE will not record the 312618334Speter values of anything set inside a libcall block, so we know they must 312718334Speter be dead at the end of the block. 312818334Speter 312918334Speter Except for the first group of insns (the ones setting pseudos), the 313018334Speter block is delimited by REG_RETVAL and REG_LIBCALL notes. */ 313118334Speter 313218334Spetervoid 313318334Speteremit_libcall_block (insns, target, result, equiv) 313418334Speter rtx insns; 313518334Speter rtx target; 313618334Speter rtx result; 313718334Speter rtx equiv; 313818334Speter{ 313970635Sobrien rtx final_dest = target; 314018334Speter rtx prev, next, first, last, insn; 314118334Speter 314270635Sobrien /* If this is a reg with REG_USERVAR_P set, then it could possibly turn 314370635Sobrien into a MEM later. Protect the libcall block from this change. */ 314470635Sobrien if (! REG_P (target) || REG_USERVAR_P (target)) 314570635Sobrien target = gen_reg_rtx (GET_MODE (target)); 314690075Sobrien 314790075Sobrien /* If we're using non-call exceptions, a libcall corresponding to an 314890075Sobrien operation that may trap may also trap. */ 314990075Sobrien if (flag_non_call_exceptions && may_trap_p (equiv)) 315090075Sobrien { 315190075Sobrien for (insn = insns; insn; insn = NEXT_INSN (insn)) 315290075Sobrien if (GET_CODE (insn) == CALL_INSN) 315390075Sobrien { 315490075Sobrien rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 315590075Sobrien 315690075Sobrien if (note != 0 && INTVAL (XEXP (note, 0)) <= 0) 315790075Sobrien remove_note (insn, note); 315890075Sobrien } 315990075Sobrien } 316090075Sobrien else 316152284Sobrien /* look for any CALL_INSNs in this sequence, and attach a REG_EH_REGION 316290075Sobrien reg note to indicate that this call cannot throw or execute a nonlocal 316390075Sobrien goto (unless there is already a REG_EH_REGION note, in which case 316490075Sobrien we update it). */ 316590075Sobrien for (insn = insns; insn; insn = NEXT_INSN (insn)) 316652284Sobrien if (GET_CODE (insn) == CALL_INSN) 316790075Sobrien { 316890075Sobrien rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 316990075Sobrien 317090075Sobrien if (note != 0) 317190075Sobrien XEXP (note, 0) = GEN_INT (-1); 317290075Sobrien else 317390075Sobrien REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, GEN_INT (-1), 317490075Sobrien REG_NOTES (insn)); 317590075Sobrien } 317652284Sobrien 317718334Speter /* First emit all insns that set pseudos. Remove them from the list as 317818334Speter we go. Avoid insns that set pseudos which were referenced in previous 317918334Speter insns. These can be generated by move_by_pieces, for example, 318018334Speter to update an address. Similarly, avoid insns that reference things 318118334Speter set in previous insns. */ 318218334Speter 318318334Speter for (insn = insns; insn; insn = next) 318418334Speter { 318518334Speter rtx set = single_set (insn); 318696263Sobrien rtx note; 318718334Speter 318896263Sobrien /* Some ports (cris) create an libcall regions at their own. We must 318996263Sobrien avoid any potential nesting of LIBCALLs. */ 319096263Sobrien if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL) 319196263Sobrien remove_note (insn, note); 319296263Sobrien if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL) 319396263Sobrien remove_note (insn, note); 319496263Sobrien 319518334Speter next = NEXT_INSN (insn); 319618334Speter 319718334Speter if (set != 0 && GET_CODE (SET_DEST (set)) == REG 319818334Speter && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER 319918334Speter && (insn == insns 320090075Sobrien || ((! INSN_P(insns) 320190075Sobrien || ! reg_mentioned_p (SET_DEST (set), PATTERN (insns))) 320218334Speter && ! reg_used_between_p (SET_DEST (set), insns, insn) 320318334Speter && ! modified_in_p (SET_SRC (set), insns) 320418334Speter && ! modified_between_p (SET_SRC (set), insns, insn)))) 320518334Speter { 320618334Speter if (PREV_INSN (insn)) 320718334Speter NEXT_INSN (PREV_INSN (insn)) = next; 320818334Speter else 320918334Speter insns = next; 321018334Speter 321118334Speter if (next) 321218334Speter PREV_INSN (next) = PREV_INSN (insn); 321318334Speter 321418334Speter add_insn (insn); 321518334Speter } 321618334Speter } 321718334Speter 321818334Speter prev = get_last_insn (); 321918334Speter 322018334Speter /* Write the remaining insns followed by the final copy. */ 322118334Speter 322218334Speter for (insn = insns; insn; insn = next) 322318334Speter { 322418334Speter next = NEXT_INSN (insn); 322518334Speter 322618334Speter add_insn (insn); 322718334Speter } 322818334Speter 322918334Speter last = emit_move_insn (target, result); 323050397Sobrien if (mov_optab->handlers[(int) GET_MODE (target)].insn_code 323150397Sobrien != CODE_FOR_nothing) 323252284Sobrien set_unique_reg_note (last, REG_EQUAL, copy_rtx (equiv)); 323390075Sobrien else 323490075Sobrien { 323590075Sobrien /* Remove any existing REG_EQUAL note from "last", or else it will 323690075Sobrien be mistaken for a note referring to the full contents of the 323790075Sobrien libcall value when found together with the REG_RETVAL note added 323890075Sobrien below. An existing note can come from an insn expansion at 323990075Sobrien "last". */ 324090075Sobrien remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX)); 324190075Sobrien } 324218334Speter 324370635Sobrien if (final_dest != target) 324470635Sobrien emit_move_insn (final_dest, target); 324570635Sobrien 324618334Speter if (prev == 0) 324718334Speter first = get_insns (); 324818334Speter else 324918334Speter first = NEXT_INSN (prev); 325018334Speter 325118334Speter /* Encapsulate the block so it gets manipulated as a unit. */ 325290075Sobrien if (!flag_non_call_exceptions || !may_trap_p (equiv)) 325390075Sobrien { 3254110611Skan /* We can't attach the REG_LIBCALL and REG_RETVAL notes 3255110611Skan when the encapsulated region would not be in one basic block, 3256110611Skan i.e. when there is a control_flow_insn_p insn between FIRST and LAST. 3257110611Skan */ 3258110611Skan bool attach_libcall_retval_notes = true; 3259110611Skan next = NEXT_INSN (last); 3260110611Skan for (insn = first; insn != next; insn = NEXT_INSN (insn)) 3261110611Skan if (control_flow_insn_p (insn)) 3262110611Skan { 3263110611Skan attach_libcall_retval_notes = false; 3264110611Skan break; 3265110611Skan } 3266110611Skan 3267110611Skan if (attach_libcall_retval_notes) 3268110611Skan { 3269110611Skan REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, 3270110611Skan REG_NOTES (first)); 3271110611Skan REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, 3272110611Skan REG_NOTES (last)); 3273110611Skan } 327490075Sobrien } 327518334Speter} 327618334Speter 327718334Speter/* Generate code to store zero in X. */ 327818334Speter 327918334Spetervoid 328018334Speteremit_clr_insn (x) 328118334Speter rtx x; 328218334Speter{ 328318334Speter emit_move_insn (x, const0_rtx); 328418334Speter} 328518334Speter 328618334Speter/* Generate code to store 1 in X 328718334Speter assuming it contains zero beforehand. */ 328818334Speter 328918334Spetervoid 329018334Speteremit_0_to_1_insn (x) 329118334Speter rtx x; 329218334Speter{ 329318334Speter emit_move_insn (x, const1_rtx); 329418334Speter} 329518334Speter 329690075Sobrien/* Nonzero if we can perform a comparison of mode MODE straightforwardly. 329790075Sobrien PURPOSE describes how this comparison will be used. CODE is the rtx 329890075Sobrien comparison code we will be using. 329918334Speter 330090075Sobrien ??? Actually, CODE is slightly weaker than that. A target is still 330190075Sobrien required to implement all of the normal bcc operations, but not 330290075Sobrien required to implement all (or any) of the unordered bcc operations. */ 330390075Sobrien 330490075Sobrienint 330590075Sobriencan_compare_p (code, mode, purpose) 330690075Sobrien enum rtx_code code; 330790075Sobrien enum machine_mode mode; 330890075Sobrien enum can_compare_purpose purpose; 330990075Sobrien{ 331090075Sobrien do 331190075Sobrien { 3312117395Skan if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 331390075Sobrien { 331490075Sobrien if (purpose == ccp_jump) 3315117395Skan return bcc_gen_fctn[(int) code] != NULL; 331690075Sobrien else if (purpose == ccp_store_flag) 3317117395Skan return setcc_gen_code[(int) code] != CODE_FOR_nothing; 331890075Sobrien else 331990075Sobrien /* There's only one cmov entry point, and it's allowed to fail. */ 332090075Sobrien return 1; 332190075Sobrien } 332290075Sobrien if (purpose == ccp_jump 3323117395Skan && cbranch_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 332490075Sobrien return 1; 332590075Sobrien if (purpose == ccp_cmov 3326117395Skan && cmov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 332790075Sobrien return 1; 332890075Sobrien if (purpose == ccp_store_flag 3329117395Skan && cstore_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 333090075Sobrien return 1; 333190075Sobrien 333290075Sobrien mode = GET_MODE_WIDER_MODE (mode); 333390075Sobrien } 333490075Sobrien while (mode != VOIDmode); 333590075Sobrien 333690075Sobrien return 0; 333790075Sobrien} 333890075Sobrien 333990075Sobrien/* This function is called when we are going to emit a compare instruction that 334090075Sobrien compares the values found in *PX and *PY, using the rtl operator COMPARISON. 334190075Sobrien 334290075Sobrien *PMODE is the mode of the inputs (in case they are const_int). 334390075Sobrien *PUNSIGNEDP nonzero says that the operands are unsigned; 334418334Speter this matters if they need to be widened. 334518334Speter 334690075Sobrien If they have mode BLKmode, then SIZE specifies the size of both operands. 334718334Speter 334890075Sobrien This function performs all the setup necessary so that the caller only has 334990075Sobrien to emit a single comparison insn. This setup can involve doing a BLKmode 335090075Sobrien comparison or emitting a library call to perform the comparison if no insn 335190075Sobrien is available to handle it. 335290075Sobrien The values which are passed in through pointers can be modified; the caller 335390075Sobrien should perform the comparison on the modified values. */ 335418334Speter 335590075Sobrienstatic void 335690075Sobrienprepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose) 335790075Sobrien rtx *px, *py; 335890075Sobrien enum rtx_code *pcomparison; 335918334Speter rtx size; 336090075Sobrien enum machine_mode *pmode; 336190075Sobrien int *punsignedp; 336290075Sobrien enum can_compare_purpose purpose; 336318334Speter{ 336490075Sobrien enum machine_mode mode = *pmode; 336590075Sobrien rtx x = *px, y = *py; 336690075Sobrien int unsignedp = *punsignedp; 336718334Speter enum mode_class class; 336818334Speter 336918334Speter class = GET_MODE_CLASS (mode); 337018334Speter 337118334Speter /* They could both be VOIDmode if both args are immediate constants, 337218334Speter but we should fold that at an earlier stage. 337318334Speter With no special code here, this will call abort, 337418334Speter reminding the programmer to implement such folding. */ 337518334Speter 337618334Speter if (mode != BLKmode && flag_force_mem) 337718334Speter { 337818334Speter x = force_not_mem (x); 337918334Speter y = force_not_mem (y); 338018334Speter } 338118334Speter 338218334Speter /* If we are inside an appropriately-short loop and one operand is an 338318334Speter expensive constant, force it into a register. */ 338490075Sobrien if (CONSTANT_P (x) && preserve_subexpressions_p () 338590075Sobrien && rtx_cost (x, COMPARE) > COSTS_N_INSNS (1)) 338618334Speter x = force_reg (mode, x); 338718334Speter 338890075Sobrien if (CONSTANT_P (y) && preserve_subexpressions_p () 338990075Sobrien && rtx_cost (y, COMPARE) > COSTS_N_INSNS (1)) 339018334Speter y = force_reg (mode, y); 339118334Speter 339252284Sobrien#ifdef HAVE_cc0 339352284Sobrien /* Abort if we have a non-canonical comparison. The RTL documentation 339452284Sobrien states that canonical comparisons are required only for targets which 339552284Sobrien have cc0. */ 339652284Sobrien if (CONSTANT_P (x) && ! CONSTANT_P (y)) 3397117395Skan abort (); 339852284Sobrien#endif 339952284Sobrien 340018334Speter /* Don't let both operands fail to indicate the mode. */ 340118334Speter if (GET_MODE (x) == VOIDmode && GET_MODE (y) == VOIDmode) 340218334Speter x = force_reg (mode, x); 340318334Speter 340418334Speter /* Handle all BLKmode compares. */ 340518334Speter 340618334Speter if (mode == BLKmode) 340718334Speter { 340890075Sobrien rtx result; 340990075Sobrien enum machine_mode result_mode; 341090075Sobrien rtx opalign ATTRIBUTE_UNUSED 341190075Sobrien = GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT); 341290075Sobrien 341318334Speter emit_queue (); 341418334Speter x = protect_from_queue (x, 0); 341518334Speter y = protect_from_queue (y, 0); 341618334Speter 341718334Speter if (size == 0) 341818334Speter abort (); 341918334Speter#ifdef HAVE_cmpstrqi 342018334Speter if (HAVE_cmpstrqi 342118334Speter && GET_CODE (size) == CONST_INT 342218334Speter && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode))) 342318334Speter { 342490075Sobrien result_mode = insn_data[(int) CODE_FOR_cmpstrqi].operand[0].mode; 342590075Sobrien result = gen_reg_rtx (result_mode); 342690075Sobrien emit_insn (gen_cmpstrqi (result, x, y, size, opalign)); 342718334Speter } 342818334Speter else 342918334Speter#endif 343018334Speter#ifdef HAVE_cmpstrhi 343118334Speter if (HAVE_cmpstrhi 343218334Speter && GET_CODE (size) == CONST_INT 343318334Speter && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode))) 343418334Speter { 343590075Sobrien result_mode = insn_data[(int) CODE_FOR_cmpstrhi].operand[0].mode; 343690075Sobrien result = gen_reg_rtx (result_mode); 343790075Sobrien emit_insn (gen_cmpstrhi (result, x, y, size, opalign)); 343818334Speter } 343918334Speter else 344018334Speter#endif 344118334Speter#ifdef HAVE_cmpstrsi 344218334Speter if (HAVE_cmpstrsi) 344318334Speter { 344490075Sobrien result_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; 344590075Sobrien result = gen_reg_rtx (result_mode); 344618334Speter size = protect_from_queue (size, 0); 344718334Speter emit_insn (gen_cmpstrsi (result, x, y, 344818334Speter convert_to_mode (SImode, size, 1), 344990075Sobrien opalign)); 345018334Speter } 345118334Speter else 345218334Speter#endif 345318334Speter { 345418334Speter#ifdef TARGET_MEM_FUNCTIONS 3455117395Skan result = emit_library_call_value (memcmp_libfunc, NULL_RTX, LCT_PURE_MAKE_BLOCK, 3456117395Skan TYPE_MODE (integer_type_node), 3, 3457117395Skan XEXP (x, 0), Pmode, XEXP (y, 0), Pmode, 3458117395Skan convert_to_mode (TYPE_MODE (sizetype), size, 3459117395Skan TREE_UNSIGNED (sizetype)), 3460117395Skan TYPE_MODE (sizetype)); 346118334Speter#else 3462117395Skan result = emit_library_call_value (bcmp_libfunc, NULL_RTX, LCT_PURE_MAKE_BLOCK, 3463117395Skan TYPE_MODE (integer_type_node), 3, 3464117395Skan XEXP (x, 0), Pmode, XEXP (y, 0), Pmode, 3465117395Skan convert_to_mode (TYPE_MODE (integer_type_node), 3466117395Skan size, 3467117395Skan TREE_UNSIGNED (integer_type_node)), 3468117395Skan TYPE_MODE (integer_type_node)); 346918334Speter#endif 347050397Sobrien 347190075Sobrien result_mode = TYPE_MODE (integer_type_node); 347218334Speter } 347390075Sobrien *px = result; 347490075Sobrien *py = const0_rtx; 347590075Sobrien *pmode = result_mode; 347618334Speter return; 347718334Speter } 347818334Speter 347990075Sobrien *px = x; 348090075Sobrien *py = y; 348190075Sobrien if (can_compare_p (*pcomparison, mode, purpose)) 348290075Sobrien return; 348318334Speter 348418334Speter /* Handle a lib call just for the mode we are using. */ 348518334Speter 348690075Sobrien if (cmp_optab->handlers[(int) mode].libfunc && class != MODE_FLOAT) 348718334Speter { 348818334Speter rtx libfunc = cmp_optab->handlers[(int) mode].libfunc; 348950397Sobrien rtx result; 349050397Sobrien 349118334Speter /* If we want unsigned, and this mode has a distinct unsigned 349218334Speter comparison routine, use that. */ 349318334Speter if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc) 349418334Speter libfunc = ucmp_optab->handlers[(int) mode].libfunc; 349518334Speter 3496117395Skan result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK, 3497117395Skan word_mode, 2, x, mode, y, mode); 349818334Speter 349918334Speter /* Integer comparison returns a result that must be compared against 1, 350018334Speter so that even if we do an unsigned compare afterward, 350118334Speter there is still a value that can represent the result "less than". */ 350290075Sobrien *px = result; 350390075Sobrien *py = const1_rtx; 350490075Sobrien *pmode = word_mode; 350518334Speter return; 350618334Speter } 350718334Speter 350818334Speter if (class == MODE_FLOAT) 350990075Sobrien prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp); 351018334Speter 351118334Speter else 351218334Speter abort (); 351318334Speter} 351418334Speter 351590075Sobrien/* Before emitting an insn with code ICODE, make sure that X, which is going 351690075Sobrien to be used for operand OPNUM of the insn, is converted from mode MODE to 351790075Sobrien WIDER_MODE (UNSIGNEDP determines whether it is an unsigned conversion), and 351890075Sobrien that it is accepted by the operand predicate. Return the new value. */ 351990075Sobrien 352090075Sobrienrtx 352190075Sobrienprepare_operand (icode, x, opnum, mode, wider_mode, unsignedp) 352290075Sobrien int icode; 352390075Sobrien rtx x; 352490075Sobrien int opnum; 352590075Sobrien enum machine_mode mode, wider_mode; 352690075Sobrien int unsignedp; 352790075Sobrien{ 352890075Sobrien x = protect_from_queue (x, 0); 352990075Sobrien 353090075Sobrien if (mode != wider_mode) 353190075Sobrien x = convert_modes (wider_mode, mode, x, unsignedp); 353290075Sobrien 353390075Sobrien if (! (*insn_data[icode].operand[opnum].predicate) 353490075Sobrien (x, insn_data[icode].operand[opnum].mode)) 3535119256Skan { 3536119256Skan if (no_new_pseudos) 3537119256Skan return NULL_RTX; 3538119256Skan x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x); 3539119256Skan } 3540119256Skan 354190075Sobrien return x; 354290075Sobrien} 354390075Sobrien 354490075Sobrien/* Subroutine of emit_cmp_and_jump_insns; this function is called when we know 354590075Sobrien we can do the comparison. 354690075Sobrien The arguments are the same as for emit_cmp_and_jump_insns; but LABEL may 354790075Sobrien be NULL_RTX which indicates that only a comparison is to be generated. */ 354890075Sobrien 354990075Sobrienstatic void 355090075Sobrienemit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label) 355190075Sobrien rtx x, y; 355290075Sobrien enum machine_mode mode; 355390075Sobrien enum rtx_code comparison; 355490075Sobrien int unsignedp; 355590075Sobrien rtx label; 355690075Sobrien{ 355790075Sobrien rtx test = gen_rtx_fmt_ee (comparison, mode, x, y); 355890075Sobrien enum mode_class class = GET_MODE_CLASS (mode); 355990075Sobrien enum machine_mode wider_mode = mode; 356090075Sobrien 356190075Sobrien /* Try combined insns first. */ 356290075Sobrien do 356390075Sobrien { 356490075Sobrien enum insn_code icode; 356590075Sobrien PUT_MODE (test, wider_mode); 356690075Sobrien 356790075Sobrien if (label) 356890075Sobrien { 3569117395Skan icode = cbranch_optab->handlers[(int) wider_mode].insn_code; 357090075Sobrien 357190075Sobrien if (icode != CODE_FOR_nothing 357290075Sobrien && (*insn_data[icode].operand[0].predicate) (test, wider_mode)) 357390075Sobrien { 357490075Sobrien x = prepare_operand (icode, x, 1, mode, wider_mode, unsignedp); 357590075Sobrien y = prepare_operand (icode, y, 2, mode, wider_mode, unsignedp); 357690075Sobrien emit_jump_insn (GEN_FCN (icode) (test, x, y, label)); 357790075Sobrien return; 357890075Sobrien } 357990075Sobrien } 358090075Sobrien 358190075Sobrien /* Handle some compares against zero. */ 358290075Sobrien icode = (int) tst_optab->handlers[(int) wider_mode].insn_code; 358390075Sobrien if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing) 358490075Sobrien { 358590075Sobrien x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp); 358690075Sobrien emit_insn (GEN_FCN (icode) (x)); 358790075Sobrien if (label) 358890075Sobrien emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label)); 358990075Sobrien return; 359090075Sobrien } 359190075Sobrien 359290075Sobrien /* Handle compares for which there is a directly suitable insn. */ 359390075Sobrien 359490075Sobrien icode = (int) cmp_optab->handlers[(int) wider_mode].insn_code; 359590075Sobrien if (icode != CODE_FOR_nothing) 359690075Sobrien { 359790075Sobrien x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp); 359890075Sobrien y = prepare_operand (icode, y, 1, mode, wider_mode, unsignedp); 359990075Sobrien emit_insn (GEN_FCN (icode) (x, y)); 360090075Sobrien if (label) 360190075Sobrien emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label)); 360290075Sobrien return; 360390075Sobrien } 360490075Sobrien 360590075Sobrien if (class != MODE_INT && class != MODE_FLOAT 360690075Sobrien && class != MODE_COMPLEX_FLOAT) 360790075Sobrien break; 360890075Sobrien 360990075Sobrien wider_mode = GET_MODE_WIDER_MODE (wider_mode); 3610117395Skan } 3611117395Skan while (wider_mode != VOIDmode); 361290075Sobrien 361390075Sobrien abort (); 361490075Sobrien} 361590075Sobrien 361652284Sobrien/* Generate code to compare X with Y so that the condition codes are 361752284Sobrien set and to jump to LABEL if the condition is true. If X is a 361852284Sobrien constant and Y is not a constant, then the comparison is swapped to 361952284Sobrien ensure that the comparison RTL has the canonical form. 362052284Sobrien 362152284Sobrien UNSIGNEDP nonzero says that X and Y are unsigned; this matters if they 362252284Sobrien need to be widened by emit_cmp_insn. UNSIGNEDP is also used to select 362352284Sobrien the proper branch condition code. 362452284Sobrien 362590075Sobrien If X and Y have mode BLKmode, then SIZE specifies the size of both X and Y. 362652284Sobrien 362752284Sobrien MODE is the mode of the inputs (in case they are const_int). 362852284Sobrien 362952284Sobrien COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). It will 363052284Sobrien be passed unchanged to emit_cmp_insn, then potentially converted into an 363152284Sobrien unsigned variant based on UNSIGNEDP to select a proper jump instruction. */ 363252284Sobrien 363352284Sobrienvoid 363490075Sobrienemit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, label) 363552284Sobrien rtx x, y; 363652284Sobrien enum rtx_code comparison; 363752284Sobrien rtx size; 363852284Sobrien enum machine_mode mode; 363952284Sobrien int unsignedp; 364052284Sobrien rtx label; 364152284Sobrien{ 364290075Sobrien rtx op0 = x, op1 = y; 364390075Sobrien 364490075Sobrien /* Swap operands and condition to ensure canonical RTL. */ 364590075Sobrien if (swap_commutative_operands_p (x, y)) 364652284Sobrien { 364790075Sobrien /* If we're not emitting a branch, this means some caller 364890075Sobrien is out of sync. */ 364990075Sobrien if (! label) 365090075Sobrien abort (); 365190075Sobrien 365290075Sobrien op0 = y, op1 = x; 365352284Sobrien comparison = swap_condition (comparison); 365452284Sobrien } 365552284Sobrien 365652284Sobrien#ifdef HAVE_cc0 365752284Sobrien /* If OP0 is still a constant, then both X and Y must be constants. Force 365852284Sobrien X into a register to avoid aborting in emit_cmp_insn due to non-canonical 365952284Sobrien RTL. */ 366052284Sobrien if (CONSTANT_P (op0)) 366152284Sobrien op0 = force_reg (mode, op0); 366252284Sobrien#endif 366352284Sobrien 366490075Sobrien emit_queue (); 366552284Sobrien if (unsignedp) 366652284Sobrien comparison = unsigned_condition (comparison); 366790075Sobrien 366890075Sobrien prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp, 366990075Sobrien ccp_jump); 367090075Sobrien emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label); 367152284Sobrien} 367252284Sobrien 367390075Sobrien/* Like emit_cmp_and_jump_insns, but generate only the comparison. */ 367452284Sobrien 367590075Sobrienvoid 367690075Sobrienemit_cmp_insn (x, y, comparison, size, mode, unsignedp) 367790075Sobrien rtx x, y; 367890075Sobrien enum rtx_code comparison; 367990075Sobrien rtx size; 368018334Speter enum machine_mode mode; 368190075Sobrien int unsignedp; 368218334Speter{ 368390075Sobrien emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, 0); 368418334Speter} 368518334Speter 368618334Speter/* Emit a library call comparison between floating point X and Y. 368718334Speter COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). */ 368818334Speter 368990075Sobrienstatic void 369090075Sobrienprepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp) 369190075Sobrien rtx *px, *py; 369290075Sobrien enum rtx_code *pcomparison; 369390075Sobrien enum machine_mode *pmode; 369490075Sobrien int *punsignedp; 369518334Speter{ 369690075Sobrien enum rtx_code comparison = *pcomparison; 3697117395Skan rtx tmp; 369890075Sobrien rtx x = *px = protect_from_queue (*px, 0); 369990075Sobrien rtx y = *py = protect_from_queue (*py, 0); 370018334Speter enum machine_mode mode = GET_MODE (x); 370118334Speter rtx libfunc = 0; 370250397Sobrien rtx result; 370318334Speter 370418334Speter if (mode == HFmode) 370518334Speter switch (comparison) 370618334Speter { 370718334Speter case EQ: 370818334Speter libfunc = eqhf2_libfunc; 370918334Speter break; 371018334Speter 371118334Speter case NE: 371218334Speter libfunc = nehf2_libfunc; 371318334Speter break; 371418334Speter 371518334Speter case GT: 371618334Speter libfunc = gthf2_libfunc; 3717117395Skan if (libfunc == NULL_RTX) 3718117395Skan { 3719117395Skan tmp = x; x = y; y = tmp; 3720117395Skan *pcomparison = LT; 3721117395Skan libfunc = lthf2_libfunc; 3722117395Skan } 372318334Speter break; 372418334Speter 372518334Speter case GE: 372618334Speter libfunc = gehf2_libfunc; 3727117395Skan if (libfunc == NULL_RTX) 3728117395Skan { 3729117395Skan tmp = x; x = y; y = tmp; 3730117395Skan *pcomparison = LE; 3731117395Skan libfunc = lehf2_libfunc; 3732117395Skan } 373318334Speter break; 373418334Speter 373518334Speter case LT: 373618334Speter libfunc = lthf2_libfunc; 3737117395Skan if (libfunc == NULL_RTX) 3738117395Skan { 3739117395Skan tmp = x; x = y; y = tmp; 3740117395Skan *pcomparison = GT; 3741117395Skan libfunc = gthf2_libfunc; 3742117395Skan } 374318334Speter break; 374418334Speter 374518334Speter case LE: 374618334Speter libfunc = lehf2_libfunc; 3747117395Skan if (libfunc == NULL_RTX) 3748117395Skan { 3749117395Skan tmp = x; x = y; y = tmp; 3750117395Skan *pcomparison = GE; 3751117395Skan libfunc = gehf2_libfunc; 3752117395Skan } 375318334Speter break; 375450397Sobrien 375590075Sobrien case UNORDERED: 375690075Sobrien libfunc = unordhf2_libfunc; 375790075Sobrien break; 375890075Sobrien 375950397Sobrien default: 376050397Sobrien break; 376118334Speter } 376218334Speter else if (mode == SFmode) 376318334Speter switch (comparison) 376418334Speter { 376518334Speter case EQ: 376618334Speter libfunc = eqsf2_libfunc; 376718334Speter break; 376818334Speter 376918334Speter case NE: 377018334Speter libfunc = nesf2_libfunc; 377118334Speter break; 377218334Speter 377318334Speter case GT: 377418334Speter libfunc = gtsf2_libfunc; 3775117395Skan if (libfunc == NULL_RTX) 3776117395Skan { 3777117395Skan tmp = x; x = y; y = tmp; 3778117395Skan *pcomparison = LT; 3779117395Skan libfunc = ltsf2_libfunc; 3780117395Skan } 378118334Speter break; 378218334Speter 378318334Speter case GE: 378418334Speter libfunc = gesf2_libfunc; 3785117395Skan if (libfunc == NULL_RTX) 3786117395Skan { 3787117395Skan tmp = x; x = y; y = tmp; 3788117395Skan *pcomparison = LE; 3789117395Skan libfunc = lesf2_libfunc; 3790117395Skan } 379118334Speter break; 379218334Speter 379318334Speter case LT: 379418334Speter libfunc = ltsf2_libfunc; 3795117395Skan if (libfunc == NULL_RTX) 3796117395Skan { 3797117395Skan tmp = x; x = y; y = tmp; 3798117395Skan *pcomparison = GT; 3799117395Skan libfunc = gtsf2_libfunc; 3800117395Skan } 380118334Speter break; 380218334Speter 380318334Speter case LE: 380418334Speter libfunc = lesf2_libfunc; 3805117395Skan if (libfunc == NULL_RTX) 3806117395Skan { 3807117395Skan tmp = x; x = y; y = tmp; 3808117395Skan *pcomparison = GE; 3809117395Skan libfunc = gesf2_libfunc; 3810117395Skan } 381118334Speter break; 381250397Sobrien 381390075Sobrien case UNORDERED: 381490075Sobrien libfunc = unordsf2_libfunc; 381590075Sobrien break; 381690075Sobrien 381750397Sobrien default: 381850397Sobrien break; 381918334Speter } 382018334Speter else if (mode == DFmode) 382118334Speter switch (comparison) 382218334Speter { 382318334Speter case EQ: 382418334Speter libfunc = eqdf2_libfunc; 382518334Speter break; 382618334Speter 382718334Speter case NE: 382818334Speter libfunc = nedf2_libfunc; 382918334Speter break; 383018334Speter 383118334Speter case GT: 383218334Speter libfunc = gtdf2_libfunc; 3833117395Skan if (libfunc == NULL_RTX) 3834117395Skan { 3835117395Skan tmp = x; x = y; y = tmp; 3836117395Skan *pcomparison = LT; 3837117395Skan libfunc = ltdf2_libfunc; 3838117395Skan } 383918334Speter break; 384018334Speter 384118334Speter case GE: 384218334Speter libfunc = gedf2_libfunc; 3843117395Skan if (libfunc == NULL_RTX) 3844117395Skan { 3845117395Skan tmp = x; x = y; y = tmp; 3846117395Skan *pcomparison = LE; 3847117395Skan libfunc = ledf2_libfunc; 3848117395Skan } 384918334Speter break; 385018334Speter 385118334Speter case LT: 385218334Speter libfunc = ltdf2_libfunc; 3853117395Skan if (libfunc == NULL_RTX) 3854117395Skan { 3855117395Skan tmp = x; x = y; y = tmp; 3856117395Skan *pcomparison = GT; 3857117395Skan libfunc = gtdf2_libfunc; 3858117395Skan } 385918334Speter break; 386018334Speter 386118334Speter case LE: 386218334Speter libfunc = ledf2_libfunc; 3863117395Skan if (libfunc == NULL_RTX) 3864117395Skan { 3865117395Skan tmp = x; x = y; y = tmp; 3866117395Skan *pcomparison = GE; 3867117395Skan libfunc = gedf2_libfunc; 3868117395Skan } 386918334Speter break; 387050397Sobrien 387190075Sobrien case UNORDERED: 387290075Sobrien libfunc = unorddf2_libfunc; 387390075Sobrien break; 387490075Sobrien 387550397Sobrien default: 387650397Sobrien break; 387718334Speter } 387818334Speter else if (mode == XFmode) 387918334Speter switch (comparison) 388018334Speter { 388118334Speter case EQ: 388218334Speter libfunc = eqxf2_libfunc; 388318334Speter break; 388418334Speter 388518334Speter case NE: 388618334Speter libfunc = nexf2_libfunc; 388718334Speter break; 388818334Speter 388918334Speter case GT: 389018334Speter libfunc = gtxf2_libfunc; 3891117395Skan if (libfunc == NULL_RTX) 3892117395Skan { 3893117395Skan tmp = x; x = y; y = tmp; 3894117395Skan *pcomparison = LT; 3895117395Skan libfunc = ltxf2_libfunc; 3896117395Skan } 389718334Speter break; 389818334Speter 389918334Speter case GE: 390018334Speter libfunc = gexf2_libfunc; 3901117395Skan if (libfunc == NULL_RTX) 3902117395Skan { 3903117395Skan tmp = x; x = y; y = tmp; 3904117395Skan *pcomparison = LE; 3905117395Skan libfunc = lexf2_libfunc; 3906117395Skan } 390718334Speter break; 390818334Speter 390918334Speter case LT: 391018334Speter libfunc = ltxf2_libfunc; 3911117395Skan if (libfunc == NULL_RTX) 3912117395Skan { 3913117395Skan tmp = x; x = y; y = tmp; 3914117395Skan *pcomparison = GT; 3915117395Skan libfunc = gtxf2_libfunc; 3916117395Skan } 391718334Speter break; 391818334Speter 391918334Speter case LE: 392018334Speter libfunc = lexf2_libfunc; 3921117395Skan if (libfunc == NULL_RTX) 3922117395Skan { 3923117395Skan tmp = x; x = y; y = tmp; 3924117395Skan *pcomparison = GE; 3925117395Skan libfunc = gexf2_libfunc; 3926117395Skan } 392718334Speter break; 392850397Sobrien 392990075Sobrien case UNORDERED: 393090075Sobrien libfunc = unordxf2_libfunc; 393190075Sobrien break; 393290075Sobrien 393350397Sobrien default: 393450397Sobrien break; 393518334Speter } 393618334Speter else if (mode == TFmode) 393718334Speter switch (comparison) 393818334Speter { 393918334Speter case EQ: 394018334Speter libfunc = eqtf2_libfunc; 394118334Speter break; 394218334Speter 394318334Speter case NE: 394418334Speter libfunc = netf2_libfunc; 394518334Speter break; 394618334Speter 394718334Speter case GT: 394818334Speter libfunc = gttf2_libfunc; 3949117395Skan if (libfunc == NULL_RTX) 3950117395Skan { 3951117395Skan tmp = x; x = y; y = tmp; 3952117395Skan *pcomparison = LT; 3953117395Skan libfunc = lttf2_libfunc; 3954117395Skan } 395518334Speter break; 395618334Speter 395718334Speter case GE: 395818334Speter libfunc = getf2_libfunc; 3959117395Skan if (libfunc == NULL_RTX) 3960117395Skan { 3961117395Skan tmp = x; x = y; y = tmp; 3962117395Skan *pcomparison = LE; 3963117395Skan libfunc = letf2_libfunc; 3964117395Skan } 396518334Speter break; 396618334Speter 396718334Speter case LT: 396818334Speter libfunc = lttf2_libfunc; 3969117395Skan if (libfunc == NULL_RTX) 3970117395Skan { 3971117395Skan tmp = x; x = y; y = tmp; 3972117395Skan *pcomparison = GT; 3973117395Skan libfunc = gttf2_libfunc; 3974117395Skan } 397518334Speter break; 397618334Speter 397718334Speter case LE: 397818334Speter libfunc = letf2_libfunc; 3979117395Skan if (libfunc == NULL_RTX) 3980117395Skan { 3981117395Skan tmp = x; x = y; y = tmp; 3982117395Skan *pcomparison = GE; 3983117395Skan libfunc = getf2_libfunc; 3984117395Skan } 398518334Speter break; 398650397Sobrien 398790075Sobrien case UNORDERED: 398890075Sobrien libfunc = unordtf2_libfunc; 398990075Sobrien break; 399090075Sobrien 399150397Sobrien default: 399250397Sobrien break; 399318334Speter } 399418334Speter else 399518334Speter { 399618334Speter enum machine_mode wider_mode; 399718334Speter 399818334Speter for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; 399918334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 400018334Speter { 400118334Speter if ((cmp_optab->handlers[(int) wider_mode].insn_code 400218334Speter != CODE_FOR_nothing) 400318334Speter || (cmp_optab->handlers[(int) wider_mode].libfunc != 0)) 400418334Speter { 400518334Speter x = protect_from_queue (x, 0); 400618334Speter y = protect_from_queue (y, 0); 400790075Sobrien *px = convert_to_mode (wider_mode, x, 0); 400890075Sobrien *py = convert_to_mode (wider_mode, y, 0); 400990075Sobrien prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp); 401018334Speter return; 401118334Speter } 401218334Speter } 401318334Speter abort (); 401418334Speter } 401518334Speter 401618334Speter if (libfunc == 0) 401718334Speter abort (); 401818334Speter 4019117395Skan result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK, 4020117395Skan word_mode, 2, x, mode, y, mode); 402190075Sobrien *px = result; 402290075Sobrien *py = const0_rtx; 402390075Sobrien *pmode = word_mode; 402490075Sobrien if (comparison == UNORDERED) 402590075Sobrien *pcomparison = NE; 402690075Sobrien#ifdef FLOAT_LIB_COMPARE_RETURNS_BOOL 402790075Sobrien else if (FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison)) 402890075Sobrien *pcomparison = NE; 402990075Sobrien#endif 403090075Sobrien *punsignedp = 0; 403118334Speter} 403218334Speter 403318334Speter/* Generate code to indirectly jump to a location given in the rtx LOC. */ 403418334Speter 403518334Spetervoid 403618334Speteremit_indirect_jump (loc) 403718334Speter rtx loc; 403818334Speter{ 4039117395Skan if (! ((*insn_data[(int) CODE_FOR_indirect_jump].operand[0].predicate) 404018334Speter (loc, Pmode))) 404118334Speter loc = copy_to_mode_reg (Pmode, loc); 404218334Speter 404318334Speter emit_jump_insn (gen_indirect_jump (loc)); 404418334Speter emit_barrier (); 404518334Speter} 404618334Speter 404718334Speter#ifdef HAVE_conditional_move 404818334Speter 404918334Speter/* Emit a conditional move instruction if the machine supports one for that 405018334Speter condition and machine mode. 405118334Speter 405218334Speter OP0 and OP1 are the operands that should be compared using CODE. CMODE is 405318334Speter the mode to use should they be constants. If it is VOIDmode, they cannot 405418334Speter both be constants. 405518334Speter 405618334Speter OP2 should be stored in TARGET if the comparison is true, otherwise OP3 405718334Speter should be stored there. MODE is the mode to use should they be constants. 405818334Speter If it is VOIDmode, they cannot both be constants. 405918334Speter 406018334Speter The result is either TARGET (perhaps modified) or NULL_RTX if the operation 406118334Speter is not supported. */ 406218334Speter 406318334Speterrtx 406418334Speteremit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode, 406518334Speter unsignedp) 406618334Speter rtx target; 406718334Speter enum rtx_code code; 406818334Speter rtx op0, op1; 406918334Speter enum machine_mode cmode; 407018334Speter rtx op2, op3; 407118334Speter enum machine_mode mode; 407218334Speter int unsignedp; 407318334Speter{ 407418334Speter rtx tem, subtarget, comparison, insn; 407518334Speter enum insn_code icode; 407690075Sobrien enum rtx_code reversed; 407718334Speter 407818334Speter /* If one operand is constant, make it the second one. Only do this 407918334Speter if the other operand is not constant as well. */ 408018334Speter 408190075Sobrien if (swap_commutative_operands_p (op0, op1)) 408218334Speter { 408318334Speter tem = op0; 408418334Speter op0 = op1; 408518334Speter op1 = tem; 408618334Speter code = swap_condition (code); 408718334Speter } 408818334Speter 408990075Sobrien /* get_condition will prefer to generate LT and GT even if the old 409090075Sobrien comparison was against zero, so undo that canonicalization here since 409190075Sobrien comparisons against zero are cheaper. */ 409290075Sobrien if (code == LT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == 1) 409390075Sobrien code = LE, op1 = const0_rtx; 409490075Sobrien else if (code == GT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == -1) 409590075Sobrien code = GE, op1 = const0_rtx; 409690075Sobrien 409718334Speter if (cmode == VOIDmode) 409818334Speter cmode = GET_MODE (op0); 409918334Speter 410090075Sobrien if (swap_commutative_operands_p (op2, op3) 410190075Sobrien && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL)) 410290075Sobrien != UNKNOWN)) 410318334Speter { 410418334Speter tem = op2; 410518334Speter op2 = op3; 410618334Speter op3 = tem; 410790075Sobrien code = reversed; 410818334Speter } 410918334Speter 411018334Speter if (mode == VOIDmode) 411118334Speter mode = GET_MODE (op2); 411218334Speter 411318334Speter icode = movcc_gen_code[mode]; 411418334Speter 411518334Speter if (icode == CODE_FOR_nothing) 411618334Speter return 0; 411718334Speter 411818334Speter if (flag_force_mem) 411918334Speter { 412018334Speter op2 = force_not_mem (op2); 412118334Speter op3 = force_not_mem (op3); 412218334Speter } 412318334Speter 412418334Speter if (target) 412518334Speter target = protect_from_queue (target, 1); 412618334Speter else 412718334Speter target = gen_reg_rtx (mode); 412818334Speter 412918334Speter subtarget = target; 413018334Speter 413118334Speter emit_queue (); 413218334Speter 413318334Speter op2 = protect_from_queue (op2, 0); 413418334Speter op3 = protect_from_queue (op3, 0); 413518334Speter 413618334Speter /* If the insn doesn't accept these operands, put them in pseudos. */ 413718334Speter 413890075Sobrien if (! (*insn_data[icode].operand[0].predicate) 413990075Sobrien (subtarget, insn_data[icode].operand[0].mode)) 414090075Sobrien subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode); 414118334Speter 414290075Sobrien if (! (*insn_data[icode].operand[2].predicate) 414390075Sobrien (op2, insn_data[icode].operand[2].mode)) 414490075Sobrien op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2); 414518334Speter 414690075Sobrien if (! (*insn_data[icode].operand[3].predicate) 414790075Sobrien (op3, insn_data[icode].operand[3].mode)) 414890075Sobrien op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3); 414918334Speter 415018334Speter /* Everything should now be in the suitable form, so emit the compare insn 415118334Speter and then the conditional move. */ 415218334Speter 415318334Speter comparison 415490075Sobrien = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX); 415518334Speter 415618334Speter /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)? */ 415790075Sobrien /* We can get const0_rtx or const_true_rtx in some circumstances. Just 415890075Sobrien return NULL and let the caller figure out how best to deal with this 415990075Sobrien situation. */ 416018334Speter if (GET_CODE (comparison) != code) 416190075Sobrien return NULL_RTX; 416218334Speter 416318334Speter insn = GEN_FCN (icode) (subtarget, comparison, op2, op3); 416418334Speter 416518334Speter /* If that failed, then give up. */ 416618334Speter if (insn == 0) 416718334Speter return 0; 416818334Speter 416918334Speter emit_insn (insn); 417018334Speter 417118334Speter if (subtarget != target) 417218334Speter convert_move (target, subtarget, 0); 417318334Speter 417418334Speter return target; 417518334Speter} 417618334Speter 4177117395Skan/* Return nonzero if a conditional move of mode MODE is supported. 417818334Speter 417918334Speter This function is for combine so it can tell whether an insn that looks 418018334Speter like a conditional move is actually supported by the hardware. If we 418118334Speter guess wrong we lose a bit on optimization, but that's it. */ 418218334Speter/* ??? sparc64 supports conditionally moving integers values based on fp 418318334Speter comparisons, and vice versa. How do we handle them? */ 418418334Speter 418518334Speterint 418618334Spetercan_conditionally_move_p (mode) 418718334Speter enum machine_mode mode; 418818334Speter{ 418918334Speter if (movcc_gen_code[mode] != CODE_FOR_nothing) 419018334Speter return 1; 419118334Speter 419218334Speter return 0; 419318334Speter} 419418334Speter 419518334Speter#endif /* HAVE_conditional_move */ 419618334Speter 419790075Sobrien/* These functions generate an insn body and return it 419818334Speter rather than emitting the insn. 419918334Speter 420018334Speter They do not protect from queued increments, 420118334Speter because they may be used 1) in protect_from_queue itself 420218334Speter and 2) in other passes where there is no queue. */ 420318334Speter 420418334Speter/* Generate and return an insn body to add Y to X. */ 420518334Speter 420618334Speterrtx 420718334Spetergen_add2_insn (x, y) 420818334Speter rtx x, y; 420918334Speter{ 421018334Speter int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code; 421118334Speter 421290075Sobrien if (! ((*insn_data[icode].operand[0].predicate) 421390075Sobrien (x, insn_data[icode].operand[0].mode)) 421490075Sobrien || ! ((*insn_data[icode].operand[1].predicate) 421590075Sobrien (x, insn_data[icode].operand[1].mode)) 421690075Sobrien || ! ((*insn_data[icode].operand[2].predicate) 421790075Sobrien (y, insn_data[icode].operand[2].mode))) 421818334Speter abort (); 421918334Speter 422018334Speter return (GEN_FCN (icode) (x, x, y)); 422118334Speter} 422218334Speter 422390075Sobrien/* Generate and return an insn body to add r1 and c, 422490075Sobrien storing the result in r0. */ 422590075Sobrienrtx 422690075Sobriengen_add3_insn (r0, r1, c) 422790075Sobrien rtx r0, r1, c; 422890075Sobrien{ 422990075Sobrien int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code; 423090075Sobrien 4231117395Skan if (icode == CODE_FOR_nothing 423290075Sobrien || ! ((*insn_data[icode].operand[0].predicate) 423390075Sobrien (r0, insn_data[icode].operand[0].mode)) 423490075Sobrien || ! ((*insn_data[icode].operand[1].predicate) 423590075Sobrien (r1, insn_data[icode].operand[1].mode)) 423690075Sobrien || ! ((*insn_data[icode].operand[2].predicate) 423790075Sobrien (c, insn_data[icode].operand[2].mode))) 423890075Sobrien return NULL_RTX; 423990075Sobrien 424090075Sobrien return (GEN_FCN (icode) (r0, r1, c)); 424190075Sobrien} 424290075Sobrien 424318334Speterint 424490075Sobrienhave_add2_insn (x, y) 424590075Sobrien rtx x, y; 424618334Speter{ 424790075Sobrien int icode; 424890075Sobrien 424990075Sobrien if (GET_MODE (x) == VOIDmode) 425090075Sobrien abort (); 425190075Sobrien 425290075Sobrien icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code; 425390075Sobrien 425490075Sobrien if (icode == CODE_FOR_nothing) 425590075Sobrien return 0; 425690075Sobrien 425790075Sobrien if (! ((*insn_data[icode].operand[0].predicate) 425890075Sobrien (x, insn_data[icode].operand[0].mode)) 425990075Sobrien || ! ((*insn_data[icode].operand[1].predicate) 426090075Sobrien (x, insn_data[icode].operand[1].mode)) 426190075Sobrien || ! ((*insn_data[icode].operand[2].predicate) 426290075Sobrien (y, insn_data[icode].operand[2].mode))) 426390075Sobrien return 0; 426490075Sobrien 426590075Sobrien return 1; 426618334Speter} 426718334Speter 426818334Speter/* Generate and return an insn body to subtract Y from X. */ 426918334Speter 427018334Speterrtx 427118334Spetergen_sub2_insn (x, y) 427218334Speter rtx x, y; 427318334Speter{ 427418334Speter int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code; 427518334Speter 427690075Sobrien if (! ((*insn_data[icode].operand[0].predicate) 427790075Sobrien (x, insn_data[icode].operand[0].mode)) 427890075Sobrien || ! ((*insn_data[icode].operand[1].predicate) 427990075Sobrien (x, insn_data[icode].operand[1].mode)) 428090075Sobrien || ! ((*insn_data[icode].operand[2].predicate) 428190075Sobrien (y, insn_data[icode].operand[2].mode))) 428218334Speter abort (); 428318334Speter 428418334Speter return (GEN_FCN (icode) (x, x, y)); 428518334Speter} 428618334Speter 428790075Sobrien/* Generate and return an insn body to subtract r1 and c, 428890075Sobrien storing the result in r0. */ 428990075Sobrienrtx 429090075Sobriengen_sub3_insn (r0, r1, c) 429190075Sobrien rtx r0, r1, c; 429290075Sobrien{ 429390075Sobrien int icode = (int) sub_optab->handlers[(int) GET_MODE (r0)].insn_code; 429490075Sobrien 4295117395Skan if (icode == CODE_FOR_nothing 429690075Sobrien || ! ((*insn_data[icode].operand[0].predicate) 429790075Sobrien (r0, insn_data[icode].operand[0].mode)) 429890075Sobrien || ! ((*insn_data[icode].operand[1].predicate) 429990075Sobrien (r1, insn_data[icode].operand[1].mode)) 430090075Sobrien || ! ((*insn_data[icode].operand[2].predicate) 430190075Sobrien (c, insn_data[icode].operand[2].mode))) 430290075Sobrien return NULL_RTX; 430390075Sobrien 430490075Sobrien return (GEN_FCN (icode) (r0, r1, c)); 430590075Sobrien} 430690075Sobrien 430718334Speterint 430890075Sobrienhave_sub2_insn (x, y) 430990075Sobrien rtx x, y; 431018334Speter{ 431190075Sobrien int icode; 431290075Sobrien 431390075Sobrien if (GET_MODE (x) == VOIDmode) 431490075Sobrien abort (); 431590075Sobrien 431690075Sobrien icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code; 431790075Sobrien 431890075Sobrien if (icode == CODE_FOR_nothing) 431990075Sobrien return 0; 432090075Sobrien 432190075Sobrien if (! ((*insn_data[icode].operand[0].predicate) 432290075Sobrien (x, insn_data[icode].operand[0].mode)) 432390075Sobrien || ! ((*insn_data[icode].operand[1].predicate) 432490075Sobrien (x, insn_data[icode].operand[1].mode)) 432590075Sobrien || ! ((*insn_data[icode].operand[2].predicate) 432690075Sobrien (y, insn_data[icode].operand[2].mode))) 432790075Sobrien return 0; 432890075Sobrien 432990075Sobrien return 1; 433018334Speter} 433118334Speter 433218334Speter/* Generate the body of an instruction to copy Y into X. 4333117395Skan It may be a list of insns, if one insn isn't enough. */ 433418334Speter 433518334Speterrtx 433618334Spetergen_move_insn (x, y) 433718334Speter rtx x, y; 433818334Speter{ 433990075Sobrien enum machine_mode mode = GET_MODE (x); 434018334Speter enum insn_code insn_code; 434118334Speter rtx seq; 434218334Speter 434318334Speter if (mode == VOIDmode) 434418334Speter mode = GET_MODE (y); 434518334Speter 434618334Speter insn_code = mov_optab->handlers[(int) mode].insn_code; 434718334Speter 434818334Speter /* Handle MODE_CC modes: If we don't have a special move insn for this mode, 434918334Speter find a mode to do it in. If we have a movcc, use it. Otherwise, 435018334Speter find the MODE_INT mode of the same width. */ 435118334Speter 435218334Speter if (GET_MODE_CLASS (mode) == MODE_CC && insn_code == CODE_FOR_nothing) 435318334Speter { 435418334Speter enum machine_mode tmode = VOIDmode; 435518334Speter rtx x1 = x, y1 = y; 435618334Speter 435718334Speter if (mode != CCmode 435818334Speter && mov_optab->handlers[(int) CCmode].insn_code != CODE_FOR_nothing) 435918334Speter tmode = CCmode; 436018334Speter else 436118334Speter for (tmode = QImode; tmode != VOIDmode; 436218334Speter tmode = GET_MODE_WIDER_MODE (tmode)) 436318334Speter if (GET_MODE_SIZE (tmode) == GET_MODE_SIZE (mode)) 436418334Speter break; 436518334Speter 436618334Speter if (tmode == VOIDmode) 436718334Speter abort (); 436818334Speter 436918334Speter /* Get X and Y in TMODE. We can't use gen_lowpart here because it 437018334Speter may call change_address which is not appropriate if we were 437118334Speter called when a reload was in progress. We don't have to worry 437218334Speter about changing the address since the size in bytes is supposed to 437318334Speter be the same. Copy the MEM to change the mode and move any 437418334Speter substitutions from the old MEM to the new one. */ 437518334Speter 437618334Speter if (reload_in_progress) 437718334Speter { 437818334Speter x = gen_lowpart_common (tmode, x1); 437918334Speter if (x == 0 && GET_CODE (x1) == MEM) 438018334Speter { 438190075Sobrien x = adjust_address_nv (x1, tmode, 0); 438218334Speter copy_replacements (x1, x); 438318334Speter } 438418334Speter 438518334Speter y = gen_lowpart_common (tmode, y1); 438618334Speter if (y == 0 && GET_CODE (y1) == MEM) 438718334Speter { 438890075Sobrien y = adjust_address_nv (y1, tmode, 0); 438918334Speter copy_replacements (y1, y); 439018334Speter } 439118334Speter } 439218334Speter else 439318334Speter { 439418334Speter x = gen_lowpart (tmode, x); 439518334Speter y = gen_lowpart (tmode, y); 439618334Speter } 439718334Speter 439818334Speter insn_code = mov_optab->handlers[(int) tmode].insn_code; 439918334Speter return (GEN_FCN (insn_code) (x, y)); 440018334Speter } 440118334Speter 440218334Speter start_sequence (); 440318334Speter emit_move_insn_1 (x, y); 4404117395Skan seq = get_insns (); 440518334Speter end_sequence (); 440618334Speter return seq; 440718334Speter} 440818334Speter 440918334Speter/* Return the insn code used to extend FROM_MODE to TO_MODE. 441018334Speter UNSIGNEDP specifies zero-extension instead of sign-extension. If 441118334Speter no such operation exists, CODE_FOR_nothing will be returned. */ 441218334Speter 441318334Speterenum insn_code 441418334Spetercan_extend_p (to_mode, from_mode, unsignedp) 441518334Speter enum machine_mode to_mode, from_mode; 441618334Speter int unsignedp; 441718334Speter{ 441890075Sobrien#ifdef HAVE_ptr_extend 441990075Sobrien if (unsignedp < 0) 442090075Sobrien return CODE_FOR_ptr_extend; 442190075Sobrien else 442290075Sobrien#endif 442390075Sobrien return extendtab[(int) to_mode][(int) from_mode][unsignedp != 0]; 442418334Speter} 442518334Speter 442618334Speter/* Generate the body of an insn to extend Y (with mode MFROM) 442718334Speter into X (with mode MTO). Do zero-extension if UNSIGNEDP is nonzero. */ 442818334Speter 442918334Speterrtx 443018334Spetergen_extend_insn (x, y, mto, mfrom, unsignedp) 443118334Speter rtx x, y; 443218334Speter enum machine_mode mto, mfrom; 443318334Speter int unsignedp; 443418334Speter{ 443590075Sobrien return (GEN_FCN (extendtab[(int) mto][(int) mfrom][unsignedp != 0]) (x, y)); 443618334Speter} 443718334Speter 443818334Speter/* can_fix_p and can_float_p say whether the target machine 443918334Speter can directly convert a given fixed point type to 444018334Speter a given floating point type, or vice versa. 444118334Speter The returned value is the CODE_FOR_... value to use, 444218334Speter or CODE_FOR_nothing if these modes cannot be directly converted. 444318334Speter 444418334Speter *TRUNCP_PTR is set to 1 if it is necessary to output 444518334Speter an explicit FTRUNC insn before the fix insn; otherwise 0. */ 444618334Speter 444718334Speterstatic enum insn_code 444818334Spetercan_fix_p (fixmode, fltmode, unsignedp, truncp_ptr) 444918334Speter enum machine_mode fltmode, fixmode; 445018334Speter int unsignedp; 445118334Speter int *truncp_ptr; 445218334Speter{ 445318334Speter *truncp_ptr = 0; 445490075Sobrien if (fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0] 445590075Sobrien != CODE_FOR_nothing) 445690075Sobrien return fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0]; 445718334Speter 445818334Speter if (ftrunc_optab->handlers[(int) fltmode].insn_code != CODE_FOR_nothing) 445918334Speter { 446018334Speter *truncp_ptr = 1; 446190075Sobrien return fixtab[(int) fltmode][(int) fixmode][unsignedp != 0]; 446218334Speter } 446318334Speter return CODE_FOR_nothing; 446418334Speter} 446518334Speter 446618334Speterstatic enum insn_code 446718334Spetercan_float_p (fltmode, fixmode, unsignedp) 446818334Speter enum machine_mode fixmode, fltmode; 446918334Speter int unsignedp; 447018334Speter{ 447190075Sobrien return floattab[(int) fltmode][(int) fixmode][unsignedp != 0]; 447218334Speter} 447318334Speter 447418334Speter/* Generate code to convert FROM to floating point 447518334Speter and store in TO. FROM must be fixed point and not VOIDmode. 447618334Speter UNSIGNEDP nonzero means regard FROM as unsigned. 447718334Speter Normally this is done by correcting the final value 447818334Speter if it is negative. */ 447918334Speter 448018334Spetervoid 448118334Speterexpand_float (to, from, unsignedp) 448218334Speter rtx to, from; 448318334Speter int unsignedp; 448418334Speter{ 448518334Speter enum insn_code icode; 448690075Sobrien rtx target = to; 448718334Speter enum machine_mode fmode, imode; 448818334Speter 448918334Speter /* Crash now, because we won't be able to decide which mode to use. */ 449018334Speter if (GET_MODE (from) == VOIDmode) 449118334Speter abort (); 449218334Speter 449318334Speter /* Look for an insn to do the conversion. Do it in the specified 449418334Speter modes if possible; otherwise convert either input, output or both to 449518334Speter wider mode. If the integer mode is wider than the mode of FROM, 449618334Speter we can do the conversion signed even if the input is unsigned. */ 449718334Speter 4498117395Skan for (fmode = GET_MODE (to); fmode != VOIDmode; 4499117395Skan fmode = GET_MODE_WIDER_MODE (fmode)) 4500117395Skan for (imode = GET_MODE (from); imode != VOIDmode; 4501117395Skan imode = GET_MODE_WIDER_MODE (imode)) 450218334Speter { 450318334Speter int doing_unsigned = unsignedp; 450418334Speter 450590075Sobrien if (fmode != GET_MODE (to) 450690075Sobrien && significand_size (fmode) < GET_MODE_BITSIZE (GET_MODE (from))) 450790075Sobrien continue; 450890075Sobrien 450918334Speter icode = can_float_p (fmode, imode, unsignedp); 451018334Speter if (icode == CODE_FOR_nothing && imode != GET_MODE (from) && unsignedp) 451118334Speter icode = can_float_p (fmode, imode, 0), doing_unsigned = 0; 451218334Speter 451318334Speter if (icode != CODE_FOR_nothing) 451418334Speter { 451518334Speter to = protect_from_queue (to, 1); 451618334Speter from = protect_from_queue (from, 0); 451718334Speter 451818334Speter if (imode != GET_MODE (from)) 451918334Speter from = convert_to_mode (imode, from, unsignedp); 452018334Speter 452118334Speter if (fmode != GET_MODE (to)) 452218334Speter target = gen_reg_rtx (fmode); 452318334Speter 452418334Speter emit_unop_insn (icode, target, from, 452518334Speter doing_unsigned ? UNSIGNED_FLOAT : FLOAT); 452618334Speter 452718334Speter if (target != to) 452818334Speter convert_move (to, target, 0); 452918334Speter return; 453018334Speter } 4531117395Skan } 453218334Speter 453318334Speter /* Unsigned integer, and no way to convert directly. 453418334Speter Convert as signed, then conditionally adjust the result. */ 453518334Speter if (unsignedp) 453618334Speter { 453718334Speter rtx label = gen_label_rtx (); 453818334Speter rtx temp; 453918334Speter REAL_VALUE_TYPE offset; 454018334Speter 454118334Speter emit_queue (); 454218334Speter 454318334Speter to = protect_from_queue (to, 1); 454418334Speter from = protect_from_queue (from, 0); 454518334Speter 454618334Speter if (flag_force_mem) 454718334Speter from = force_not_mem (from); 454818334Speter 454918334Speter /* Look for a usable floating mode FMODE wider than the source and at 455018334Speter least as wide as the target. Using FMODE will avoid rounding woes 455118334Speter with unsigned values greater than the signed maximum value. */ 455218334Speter 455318334Speter for (fmode = GET_MODE (to); fmode != VOIDmode; 455418334Speter fmode = GET_MODE_WIDER_MODE (fmode)) 455518334Speter if (GET_MODE_BITSIZE (GET_MODE (from)) < GET_MODE_BITSIZE (fmode) 455618334Speter && can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing) 455718334Speter break; 455818334Speter 455918334Speter if (fmode == VOIDmode) 456018334Speter { 456118334Speter /* There is no such mode. Pretend the target is wide enough. */ 456218334Speter fmode = GET_MODE (to); 456318334Speter 456450397Sobrien /* Avoid double-rounding when TO is narrower than FROM. */ 456518334Speter if ((significand_size (fmode) + 1) 456618334Speter < GET_MODE_BITSIZE (GET_MODE (from))) 456718334Speter { 456818334Speter rtx temp1; 456918334Speter rtx neglabel = gen_label_rtx (); 457018334Speter 457118334Speter /* Don't use TARGET if it isn't a register, is a hard register, 457218334Speter or is the wrong mode. */ 457318334Speter if (GET_CODE (target) != REG 457418334Speter || REGNO (target) < FIRST_PSEUDO_REGISTER 457518334Speter || GET_MODE (target) != fmode) 457618334Speter target = gen_reg_rtx (fmode); 457718334Speter 457818334Speter imode = GET_MODE (from); 457918334Speter do_pending_stack_adjust (); 458018334Speter 458118334Speter /* Test whether the sign bit is set. */ 458290075Sobrien emit_cmp_and_jump_insns (from, const0_rtx, LT, NULL_RTX, imode, 458390075Sobrien 0, neglabel); 458418334Speter 458518334Speter /* The sign bit is not set. Convert as signed. */ 458618334Speter expand_float (target, from, 0); 458718334Speter emit_jump_insn (gen_jump (label)); 458818334Speter emit_barrier (); 458918334Speter 459018334Speter /* The sign bit is set. 459118334Speter Convert to a usable (positive signed) value by shifting right 459218334Speter one bit, while remembering if a nonzero bit was shifted 459318334Speter out; i.e., compute (from & 1) | (from >> 1). */ 459418334Speter 459518334Speter emit_label (neglabel); 459618334Speter temp = expand_binop (imode, and_optab, from, const1_rtx, 459718334Speter NULL_RTX, 1, OPTAB_LIB_WIDEN); 459818334Speter temp1 = expand_shift (RSHIFT_EXPR, imode, from, integer_one_node, 459918334Speter NULL_RTX, 1); 460018334Speter temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1, 460118334Speter OPTAB_LIB_WIDEN); 460218334Speter expand_float (target, temp, 0); 460318334Speter 460418334Speter /* Multiply by 2 to undo the shift above. */ 460518334Speter temp = expand_binop (fmode, add_optab, target, target, 4606117395Skan target, 0, OPTAB_LIB_WIDEN); 460718334Speter if (temp != target) 460818334Speter emit_move_insn (target, temp); 460918334Speter 461018334Speter do_pending_stack_adjust (); 461118334Speter emit_label (label); 461218334Speter goto done; 461318334Speter } 461418334Speter } 461518334Speter 461618334Speter /* If we are about to do some arithmetic to correct for an 461718334Speter unsigned operand, do it in a pseudo-register. */ 461818334Speter 461918334Speter if (GET_MODE (to) != fmode 462018334Speter || GET_CODE (to) != REG || REGNO (to) < FIRST_PSEUDO_REGISTER) 462118334Speter target = gen_reg_rtx (fmode); 462218334Speter 462318334Speter /* Convert as signed integer to floating. */ 462418334Speter expand_float (target, from, 0); 462518334Speter 462618334Speter /* If FROM is negative (and therefore TO is negative), 462718334Speter correct its value by 2**bitwidth. */ 462818334Speter 462918334Speter do_pending_stack_adjust (); 463052284Sobrien emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from), 463190075Sobrien 0, label); 463218334Speter 4633117395Skan 4634117395Skan real_2expN (&offset, GET_MODE_BITSIZE (GET_MODE (from))); 463518334Speter temp = expand_binop (fmode, add_optab, target, 463618334Speter CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode), 463718334Speter target, 0, OPTAB_LIB_WIDEN); 463818334Speter if (temp != target) 463918334Speter emit_move_insn (target, temp); 464018334Speter 464118334Speter do_pending_stack_adjust (); 464218334Speter emit_label (label); 464318334Speter goto done; 464418334Speter } 464518334Speter 464618334Speter /* No hardware instruction available; call a library routine to convert from 464718334Speter SImode, DImode, or TImode into SFmode, DFmode, XFmode, or TFmode. */ 464818334Speter { 464918334Speter rtx libfcn; 465018334Speter rtx insns; 465118334Speter rtx value; 465218334Speter 465318334Speter to = protect_from_queue (to, 1); 465418334Speter from = protect_from_queue (from, 0); 465518334Speter 465618334Speter if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode)) 465718334Speter from = convert_to_mode (SImode, from, unsignedp); 465818334Speter 465918334Speter if (flag_force_mem) 466018334Speter from = force_not_mem (from); 466118334Speter 466218334Speter if (GET_MODE (to) == SFmode) 466318334Speter { 466418334Speter if (GET_MODE (from) == SImode) 466518334Speter libfcn = floatsisf_libfunc; 466618334Speter else if (GET_MODE (from) == DImode) 466718334Speter libfcn = floatdisf_libfunc; 466818334Speter else if (GET_MODE (from) == TImode) 466918334Speter libfcn = floattisf_libfunc; 467018334Speter else 467118334Speter abort (); 467218334Speter } 467318334Speter else if (GET_MODE (to) == DFmode) 467418334Speter { 467518334Speter if (GET_MODE (from) == SImode) 467618334Speter libfcn = floatsidf_libfunc; 467718334Speter else if (GET_MODE (from) == DImode) 467818334Speter libfcn = floatdidf_libfunc; 467918334Speter else if (GET_MODE (from) == TImode) 468018334Speter libfcn = floattidf_libfunc; 468118334Speter else 468218334Speter abort (); 468318334Speter } 468418334Speter else if (GET_MODE (to) == XFmode) 468518334Speter { 468618334Speter if (GET_MODE (from) == SImode) 468718334Speter libfcn = floatsixf_libfunc; 468818334Speter else if (GET_MODE (from) == DImode) 468918334Speter libfcn = floatdixf_libfunc; 469018334Speter else if (GET_MODE (from) == TImode) 469118334Speter libfcn = floattixf_libfunc; 469218334Speter else 469318334Speter abort (); 469418334Speter } 469518334Speter else if (GET_MODE (to) == TFmode) 469618334Speter { 469718334Speter if (GET_MODE (from) == SImode) 469818334Speter libfcn = floatsitf_libfunc; 469918334Speter else if (GET_MODE (from) == DImode) 470018334Speter libfcn = floatditf_libfunc; 470118334Speter else if (GET_MODE (from) == TImode) 470218334Speter libfcn = floattitf_libfunc; 470318334Speter else 470418334Speter abort (); 470518334Speter } 470618334Speter else 470718334Speter abort (); 470818334Speter 470918334Speter start_sequence (); 471018334Speter 471190075Sobrien value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST, 471290075Sobrien GET_MODE (to), 1, from, 471390075Sobrien GET_MODE (from)); 471418334Speter insns = get_insns (); 471518334Speter end_sequence (); 471618334Speter 471718334Speter emit_libcall_block (insns, target, value, 471850397Sobrien gen_rtx_FLOAT (GET_MODE (to), from)); 471918334Speter } 472018334Speter 472118334Speter done: 472218334Speter 472318334Speter /* Copy result to requested destination 472418334Speter if we have been computing in a temp location. */ 472518334Speter 472618334Speter if (target != to) 472718334Speter { 472818334Speter if (GET_MODE (target) == GET_MODE (to)) 472918334Speter emit_move_insn (to, target); 473018334Speter else 473118334Speter convert_move (to, target, 0); 473218334Speter } 473318334Speter} 473418334Speter 473518334Speter/* expand_fix: generate code to convert FROM to fixed point 473618334Speter and store in TO. FROM must be floating point. */ 473718334Speter 473818334Speterstatic rtx 473918334Speterftruncify (x) 474018334Speter rtx x; 474118334Speter{ 474218334Speter rtx temp = gen_reg_rtx (GET_MODE (x)); 474318334Speter return expand_unop (GET_MODE (x), ftrunc_optab, x, temp, 0); 474418334Speter} 474518334Speter 474618334Spetervoid 474718334Speterexpand_fix (to, from, unsignedp) 474890075Sobrien rtx to, from; 474918334Speter int unsignedp; 475018334Speter{ 475118334Speter enum insn_code icode; 475290075Sobrien rtx target = to; 475318334Speter enum machine_mode fmode, imode; 475418334Speter int must_trunc = 0; 475518334Speter rtx libfcn = 0; 475618334Speter 475718334Speter /* We first try to find a pair of modes, one real and one integer, at 475818334Speter least as wide as FROM and TO, respectively, in which we can open-code 475918334Speter this conversion. If the integer mode is wider than the mode of TO, 476018334Speter we can do the conversion either signed or unsigned. */ 476118334Speter 476290075Sobrien for (fmode = GET_MODE (from); fmode != VOIDmode; 476390075Sobrien fmode = GET_MODE_WIDER_MODE (fmode)) 476490075Sobrien for (imode = GET_MODE (to); imode != VOIDmode; 476590075Sobrien imode = GET_MODE_WIDER_MODE (imode)) 476618334Speter { 476718334Speter int doing_unsigned = unsignedp; 476818334Speter 476918334Speter icode = can_fix_p (imode, fmode, unsignedp, &must_trunc); 477018334Speter if (icode == CODE_FOR_nothing && imode != GET_MODE (to) && unsignedp) 477118334Speter icode = can_fix_p (imode, fmode, 0, &must_trunc), doing_unsigned = 0; 477218334Speter 477318334Speter if (icode != CODE_FOR_nothing) 477418334Speter { 477518334Speter to = protect_from_queue (to, 1); 477618334Speter from = protect_from_queue (from, 0); 477718334Speter 477818334Speter if (fmode != GET_MODE (from)) 477918334Speter from = convert_to_mode (fmode, from, 0); 478018334Speter 478118334Speter if (must_trunc) 478218334Speter from = ftruncify (from); 478318334Speter 478418334Speter if (imode != GET_MODE (to)) 478518334Speter target = gen_reg_rtx (imode); 478618334Speter 478718334Speter emit_unop_insn (icode, target, from, 478818334Speter doing_unsigned ? UNSIGNED_FIX : FIX); 478918334Speter if (target != to) 479018334Speter convert_move (to, target, unsignedp); 479118334Speter return; 479218334Speter } 479318334Speter } 479418334Speter 479518334Speter /* For an unsigned conversion, there is one more way to do it. 479618334Speter If we have a signed conversion, we generate code that compares 479718334Speter the real value to the largest representable positive number. If if 479818334Speter is smaller, the conversion is done normally. Otherwise, subtract 479918334Speter one plus the highest signed number, convert, and add it back. 480018334Speter 480118334Speter We only need to check all real modes, since we know we didn't find 480218334Speter anything with a wider integer mode. */ 480318334Speter 480418334Speter if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT) 480518334Speter for (fmode = GET_MODE (from); fmode != VOIDmode; 480618334Speter fmode = GET_MODE_WIDER_MODE (fmode)) 480718334Speter /* Make sure we won't lose significant bits doing this. */ 480818334Speter if (GET_MODE_BITSIZE (fmode) > GET_MODE_BITSIZE (GET_MODE (to)) 480918334Speter && CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0, 481018334Speter &must_trunc)) 481118334Speter { 481218334Speter int bitsize; 481318334Speter REAL_VALUE_TYPE offset; 481418334Speter rtx limit, lab1, lab2, insn; 481518334Speter 481618334Speter bitsize = GET_MODE_BITSIZE (GET_MODE (to)); 4817117395Skan real_2expN (&offset, bitsize - 1); 481818334Speter limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode); 481918334Speter lab1 = gen_label_rtx (); 482018334Speter lab2 = gen_label_rtx (); 482118334Speter 482218334Speter emit_queue (); 482318334Speter to = protect_from_queue (to, 1); 482418334Speter from = protect_from_queue (from, 0); 482518334Speter 482618334Speter if (flag_force_mem) 482718334Speter from = force_not_mem (from); 482818334Speter 482918334Speter if (fmode != GET_MODE (from)) 483018334Speter from = convert_to_mode (fmode, from, 0); 483118334Speter 483218334Speter /* See if we need to do the subtraction. */ 483318334Speter do_pending_stack_adjust (); 483452284Sobrien emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, GET_MODE (from), 483590075Sobrien 0, lab1); 483618334Speter 483718334Speter /* If not, do the signed "fix" and branch around fixup code. */ 483818334Speter expand_fix (to, from, 0); 483918334Speter emit_jump_insn (gen_jump (lab2)); 484018334Speter emit_barrier (); 484118334Speter 484218334Speter /* Otherwise, subtract 2**(N-1), convert to signed number, 484318334Speter then add 2**(N-1). Do the addition using XOR since this 484418334Speter will often generate better code. */ 484518334Speter emit_label (lab1); 484618334Speter target = expand_binop (GET_MODE (from), sub_optab, from, limit, 484718334Speter NULL_RTX, 0, OPTAB_LIB_WIDEN); 484818334Speter expand_fix (to, target, 0); 484918334Speter target = expand_binop (GET_MODE (to), xor_optab, to, 4850117395Skan gen_int_mode 4851117395Skan ((HOST_WIDE_INT) 1 << (bitsize - 1), 4852117395Skan GET_MODE (to)), 485318334Speter to, 1, OPTAB_LIB_WIDEN); 485418334Speter 485518334Speter if (target != to) 485618334Speter emit_move_insn (to, target); 485718334Speter 485818334Speter emit_label (lab2); 485918334Speter 486050397Sobrien if (mov_optab->handlers[(int) GET_MODE (to)].insn_code 486150397Sobrien != CODE_FOR_nothing) 486250397Sobrien { 486350397Sobrien /* Make a place for a REG_NOTE and add it. */ 486450397Sobrien insn = emit_move_insn (to, to); 486552284Sobrien set_unique_reg_note (insn, 486652284Sobrien REG_EQUAL, 486752284Sobrien gen_rtx_fmt_e (UNSIGNED_FIX, 486852284Sobrien GET_MODE (to), 486952284Sobrien copy_rtx (from))); 487050397Sobrien } 487190075Sobrien 487218334Speter return; 487318334Speter } 487418334Speter 487518334Speter /* We can't do it with an insn, so use a library call. But first ensure 487618334Speter that the mode of TO is at least as wide as SImode, since those are the 487718334Speter only library calls we know about. */ 487818334Speter 487918334Speter if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode)) 488018334Speter { 488118334Speter target = gen_reg_rtx (SImode); 488218334Speter 488318334Speter expand_fix (target, from, unsignedp); 488418334Speter } 488518334Speter else if (GET_MODE (from) == SFmode) 488618334Speter { 488718334Speter if (GET_MODE (to) == SImode) 488818334Speter libfcn = unsignedp ? fixunssfsi_libfunc : fixsfsi_libfunc; 488918334Speter else if (GET_MODE (to) == DImode) 489018334Speter libfcn = unsignedp ? fixunssfdi_libfunc : fixsfdi_libfunc; 489118334Speter else if (GET_MODE (to) == TImode) 489218334Speter libfcn = unsignedp ? fixunssfti_libfunc : fixsfti_libfunc; 489318334Speter else 489418334Speter abort (); 489518334Speter } 489618334Speter else if (GET_MODE (from) == DFmode) 489718334Speter { 489818334Speter if (GET_MODE (to) == SImode) 489918334Speter libfcn = unsignedp ? fixunsdfsi_libfunc : fixdfsi_libfunc; 490018334Speter else if (GET_MODE (to) == DImode) 490118334Speter libfcn = unsignedp ? fixunsdfdi_libfunc : fixdfdi_libfunc; 490218334Speter else if (GET_MODE (to) == TImode) 490318334Speter libfcn = unsignedp ? fixunsdfti_libfunc : fixdfti_libfunc; 490418334Speter else 490518334Speter abort (); 490618334Speter } 490718334Speter else if (GET_MODE (from) == XFmode) 490818334Speter { 490918334Speter if (GET_MODE (to) == SImode) 491018334Speter libfcn = unsignedp ? fixunsxfsi_libfunc : fixxfsi_libfunc; 491118334Speter else if (GET_MODE (to) == DImode) 491218334Speter libfcn = unsignedp ? fixunsxfdi_libfunc : fixxfdi_libfunc; 491318334Speter else if (GET_MODE (to) == TImode) 491418334Speter libfcn = unsignedp ? fixunsxfti_libfunc : fixxfti_libfunc; 491518334Speter else 491618334Speter abort (); 491718334Speter } 491818334Speter else if (GET_MODE (from) == TFmode) 491918334Speter { 492018334Speter if (GET_MODE (to) == SImode) 492118334Speter libfcn = unsignedp ? fixunstfsi_libfunc : fixtfsi_libfunc; 492218334Speter else if (GET_MODE (to) == DImode) 492318334Speter libfcn = unsignedp ? fixunstfdi_libfunc : fixtfdi_libfunc; 492418334Speter else if (GET_MODE (to) == TImode) 492518334Speter libfcn = unsignedp ? fixunstfti_libfunc : fixtfti_libfunc; 492618334Speter else 492718334Speter abort (); 492818334Speter } 492918334Speter else 493018334Speter abort (); 493118334Speter 493218334Speter if (libfcn) 493318334Speter { 493418334Speter rtx insns; 493518334Speter rtx value; 493618334Speter 493718334Speter to = protect_from_queue (to, 1); 493818334Speter from = protect_from_queue (from, 0); 493918334Speter 494018334Speter if (flag_force_mem) 494118334Speter from = force_not_mem (from); 494218334Speter 494318334Speter start_sequence (); 494418334Speter 494590075Sobrien value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST, 494690075Sobrien GET_MODE (to), 1, from, 494790075Sobrien GET_MODE (from)); 494818334Speter insns = get_insns (); 494918334Speter end_sequence (); 495018334Speter 495118334Speter emit_libcall_block (insns, target, value, 495250397Sobrien gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX, 495350397Sobrien GET_MODE (to), from)); 495418334Speter } 495518334Speter 495650397Sobrien if (target != to) 495750397Sobrien { 495850397Sobrien if (GET_MODE (to) == GET_MODE (target)) 495950397Sobrien emit_move_insn (to, target); 496050397Sobrien else 496150397Sobrien convert_move (to, target, 0); 496250397Sobrien } 496318334Speter} 496418334Speter 496590075Sobrien/* Report whether we have an instruction to perform the operation 496690075Sobrien specified by CODE on operands of mode MODE. */ 496790075Sobrienint 496890075Sobrienhave_insn_for (code, mode) 496918334Speter enum rtx_code code; 497090075Sobrien enum machine_mode mode; 497118334Speter{ 497290075Sobrien return (code_to_optab[(int) code] != 0 497390075Sobrien && (code_to_optab[(int) code]->handlers[(int) mode].insn_code 497490075Sobrien != CODE_FOR_nothing)); 497590075Sobrien} 497690075Sobrien 497790075Sobrien/* Create a blank optab. */ 497890075Sobrienstatic optab 497990075Sobriennew_optab () 498090075Sobrien{ 498118334Speter int i; 4982117395Skan optab op = (optab) ggc_alloc (sizeof (struct optab)); 498318334Speter for (i = 0; i < NUM_MACHINE_MODES; i++) 498418334Speter { 498518334Speter op->handlers[i].insn_code = CODE_FOR_nothing; 498618334Speter op->handlers[i].libfunc = 0; 498718334Speter } 498818334Speter 498990075Sobrien return op; 499090075Sobrien} 499118334Speter 499290075Sobrien/* Same, but fill in its code as CODE, and write it into the 499390075Sobrien code_to_optab table. */ 499490075Sobrienstatic inline optab 499590075Sobrieninit_optab (code) 499690075Sobrien enum rtx_code code; 499790075Sobrien{ 499890075Sobrien optab op = new_optab (); 499990075Sobrien op->code = code; 500090075Sobrien code_to_optab[(int) code] = op; 500118334Speter return op; 500218334Speter} 500318334Speter 500490075Sobrien/* Same, but fill in its code as CODE, and do _not_ write it into 500590075Sobrien the code_to_optab table. */ 500690075Sobrienstatic inline optab 500790075Sobrieninit_optabv (code) 500890075Sobrien enum rtx_code code; 500990075Sobrien{ 501090075Sobrien optab op = new_optab (); 501190075Sobrien op->code = code; 501290075Sobrien return op; 501390075Sobrien} 501490075Sobrien 501518334Speter/* Initialize the libfunc fields of an entire group of entries in some 501618334Speter optab. Each entry is set equal to a string consisting of a leading 501718334Speter pair of underscores followed by a generic operation name followed by 501818334Speter a mode name (downshifted to lower case) followed by a single character 501918334Speter representing the number of operands for the given operation (which is 502018334Speter usually one of the characters '2', '3', or '4'). 502118334Speter 502218334Speter OPTABLE is the table in which libfunc fields are to be initialized. 502318334Speter FIRST_MODE is the first machine mode index in the given optab to 502418334Speter initialize. 502518334Speter LAST_MODE is the last machine mode index in the given optab to 502618334Speter initialize. 502718334Speter OPNAME is the generic (string) name of the operation. 502818334Speter SUFFIX is the character which specifies the number of operands for 502918334Speter the given generic operation. 503018334Speter*/ 503118334Speter 503218334Speterstatic void 503318334Speterinit_libfuncs (optable, first_mode, last_mode, opname, suffix) 5034117395Skan optab optable; 5035117395Skan int first_mode; 5036117395Skan int last_mode; 5037117395Skan const char *opname; 5038117395Skan int suffix; 503918334Speter{ 504090075Sobrien int mode; 504190075Sobrien unsigned opname_len = strlen (opname); 504218334Speter 504318334Speter for (mode = first_mode; (int) mode <= (int) last_mode; 504418334Speter mode = (enum machine_mode) ((int) mode + 1)) 504518334Speter { 5046117395Skan const char *mname = GET_MODE_NAME (mode); 504790075Sobrien unsigned mname_len = strlen (mname); 504890075Sobrien char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1); 504990075Sobrien char *p; 505090075Sobrien const char *q; 505118334Speter 505218334Speter p = libfunc_name; 505318334Speter *p++ = '_'; 505418334Speter *p++ = '_'; 505518334Speter for (q = opname; *q; ) 505618334Speter *p++ = *q++; 505718334Speter for (q = mname; *q; q++) 505890075Sobrien *p++ = TOLOWER (*q); 505918334Speter *p++ = suffix; 506090075Sobrien *p = '\0'; 506190075Sobrien 506218334Speter optable->handlers[(int) mode].libfunc 506390075Sobrien = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (libfunc_name, 506490075Sobrien p - libfunc_name)); 506518334Speter } 506618334Speter} 506718334Speter 506818334Speter/* Initialize the libfunc fields of an entire group of entries in some 506918334Speter optab which correspond to all integer mode operations. The parameters 507018334Speter have the same meaning as similarly named ones for the `init_libfuncs' 507118334Speter routine. (See above). */ 507218334Speter 507318334Speterstatic void 507418334Speterinit_integral_libfuncs (optable, opname, suffix) 5075117395Skan optab optable; 5076117395Skan const char *opname; 5077117395Skan int suffix; 507818334Speter{ 507918334Speter init_libfuncs (optable, SImode, TImode, opname, suffix); 508018334Speter} 508118334Speter 508218334Speter/* Initialize the libfunc fields of an entire group of entries in some 508318334Speter optab which correspond to all real mode operations. The parameters 508418334Speter have the same meaning as similarly named ones for the `init_libfuncs' 508518334Speter routine. (See above). */ 508618334Speter 508718334Speterstatic void 508818334Speterinit_floating_libfuncs (optable, opname, suffix) 5089117395Skan optab optable; 5090117395Skan const char *opname; 5091117395Skan int suffix; 509218334Speter{ 509318334Speter init_libfuncs (optable, SFmode, TFmode, opname, suffix); 509418334Speter} 509518334Speter 509690075Sobrienrtx 509790075Sobrieninit_one_libfunc (name) 509890075Sobrien const char *name; 509990075Sobrien{ 5100117395Skan /* Create a FUNCTION_DECL that can be passed to 5101117395Skan targetm.encode_section_info. */ 510290075Sobrien /* ??? We don't have any type information except for this is 510390075Sobrien a function. Pretend this is "int foo()". */ 510490075Sobrien tree decl = build_decl (FUNCTION_DECL, get_identifier (name), 510590075Sobrien build_function_type (integer_type_node, NULL_TREE)); 510690075Sobrien DECL_ARTIFICIAL (decl) = 1; 510790075Sobrien DECL_EXTERNAL (decl) = 1; 510890075Sobrien TREE_PUBLIC (decl) = 1; 510918334Speter 511090075Sobrien /* Return the symbol_ref from the mem rtx. */ 511190075Sobrien return XEXP (DECL_RTL (decl), 0); 511290075Sobrien} 511390075Sobrien 511418334Speter/* Call this once to initialize the contents of the optabs 511518334Speter appropriately for the current target machine. */ 511618334Speter 511718334Spetervoid 511818334Speterinit_optabs () 511918334Speter{ 512090075Sobrien unsigned int i, j, k; 512150397Sobrien 512218334Speter /* Start by initializing all tables to contain CODE_FOR_nothing. */ 512318334Speter 512490075Sobrien for (i = 0; i < ARRAY_SIZE (fixtab); i++) 512590075Sobrien for (j = 0; j < ARRAY_SIZE (fixtab[0]); j++) 512690075Sobrien for (k = 0; k < ARRAY_SIZE (fixtab[0][0]); k++) 512790075Sobrien fixtab[i][j][k] = CODE_FOR_nothing; 512818334Speter 512990075Sobrien for (i = 0; i < ARRAY_SIZE (fixtrunctab); i++) 513090075Sobrien for (j = 0; j < ARRAY_SIZE (fixtrunctab[0]); j++) 513190075Sobrien for (k = 0; k < ARRAY_SIZE (fixtrunctab[0][0]); k++) 513290075Sobrien fixtrunctab[i][j][k] = CODE_FOR_nothing; 513318334Speter 513490075Sobrien for (i = 0; i < ARRAY_SIZE (floattab); i++) 513590075Sobrien for (j = 0; j < ARRAY_SIZE (floattab[0]); j++) 513690075Sobrien for (k = 0; k < ARRAY_SIZE (floattab[0][0]); k++) 513790075Sobrien floattab[i][j][k] = CODE_FOR_nothing; 513818334Speter 513990075Sobrien for (i = 0; i < ARRAY_SIZE (extendtab); i++) 514090075Sobrien for (j = 0; j < ARRAY_SIZE (extendtab[0]); j++) 514190075Sobrien for (k = 0; k < ARRAY_SIZE (extendtab[0][0]); k++) 514290075Sobrien extendtab[i][j][k] = CODE_FOR_nothing; 514318334Speter 514418334Speter for (i = 0; i < NUM_RTX_CODE; i++) 514518334Speter setcc_gen_code[i] = CODE_FOR_nothing; 514618334Speter 514718334Speter#ifdef HAVE_conditional_move 514818334Speter for (i = 0; i < NUM_MACHINE_MODES; i++) 514918334Speter movcc_gen_code[i] = CODE_FOR_nothing; 515018334Speter#endif 515118334Speter 515218334Speter add_optab = init_optab (PLUS); 515390075Sobrien addv_optab = init_optabv (PLUS); 515418334Speter sub_optab = init_optab (MINUS); 515590075Sobrien subv_optab = init_optabv (MINUS); 515618334Speter smul_optab = init_optab (MULT); 515790075Sobrien smulv_optab = init_optabv (MULT); 515818334Speter smul_highpart_optab = init_optab (UNKNOWN); 515918334Speter umul_highpart_optab = init_optab (UNKNOWN); 516018334Speter smul_widen_optab = init_optab (UNKNOWN); 516118334Speter umul_widen_optab = init_optab (UNKNOWN); 516218334Speter sdiv_optab = init_optab (DIV); 516390075Sobrien sdivv_optab = init_optabv (DIV); 516418334Speter sdivmod_optab = init_optab (UNKNOWN); 516518334Speter udiv_optab = init_optab (UDIV); 516618334Speter udivmod_optab = init_optab (UNKNOWN); 516718334Speter smod_optab = init_optab (MOD); 516818334Speter umod_optab = init_optab (UMOD); 516918334Speter ftrunc_optab = init_optab (UNKNOWN); 517018334Speter and_optab = init_optab (AND); 517118334Speter ior_optab = init_optab (IOR); 517218334Speter xor_optab = init_optab (XOR); 517318334Speter ashl_optab = init_optab (ASHIFT); 517418334Speter ashr_optab = init_optab (ASHIFTRT); 517518334Speter lshr_optab = init_optab (LSHIFTRT); 517618334Speter rotl_optab = init_optab (ROTATE); 517718334Speter rotr_optab = init_optab (ROTATERT); 517818334Speter smin_optab = init_optab (SMIN); 517918334Speter smax_optab = init_optab (SMAX); 518018334Speter umin_optab = init_optab (UMIN); 518118334Speter umax_optab = init_optab (UMAX); 518290075Sobrien 518390075Sobrien /* These three have codes assigned exclusively for the sake of 518490075Sobrien have_insn_for. */ 518590075Sobrien mov_optab = init_optab (SET); 518690075Sobrien movstrict_optab = init_optab (STRICT_LOW_PART); 518790075Sobrien cmp_optab = init_optab (COMPARE); 518890075Sobrien 518918334Speter ucmp_optab = init_optab (UNKNOWN); 519018334Speter tst_optab = init_optab (UNKNOWN); 519118334Speter neg_optab = init_optab (NEG); 519290075Sobrien negv_optab = init_optabv (NEG); 519318334Speter abs_optab = init_optab (ABS); 519490075Sobrien absv_optab = init_optabv (ABS); 519518334Speter one_cmpl_optab = init_optab (NOT); 519618334Speter ffs_optab = init_optab (FFS); 519718334Speter sqrt_optab = init_optab (SQRT); 519818334Speter sin_optab = init_optab (UNKNOWN); 519918334Speter cos_optab = init_optab (UNKNOWN); 5200117395Skan exp_optab = init_optab (UNKNOWN); 5201117395Skan log_optab = init_optab (UNKNOWN); 520218334Speter strlen_optab = init_optab (UNKNOWN); 520390075Sobrien cbranch_optab = init_optab (UNKNOWN); 520490075Sobrien cmov_optab = init_optab (UNKNOWN); 520590075Sobrien cstore_optab = init_optab (UNKNOWN); 520690075Sobrien push_optab = init_optab (UNKNOWN); 520718334Speter 520818334Speter for (i = 0; i < NUM_MACHINE_MODES; i++) 520918334Speter { 521018334Speter movstr_optab[i] = CODE_FOR_nothing; 521150397Sobrien clrstr_optab[i] = CODE_FOR_nothing; 521218334Speter 521318334Speter#ifdef HAVE_SECONDARY_RELOADS 521418334Speter reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing; 521518334Speter#endif 521618334Speter } 521718334Speter 521818334Speter /* Fill in the optabs with the insns we support. */ 521918334Speter init_all_optabs (); 522018334Speter 522118334Speter#ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC 522218334Speter /* This flag says the same insns that convert to a signed fixnum 522318334Speter also convert validly to an unsigned one. */ 522418334Speter for (i = 0; i < NUM_MACHINE_MODES; i++) 522518334Speter for (j = 0; j < NUM_MACHINE_MODES; j++) 522618334Speter fixtrunctab[i][j][1] = fixtrunctab[i][j][0]; 522718334Speter#endif 522818334Speter 522918334Speter /* Initialize the optabs with the names of the library functions. */ 523018334Speter init_integral_libfuncs (add_optab, "add", '3'); 523118334Speter init_floating_libfuncs (add_optab, "add", '3'); 523290075Sobrien init_integral_libfuncs (addv_optab, "addv", '3'); 523390075Sobrien init_floating_libfuncs (addv_optab, "add", '3'); 523418334Speter init_integral_libfuncs (sub_optab, "sub", '3'); 523518334Speter init_floating_libfuncs (sub_optab, "sub", '3'); 523690075Sobrien init_integral_libfuncs (subv_optab, "subv", '3'); 523790075Sobrien init_floating_libfuncs (subv_optab, "sub", '3'); 523818334Speter init_integral_libfuncs (smul_optab, "mul", '3'); 523918334Speter init_floating_libfuncs (smul_optab, "mul", '3'); 524090075Sobrien init_integral_libfuncs (smulv_optab, "mulv", '3'); 524190075Sobrien init_floating_libfuncs (smulv_optab, "mul", '3'); 524218334Speter init_integral_libfuncs (sdiv_optab, "div", '3'); 524390075Sobrien init_floating_libfuncs (sdiv_optab, "div", '3'); 524490075Sobrien init_integral_libfuncs (sdivv_optab, "divv", '3'); 524518334Speter init_integral_libfuncs (udiv_optab, "udiv", '3'); 524618334Speter init_integral_libfuncs (sdivmod_optab, "divmod", '4'); 524718334Speter init_integral_libfuncs (udivmod_optab, "udivmod", '4'); 524818334Speter init_integral_libfuncs (smod_optab, "mod", '3'); 524918334Speter init_integral_libfuncs (umod_optab, "umod", '3'); 525018334Speter init_floating_libfuncs (ftrunc_optab, "ftrunc", '2'); 525118334Speter init_integral_libfuncs (and_optab, "and", '3'); 525218334Speter init_integral_libfuncs (ior_optab, "ior", '3'); 525318334Speter init_integral_libfuncs (xor_optab, "xor", '3'); 525418334Speter init_integral_libfuncs (ashl_optab, "ashl", '3'); 525518334Speter init_integral_libfuncs (ashr_optab, "ashr", '3'); 525618334Speter init_integral_libfuncs (lshr_optab, "lshr", '3'); 525718334Speter init_integral_libfuncs (smin_optab, "min", '3'); 525818334Speter init_floating_libfuncs (smin_optab, "min", '3'); 525918334Speter init_integral_libfuncs (smax_optab, "max", '3'); 526018334Speter init_floating_libfuncs (smax_optab, "max", '3'); 526118334Speter init_integral_libfuncs (umin_optab, "umin", '3'); 526218334Speter init_integral_libfuncs (umax_optab, "umax", '3'); 526318334Speter init_integral_libfuncs (neg_optab, "neg", '2'); 526418334Speter init_floating_libfuncs (neg_optab, "neg", '2'); 526590075Sobrien init_integral_libfuncs (negv_optab, "negv", '2'); 526690075Sobrien init_floating_libfuncs (negv_optab, "neg", '2'); 526718334Speter init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2'); 526818334Speter init_integral_libfuncs (ffs_optab, "ffs", '2'); 526918334Speter 527018334Speter /* Comparison libcalls for integers MUST come in pairs, signed/unsigned. */ 527118334Speter init_integral_libfuncs (cmp_optab, "cmp", '2'); 527218334Speter init_integral_libfuncs (ucmp_optab, "ucmp", '2'); 527318334Speter init_floating_libfuncs (cmp_optab, "cmp", '2'); 527418334Speter 527518334Speter#ifdef MULSI3_LIBCALL 527618334Speter smul_optab->handlers[(int) SImode].libfunc 527790075Sobrien = init_one_libfunc (MULSI3_LIBCALL); 527818334Speter#endif 527918334Speter#ifdef MULDI3_LIBCALL 528018334Speter smul_optab->handlers[(int) DImode].libfunc 528190075Sobrien = init_one_libfunc (MULDI3_LIBCALL); 528218334Speter#endif 528318334Speter 528418334Speter#ifdef DIVSI3_LIBCALL 528518334Speter sdiv_optab->handlers[(int) SImode].libfunc 528690075Sobrien = init_one_libfunc (DIVSI3_LIBCALL); 528718334Speter#endif 528818334Speter#ifdef DIVDI3_LIBCALL 528918334Speter sdiv_optab->handlers[(int) DImode].libfunc 529090075Sobrien = init_one_libfunc (DIVDI3_LIBCALL); 529118334Speter#endif 529218334Speter 529318334Speter#ifdef UDIVSI3_LIBCALL 529418334Speter udiv_optab->handlers[(int) SImode].libfunc 529590075Sobrien = init_one_libfunc (UDIVSI3_LIBCALL); 529618334Speter#endif 529718334Speter#ifdef UDIVDI3_LIBCALL 529818334Speter udiv_optab->handlers[(int) DImode].libfunc 529990075Sobrien = init_one_libfunc (UDIVDI3_LIBCALL); 530018334Speter#endif 530118334Speter 530218334Speter#ifdef MODSI3_LIBCALL 530318334Speter smod_optab->handlers[(int) SImode].libfunc 530490075Sobrien = init_one_libfunc (MODSI3_LIBCALL); 530518334Speter#endif 530618334Speter#ifdef MODDI3_LIBCALL 530718334Speter smod_optab->handlers[(int) DImode].libfunc 530890075Sobrien = init_one_libfunc (MODDI3_LIBCALL); 530918334Speter#endif 531018334Speter 531118334Speter#ifdef UMODSI3_LIBCALL 531218334Speter umod_optab->handlers[(int) SImode].libfunc 531390075Sobrien = init_one_libfunc (UMODSI3_LIBCALL); 531418334Speter#endif 531518334Speter#ifdef UMODDI3_LIBCALL 531618334Speter umod_optab->handlers[(int) DImode].libfunc 531790075Sobrien = init_one_libfunc (UMODDI3_LIBCALL); 531818334Speter#endif 531918334Speter 532018334Speter /* Use cabs for DC complex abs, since systems generally have cabs. 532118334Speter Don't define any libcall for SCmode, so that cabs will be used. */ 532218334Speter abs_optab->handlers[(int) DCmode].libfunc 532390075Sobrien = init_one_libfunc ("cabs"); 532418334Speter 532518334Speter /* The ffs function operates on `int'. */ 532690075Sobrien ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc 532790075Sobrien = init_one_libfunc ("ffs"); 532818334Speter 532990075Sobrien extendsfdf2_libfunc = init_one_libfunc ("__extendsfdf2"); 533090075Sobrien extendsfxf2_libfunc = init_one_libfunc ("__extendsfxf2"); 533190075Sobrien extendsftf2_libfunc = init_one_libfunc ("__extendsftf2"); 533290075Sobrien extenddfxf2_libfunc = init_one_libfunc ("__extenddfxf2"); 533390075Sobrien extenddftf2_libfunc = init_one_libfunc ("__extenddftf2"); 533418334Speter 533590075Sobrien truncdfsf2_libfunc = init_one_libfunc ("__truncdfsf2"); 533690075Sobrien truncxfsf2_libfunc = init_one_libfunc ("__truncxfsf2"); 533790075Sobrien trunctfsf2_libfunc = init_one_libfunc ("__trunctfsf2"); 533890075Sobrien truncxfdf2_libfunc = init_one_libfunc ("__truncxfdf2"); 533990075Sobrien trunctfdf2_libfunc = init_one_libfunc ("__trunctfdf2"); 534018334Speter 534196263Sobrien abort_libfunc = init_one_libfunc ("abort"); 534290075Sobrien memcpy_libfunc = init_one_libfunc ("memcpy"); 534390075Sobrien memmove_libfunc = init_one_libfunc ("memmove"); 534490075Sobrien bcopy_libfunc = init_one_libfunc ("bcopy"); 534590075Sobrien memcmp_libfunc = init_one_libfunc ("memcmp"); 534690075Sobrien bcmp_libfunc = init_one_libfunc ("__gcc_bcmp"); 534790075Sobrien memset_libfunc = init_one_libfunc ("memset"); 534890075Sobrien bzero_libfunc = init_one_libfunc ("bzero"); 534918334Speter 535090075Sobrien unwind_resume_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS 535190075Sobrien ? "_Unwind_SjLj_Resume" 535290075Sobrien : "_Unwind_Resume"); 535350397Sobrien#ifndef DONT_USE_BUILTIN_SETJMP 535490075Sobrien setjmp_libfunc = init_one_libfunc ("__builtin_setjmp"); 535590075Sobrien longjmp_libfunc = init_one_libfunc ("__builtin_longjmp"); 535650397Sobrien#else 535790075Sobrien setjmp_libfunc = init_one_libfunc ("setjmp"); 535890075Sobrien longjmp_libfunc = init_one_libfunc ("longjmp"); 535950397Sobrien#endif 536090075Sobrien unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register"); 536190075Sobrien unwind_sjlj_unregister_libfunc 536290075Sobrien = init_one_libfunc ("_Unwind_SjLj_Unregister"); 536318334Speter 536490075Sobrien eqhf2_libfunc = init_one_libfunc ("__eqhf2"); 536590075Sobrien nehf2_libfunc = init_one_libfunc ("__nehf2"); 536690075Sobrien gthf2_libfunc = init_one_libfunc ("__gthf2"); 536790075Sobrien gehf2_libfunc = init_one_libfunc ("__gehf2"); 536890075Sobrien lthf2_libfunc = init_one_libfunc ("__lthf2"); 536990075Sobrien lehf2_libfunc = init_one_libfunc ("__lehf2"); 537090075Sobrien unordhf2_libfunc = init_one_libfunc ("__unordhf2"); 537118334Speter 537290075Sobrien eqsf2_libfunc = init_one_libfunc ("__eqsf2"); 537390075Sobrien nesf2_libfunc = init_one_libfunc ("__nesf2"); 537490075Sobrien gtsf2_libfunc = init_one_libfunc ("__gtsf2"); 537590075Sobrien gesf2_libfunc = init_one_libfunc ("__gesf2"); 537690075Sobrien ltsf2_libfunc = init_one_libfunc ("__ltsf2"); 537790075Sobrien lesf2_libfunc = init_one_libfunc ("__lesf2"); 537890075Sobrien unordsf2_libfunc = init_one_libfunc ("__unordsf2"); 537918334Speter 538090075Sobrien eqdf2_libfunc = init_one_libfunc ("__eqdf2"); 538190075Sobrien nedf2_libfunc = init_one_libfunc ("__nedf2"); 538290075Sobrien gtdf2_libfunc = init_one_libfunc ("__gtdf2"); 538390075Sobrien gedf2_libfunc = init_one_libfunc ("__gedf2"); 538490075Sobrien ltdf2_libfunc = init_one_libfunc ("__ltdf2"); 538590075Sobrien ledf2_libfunc = init_one_libfunc ("__ledf2"); 538690075Sobrien unorddf2_libfunc = init_one_libfunc ("__unorddf2"); 538718334Speter 538890075Sobrien eqxf2_libfunc = init_one_libfunc ("__eqxf2"); 538990075Sobrien nexf2_libfunc = init_one_libfunc ("__nexf2"); 539090075Sobrien gtxf2_libfunc = init_one_libfunc ("__gtxf2"); 539190075Sobrien gexf2_libfunc = init_one_libfunc ("__gexf2"); 539290075Sobrien ltxf2_libfunc = init_one_libfunc ("__ltxf2"); 539390075Sobrien lexf2_libfunc = init_one_libfunc ("__lexf2"); 539490075Sobrien unordxf2_libfunc = init_one_libfunc ("__unordxf2"); 539518334Speter 539690075Sobrien eqtf2_libfunc = init_one_libfunc ("__eqtf2"); 539790075Sobrien netf2_libfunc = init_one_libfunc ("__netf2"); 539890075Sobrien gttf2_libfunc = init_one_libfunc ("__gttf2"); 539990075Sobrien getf2_libfunc = init_one_libfunc ("__getf2"); 540090075Sobrien lttf2_libfunc = init_one_libfunc ("__lttf2"); 540190075Sobrien letf2_libfunc = init_one_libfunc ("__letf2"); 540290075Sobrien unordtf2_libfunc = init_one_libfunc ("__unordtf2"); 540318334Speter 540490075Sobrien floatsisf_libfunc = init_one_libfunc ("__floatsisf"); 540590075Sobrien floatdisf_libfunc = init_one_libfunc ("__floatdisf"); 540690075Sobrien floattisf_libfunc = init_one_libfunc ("__floattisf"); 540718334Speter 540890075Sobrien floatsidf_libfunc = init_one_libfunc ("__floatsidf"); 540990075Sobrien floatdidf_libfunc = init_one_libfunc ("__floatdidf"); 541090075Sobrien floattidf_libfunc = init_one_libfunc ("__floattidf"); 541118334Speter 541290075Sobrien floatsixf_libfunc = init_one_libfunc ("__floatsixf"); 541390075Sobrien floatdixf_libfunc = init_one_libfunc ("__floatdixf"); 541490075Sobrien floattixf_libfunc = init_one_libfunc ("__floattixf"); 541518334Speter 541690075Sobrien floatsitf_libfunc = init_one_libfunc ("__floatsitf"); 541790075Sobrien floatditf_libfunc = init_one_libfunc ("__floatditf"); 541890075Sobrien floattitf_libfunc = init_one_libfunc ("__floattitf"); 541918334Speter 542090075Sobrien fixsfsi_libfunc = init_one_libfunc ("__fixsfsi"); 542190075Sobrien fixsfdi_libfunc = init_one_libfunc ("__fixsfdi"); 542290075Sobrien fixsfti_libfunc = init_one_libfunc ("__fixsfti"); 542318334Speter 542490075Sobrien fixdfsi_libfunc = init_one_libfunc ("__fixdfsi"); 542590075Sobrien fixdfdi_libfunc = init_one_libfunc ("__fixdfdi"); 542690075Sobrien fixdfti_libfunc = init_one_libfunc ("__fixdfti"); 542718334Speter 542890075Sobrien fixxfsi_libfunc = init_one_libfunc ("__fixxfsi"); 542990075Sobrien fixxfdi_libfunc = init_one_libfunc ("__fixxfdi"); 543090075Sobrien fixxfti_libfunc = init_one_libfunc ("__fixxfti"); 543118334Speter 543290075Sobrien fixtfsi_libfunc = init_one_libfunc ("__fixtfsi"); 543390075Sobrien fixtfdi_libfunc = init_one_libfunc ("__fixtfdi"); 543490075Sobrien fixtfti_libfunc = init_one_libfunc ("__fixtfti"); 543518334Speter 543690075Sobrien fixunssfsi_libfunc = init_one_libfunc ("__fixunssfsi"); 543790075Sobrien fixunssfdi_libfunc = init_one_libfunc ("__fixunssfdi"); 543890075Sobrien fixunssfti_libfunc = init_one_libfunc ("__fixunssfti"); 543918334Speter 544090075Sobrien fixunsdfsi_libfunc = init_one_libfunc ("__fixunsdfsi"); 544190075Sobrien fixunsdfdi_libfunc = init_one_libfunc ("__fixunsdfdi"); 544290075Sobrien fixunsdfti_libfunc = init_one_libfunc ("__fixunsdfti"); 544318334Speter 544490075Sobrien fixunsxfsi_libfunc = init_one_libfunc ("__fixunsxfsi"); 544590075Sobrien fixunsxfdi_libfunc = init_one_libfunc ("__fixunsxfdi"); 544690075Sobrien fixunsxfti_libfunc = init_one_libfunc ("__fixunsxfti"); 544718334Speter 544890075Sobrien fixunstfsi_libfunc = init_one_libfunc ("__fixunstfsi"); 544990075Sobrien fixunstfdi_libfunc = init_one_libfunc ("__fixunstfdi"); 545090075Sobrien fixunstfti_libfunc = init_one_libfunc ("__fixunstfti"); 545150397Sobrien 545252284Sobrien /* For function entry/exit instrumentation. */ 545352284Sobrien profile_function_entry_libfunc 545490075Sobrien = init_one_libfunc ("__cyg_profile_func_enter"); 545552284Sobrien profile_function_exit_libfunc 545690075Sobrien = init_one_libfunc ("__cyg_profile_func_exit"); 545752284Sobrien 5458117395Skan if (HAVE_conditional_trap) 5459117395Skan trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX); 546050397Sobrien 546118334Speter#ifdef INIT_TARGET_OPTABS 546218334Speter /* Allow the target to add more libcalls or rename some, etc. */ 546318334Speter INIT_TARGET_OPTABS; 546418334Speter#endif 546518334Speter} 546650397Sobrien 546750397Sobrien/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition 546850397Sobrien CODE. Return 0 on failure. */ 546950397Sobrien 547050397Sobrienrtx 547150397Sobriengen_cond_trap (code, op1, op2, tcode) 5472117395Skan enum rtx_code code ATTRIBUTE_UNUSED; 5473117395Skan rtx op1, op2 ATTRIBUTE_UNUSED, tcode ATTRIBUTE_UNUSED; 547450397Sobrien{ 547550397Sobrien enum machine_mode mode = GET_MODE (op1); 5476117395Skan enum insn_code icode; 5477117395Skan rtx insn; 547850397Sobrien 5479117395Skan if (!HAVE_conditional_trap) 5480117395Skan return 0; 5481117395Skan 548250397Sobrien if (mode == VOIDmode) 548350397Sobrien return 0; 548450397Sobrien 5485117395Skan icode = cmp_optab->handlers[(int) mode].insn_code; 5486117395Skan if (icode == CODE_FOR_nothing) 5487117395Skan return 0; 5488117395Skan 5489117395Skan start_sequence (); 5490117395Skan op1 = prepare_operand (icode, op1, 0, mode, mode, 0); 5491119256Skan op2 = prepare_operand (icode, op2, 1, mode, mode, 0); 5492119256Skan if (!op1 || !op2) 5493119256Skan { 5494119256Skan end_sequence (); 5495119256Skan return 0; 5496119256Skan } 5497117395Skan emit_insn (GEN_FCN (icode) (op1, op2)); 5498117395Skan 5499117395Skan PUT_CODE (trap_rtx, code); 5500117395Skan insn = gen_conditional_trap (trap_rtx, tcode); 5501117395Skan if (insn) 550250397Sobrien { 5503117395Skan emit_insn (insn); 5504117395Skan insn = get_insns (); 550550397Sobrien } 5506117395Skan end_sequence (); 550750397Sobrien 5508117395Skan return insn; 550950397Sobrien} 5510117395Skan 5511117395Skan#include "gt-optabs.h" 5512