1132718Skan/* Convert tree expression to rtl instructions, for GNU compiler.
2132718Skan   Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3169689Skan   2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
4132718Skan
5132718SkanThis file is part of GCC.
6132718Skan
7132718SkanGCC is free software; you can redistribute it and/or modify it under
8132718Skanthe terms of the GNU General Public License as published by the Free
9132718SkanSoftware Foundation; either version 2, or (at your option) any later
10132718Skanversion.
11132718Skan
12132718SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY
13132718SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or
14132718SkanFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15132718Skanfor more details.
16132718Skan
17132718SkanYou should have received a copy of the GNU General Public License
18132718Skanalong with GCC; see the file COPYING.  If not, write to the Free
19169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
20169689Skan02110-1301, USA.  */
21132718Skan
22132718Skan#include "config.h"
23132718Skan#include "system.h"
24132718Skan#include "coretypes.h"
25132718Skan#include "tm.h"
26132718Skan#include "rtl.h"
27132718Skan#include "tree.h"
28132718Skan#include "flags.h"
29132718Skan#include "function.h"
30132718Skan#include "insn-config.h"
31132718Skan#include "insn-attr.h"
32132718Skan/* Include expr.h after insn-config.h so we get HAVE_conditional_move.  */
33132718Skan#include "expr.h"
34132718Skan#include "optabs.h"
35132718Skan#include "langhooks.h"
36146895Skan#include "ggc.h"
37132718Skan
38146895Skanstatic bool prefer_and_bit_test (enum machine_mode, int);
39132718Skanstatic void do_jump_by_parts_greater (tree, int, rtx, rtx);
40132718Skanstatic void do_jump_by_parts_equality (tree, rtx, rtx);
41132718Skanstatic void do_compare_and_jump	(tree, enum rtx_code, enum rtx_code, rtx,
42132718Skan				 rtx);
43132718Skan
44132718Skan/* At the start of a function, record that we have no previously-pushed
45132718Skan   arguments waiting to be popped.  */
46132718Skan
47132718Skanvoid
48132718Skaninit_pending_stack_adjust (void)
49132718Skan{
50132718Skan  pending_stack_adjust = 0;
51132718Skan}
52132718Skan
53146895Skan/* Discard any pending stack adjustment.  This avoid relying on the
54146895Skan   RTL optimizers to remove useless adjustments when we know the
55146895Skan   stack pointer value is dead.  */
56169689Skanvoid
57169689Skandiscard_pending_stack_adjust (void)
58146895Skan{
59146895Skan  stack_pointer_delta -= pending_stack_adjust;
60146895Skan  pending_stack_adjust = 0;
61146895Skan}
62146895Skan
63132718Skan/* When exiting from function, if safe, clear out any pending stack adjust
64132718Skan   so the adjustment won't get done.
65132718Skan
66132718Skan   Note, if the current function calls alloca, then it must have a
67132718Skan   frame pointer regardless of the value of flag_omit_frame_pointer.  */
68132718Skan
69132718Skanvoid
70132718Skanclear_pending_stack_adjust (void)
71132718Skan{
72132718Skan  if (optimize > 0
73132718Skan      && (! flag_omit_frame_pointer || current_function_calls_alloca)
74132718Skan      && EXIT_IGNORE_STACK
75169689Skan      && ! (DECL_INLINE (current_function_decl) && ! flag_no_inline))
76146895Skan    discard_pending_stack_adjust ();
77132718Skan}
78132718Skan
79132718Skan/* Pop any previously-pushed arguments that have not been popped yet.  */
80132718Skan
81132718Skanvoid
82132718Skando_pending_stack_adjust (void)
83132718Skan{
84132718Skan  if (inhibit_defer_pop == 0)
85132718Skan    {
86132718Skan      if (pending_stack_adjust != 0)
87132718Skan        adjust_stack (GEN_INT (pending_stack_adjust));
88132718Skan      pending_stack_adjust = 0;
89132718Skan    }
90132718Skan}
91132718Skan
92132718Skan/* Expand conditional expressions.  */
93132718Skan
94132718Skan/* Generate code to evaluate EXP and jump to LABEL if the value is zero.
95132718Skan   LABEL is an rtx of code CODE_LABEL, in this function and all the
96132718Skan   functions here.  */
97132718Skan
98132718Skanvoid
99132718Skanjumpifnot (tree exp, rtx label)
100132718Skan{
101132718Skan  do_jump (exp, label, NULL_RTX);
102132718Skan}
103132718Skan
104132718Skan/* Generate code to evaluate EXP and jump to LABEL if the value is nonzero.  */
105132718Skan
106132718Skanvoid
107132718Skanjumpif (tree exp, rtx label)
108132718Skan{
109132718Skan  do_jump (exp, NULL_RTX, label);
110132718Skan}
111132718Skan
112146895Skan/* Used internally by prefer_and_bit_test.  */
113146895Skan
114146895Skanstatic GTY(()) rtx and_reg;
115146895Skanstatic GTY(()) rtx and_test;
116146895Skanstatic GTY(()) rtx shift_test;
117146895Skan
118169689Skan/* Compare the relative costs of "(X & (1 << BITNUM))" and "(X >> BITNUM) & 1",
119146895Skan   where X is an arbitrary register of mode MODE.  Return true if the former
120146895Skan   is preferred.  */
121146895Skan
122146895Skanstatic bool
123146895Skanprefer_and_bit_test (enum machine_mode mode, int bitnum)
124146895Skan{
125146895Skan  if (and_test == 0)
126146895Skan    {
127146895Skan      /* Set up rtxes for the two variations.  Use NULL as a placeholder
128146895Skan	 for the BITNUM-based constants.  */
129146895Skan      and_reg = gen_rtx_REG (mode, FIRST_PSEUDO_REGISTER);
130146895Skan      and_test = gen_rtx_AND (mode, and_reg, NULL);
131146895Skan      shift_test = gen_rtx_AND (mode, gen_rtx_ASHIFTRT (mode, and_reg, NULL),
132146895Skan				const1_rtx);
133146895Skan    }
134146895Skan  else
135146895Skan    {
136146895Skan      /* Change the mode of the previously-created rtxes.  */
137146895Skan      PUT_MODE (and_reg, mode);
138146895Skan      PUT_MODE (and_test, mode);
139146895Skan      PUT_MODE (shift_test, mode);
140146895Skan      PUT_MODE (XEXP (shift_test, 0), mode);
141146895Skan    }
142146895Skan
143146895Skan  /* Fill in the integers.  */
144146895Skan  XEXP (and_test, 1) = GEN_INT ((unsigned HOST_WIDE_INT) 1 << bitnum);
145146895Skan  XEXP (XEXP (shift_test, 0), 1) = GEN_INT (bitnum);
146146895Skan
147146895Skan  return (rtx_cost (and_test, IF_THEN_ELSE)
148146895Skan	  <= rtx_cost (shift_test, IF_THEN_ELSE));
149146895Skan}
150146895Skan
151132718Skan/* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if
152132718Skan   the result is zero, or IF_TRUE_LABEL if the result is one.
153132718Skan   Either of IF_FALSE_LABEL and IF_TRUE_LABEL may be zero,
154132718Skan   meaning fall through in that case.
155132718Skan
156132718Skan   do_jump always does any pending stack adjust except when it does not
157132718Skan   actually perform a jump.  An example where there is no jump
158169689Skan   is when EXP is `(foo (), 0)' and IF_FALSE_LABEL is null.  */
159132718Skan
160132718Skanvoid
161132718Skando_jump (tree exp, rtx if_false_label, rtx if_true_label)
162132718Skan{
163132718Skan  enum tree_code code = TREE_CODE (exp);
164132718Skan  rtx temp;
165132718Skan  int i;
166132718Skan  tree type;
167132718Skan  enum machine_mode mode;
168169689Skan  rtx drop_through_label = 0;
169132718Skan
170132718Skan  switch (code)
171132718Skan    {
172132718Skan    case ERROR_MARK:
173132718Skan      break;
174132718Skan
175132718Skan    case INTEGER_CST:
176132718Skan      temp = integer_zerop (exp) ? if_false_label : if_true_label;
177132718Skan      if (temp)
178132718Skan        emit_jump (temp);
179132718Skan      break;
180132718Skan
181132718Skan#if 0
182132718Skan      /* This is not true with #pragma weak  */
183132718Skan    case ADDR_EXPR:
184132718Skan      /* The address of something can never be zero.  */
185132718Skan      if (if_true_label)
186132718Skan        emit_jump (if_true_label);
187132718Skan      break;
188132718Skan#endif
189132718Skan
190132718Skan    case NOP_EXPR:
191132718Skan      if (TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF
192132718Skan          || TREE_CODE (TREE_OPERAND (exp, 0)) == BIT_FIELD_REF
193132718Skan          || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_REF
194132718Skan          || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_RANGE_REF)
195132718Skan        goto normal;
196132718Skan    case CONVERT_EXPR:
197132718Skan      /* If we are narrowing the operand, we have to do the compare in the
198132718Skan         narrower mode.  */
199132718Skan      if ((TYPE_PRECISION (TREE_TYPE (exp))
200132718Skan           < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0)))))
201132718Skan        goto normal;
202132718Skan    case NON_LVALUE_EXPR:
203132718Skan    case ABS_EXPR:
204132718Skan    case NEGATE_EXPR:
205132718Skan    case LROTATE_EXPR:
206132718Skan    case RROTATE_EXPR:
207132718Skan      /* These cannot change zero->nonzero or vice versa.  */
208132718Skan      do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
209132718Skan      break;
210132718Skan
211132718Skan    case BIT_AND_EXPR:
212146895Skan      /* fold_single_bit_test() converts (X & (1 << C)) into (X >> C) & 1.
213146895Skan	 See if the former is preferred for jump tests and restore it
214146895Skan	 if so.  */
215146895Skan      if (integer_onep (TREE_OPERAND (exp, 1)))
216146895Skan	{
217146895Skan	  tree exp0 = TREE_OPERAND (exp, 0);
218146895Skan	  rtx set_label, clr_label;
219146895Skan
220146895Skan	  /* Strip narrowing integral type conversions.  */
221146895Skan	  while ((TREE_CODE (exp0) == NOP_EXPR
222146895Skan		  || TREE_CODE (exp0) == CONVERT_EXPR
223146895Skan		  || TREE_CODE (exp0) == NON_LVALUE_EXPR)
224146895Skan		 && TREE_OPERAND (exp0, 0) != error_mark_node
225146895Skan		 && TYPE_PRECISION (TREE_TYPE (exp0))
226146895Skan		    <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp0, 0))))
227146895Skan	    exp0 = TREE_OPERAND (exp0, 0);
228146895Skan
229146895Skan	  /* "exp0 ^ 1" inverts the sense of the single bit test.  */
230146895Skan	  if (TREE_CODE (exp0) == BIT_XOR_EXPR
231146895Skan	      && integer_onep (TREE_OPERAND (exp0, 1)))
232146895Skan	    {
233146895Skan	      exp0 = TREE_OPERAND (exp0, 0);
234146895Skan	      clr_label = if_true_label;
235146895Skan	      set_label = if_false_label;
236146895Skan	    }
237146895Skan	  else
238146895Skan	    {
239146895Skan	      clr_label = if_false_label;
240146895Skan	      set_label = if_true_label;
241146895Skan	    }
242146895Skan
243146895Skan	  if (TREE_CODE (exp0) == RSHIFT_EXPR)
244146895Skan	    {
245146895Skan	      tree arg = TREE_OPERAND (exp0, 0);
246146895Skan	      tree shift = TREE_OPERAND (exp0, 1);
247146895Skan	      tree argtype = TREE_TYPE (arg);
248146895Skan	      if (TREE_CODE (shift) == INTEGER_CST
249146895Skan		  && compare_tree_int (shift, 0) >= 0
250146895Skan		  && compare_tree_int (shift, HOST_BITS_PER_WIDE_INT) < 0
251146895Skan		  && prefer_and_bit_test (TYPE_MODE (argtype),
252146895Skan					  TREE_INT_CST_LOW (shift)))
253146895Skan		{
254146895Skan		  HOST_WIDE_INT mask = (HOST_WIDE_INT) 1
255146895Skan				       << TREE_INT_CST_LOW (shift);
256169689Skan		  do_jump (build2 (BIT_AND_EXPR, argtype, arg,
257169689Skan				   build_int_cst_type (argtype, mask)),
258146895Skan			   clr_label, set_label);
259146895Skan		  break;
260146895Skan		}
261146895Skan	    }
262146895Skan	}
263146895Skan
264132718Skan      /* If we are AND'ing with a small constant, do this comparison in the
265132718Skan         smallest type that fits.  If the machine doesn't have comparisons
266132718Skan         that small, it will be converted back to the wider comparison.
267132718Skan         This helps if we are testing the sign bit of a narrower object.
268132718Skan         combine can't do this for us because it can't know whether a
269132718Skan         ZERO_EXTRACT or a compare in a smaller mode exists, but we do.  */
270132718Skan
271132718Skan      if (! SLOW_BYTE_ACCESS
272132718Skan          && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
273132718Skan          && TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT
274132718Skan          && (i = tree_floor_log2 (TREE_OPERAND (exp, 1))) >= 0
275132718Skan          && (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode
276169689Skan          && (type = lang_hooks.types.type_for_mode (mode, 1)) != 0
277132718Skan          && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
278132718Skan          && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code
279132718Skan              != CODE_FOR_nothing))
280132718Skan        {
281169689Skan          do_jump (fold_convert (type, exp), if_false_label, if_true_label);
282132718Skan          break;
283132718Skan        }
284132718Skan      goto normal;
285132718Skan
286132718Skan    case TRUTH_NOT_EXPR:
287132718Skan      do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
288132718Skan      break;
289132718Skan
290169689Skan    case COND_EXPR:
291169689Skan      {
292169689Skan	rtx label1 = gen_label_rtx ();
293169689Skan	if (!if_true_label || !if_false_label)
294169689Skan	  {
295169689Skan	    drop_through_label = gen_label_rtx ();
296169689Skan	    if (!if_true_label)
297169689Skan	      if_true_label = drop_through_label;
298169689Skan	    if (!if_false_label)
299169689Skan	      if_false_label = drop_through_label;
300169689Skan	  }
301169689Skan
302169689Skan        do_pending_stack_adjust ();
303169689Skan        do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
304169689Skan        do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
305169689Skan        emit_label (label1);
306169689Skan        do_jump (TREE_OPERAND (exp, 2), if_false_label, if_true_label);
307169689Skan	break;
308169689Skan      }
309169689Skan
310132718Skan    case TRUTH_ANDIF_EXPR:
311132718Skan    case TRUTH_ORIF_EXPR:
312132718Skan    case COMPOUND_EXPR:
313169689Skan      /* Lowered by gimplify.c.  */
314169689Skan      gcc_unreachable ();
315132718Skan
316132718Skan    case COMPONENT_REF:
317132718Skan    case BIT_FIELD_REF:
318132718Skan    case ARRAY_REF:
319132718Skan    case ARRAY_RANGE_REF:
320132718Skan      {
321132718Skan        HOST_WIDE_INT bitsize, bitpos;
322132718Skan        int unsignedp;
323132718Skan        enum machine_mode mode;
324132718Skan        tree type;
325132718Skan        tree offset;
326132718Skan        int volatilep = 0;
327132718Skan
328132718Skan        /* Get description of this reference.  We don't actually care
329132718Skan           about the underlying object here.  */
330132718Skan        get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode,
331169689Skan                             &unsignedp, &volatilep, false);
332132718Skan
333169689Skan        type = lang_hooks.types.type_for_size (bitsize, unsignedp);
334132718Skan        if (! SLOW_BYTE_ACCESS
335132718Skan            && type != 0 && bitsize >= 0
336132718Skan            && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
337132718Skan            && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code
338169689Skan		!= CODE_FOR_nothing))
339132718Skan          {
340169689Skan            do_jump (fold_convert (type, exp), if_false_label, if_true_label);
341132718Skan            break;
342132718Skan          }
343132718Skan        goto normal;
344132718Skan      }
345132718Skan
346132718Skan    case EQ_EXPR:
347132718Skan      {
348132718Skan        tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
349132718Skan
350169689Skan        gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type))
351169689Skan		    != MODE_COMPLEX_FLOAT);
352169689Skan	gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type))
353169689Skan		    != MODE_COMPLEX_INT);
354169689Skan
355169689Skan        if (integer_zerop (TREE_OPERAND (exp, 1)))
356132718Skan          do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
357132718Skan        else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
358132718Skan                 && !can_compare_p (EQ, TYPE_MODE (inner_type), ccp_jump))
359132718Skan          do_jump_by_parts_equality (exp, if_false_label, if_true_label);
360132718Skan        else
361132718Skan          do_compare_and_jump (exp, EQ, EQ, if_false_label, if_true_label);
362132718Skan        break;
363132718Skan      }
364132718Skan
365169689Skan    case MINUS_EXPR:
366169689Skan      /* Nonzero iff operands of minus differ.  */
367169689Skan      exp = build2 (NE_EXPR, TREE_TYPE (exp),
368169689Skan		    TREE_OPERAND (exp, 0),
369169689Skan		    TREE_OPERAND (exp, 1));
370169689Skan      /* FALLTHRU */
371132718Skan    case NE_EXPR:
372132718Skan      {
373132718Skan        tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
374132718Skan
375169689Skan        gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type))
376169689Skan		    != MODE_COMPLEX_FLOAT);
377169689Skan	gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type))
378169689Skan		    != MODE_COMPLEX_INT);
379169689Skan
380169689Skan        if (integer_zerop (TREE_OPERAND (exp, 1)))
381132718Skan          do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
382132718Skan        else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
383132718Skan           && !can_compare_p (NE, TYPE_MODE (inner_type), ccp_jump))
384132718Skan          do_jump_by_parts_equality (exp, if_true_label, if_false_label);
385132718Skan        else
386132718Skan          do_compare_and_jump (exp, NE, NE, if_false_label, if_true_label);
387132718Skan        break;
388132718Skan      }
389132718Skan
390132718Skan    case LT_EXPR:
391132718Skan      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
392132718Skan      if (GET_MODE_CLASS (mode) == MODE_INT
393132718Skan          && ! can_compare_p (LT, mode, ccp_jump))
394132718Skan        do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label);
395132718Skan      else
396132718Skan        do_compare_and_jump (exp, LT, LTU, if_false_label, if_true_label);
397132718Skan      break;
398132718Skan
399132718Skan    case LE_EXPR:
400132718Skan      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
401132718Skan      if (GET_MODE_CLASS (mode) == MODE_INT
402132718Skan          && ! can_compare_p (LE, mode, ccp_jump))
403132718Skan        do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label);
404132718Skan      else
405132718Skan        do_compare_and_jump (exp, LE, LEU, if_false_label, if_true_label);
406132718Skan      break;
407132718Skan
408132718Skan    case GT_EXPR:
409132718Skan      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
410132718Skan      if (GET_MODE_CLASS (mode) == MODE_INT
411132718Skan          && ! can_compare_p (GT, mode, ccp_jump))
412132718Skan        do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label);
413132718Skan      else
414132718Skan        do_compare_and_jump (exp, GT, GTU, if_false_label, if_true_label);
415132718Skan      break;
416132718Skan
417132718Skan    case GE_EXPR:
418132718Skan      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
419132718Skan      if (GET_MODE_CLASS (mode) == MODE_INT
420132718Skan          && ! can_compare_p (GE, mode, ccp_jump))
421132718Skan        do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label);
422132718Skan      else
423132718Skan        do_compare_and_jump (exp, GE, GEU, if_false_label, if_true_label);
424132718Skan      break;
425132718Skan
426132718Skan    case UNORDERED_EXPR:
427132718Skan    case ORDERED_EXPR:
428132718Skan      {
429132718Skan        enum rtx_code cmp, rcmp;
430132718Skan        int do_rev;
431132718Skan
432132718Skan        if (code == UNORDERED_EXPR)
433132718Skan          cmp = UNORDERED, rcmp = ORDERED;
434132718Skan        else
435132718Skan          cmp = ORDERED, rcmp = UNORDERED;
436132718Skan        mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
437132718Skan
438132718Skan        do_rev = 0;
439132718Skan        if (! can_compare_p (cmp, mode, ccp_jump)
440132718Skan            && (can_compare_p (rcmp, mode, ccp_jump)
441132718Skan          /* If the target doesn't provide either UNORDERED or ORDERED
442132718Skan             comparisons, canonicalize on UNORDERED for the library.  */
443132718Skan          || rcmp == UNORDERED))
444132718Skan          do_rev = 1;
445132718Skan
446132718Skan        if (! do_rev)
447132718Skan          do_compare_and_jump (exp, cmp, cmp, if_false_label, if_true_label);
448132718Skan        else
449132718Skan          do_compare_and_jump (exp, rcmp, rcmp, if_true_label, if_false_label);
450132718Skan      }
451132718Skan      break;
452132718Skan
453132718Skan    {
454132718Skan      enum rtx_code rcode1;
455169689Skan      enum tree_code tcode1, tcode2;
456132718Skan
457132718Skan      case UNLT_EXPR:
458132718Skan        rcode1 = UNLT;
459169689Skan        tcode1 = UNORDERED_EXPR;
460132718Skan        tcode2 = LT_EXPR;
461132718Skan        goto unordered_bcc;
462132718Skan      case UNLE_EXPR:
463132718Skan        rcode1 = UNLE;
464169689Skan        tcode1 = UNORDERED_EXPR;
465132718Skan        tcode2 = LE_EXPR;
466132718Skan        goto unordered_bcc;
467132718Skan      case UNGT_EXPR:
468132718Skan        rcode1 = UNGT;
469169689Skan        tcode1 = UNORDERED_EXPR;
470132718Skan        tcode2 = GT_EXPR;
471132718Skan        goto unordered_bcc;
472132718Skan      case UNGE_EXPR:
473132718Skan        rcode1 = UNGE;
474169689Skan        tcode1 = UNORDERED_EXPR;
475132718Skan        tcode2 = GE_EXPR;
476132718Skan        goto unordered_bcc;
477132718Skan      case UNEQ_EXPR:
478132718Skan        rcode1 = UNEQ;
479169689Skan        tcode1 = UNORDERED_EXPR;
480132718Skan        tcode2 = EQ_EXPR;
481132718Skan        goto unordered_bcc;
482169689Skan      case LTGT_EXPR:
483169689Skan	/* It is ok for LTGT_EXPR to trap when the result is unordered,
484169689Skan	   so expand to (a < b) || (a > b).  */
485169689Skan        rcode1 = LTGT;
486169689Skan        tcode1 = LT_EXPR;
487169689Skan        tcode2 = GT_EXPR;
488169689Skan        goto unordered_bcc;
489132718Skan
490132718Skan      unordered_bcc:
491132718Skan        mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
492132718Skan        if (can_compare_p (rcode1, mode, ccp_jump))
493132718Skan          do_compare_and_jump (exp, rcode1, rcode1, if_false_label,
494132718Skan                               if_true_label);
495132718Skan        else
496132718Skan          {
497132718Skan            tree op0 = save_expr (TREE_OPERAND (exp, 0));
498132718Skan            tree op1 = save_expr (TREE_OPERAND (exp, 1));
499132718Skan            tree cmp0, cmp1;
500132718Skan
501132718Skan            /* If the target doesn't support combined unordered
502169689Skan               compares, decompose into two comparisons.  */
503169689Skan	    if (if_true_label == 0)
504169689Skan	      drop_through_label = if_true_label = gen_label_rtx ();
505169689Skan
506169689Skan            cmp0 = fold_build2 (tcode1, TREE_TYPE (exp), op0, op1);
507169689Skan            cmp1 = fold_build2 (tcode2, TREE_TYPE (exp), op0, op1);
508169689Skan	    do_jump (cmp0, 0, if_true_label);
509169689Skan	    do_jump (cmp1, if_false_label, if_true_label);
510132718Skan          }
511132718Skan      }
512132718Skan      break;
513132718Skan
514169689Skan    case TRUTH_AND_EXPR:
515169689Skan      /* High branch cost, expand as the bitwise AND of the conditions.
516169689Skan	 Do the same if the RHS has side effects, because we're effectively
517169689Skan	 turning a TRUTH_AND_EXPR into a TRUTH_ANDIF_EXPR.  */
518169689Skan      if (BRANCH_COST >= 4 || TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 1)))
519169689Skan	goto normal;
520169689Skan
521169689Skan      if (if_false_label == NULL_RTX)
522169689Skan        {
523169689Skan	  drop_through_label = gen_label_rtx ();
524169689Skan          do_jump (TREE_OPERAND (exp, 0), drop_through_label, NULL_RTX);
525169689Skan          do_jump (TREE_OPERAND (exp, 1), NULL_RTX, if_true_label);
526169689Skan	}
527169689Skan      else
528169689Skan	{
529169689Skan	  do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
530169689Skan          do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
531169689Skan	}
532169689Skan      break;
533169689Skan
534169689Skan    case TRUTH_OR_EXPR:
535169689Skan      /* High branch cost, expand as the bitwise OR of the conditions.
536169689Skan	 Do the same if the RHS has side effects, because we're effectively
537169689Skan	 turning a TRUTH_OR_EXPR into a TRUTH_ORIF_EXPR.  */
538169689Skan      if (BRANCH_COST >= 4 || TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 1)))
539169689Skan	goto normal;
540169689Skan
541169689Skan      if (if_true_label == NULL_RTX)
542169689Skan	{
543169689Skan          drop_through_label = gen_label_rtx ();
544169689Skan          do_jump (TREE_OPERAND (exp, 0), NULL_RTX, drop_through_label);
545169689Skan          do_jump (TREE_OPERAND (exp, 1), if_false_label, NULL_RTX);
546169689Skan	}
547169689Skan      else
548169689Skan	{
549169689Skan          do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
550169689Skan          do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
551169689Skan	}
552169689Skan      break;
553169689Skan
554132718Skan      /* Special case:
555132718Skan          __builtin_expect (<test>, 0)	and
556132718Skan          __builtin_expect (<test>, 1)
557132718Skan
558132718Skan         We need to do this here, so that <test> is not converted to a SCC
559132718Skan         operation on machines that use condition code registers and COMPARE
560132718Skan         like the PowerPC, and then the jump is done based on whether the SCC
561132718Skan         operation produced a 1 or 0.  */
562132718Skan    case CALL_EXPR:
563132718Skan      /* Check for a built-in function.  */
564132718Skan      {
565132718Skan	tree fndecl = get_callee_fndecl (exp);
566132718Skan	tree arglist = TREE_OPERAND (exp, 1);
567132718Skan
568132718Skan	if (fndecl
569169689Skan	    && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
570132718Skan	    && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
571132718Skan	    && arglist != NULL_TREE
572132718Skan	    && TREE_CHAIN (arglist) != NULL_TREE)
573132718Skan	  {
574132718Skan	    rtx seq = expand_builtin_expect_jump (exp, if_false_label,
575132718Skan						  if_true_label);
576132718Skan
577132718Skan	    if (seq != NULL_RTX)
578132718Skan	      {
579132718Skan		emit_insn (seq);
580132718Skan		return;
581132718Skan	      }
582132718Skan	  }
583132718Skan      }
584169689Skan
585132718Skan      /* Fall through and generate the normal code.  */
586132718Skan    default:
587132718Skan    normal:
588169689Skan      temp = expand_normal (exp);
589132718Skan      do_pending_stack_adjust ();
590169689Skan      /* The RTL optimizers prefer comparisons against pseudos.  */
591169689Skan      if (GET_CODE (temp) == SUBREG)
592132718Skan	{
593169689Skan	  /* Compare promoted variables in their promoted mode.  */
594169689Skan	  if (SUBREG_PROMOTED_VAR_P (temp)
595169689Skan	      && REG_P (XEXP (temp, 0)))
596169689Skan	    temp = XEXP (temp, 0);
597169689Skan	  else
598169689Skan	    temp = copy_to_reg (temp);
599132718Skan	}
600169689Skan      do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
601169689Skan			       NE, TYPE_UNSIGNED (TREE_TYPE (exp)),
602169689Skan			       GET_MODE (temp), NULL_RTX,
603169689Skan			       if_false_label, if_true_label);
604132718Skan    }
605132718Skan
606132718Skan  if (drop_through_label)
607132718Skan    {
608132718Skan      do_pending_stack_adjust ();
609132718Skan      emit_label (drop_through_label);
610132718Skan    }
611132718Skan}
612132718Skan
613132718Skan/* Compare OP0 with OP1, word at a time, in mode MODE.
614132718Skan   UNSIGNEDP says to do unsigned comparison.
615132718Skan   Jump to IF_TRUE_LABEL if OP0 is greater, IF_FALSE_LABEL otherwise.  */
616132718Skan
617169689Skanstatic void
618132718Skando_jump_by_parts_greater_rtx (enum machine_mode mode, int unsignedp, rtx op0,
619132718Skan			      rtx op1, rtx if_false_label, rtx if_true_label)
620132718Skan{
621132718Skan  int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
622132718Skan  rtx drop_through_label = 0;
623132718Skan  int i;
624132718Skan
625132718Skan  if (! if_true_label || ! if_false_label)
626132718Skan    drop_through_label = gen_label_rtx ();
627132718Skan  if (! if_true_label)
628132718Skan    if_true_label = drop_through_label;
629132718Skan  if (! if_false_label)
630132718Skan    if_false_label = drop_through_label;
631132718Skan
632132718Skan  /* Compare a word at a time, high order first.  */
633132718Skan  for (i = 0; i < nwords; i++)
634132718Skan    {
635132718Skan      rtx op0_word, op1_word;
636132718Skan
637132718Skan      if (WORDS_BIG_ENDIAN)
638132718Skan        {
639132718Skan          op0_word = operand_subword_force (op0, i, mode);
640132718Skan          op1_word = operand_subword_force (op1, i, mode);
641132718Skan        }
642132718Skan      else
643132718Skan        {
644132718Skan          op0_word = operand_subword_force (op0, nwords - 1 - i, mode);
645132718Skan          op1_word = operand_subword_force (op1, nwords - 1 - i, mode);
646132718Skan        }
647132718Skan
648132718Skan      /* All but high-order word must be compared as unsigned.  */
649132718Skan      do_compare_rtx_and_jump (op0_word, op1_word, GT,
650132718Skan                               (unsignedp || i > 0), word_mode, NULL_RTX,
651132718Skan                               NULL_RTX, if_true_label);
652132718Skan
653132718Skan      /* Consider lower words only if these are equal.  */
654132718Skan      do_compare_rtx_and_jump (op0_word, op1_word, NE, unsignedp, word_mode,
655132718Skan                               NULL_RTX, NULL_RTX, if_false_label);
656132718Skan    }
657132718Skan
658132718Skan  if (if_false_label)
659132718Skan    emit_jump (if_false_label);
660132718Skan  if (drop_through_label)
661132718Skan    emit_label (drop_through_label);
662132718Skan}
663132718Skan
664169689Skan/* Given a comparison expression EXP for values too wide to be compared
665169689Skan   with one insn, test the comparison and jump to the appropriate label.
666169689Skan   The code of EXP is ignored; we always test GT if SWAP is 0,
667169689Skan   and LT if SWAP is 1.  */
668132718Skan
669132718Skanstatic void
670169689Skando_jump_by_parts_greater (tree exp, int swap, rtx if_false_label,
671169689Skan			  rtx if_true_label)
672132718Skan{
673169689Skan  rtx op0 = expand_normal (TREE_OPERAND (exp, swap));
674169689Skan  rtx op1 = expand_normal (TREE_OPERAND (exp, !swap));
675132718Skan  enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
676169689Skan  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)));
677132718Skan
678169689Skan  do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label,
679169689Skan				if_true_label);
680132718Skan}
681132718Skan
682169689Skan/* Jump according to whether OP0 is 0.  We assume that OP0 has an integer
683169689Skan   mode, MODE, that is too wide for the available compare insns.  Either
684169689Skan   Either (but not both) of IF_TRUE_LABEL and IF_FALSE_LABEL may be NULL_RTX
685169689Skan   to indicate drop through.  */
686132718Skan
687169689Skanstatic void
688169689Skando_jump_by_parts_zero_rtx (enum machine_mode mode, rtx op0,
689169689Skan			   rtx if_false_label, rtx if_true_label)
690132718Skan{
691169689Skan  int nwords = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
692132718Skan  rtx part;
693132718Skan  int i;
694132718Skan  rtx drop_through_label = 0;
695132718Skan
696132718Skan  /* The fastest way of doing this comparison on almost any machine is to
697132718Skan     "or" all the words and compare the result.  If all have to be loaded
698132718Skan     from memory and this is a very wide item, it's possible this may
699132718Skan     be slower, but that's highly unlikely.  */
700132718Skan
701132718Skan  part = gen_reg_rtx (word_mode);
702132718Skan  emit_move_insn (part, operand_subword_force (op0, 0, GET_MODE (op0)));
703132718Skan  for (i = 1; i < nwords && part != 0; i++)
704132718Skan    part = expand_binop (word_mode, ior_optab, part,
705132718Skan                         operand_subword_force (op0, i, GET_MODE (op0)),
706132718Skan                         part, 1, OPTAB_WIDEN);
707132718Skan
708132718Skan  if (part != 0)
709132718Skan    {
710132718Skan      do_compare_rtx_and_jump (part, const0_rtx, EQ, 1, word_mode,
711132718Skan                               NULL_RTX, if_false_label, if_true_label);
712132718Skan
713132718Skan      return;
714132718Skan    }
715132718Skan
716132718Skan  /* If we couldn't do the "or" simply, do this with a series of compares.  */
717132718Skan  if (! if_false_label)
718132718Skan    drop_through_label = if_false_label = gen_label_rtx ();
719132718Skan
720132718Skan  for (i = 0; i < nwords; i++)
721132718Skan    do_compare_rtx_and_jump (operand_subword_force (op0, i, GET_MODE (op0)),
722132718Skan                             const0_rtx, EQ, 1, word_mode, NULL_RTX,
723132718Skan                             if_false_label, NULL_RTX);
724132718Skan
725132718Skan  if (if_true_label)
726132718Skan    emit_jump (if_true_label);
727132718Skan
728132718Skan  if (drop_through_label)
729132718Skan    emit_label (drop_through_label);
730132718Skan}
731169689Skan
732169689Skan/* Test for the equality of two RTX expressions OP0 and OP1 in mode MODE,
733169689Skan   where MODE is an integer mode too wide to be compared with one insn.
734169689Skan   Either (but not both) of IF_TRUE_LABEL and IF_FALSE_LABEL may be NULL_RTX
735169689Skan   to indicate drop through.  */
736169689Skan
737169689Skanstatic void
738169689Skando_jump_by_parts_equality_rtx (enum machine_mode mode, rtx op0, rtx op1,
739169689Skan			       rtx if_false_label, rtx if_true_label)
740169689Skan{
741169689Skan  int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
742169689Skan  rtx drop_through_label = 0;
743169689Skan  int i;
744169689Skan
745169689Skan  if (op1 == const0_rtx)
746169689Skan    {
747169689Skan      do_jump_by_parts_zero_rtx (mode, op0, if_false_label, if_true_label);
748169689Skan      return;
749169689Skan    }
750169689Skan  else if (op0 == const0_rtx)
751169689Skan    {
752169689Skan      do_jump_by_parts_zero_rtx (mode, op1, if_false_label, if_true_label);
753169689Skan      return;
754169689Skan    }
755169689Skan
756169689Skan  if (! if_false_label)
757169689Skan    drop_through_label = if_false_label = gen_label_rtx ();
758169689Skan
759169689Skan  for (i = 0; i < nwords; i++)
760169689Skan    do_compare_rtx_and_jump (operand_subword_force (op0, i, mode),
761169689Skan                             operand_subword_force (op1, i, mode),
762169689Skan                             EQ, 0, word_mode, NULL_RTX,
763169689Skan			     if_false_label, NULL_RTX);
764169689Skan
765169689Skan  if (if_true_label)
766169689Skan    emit_jump (if_true_label);
767169689Skan  if (drop_through_label)
768169689Skan    emit_label (drop_through_label);
769169689Skan}
770169689Skan
771169689Skan/* Given an EQ_EXPR expression EXP for values too wide to be compared
772169689Skan   with one insn, test the comparison and jump to the appropriate label.  */
773169689Skan
774169689Skanstatic void
775169689Skando_jump_by_parts_equality (tree exp, rtx if_false_label, rtx if_true_label)
776169689Skan{
777169689Skan  rtx op0 = expand_normal (TREE_OPERAND (exp, 0));
778169689Skan  rtx op1 = expand_normal (TREE_OPERAND (exp, 1));
779169689Skan  enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
780169689Skan  do_jump_by_parts_equality_rtx (mode, op0, op1, if_false_label,
781169689Skan				 if_true_label);
782169689Skan}
783132718Skan
784132718Skan/* Generate code for a comparison of OP0 and OP1 with rtx code CODE.
785169689Skan   MODE is the machine mode of the comparison, not of the result.
786169689Skan   (including code to compute the values to be compared) and set CC0
787169689Skan   according to the result.  The decision as to signed or unsigned
788169689Skan   comparison must be made by the caller.
789132718Skan
790132718Skan   We force a stack adjustment unless there are currently
791132718Skan   things pushed on the stack that aren't yet used.
792132718Skan
793132718Skan   If MODE is BLKmode, SIZE is an RTX giving the size of the objects being
794132718Skan   compared.  */
795132718Skan
796132718Skanrtx
797132718Skancompare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
798132718Skan		  enum machine_mode mode, rtx size)
799132718Skan{
800132718Skan  rtx tem;
801132718Skan
802132718Skan  /* If one operand is constant, make it the second one.  Only do this
803132718Skan     if the other operand is not constant as well.  */
804132718Skan
805132718Skan  if (swap_commutative_operands_p (op0, op1))
806132718Skan    {
807132718Skan      tem = op0;
808132718Skan      op0 = op1;
809132718Skan      op1 = tem;
810132718Skan      code = swap_condition (code);
811132718Skan    }
812132718Skan
813132718Skan  do_pending_stack_adjust ();
814132718Skan
815169689Skan  code = unsignedp ? unsigned_condition (code) : code;
816169689Skan  tem = simplify_relational_operation (code, VOIDmode, mode, op0, op1);
817169689Skan  if (tem)
818169689Skan    {
819169689Skan      if (CONSTANT_P (tem))
820169689Skan	return tem;
821132718Skan
822169689Skan      if (COMPARISON_P (tem))
823169689Skan	{
824169689Skan	  code = GET_CODE (tem);
825169689Skan	  op0 = XEXP (tem, 0);
826169689Skan	  op1 = XEXP (tem, 1);
827169689Skan	  mode = GET_MODE (op0);
828169689Skan	  unsignedp = (code == GTU || code == LTU
829169689Skan		       || code == GEU || code == LEU);
830169689Skan	}
831132718Skan    }
832132718Skan
833132718Skan  emit_cmp_insn (op0, op1, code, size, mode, unsignedp);
834132718Skan
835132718Skan#if HAVE_cc0
836132718Skan  return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
837132718Skan#else
838132718Skan  return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
839132718Skan#endif
840132718Skan}
841132718Skan
842132718Skan/* Like do_compare_and_jump but expects the values to compare as two rtx's.
843132718Skan   The decision as to signed or unsigned comparison must be made by the caller.
844132718Skan
845132718Skan   If MODE is BLKmode, SIZE is an RTX giving the size of the objects being
846132718Skan   compared.  */
847132718Skan
848132718Skanvoid
849132718Skando_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
850132718Skan			 enum machine_mode mode, rtx size, rtx if_false_label,
851132718Skan			 rtx if_true_label)
852132718Skan{
853132718Skan  rtx tem;
854132718Skan  int dummy_true_label = 0;
855132718Skan
856132718Skan  /* Reverse the comparison if that is safe and we want to jump if it is
857132718Skan     false.  */
858132718Skan  if (! if_true_label && ! FLOAT_MODE_P (mode))
859132718Skan    {
860132718Skan      if_true_label = if_false_label;
861132718Skan      if_false_label = 0;
862132718Skan      code = reverse_condition (code);
863132718Skan    }
864132718Skan
865132718Skan  /* If one operand is constant, make it the second one.  Only do this
866132718Skan     if the other operand is not constant as well.  */
867132718Skan
868132718Skan  if (swap_commutative_operands_p (op0, op1))
869132718Skan    {
870132718Skan      tem = op0;
871132718Skan      op0 = op1;
872132718Skan      op1 = tem;
873132718Skan      code = swap_condition (code);
874132718Skan    }
875132718Skan
876132718Skan  do_pending_stack_adjust ();
877132718Skan
878169689Skan  code = unsignedp ? unsigned_condition (code) : code;
879169689Skan  if (0 != (tem = simplify_relational_operation (code, mode, VOIDmode,
880169689Skan						 op0, op1)))
881132718Skan    {
882169689Skan      if (CONSTANT_P (tem))
883169689Skan	{
884169689Skan	  rtx label = (tem == const0_rtx || tem == CONST0_RTX (mode))
885169689Skan		      ? if_false_label : if_true_label;
886169689Skan	  if (label)
887169689Skan	    emit_jump (label);
888169689Skan	  return;
889169689Skan	}
890169689Skan
891169689Skan      code = GET_CODE (tem);
892169689Skan      mode = GET_MODE (tem);
893169689Skan      op0 = XEXP (tem, 0);
894169689Skan      op1 = XEXP (tem, 1);
895169689Skan      unsignedp = (code == GTU || code == LTU || code == GEU || code == LEU);
896132718Skan    }
897132718Skan
898132718Skan
899132718Skan  if (! if_true_label)
900132718Skan    {
901132718Skan      dummy_true_label = 1;
902132718Skan      if_true_label = gen_label_rtx ();
903132718Skan    }
904132718Skan
905169689Skan  if (GET_MODE_CLASS (mode) == MODE_INT
906169689Skan      && ! can_compare_p (code, mode, ccp_jump))
907169689Skan    {
908169689Skan      switch (code)
909169689Skan	{
910169689Skan	case LTU:
911169689Skan	  do_jump_by_parts_greater_rtx (mode, 1, op1, op0,
912169689Skan					if_false_label, if_true_label);
913169689Skan	  break;
914132718Skan
915169689Skan	case LEU:
916169689Skan	  do_jump_by_parts_greater_rtx (mode, 1, op0, op1,
917169689Skan					if_true_label, if_false_label);
918169689Skan	  break;
919169689Skan
920169689Skan	case GTU:
921169689Skan	  do_jump_by_parts_greater_rtx (mode, 1, op0, op1,
922169689Skan					if_false_label, if_true_label);
923169689Skan	  break;
924169689Skan
925169689Skan	case GEU:
926169689Skan	  do_jump_by_parts_greater_rtx (mode, 1, op1, op0,
927169689Skan					if_true_label, if_false_label);
928169689Skan	  break;
929169689Skan
930169689Skan	case LT:
931169689Skan	  do_jump_by_parts_greater_rtx (mode, 0, op1, op0,
932169689Skan					if_false_label, if_true_label);
933169689Skan	  break;
934169689Skan
935169689Skan	case LE:
936169689Skan	  do_jump_by_parts_greater_rtx (mode, 0, op0, op1,
937169689Skan					if_true_label, if_false_label);
938169689Skan	  break;
939169689Skan
940169689Skan	case GT:
941169689Skan	  do_jump_by_parts_greater_rtx (mode, 0, op0, op1,
942169689Skan					if_false_label, if_true_label);
943169689Skan	  break;
944169689Skan
945169689Skan	case GE:
946169689Skan	  do_jump_by_parts_greater_rtx (mode, 0, op1, op0,
947169689Skan					if_true_label, if_false_label);
948169689Skan	  break;
949169689Skan
950169689Skan	case EQ:
951169689Skan	  do_jump_by_parts_equality_rtx (mode, op0, op1, if_false_label,
952169689Skan					 if_true_label);
953169689Skan	  break;
954169689Skan
955169689Skan	case NE:
956169689Skan	  do_jump_by_parts_equality_rtx (mode, op0, op1, if_true_label,
957169689Skan					 if_false_label);
958169689Skan	  break;
959169689Skan
960169689Skan	default:
961169689Skan	  gcc_unreachable ();
962169689Skan	}
963169689Skan    }
964169689Skan  else
965169689Skan    emit_cmp_and_jump_insns (op0, op1, code, size, mode, unsignedp,
966169689Skan			     if_true_label);
967169689Skan
968132718Skan  if (if_false_label)
969132718Skan    emit_jump (if_false_label);
970132718Skan  if (dummy_true_label)
971132718Skan    emit_label (if_true_label);
972132718Skan}
973132718Skan
974132718Skan/* Generate code for a comparison expression EXP (including code to compute
975132718Skan   the values to be compared) and a conditional jump to IF_FALSE_LABEL and/or
976132718Skan   IF_TRUE_LABEL.  One of the labels can be NULL_RTX, in which case the
977132718Skan   generated code will drop through.
978132718Skan   SIGNED_CODE should be the rtx operation for this comparison for
979132718Skan   signed data; UNSIGNED_CODE, likewise for use if data is unsigned.
980132718Skan
981132718Skan   We force a stack adjustment unless there are currently
982132718Skan   things pushed on the stack that aren't yet used.  */
983132718Skan
984132718Skanstatic void
985132718Skando_compare_and_jump (tree exp, enum rtx_code signed_code,
986132718Skan		     enum rtx_code unsigned_code, rtx if_false_label,
987132718Skan		     rtx if_true_label)
988132718Skan{
989132718Skan  rtx op0, op1;
990132718Skan  tree type;
991132718Skan  enum machine_mode mode;
992132718Skan  int unsignedp;
993132718Skan  enum rtx_code code;
994132718Skan
995132718Skan  /* Don't crash if the comparison was erroneous.  */
996169689Skan  op0 = expand_normal (TREE_OPERAND (exp, 0));
997132718Skan  if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
998132718Skan    return;
999132718Skan
1000169689Skan  op1 = expand_normal (TREE_OPERAND (exp, 1));
1001132718Skan  if (TREE_CODE (TREE_OPERAND (exp, 1)) == ERROR_MARK)
1002132718Skan    return;
1003132718Skan
1004132718Skan  type = TREE_TYPE (TREE_OPERAND (exp, 0));
1005132718Skan  mode = TYPE_MODE (type);
1006132718Skan  if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
1007132718Skan      && (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST
1008132718Skan          || (GET_MODE_BITSIZE (mode)
1009132718Skan              > GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp,
1010132718Skan                                                                      1)))))))
1011132718Skan    {
1012132718Skan      /* op0 might have been replaced by promoted constant, in which
1013132718Skan         case the type of second argument should be used.  */
1014132718Skan      type = TREE_TYPE (TREE_OPERAND (exp, 1));
1015132718Skan      mode = TYPE_MODE (type);
1016132718Skan    }
1017169689Skan  unsignedp = TYPE_UNSIGNED (type);
1018132718Skan  code = unsignedp ? unsigned_code : signed_code;
1019132718Skan
1020132718Skan#ifdef HAVE_canonicalize_funcptr_for_compare
1021132718Skan  /* If function pointers need to be "canonicalized" before they can
1022169689Skan     be reliably compared, then canonicalize them.
1023169689Skan     Only do this if *both* sides of the comparison are function pointers.
1024169689Skan     If one side isn't, we want a noncanonicalized comparison.  See PR
1025169689Skan     middle-end/17564.  */
1026132718Skan  if (HAVE_canonicalize_funcptr_for_compare
1027132718Skan      && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
1028169689Skan      && TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
1029169689Skan          == FUNCTION_TYPE
1030169689Skan      && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE
1031169689Skan      && TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))))
1032169689Skan          == FUNCTION_TYPE)
1033132718Skan    {
1034132718Skan      rtx new_op0 = gen_reg_rtx (mode);
1035169689Skan      rtx new_op1 = gen_reg_rtx (mode);
1036132718Skan
1037132718Skan      emit_insn (gen_canonicalize_funcptr_for_compare (new_op0, op0));
1038132718Skan      op0 = new_op0;
1039132718Skan
1040132718Skan      emit_insn (gen_canonicalize_funcptr_for_compare (new_op1, op1));
1041132718Skan      op1 = new_op1;
1042132718Skan    }
1043132718Skan#endif
1044132718Skan
1045132718Skan  do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode,
1046132718Skan                           ((mode == BLKmode)
1047132718Skan                            ? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
1048132718Skan                           if_false_label, if_true_label);
1049132718Skan}
1050146895Skan
1051146895Skan#include "gt-dojump.h"
1052