Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* Expand the basic unary and binary arithmetic operations, for GNU compiler. |
2 | Copyright (C) 1987, 1988 Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of GNU CC. | |
5 | ||
6 | GNU CC is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 1, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GNU CC is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GNU CC; see the file COPYING. If not, write to | |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | ||
20 | ||
21 | #include "config.h" | |
22 | #include "rtl.h" | |
23 | #include "tree.h" | |
24 | #include "flags.h" | |
25 | #include "insn-flags.h" | |
26 | #include "insn-codes.h" | |
27 | #include "expr.h" | |
28 | #include "insn-config.h" | |
29 | #include "recog.h" | |
30 | ||
31 | /* In ANSI C we could write MODE + 1, but traditional C compilers | |
32 | seem to reject it. */ | |
33 | #define INC_MODE(MODE) (enum machine_mode) ((int)(MODE) + 1) | |
34 | ||
35 | /* Each optab contains info on how this target machine | |
36 | can perform a particular operation | |
37 | for all sizes and kinds of operands. | |
38 | ||
39 | The operation to be performed is often specified | |
40 | by passing one of these optabs as an argument. | |
41 | ||
42 | See expr.h for documentation of these optabs. */ | |
43 | ||
44 | optab add_optab; | |
45 | optab sub_optab; | |
46 | optab smul_optab; | |
47 | optab umul_optab; | |
48 | optab smul_widen_optab; | |
49 | optab umul_widen_optab; | |
50 | optab sdiv_optab; | |
51 | optab sdivmod_optab; | |
52 | optab udiv_optab; | |
53 | optab udivmod_optab; | |
54 | optab smod_optab; | |
55 | optab umod_optab; | |
56 | optab flodiv_optab; | |
57 | optab ftrunc_optab; | |
58 | optab and_optab; | |
59 | optab andcb_optab; | |
60 | optab ior_optab; | |
61 | optab xor_optab; | |
62 | optab ashl_optab; | |
63 | optab lshr_optab; | |
64 | optab lshl_optab; | |
65 | optab ashr_optab; | |
66 | optab rotl_optab; | |
67 | optab rotr_optab; | |
68 | ||
69 | optab mov_optab; | |
70 | optab movstrict_optab; | |
71 | ||
72 | optab neg_optab; | |
73 | optab abs_optab; | |
74 | optab one_cmpl_optab; | |
75 | optab ffs_optab; | |
76 | ||
77 | optab cmp_optab; | |
78 | optab ucmp_optab; /* Used only for libcalls for unsigned comparisons. */ | |
79 | optab tst_optab; | |
80 | ||
81 | /* Indexed by the rtx-code for a conditional (eg. EQ, LT,...) | |
82 | gives the gen_function to make a branch to test that condition. */ | |
83 | ||
84 | rtxfun bcc_gen_fctn[NUM_RTX_CODE]; | |
85 | ||
86 | /* Indexed by the rtx-code for a conditional (eg. EQ, LT,...) | |
87 | gives the gen_function to make a store-condition insn | |
88 | to test that condition. */ | |
89 | ||
90 | rtxfun setcc_gen_fctn[NUM_RTX_CODE]; | |
91 | \f | |
92 | /* Generate code to perform an operation specified by BINOPTAB | |
93 | on operands OP0 and OP1, with result having machine-mode MODE. | |
94 | ||
95 | UNSIGNEDP is for the case where we have to widen the operands | |
96 | to perform the operation. It says to use zero-extension. | |
97 | ||
98 | If TARGET is nonzero, the value | |
99 | is generated there, if it is convenient to do so. | |
100 | In all cases an rtx is returned for the locus of the value; | |
101 | this may or may not be TARGET. */ | |
102 | ||
103 | rtx | |
104 | expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) | |
105 | enum machine_mode mode; | |
106 | optab binoptab; | |
107 | rtx op0, op1; | |
108 | rtx target; | |
109 | int unsignedp; | |
110 | enum optab_methods methods; | |
111 | { | |
112 | enum mode_class class; | |
113 | enum machine_mode wider_mode; | |
114 | register rtx temp; | |
115 | rtx last; | |
116 | ||
117 | class = GET_MODE_CLASS (mode); | |
118 | ||
119 | op0 = protect_from_queue (op0, 0); | |
120 | op1 = protect_from_queue (op1, 0); | |
121 | if (target) | |
122 | target = protect_from_queue (target, 1); | |
123 | ||
124 | #if 0 | |
125 | /* We may get better code by generating the result in a register | |
126 | when the target is not one of the operands. */ | |
127 | if (target && ! rtx_equal_p (target, op1) && ! rtx_equal_p (target, op0)) | |
128 | target_is_not_an_operand = 1; | |
129 | #endif | |
130 | ||
131 | if (flag_force_mem) | |
132 | { | |
133 | op0 = force_not_mem (op0); | |
134 | op1 = force_not_mem (op1); | |
135 | } | |
136 | ||
137 | /* Record where to delete back to if we backtrack. */ | |
138 | last = get_last_insn (); | |
139 | ||
140 | /* If operation is commutative, | |
141 | try to make the first operand a register. | |
142 | Even better, try to make it the same as the target. | |
143 | Also try to make the last operand a constant. */ | |
144 | if (binoptab == add_optab | |
145 | || binoptab == and_optab | |
146 | || binoptab == ior_optab | |
147 | || binoptab == xor_optab | |
148 | || binoptab == smul_optab | |
149 | || binoptab == umul_optab | |
150 | || binoptab == smul_widen_optab | |
151 | || binoptab == umul_widen_optab) | |
152 | { | |
153 | if (((target == 0 || GET_CODE (target) == REG) | |
154 | ? ((GET_CODE (op1) == REG | |
155 | && GET_CODE (op0) != REG) | |
156 | || target == op1) | |
157 | : rtx_equal_p (op1, target)) | |
158 | || | |
159 | GET_CODE (op0) == CONST_INT) | |
160 | { | |
161 | temp = op1; | |
162 | op1 = op0; | |
163 | op0 = temp; | |
164 | } | |
165 | } | |
166 | ||
167 | /* If we can do it with a three-operand insn, do so. */ | |
168 | ||
169 | if (methods != OPTAB_MUST_WIDEN | |
170 | && binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) | |
171 | { | |
172 | int icode = (int) binoptab->handlers[(int) mode].insn_code; | |
173 | enum machine_mode mode0 = insn_operand_mode[icode][1]; | |
174 | enum machine_mode mode1 = insn_operand_mode[icode][2]; | |
175 | rtx pat; | |
176 | rtx xop0 = op0, xop1 = op1; | |
177 | ||
178 | if (target) | |
179 | temp = target; | |
180 | else | |
181 | temp = gen_reg_rtx (mode); | |
182 | ||
183 | /* In case the insn wants input operands in modes different from | |
184 | the result, convert the operands. */ | |
185 | ||
186 | if (GET_MODE (op0) != VOIDmode | |
187 | && GET_MODE (op0) != mode0) | |
188 | xop0 = convert_to_mode (mode0, xop0, unsignedp); | |
189 | ||
190 | if (GET_MODE (xop1) != VOIDmode | |
191 | && GET_MODE (xop1) != mode1) | |
192 | xop1 = convert_to_mode (mode1, xop1, unsignedp); | |
193 | ||
194 | /* Now, if insn requires register operands, put operands into regs. */ | |
195 | ||
196 | if (! (*insn_operand_predicate[icode][1]) (xop0, mode0)) | |
197 | xop0 = force_reg (mode0, xop0); | |
198 | ||
199 | if (! (*insn_operand_predicate[icode][2]) (xop1, mode1)) | |
200 | xop1 = force_reg (mode1, xop1); | |
201 | ||
202 | if (! (*insn_operand_predicate[icode][0]) (temp, mode)) | |
203 | temp = gen_reg_rtx (mode); | |
204 | ||
205 | pat = GEN_FCN (icode) (temp, xop0, xop1); | |
206 | if (pat) | |
207 | { | |
208 | emit_insn (pat); | |
209 | return temp; | |
210 | } | |
211 | else | |
212 | delete_insns_since (last); | |
213 | } | |
214 | ||
215 | /* It can't be open-coded in this mode. | |
216 | Use a library call if one is available and caller says that's ok. */ | |
217 | ||
218 | if (binoptab->handlers[(int) mode].lib_call | |
219 | && (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN)) | |
220 | { | |
221 | rtx insn_before, insn_first, insn_last; | |
222 | rtx funexp = gen_rtx (SYMBOL_REF, Pmode, | |
223 | binoptab->handlers[(int) mode].lib_call); | |
224 | ||
225 | /* Pass the address through a pseudoreg, if desired, | |
226 | before the "beginning" of the library call. | |
227 | So this insn isn't "part of" the library call, in case that | |
228 | is deleted, or cse'd. */ | |
229 | #ifndef NO_FUNCTION_CSE | |
230 | if (! flag_no_function_cse) | |
231 | funexp = copy_to_mode_reg (Pmode, funexp); | |
232 | #endif | |
233 | ||
234 | insn_before = get_last_insn (); | |
235 | ||
236 | /* Cannot pass FUNEXP since emit_library_call insists | |
237 | on getting a SYMBOL_REF. But cse will make this SYMBOL_REF | |
238 | be replaced with the copy we made just above. */ | |
239 | /* Pass 1 for NO_QUEUE so we don't lose any increments | |
240 | if the libcall is cse'd or moved. */ | |
241 | emit_library_call (gen_rtx (SYMBOL_REF, Pmode, | |
242 | binoptab->handlers[(int) mode].lib_call), | |
243 | 1, mode, 2, op0, mode, op1, mode); | |
244 | target = hard_libcall_value (mode); | |
245 | temp = copy_to_reg (target); | |
246 | ||
247 | if (insn_before == 0) | |
248 | insn_first = get_insns (); | |
249 | else | |
250 | insn_first = NEXT_INSN (insn_before); | |
251 | insn_last = get_last_insn (); | |
252 | ||
253 | REG_NOTES (insn_last) | |
254 | = gen_rtx (EXPR_LIST, REG_EQUAL, | |
255 | gen_rtx (binoptab->code, mode, op0, op1), | |
256 | gen_rtx (INSN_LIST, REG_RETVAL, insn_first, | |
257 | REG_NOTES (insn_last))); | |
258 | REG_NOTES (insn_first) | |
259 | = gen_rtx (INSN_LIST, REG_LIBCALL, insn_last, | |
260 | REG_NOTES (insn_first)); | |
261 | return temp; | |
262 | } | |
263 | ||
264 | delete_insns_since (last); | |
265 | ||
266 | /* It can't be done in this mode. Can we do it in a wider mode? */ | |
267 | ||
268 | if (! (methods == OPTAB_WIDEN || methods == OPTAB_LIB_WIDEN | |
269 | || methods == OPTAB_MUST_WIDEN)) | |
270 | return 0; /* Caller says, don't even try. */ | |
271 | ||
272 | /* Compute the value of METHODS to pass to recursive calls. | |
273 | Don't allow widening to be tried recursively. */ | |
274 | ||
275 | methods = (methods == OPTAB_LIB_WIDEN ? OPTAB_LIB : OPTAB_DIRECT); | |
276 | ||
277 | /* Widening is now independent of specific machine modes. | |
278 | It is assumed that widening may be performed to any | |
279 | higher numbered mode in the same mode class. */ | |
280 | ||
281 | if (class == MODE_INT || class == MODE_FLOAT) | |
282 | { | |
283 | for (wider_mode = INC_MODE (mode); | |
284 | ((int) wider_mode < (int) MAX_MACHINE_MODE | |
285 | && GET_MODE_CLASS (wider_mode) == class); | |
286 | wider_mode = INC_MODE (wider_mode)) | |
287 | { | |
288 | if ((binoptab->handlers[(int) wider_mode].insn_code | |
289 | != CODE_FOR_nothing) | |
290 | || (methods == OPTAB_LIB | |
291 | && binoptab->handlers[(int) wider_mode].lib_call)) | |
292 | { | |
293 | rtx xop0 = op0, xop1 = op1; | |
294 | int no_extend = 0; | |
295 | ||
296 | /* For certain operations, we need not actually extend | |
297 | the narrow operands, as long as we will truncate | |
298 | the results to the same narrowness. */ | |
299 | ||
300 | if (binoptab == ior_optab || binoptab == and_optab | |
301 | || binoptab == xor_optab || binoptab == andcb_optab | |
302 | || binoptab == add_optab || binoptab == sub_optab | |
303 | || binoptab == smul_optab || binoptab == umul_optab | |
304 | || binoptab == ashl_optab || binoptab == lshl_optab) | |
305 | no_extend = 1; | |
306 | ||
307 | if (GET_MODE (xop0) != VOIDmode) | |
308 | { | |
309 | if (no_extend) | |
310 | { | |
311 | temp = force_reg (GET_MODE (xop0), xop0); | |
312 | xop0 = gen_rtx (SUBREG, wider_mode, temp, 0); | |
313 | } | |
314 | else | |
315 | { | |
316 | temp = gen_reg_rtx (wider_mode); | |
317 | convert_move (temp, xop0, unsignedp); | |
318 | xop0 = temp; | |
319 | } | |
320 | } | |
321 | if (GET_MODE (xop1) != VOIDmode) | |
322 | { | |
323 | if (no_extend) | |
324 | { | |
325 | temp = force_reg (GET_MODE (xop1), xop1); | |
326 | xop1 = gen_rtx (SUBREG, wider_mode, temp, 0); | |
327 | } | |
328 | else | |
329 | { | |
330 | temp = gen_reg_rtx (wider_mode); | |
331 | convert_move (temp, xop1, unsignedp); | |
332 | xop1 = temp; | |
333 | } | |
334 | } | |
335 | ||
336 | temp = expand_binop (wider_mode, binoptab, xop0, xop1, 0, | |
337 | unsignedp, methods); | |
338 | if (temp) | |
339 | { | |
340 | if (class == MODE_FLOAT) | |
341 | { | |
342 | if (target == 0) | |
343 | target = gen_reg_rtx (mode); | |
344 | convert_move (target, temp, 0); | |
345 | return target; | |
346 | } | |
347 | else | |
348 | return gen_lowpart (mode, temp); | |
349 | } | |
350 | else | |
351 | delete_insns_since (last); | |
352 | } | |
353 | } | |
354 | } | |
355 | ||
356 | return 0; | |
357 | } | |
358 | \f | |
359 | /* Expand a binary operator which has both signed and unsigned forms. | |
360 | UOPTAB is the optab for unsigned operations, and SOPTAB is for | |
361 | signed operations. | |
362 | ||
363 | If we widen unsigned operands, we may use a signed wider operation instead | |
364 | of an unsigned wider operation, since the result would be the same. */ | |
365 | ||
366 | rtx | |
367 | sign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods) | |
368 | enum machine_mode mode; | |
369 | optab uoptab, soptab; | |
370 | rtx op0, op1, target; | |
371 | int unsignedp; | |
372 | enum optab_methods methods; | |
373 | { | |
374 | register rtx temp; | |
375 | optab direct_optab = unsignedp ? uoptab : soptab; | |
376 | struct optab wide_soptab; | |
377 | ||
378 | /* Do it without widening, if possible. */ | |
379 | temp = expand_binop (mode, direct_optab, op0, op1, target, | |
380 | unsignedp, OPTAB_DIRECT); | |
381 | if (temp || methods == OPTAB_DIRECT) | |
382 | return temp; | |
383 | ||
384 | /* Try widening to a signed int. Make a fake signed optab that | |
385 | hides any signed insn for direct use. */ | |
386 | wide_soptab = *soptab; | |
387 | wide_soptab.handlers[(int) mode].insn_code = CODE_FOR_nothing; | |
388 | wide_soptab.handlers[(int) mode].lib_call = 0; | |
389 | ||
390 | temp = expand_binop (mode, &wide_soptab, op0, op1, target, | |
391 | unsignedp, OPTAB_WIDEN); | |
392 | ||
393 | /* For unsigned operands, try widening to an unsigned int. */ | |
394 | if (temp == 0 && unsignedp) | |
395 | temp = expand_binop (mode, uoptab, op0, op1, target, | |
396 | unsignedp, OPTAB_WIDEN); | |
397 | if (temp || methods == OPTAB_WIDEN) | |
398 | return temp; | |
399 | ||
400 | /* Use the right width lib call if that exists. */ | |
401 | temp = expand_binop (mode, direct_optab, op0, op1, target, unsignedp, OPTAB_LIB); | |
402 | if (temp || methods == OPTAB_LIB) | |
403 | return temp; | |
404 | ||
405 | /* Must widen and use a lib call, use either signed or unsigned. */ | |
406 | temp = expand_binop (mode, &wide_soptab, op0, op1, target, | |
407 | unsignedp, methods); | |
408 | if (temp != 0) | |
409 | return temp; | |
410 | if (unsignedp) | |
411 | return expand_binop (mode, uoptab, op0, op1, target, | |
412 | unsignedp, methods); | |
413 | return 0; | |
414 | } | |
415 | \f | |
416 | /* Generate code to perform an operation specified by BINOPTAB | |
417 | on operands OP0 and OP1, with two results to TARG1 and TARG2. | |
418 | We assume that the order of the operands for the instruction | |
419 | is TARG0, OP0, OP1, TARG1, which would fit a pattern like | |
420 | [(set TARG0 (operate OP0 OP1)) (set TARG1 (operate ...))]. | |
421 | ||
422 | Either TARG0 or TARG1 may be zero, but what that means is that | |
423 | that result is not actually wanted. We will generate it into | |
424 | a dummy pseudo-reg and discard it. They may not both be zero. | |
425 | ||
426 | Returns 1 if this operation can be performed; 0 if not. */ | |
427 | ||
428 | int | |
429 | expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp) | |
430 | optab binoptab; | |
431 | rtx op0, op1; | |
432 | rtx targ0, targ1; | |
433 | int unsignedp; | |
434 | { | |
435 | enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1); | |
436 | enum mode_class class; | |
437 | enum machine_mode wider_mode; | |
438 | ||
439 | class = GET_MODE_CLASS (mode); | |
440 | ||
441 | op0 = protect_from_queue (op0, 0); | |
442 | op1 = protect_from_queue (op1, 0); | |
443 | ||
444 | if (flag_force_mem) | |
445 | { | |
446 | op0 = force_not_mem (op0); | |
447 | op1 = force_not_mem (op1); | |
448 | } | |
449 | ||
450 | if (targ0) | |
451 | targ0 = protect_from_queue (targ0, 1); | |
452 | else | |
453 | targ0 = gen_reg_rtx (mode); | |
454 | if (targ1) | |
455 | targ1 = protect_from_queue (targ1, 1); | |
456 | else | |
457 | targ1 = gen_reg_rtx (mode); | |
458 | ||
459 | if (binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) | |
460 | { | |
461 | emit_insn (GEN_FCN (binoptab->handlers[(int) mode].insn_code) | |
462 | (targ0, op0, op1, targ1)); | |
463 | return 1; | |
464 | } | |
465 | ||
466 | /* It can't be done in this mode. Can we do it in a wider mode? */ | |
467 | ||
468 | if (class == MODE_INT || class == MODE_FLOAT) | |
469 | { | |
470 | for (wider_mode = INC_MODE (mode); | |
471 | ((int) wider_mode < (int) MAX_MACHINE_MODE | |
472 | && GET_MODE_CLASS (wider_mode) == class); | |
473 | wider_mode = INC_MODE (wider_mode)) | |
474 | { | |
475 | if (binoptab->handlers[(int) wider_mode].insn_code | |
476 | != CODE_FOR_nothing) | |
477 | { | |
478 | expand_twoval_binop_convert (binoptab, wider_mode, op0, op1, | |
479 | targ0, targ1, unsignedp); | |
480 | return 1; | |
481 | } | |
482 | } | |
483 | } | |
484 | return 0; | |
485 | } | |
486 | ||
487 | int | |
488 | expand_twoval_binop_convert (binoptab, mode, op0, op1, targ0, targ1, unsignedp) | |
489 | register optab binoptab; | |
490 | register rtx op0, op1, targ0, targ1; | |
491 | int unsignedp; | |
492 | { | |
493 | register rtx t0 = gen_reg_rtx (SImode); | |
494 | register rtx t1 = gen_reg_rtx (SImode); | |
495 | register rtx temp; | |
496 | ||
497 | temp = gen_reg_rtx (SImode); | |
498 | convert_move (temp, op0, unsignedp); | |
499 | op0 = temp; | |
500 | temp = gen_reg_rtx (SImode); | |
501 | convert_move (temp, op1, unsignedp); | |
502 | op1 = temp; | |
503 | ||
504 | expand_twoval_binop (binoptab, op0, op1, t0, t1, unsignedp); | |
505 | convert_move (targ0, t0, unsignedp); | |
506 | convert_move (targ1, t1, unsignedp); | |
507 | return 1; | |
508 | } | |
509 | \f | |
510 | /* Generate code to perform an operation specified by UNOPTAB | |
511 | on operand OP0, with result having machine-mode MODE. | |
512 | ||
513 | UNSIGNEDP is for the case where we have to widen the operands | |
514 | to perform the operation. It says to use zero-extension. | |
515 | ||
516 | If TARGET is nonzero, the value | |
517 | is generated there, if it is convenient to do so. | |
518 | In all cases an rtx is returned for the locus of the value; | |
519 | this may or may not be TARGET. */ | |
520 | ||
521 | rtx | |
522 | expand_unop (mode, unoptab, op0, target, unsignedp) | |
523 | enum machine_mode mode; | |
524 | optab unoptab; | |
525 | rtx op0; | |
526 | rtx target; | |
527 | int unsignedp; | |
528 | { | |
529 | enum mode_class class; | |
530 | enum machine_mode wider_mode; | |
531 | register rtx temp; | |
532 | ||
533 | class = GET_MODE_CLASS (mode); | |
534 | ||
535 | op0 = protect_from_queue (op0, 0); | |
536 | ||
537 | if (flag_force_mem) | |
538 | { | |
539 | op0 = force_not_mem (op0); | |
540 | } | |
541 | ||
542 | if (target) | |
543 | target = protect_from_queue (target, 1); | |
544 | ||
545 | if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) | |
546 | { | |
547 | int icode = (int) unoptab->handlers[(int) mode].insn_code; | |
548 | enum machine_mode mode0 = insn_operand_mode[icode][1]; | |
549 | ||
550 | if (target) | |
551 | temp = target; | |
552 | else | |
553 | temp = gen_reg_rtx (mode); | |
554 | ||
555 | if (GET_MODE (op0) != VOIDmode | |
556 | && GET_MODE (op0) != mode0) | |
557 | op0 = convert_to_mode (mode0, op0, unsignedp); | |
558 | ||
559 | /* Now, if insn requires register operands, put operands into regs. */ | |
560 | ||
561 | if (! (*insn_operand_predicate[icode][1]) (op0, mode0)) | |
562 | op0 = force_reg (mode0, op0); | |
563 | ||
564 | if (! (*insn_operand_predicate[icode][0]) (temp, mode)) | |
565 | temp = gen_reg_rtx (mode); | |
566 | ||
567 | emit_insn (GEN_FCN (icode) (temp, op0)); | |
568 | return temp; | |
569 | } | |
570 | else if (unoptab->handlers[(int) mode].lib_call) | |
571 | { | |
572 | rtx insn_before, insn_last; | |
573 | rtx funexp = gen_rtx (SYMBOL_REF, Pmode, | |
574 | unoptab->handlers[(int) mode].lib_call); | |
575 | ||
576 | /* Pass the address through a pseudoreg, if desired, | |
577 | before the "beginning" of the library call (for deletion). */ | |
578 | #ifndef NO_FUNCTION_CSE | |
579 | if (! flag_no_function_cse) | |
580 | funexp = copy_to_mode_reg (Pmode, funexp); | |
581 | #endif | |
582 | ||
583 | insn_before = get_last_insn (); | |
584 | ||
585 | /* Cannot pass FUNEXP since emit_library_call insists | |
586 | on getting a SYMBOL_REF. But cse will make this SYMBOL_REF | |
587 | be replaced with the copy we made just above. */ | |
588 | /* Pass 1 for NO_QUEUE so we don't lose any increments | |
589 | if the libcall is cse'd or moved. */ | |
590 | emit_library_call (gen_rtx (SYMBOL_REF, Pmode, | |
591 | unoptab->handlers[(int) mode].lib_call), | |
592 | 1, mode, 1, op0, mode); | |
593 | target = hard_libcall_value (mode); | |
594 | temp = copy_to_reg (target); | |
595 | insn_last = get_last_insn (); | |
596 | REG_NOTES (insn_last) | |
597 | = gen_rtx (EXPR_LIST, REG_EQUAL, | |
598 | gen_rtx (unoptab->code, mode, op0), | |
599 | gen_rtx (INSN_LIST, REG_RETVAL, | |
600 | NEXT_INSN (insn_before), | |
601 | REG_NOTES (insn_last))); | |
602 | REG_NOTES (NEXT_INSN (insn_before)) | |
603 | = gen_rtx (INSN_LIST, REG_LIBCALL, insn_last, | |
604 | REG_NOTES (NEXT_INSN (insn_before))); | |
605 | return temp; | |
606 | } | |
607 | ||
608 | /* It can't be done in this mode. Can we do it in a wider mode? */ | |
609 | ||
610 | if (class == MODE_INT || class == MODE_FLOAT) | |
611 | { | |
612 | for (wider_mode = INC_MODE (mode); | |
613 | ((int) wider_mode < (int) MAX_MACHINE_MODE | |
614 | && GET_MODE_CLASS (wider_mode) == class); | |
615 | wider_mode = INC_MODE (wider_mode)) | |
616 | { | |
617 | if ((unoptab->handlers[(int) wider_mode].insn_code | |
618 | != CODE_FOR_nothing) | |
619 | || unoptab->handlers[(int) wider_mode].lib_call) | |
620 | { | |
621 | if (GET_MODE (op0) != VOIDmode) | |
622 | { | |
623 | temp = gen_reg_rtx (wider_mode); | |
624 | convert_move (temp, op0, unsignedp); | |
625 | op0 = temp; | |
626 | } | |
627 | ||
628 | target = expand_unop (wider_mode, unoptab, op0, 0, unsignedp); | |
629 | if (class == MODE_FLOAT) | |
630 | { | |
631 | if (target == 0) | |
632 | target = gen_reg_rtx (mode); | |
633 | convert_move (target, temp, 0); | |
634 | return target; | |
635 | } | |
636 | else | |
637 | return gen_lowpart (mode, target); | |
638 | } | |
639 | } | |
640 | } | |
641 | ||
642 | return 0; | |
643 | } | |
644 | \f | |
645 | /* Generate an instruction whose insn-code is INSN_CODE, | |
646 | with two operands: an output TARGET and an input OP0. | |
647 | TARGET *must* be nonzero, and the output is always stored there. | |
648 | CODE is an rtx code such that (CODE OP0) is an rtx that describes | |
649 | the value that is stored into TARGET. */ | |
650 | ||
651 | void | |
652 | emit_unop_insn (icode, target, op0, code) | |
653 | int icode; | |
654 | rtx target; | |
655 | rtx op0; | |
656 | enum rtx_code code; | |
657 | { | |
658 | register rtx temp; | |
659 | enum machine_mode mode0 = insn_operand_mode[icode][1]; | |
660 | rtx insn; | |
661 | rtx prev_insn; | |
662 | ||
663 | temp = target = protect_from_queue (target, 1); | |
664 | ||
665 | op0 = protect_from_queue (op0, 0); | |
666 | ||
667 | if (flag_force_mem) | |
668 | op0 = force_not_mem (op0); | |
669 | ||
670 | /* Now, if insn requires register operands, put operands into regs. */ | |
671 | ||
672 | if (! (*insn_operand_predicate[icode][1]) (op0, mode0)) | |
673 | op0 = force_reg (mode0, op0); | |
674 | ||
675 | if (! (*insn_operand_predicate[icode][0]) (temp, GET_MODE (temp)) | |
676 | || (flag_force_mem && GET_CODE (temp) == MEM)) | |
677 | temp = gen_reg_rtx (GET_MODE (temp)); | |
678 | ||
679 | prev_insn = get_last_insn (); | |
680 | insn = emit_insn (GEN_FCN (icode) (temp, op0)); | |
681 | ||
682 | /* If we just made a multi-insn sequence, | |
683 | record in the last insn an equivalent expression for its value | |
684 | and a pointer to the first insn. This makes cse possible. */ | |
685 | if (code != UNKNOWN && PREV_INSN (insn) != prev_insn) | |
686 | REG_NOTES (insn) | |
687 | = gen_rtx (EXPR_LIST, REG_EQUAL, | |
688 | gen_rtx (code, GET_MODE (temp), op0), | |
689 | REG_NOTES (insn)); | |
690 | ||
691 | if (temp != target) | |
692 | emit_move_insn (target, temp); | |
693 | } | |
694 | \f | |
695 | /* Generate code to store zero in X. */ | |
696 | ||
697 | void | |
698 | emit_clr_insn (x) | |
699 | rtx x; | |
700 | { | |
701 | emit_move_insn (x, const0_rtx); | |
702 | } | |
703 | ||
704 | /* Generate code to store 1 in X | |
705 | assuming it contains zero beforehand. */ | |
706 | ||
707 | void | |
708 | emit_0_to_1_insn (x) | |
709 | rtx x; | |
710 | { | |
711 | emit_move_insn (x, const1_rtx); | |
712 | } | |
713 | ||
714 | /* Generate code to compare X with Y | |
715 | so that the condition codes are set. | |
716 | ||
717 | UNSIGNEDP nonzero says that X and Y are unsigned; | |
718 | this matters if they need to be widened. | |
719 | ||
720 | If they have mode BLKmode, then SIZE specifies the size of both X and Y, | |
721 | and ALIGN specifies the known shared alignment of X and Y. */ | |
722 | ||
723 | void | |
724 | emit_cmp_insn (x, y, size, unsignedp, align) | |
725 | rtx x, y; | |
726 | rtx size; | |
727 | int unsignedp; | |
728 | int align; | |
729 | { | |
730 | enum machine_mode mode = GET_MODE (x); | |
731 | enum mode_class class; | |
732 | enum machine_mode wider_mode; | |
733 | ||
734 | if (mode == VOIDmode) mode = GET_MODE (y); | |
735 | /* They could both be VOIDmode if both args are immediate constants, | |
736 | but we should fold that at an earlier stage. | |
737 | With no special code here, this will call abort, | |
738 | reminding the programmer to implement such folding. */ | |
739 | ||
740 | class = GET_MODE_CLASS (mode); | |
741 | ||
742 | if (mode != BLKmode && flag_force_mem) | |
743 | { | |
744 | x = force_not_mem (x); | |
745 | y = force_not_mem (y); | |
746 | } | |
747 | ||
748 | /* Handle all BLKmode compares. */ | |
749 | ||
750 | if (mode == BLKmode) | |
751 | { | |
752 | emit_queue (); | |
753 | x = protect_from_queue (x, 0); | |
754 | y = protect_from_queue (y, 0); | |
755 | ||
756 | if (size == 0) | |
757 | abort (); | |
758 | #ifdef HAVE_cmpstrqi | |
759 | if (HAVE_cmpstrqi | |
760 | && GET_CODE (size) == CONST_INT | |
761 | && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode))) | |
762 | emit_insn (gen_cmpstrqi (x, y, size, | |
763 | gen_rtx (CONST_INT, VOIDmode, align))); | |
764 | else | |
765 | #endif | |
766 | #ifdef HAVE_cmpstrhi | |
767 | if (HAVE_cmpstrhi | |
768 | && GET_CODE (size) == CONST_INT | |
769 | && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode))) | |
770 | emit_insn (gen_cmpstrhi (x, y, size, | |
771 | gen_rtx (CONST_INT, VOIDmode, align))); | |
772 | else | |
773 | #endif | |
774 | #ifdef HAVE_cmpstrsi | |
775 | if (HAVE_cmpstrsi) | |
776 | emit_insn (gen_cmpstrsi (x, y, convert_to_mode (SImode, size, 1), | |
777 | gen_rtx (CONST_INT, VOIDmode, align))); | |
778 | else | |
779 | #endif | |
780 | { | |
781 | #ifdef TARGET_MEM_FUNCTIONS | |
782 | emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcmp"), 0, | |
783 | SImode, 3, | |
784 | XEXP (x, 0), Pmode, XEXP (y, 0), Pmode, | |
785 | size, Pmode); | |
786 | #else | |
787 | emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcmp"), 0, | |
788 | SImode, 3, | |
789 | XEXP (x, 0), Pmode, XEXP (y, 0), Pmode, | |
790 | size, Pmode); | |
791 | #endif | |
792 | emit_cmp_insn (hard_libcall_value (SImode), const0_rtx, 0, 0, 0); | |
793 | } | |
794 | return; | |
795 | } | |
796 | ||
797 | /* Handle some compares against zero. */ | |
798 | ||
799 | if (y == CONST0_RTX (mode) | |
800 | && tst_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) | |
801 | { | |
802 | int icode = (int) tst_optab->handlers[(int) mode].insn_code; | |
803 | ||
804 | emit_queue (); | |
805 | x = protect_from_queue (x, 0); | |
806 | y = protect_from_queue (y, 0); | |
807 | ||
808 | /* Now, if insn requires register operands, put operands into regs. */ | |
809 | if (! (*insn_operand_predicate[icode][0]) | |
810 | (x, insn_operand_mode[icode][0])) | |
811 | x = force_reg (insn_operand_mode[icode][0], x); | |
812 | ||
813 | emit_insn (GEN_FCN (icode) (x)); | |
814 | return; | |
815 | } | |
816 | ||
817 | /* Handle compares for which there is a directly suitable insn. */ | |
818 | ||
819 | if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) | |
820 | { | |
821 | int icode = (int) cmp_optab->handlers[(int) mode].insn_code; | |
822 | ||
823 | emit_queue (); | |
824 | x = protect_from_queue (x, 0); | |
825 | y = protect_from_queue (y, 0); | |
826 | ||
827 | /* Now, if insn requires register operands, put operands into regs. */ | |
828 | if (! (*insn_operand_predicate[icode][0]) | |
829 | (x, insn_operand_mode[icode][0])) | |
830 | x = force_reg (insn_operand_mode[icode][0], x); | |
831 | ||
832 | if (! (*insn_operand_predicate[icode][1]) | |
833 | (y, insn_operand_mode[icode][1])) | |
834 | y = force_reg (insn_operand_mode[icode][1], y); | |
835 | ||
836 | emit_insn (GEN_FCN (icode) (x, y)); | |
837 | return; | |
838 | } | |
839 | ||
840 | /* Try widening if we can find a direct insn that way. */ | |
841 | ||
842 | if (class == MODE_INT || class == MODE_FLOAT) | |
843 | { | |
844 | for (wider_mode = INC_MODE (mode); | |
845 | ((int) wider_mode < (int) MAX_MACHINE_MODE | |
846 | && GET_MODE_CLASS (wider_mode) == class); | |
847 | wider_mode = INC_MODE (wider_mode)) | |
848 | { | |
849 | if (cmp_optab->handlers[(int) wider_mode].insn_code | |
850 | != CODE_FOR_nothing) | |
851 | { | |
852 | x = convert_to_mode (wider_mode, x, unsignedp); | |
853 | y = convert_to_mode (wider_mode, y, unsignedp); | |
854 | emit_cmp_insn (x, y, 0, unsignedp, align); | |
855 | return; | |
856 | } | |
857 | } | |
858 | } | |
859 | ||
860 | /* Handle a lib call just for the mode we are using. */ | |
861 | ||
862 | if (cmp_optab->handlers[(int) mode].lib_call) | |
863 | { | |
864 | char *string = cmp_optab->handlers[(int) mode].lib_call; | |
865 | /* If we want unsigned, and this mode has a distinct unsigned | |
866 | comparison routine, use that. */ | |
867 | if (unsignedp && ucmp_optab->handlers[(int) mode].lib_call) | |
868 | string = ucmp_optab->handlers[(int) mode].lib_call; | |
869 | ||
870 | emit_library_call (gen_rtx (SYMBOL_REF, Pmode, string), 0, | |
871 | SImode, 2, x, mode, y, mode); | |
872 | ||
873 | /* Integer comparison returns a result that must be compared against 1, | |
874 | so that even if we do an unsigned compare afterward, | |
875 | there is still a value that can represent the result "less than". */ | |
876 | if (GET_MODE_CLASS (mode) == MODE_INT) | |
877 | emit_cmp_insn (hard_libcall_value (SImode), const1_rtx, 0, unsignedp, 0); | |
878 | else | |
879 | emit_cmp_insn (hard_libcall_value (SImode), const0_rtx, 0, 0, 0); | |
880 | return; | |
881 | } | |
882 | ||
883 | /* Try widening and then using a libcall. */ | |
884 | ||
885 | if (class == MODE_FLOAT) | |
886 | { | |
887 | for (wider_mode = INC_MODE (mode); | |
888 | ((int) wider_mode < (int) MAX_MACHINE_MODE | |
889 | && GET_MODE_CLASS (wider_mode) == class); | |
890 | wider_mode = INC_MODE (wider_mode)) | |
891 | { | |
892 | if ((cmp_optab->handlers[(int) wider_mode].insn_code | |
893 | != CODE_FOR_nothing) | |
894 | || (cmp_optab->handlers[(int) wider_mode].lib_call != 0)) | |
895 | { | |
896 | x = convert_to_mode (wider_mode, x, unsignedp); | |
897 | y = convert_to_mode (wider_mode, y, unsignedp); | |
898 | emit_cmp_insn (x, y, 0, unsignedp, align); | |
899 | } | |
900 | } | |
901 | return; | |
902 | } | |
903 | ||
904 | abort (); | |
905 | } | |
906 | \f | |
907 | /* These three functions generate an insn body and return it | |
908 | rather than emitting the insn. | |
909 | ||
910 | They do not protect from queued increments, | |
911 | because they may be used 1) in protect_from_queue itself | |
912 | and 2) in other passes where there is no queue. */ | |
913 | ||
914 | /* Generate and return an insn body to add Y to X. */ | |
915 | ||
916 | rtx | |
917 | gen_add2_insn (x, y) | |
918 | rtx x, y; | |
919 | { | |
920 | return (GEN_FCN (add_optab->handlers[(int) GET_MODE (x)].insn_code) | |
921 | (x, x, y)); | |
922 | } | |
923 | ||
924 | int | |
925 | have_add2_insn (mode) | |
926 | enum machine_mode mode; | |
927 | { | |
928 | return add_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing; | |
929 | } | |
930 | ||
931 | /* Generate and return an insn body to subtract Y from X. */ | |
932 | ||
933 | rtx | |
934 | gen_sub2_insn (x, y) | |
935 | rtx x, y; | |
936 | { | |
937 | return (GEN_FCN (sub_optab->handlers[(int) GET_MODE (x)].insn_code) | |
938 | (x, x, y)); | |
939 | } | |
940 | ||
941 | int | |
942 | have_sub2_insn (mode) | |
943 | enum machine_mode mode; | |
944 | { | |
945 | return add_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing; | |
946 | } | |
947 | ||
948 | /* Generate the body of an instruction to copy Y into X. */ | |
949 | ||
950 | rtx | |
951 | gen_move_insn (x, y) | |
952 | rtx x, y; | |
953 | { | |
954 | register enum machine_mode mode = GET_MODE (x); | |
955 | if (mode == VOIDmode) | |
956 | mode = GET_MODE (y); | |
957 | return (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y)); | |
958 | } | |
959 | \f | |
960 | #if 0 | |
961 | /* Tables of patterns for extending one integer mode to another. */ | |
962 | enum insn_code zero_extend_optab[MAX_MACHINE_MODE][MAX_MACHINE_MODE]; | |
963 | enum insn_code sign_extend_optab[MAX_MACHINE_MODE][MAX_MACHINE_MODE]; | |
964 | ||
965 | /* Generate the body of an insn to extend Y (with mode MFROM) | |
966 | into X (with mode MTO). Do zero-extension if UNSIGNEDP is nonzero. */ | |
967 | ||
968 | rtx | |
969 | gen_extend_insn (x, y, mto, mfrom, unsignedp) | |
970 | rtx x, y; | |
971 | enum machine_mode mto, mfrom; | |
972 | int unsignedp; | |
973 | { | |
974 | return (GEN_FCN ((unsignedp ? zero_extend_optab : sign_extend_optab) | |
975 | [(int)mto][(int)mfrom]) | |
976 | (x, y)); | |
977 | } | |
978 | ||
979 | static void | |
980 | init_extends () | |
981 | { | |
982 | bzero (sign_extend_optab, sizeof sign_extend_optab); | |
983 | bzero (zero_extend_optab, sizeof zero_extend_optab); | |
984 | sign_extend_optab[(int) SImode][(int) HImode] = CODE_FOR_extendhisi2; | |
985 | sign_extend_optab[(int) SImode][(int) QImode] = CODE_FOR_extendqisi2; | |
986 | sign_extend_optab[(int) HImode][(int) QImode] = CODE_FOR_extendqihi2; | |
987 | zero_extend_optab[(int) SImode][(int) HImode] = CODE_FOR_zero_extendhisi2; | |
988 | zero_extend_optab[(int) SImode][(int) QImode] = CODE_FOR_zero_extendqisi2; | |
989 | zero_extend_optab[(int) HImode][(int) QImode] = CODE_FOR_zero_extendqihi2; | |
990 | } | |
991 | #endif | |
992 | \f | |
993 | /* can_fix_p and can_float_p say whether the target machine | |
994 | can directly convert a given fixed point type to | |
995 | a given floating point type, or vice versa. | |
996 | The returned value is the CODE_FOR_... value to use, | |
997 | or CODE_FOR_nothing if these modes cannot be directly converted. */ | |
998 | ||
999 | static enum insn_code fixtab[2][2][2]; | |
1000 | static enum insn_code fixtrunctab[2][2][2]; | |
1001 | static enum insn_code floattab[2][2]; | |
1002 | ||
1003 | /* *TRUNCP_PTR is set to 1 if it is necessary to output | |
1004 | an explicit FTRUNC insn before the fix insn; otherwise 0. */ | |
1005 | ||
1006 | static enum insn_code | |
1007 | can_fix_p (fixmode, fltmode, unsignedp, truncp_ptr) | |
1008 | enum machine_mode fltmode, fixmode; | |
1009 | int unsignedp; | |
1010 | int *truncp_ptr; | |
1011 | { | |
1012 | *truncp_ptr = 0; | |
1013 | if (fixtrunctab[fltmode != SFmode][fixmode == DImode][unsignedp] | |
1014 | != CODE_FOR_nothing) | |
1015 | return fixtrunctab[fltmode != SFmode][fixmode == DImode][unsignedp]; | |
1016 | if (ftrunc_optab->handlers[(int) fltmode].insn_code != CODE_FOR_nothing) | |
1017 | { | |
1018 | *truncp_ptr = 1; | |
1019 | return fixtab[fltmode != SFmode][fixmode == DImode][unsignedp]; | |
1020 | } | |
1021 | return CODE_FOR_nothing; | |
1022 | } | |
1023 | ||
1024 | static enum insn_code | |
1025 | can_float_p (fltmode, fixmode) | |
1026 | enum machine_mode fixmode, fltmode; | |
1027 | { | |
1028 | return floattab[fltmode != SFmode][fixmode == DImode]; | |
1029 | } | |
1030 | ||
1031 | void | |
1032 | init_fixtab () | |
1033 | { | |
1034 | enum insn_code *p; | |
1035 | for (p = fixtab[0][0]; | |
1036 | p < fixtab[0][0] + sizeof fixtab / sizeof (fixtab[0][0][0]); | |
1037 | p++) | |
1038 | *p = CODE_FOR_nothing; | |
1039 | for (p = fixtrunctab[0][0]; | |
1040 | p < fixtrunctab[0][0] + sizeof fixtrunctab / sizeof (fixtrunctab[0][0][0]); | |
1041 | p++) | |
1042 | *p = CODE_FOR_nothing; | |
1043 | ||
1044 | #ifdef HAVE_fixsfsi2 | |
1045 | if (HAVE_fixsfsi2) | |
1046 | fixtab[0][0][0] = CODE_FOR_fixsfsi2; | |
1047 | #endif | |
1048 | #ifdef HAVE_fixsfdi2 | |
1049 | if (HAVE_fixsfdi2) | |
1050 | fixtab[0][1][0] = CODE_FOR_fixsfdi2; | |
1051 | #endif | |
1052 | #ifdef HAVE_fixdfsi2 | |
1053 | if (HAVE_fixdfsi2) | |
1054 | fixtab[1][0][0] = CODE_FOR_fixdfsi2; | |
1055 | #endif | |
1056 | #ifdef HAVE_fixdfdi2 | |
1057 | if (HAVE_fixdfdi2) | |
1058 | fixtab[1][1][0] = CODE_FOR_fixdfdi2; | |
1059 | #endif | |
1060 | ||
1061 | #ifdef HAVE_fixunssfsi2 | |
1062 | if (HAVE_fixunssfsi2) | |
1063 | fixtab[0][0][1] = CODE_FOR_fixunssfsi2; | |
1064 | #endif | |
1065 | #ifdef HAVE_fixunssfdi2 | |
1066 | if (HAVE_fixunssfdi2) | |
1067 | fixtab[0][1][1] = CODE_FOR_fixunssfdi2; | |
1068 | #endif | |
1069 | #ifdef HAVE_fixunsdfsi2 | |
1070 | if (HAVE_fixunsdfsi2) | |
1071 | fixtab[1][0][1] = CODE_FOR_fixunsdfsi2; | |
1072 | #endif | |
1073 | #ifdef HAVE_fixunsdfdi2 | |
1074 | if (HAVE_fixunsdfdi2) | |
1075 | fixtab[1][1][1] = CODE_FOR_fixunsdfdi2; | |
1076 | #endif | |
1077 | ||
1078 | #ifdef HAVE_fix_truncsfsi2 | |
1079 | if (HAVE_fix_truncsfsi2) | |
1080 | fixtrunctab[0][0][0] = CODE_FOR_fix_truncsfsi2; | |
1081 | #endif | |
1082 | #ifdef HAVE_fix_truncsfdi2 | |
1083 | if (HAVE_fix_truncsfdi2) | |
1084 | fixtrunctab[0][1][0] = CODE_FOR_fix_truncsfdi2; | |
1085 | #endif | |
1086 | #ifdef HAVE_fix_truncdfsi2 | |
1087 | if (HAVE_fix_truncdfsi2) | |
1088 | fixtrunctab[1][0][0] = CODE_FOR_fix_truncdfsi2; | |
1089 | #endif | |
1090 | #ifdef HAVE_fix_truncdfdi2 | |
1091 | if (HAVE_fix_truncdfdi2) | |
1092 | fixtrunctab[1][1][0] = CODE_FOR_fix_truncdfdi2; | |
1093 | #endif | |
1094 | ||
1095 | #ifdef HAVE_fixuns_truncsfsi2 | |
1096 | if (HAVE_fixuns_truncsfsi2) | |
1097 | fixtrunctab[0][0][1] = CODE_FOR_fixuns_truncsfsi2; | |
1098 | #endif | |
1099 | #ifdef HAVE_fixuns_truncsfdi2 | |
1100 | if (HAVE_fixuns_truncsfdi2) | |
1101 | fixtrunctab[0][1][1] = CODE_FOR_fixuns_truncsfdi2; | |
1102 | #endif | |
1103 | #ifdef HAVE_fixuns_truncdfsi2 | |
1104 | if (HAVE_fixuns_truncdfsi2) | |
1105 | fixtrunctab[1][0][1] = CODE_FOR_fixuns_truncdfsi2; | |
1106 | #endif | |
1107 | #ifdef HAVE_fixuns_truncdfdi2 | |
1108 | if (HAVE_fixuns_truncdfdi2) | |
1109 | fixtrunctab[1][1][1] = CODE_FOR_fixuns_truncdfdi2; | |
1110 | #endif | |
1111 | ||
1112 | #ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC | |
1113 | /* This flag says the same insns that convert to a signed fixnum | |
1114 | also convert validly to an unsigned one. */ | |
1115 | { | |
1116 | int i; | |
1117 | int j; | |
1118 | for (i = 0; i < 2; i++) | |
1119 | for (j = 0; j < 2; j++) | |
1120 | fixtrunctab[i][j][1] = fixtrunctab[i][j][0]; | |
1121 | } | |
1122 | #endif | |
1123 | } | |
1124 | ||
1125 | void | |
1126 | init_floattab () | |
1127 | { | |
1128 | enum insn_code *p; | |
1129 | for (p = floattab[0]; | |
1130 | p < floattab[0] + sizeof floattab / sizeof (floattab[0][0]); | |
1131 | p++) | |
1132 | *p = CODE_FOR_nothing; | |
1133 | ||
1134 | #ifdef HAVE_floatsisf2 | |
1135 | if (HAVE_floatsisf2) | |
1136 | floattab[0][0] = CODE_FOR_floatsisf2; | |
1137 | #endif | |
1138 | #ifdef HAVE_floatdisf2 | |
1139 | if (HAVE_floatdisf2) | |
1140 | floattab[0][1] = CODE_FOR_floatdisf2; | |
1141 | #endif | |
1142 | #ifdef HAVE_floatsidf2 | |
1143 | if (HAVE_floatsidf2) | |
1144 | floattab[1][0] = CODE_FOR_floatsidf2; | |
1145 | #endif | |
1146 | #ifdef HAVE_floatdidf2 | |
1147 | if (HAVE_floatdidf2) | |
1148 | floattab[1][1] = CODE_FOR_floatdidf2; | |
1149 | #endif | |
1150 | } | |
1151 | \f | |
1152 | /* Generate code to convert FROM to floating point | |
1153 | and store in TO. FROM must be fixed point. | |
1154 | UNSIGNEDP nonzero means regard FROM as unsigned. | |
1155 | Normally this is done by correcting the final value | |
1156 | if it is negative. */ | |
1157 | ||
1158 | void | |
1159 | expand_float (real_to, from, unsignedp) | |
1160 | rtx real_to, from; | |
1161 | int unsignedp; | |
1162 | { | |
1163 | enum insn_code icode; | |
1164 | register rtx to; | |
1165 | ||
1166 | /* Constants should get converted in `fold'. | |
1167 | We lose here since we don't know the mode. */ | |
1168 | if (GET_MODE (from) == VOIDmode) | |
1169 | abort (); | |
1170 | ||
1171 | to = real_to = protect_from_queue (real_to, 1); | |
1172 | from = protect_from_queue (from, 0); | |
1173 | ||
1174 | if (flag_force_mem) | |
1175 | { | |
1176 | from = force_not_mem (from); | |
1177 | } | |
1178 | ||
1179 | /* If we are about to do some arithmetic to correct for an | |
1180 | unsigned operand, do it in a pseudo-register. */ | |
1181 | ||
1182 | if (unsignedp | |
1183 | && ! (GET_CODE (to) == REG && REGNO (to) >= FIRST_PSEUDO_REGISTER)) | |
1184 | to = gen_reg_rtx (GET_MODE (to)); | |
1185 | ||
1186 | /* Now do the basic conversion. Do it in the specified modes if possible; | |
1187 | otherwise convert either input, output or both with wider mode; | |
1188 | otherwise use a library call. */ | |
1189 | ||
1190 | if ((icode = can_float_p (GET_MODE (to), GET_MODE (from))) | |
1191 | != CODE_FOR_nothing) | |
1192 | { | |
1193 | emit_unop_insn (icode, to, from, FLOAT); | |
1194 | } | |
1195 | else if (GET_MODE (to) == SFmode | |
1196 | && ((icode = can_float_p (DFmode, GET_MODE (from))) | |
1197 | != CODE_FOR_nothing)) | |
1198 | { | |
1199 | to = gen_reg_rtx (DFmode); | |
1200 | emit_unop_insn (icode, to, from, FLOAT); | |
1201 | } | |
1202 | /* If we can't float a SI, maybe we can float a DI. | |
1203 | If so, convert to DI and then float. */ | |
1204 | else if (GET_MODE (from) != DImode | |
1205 | && (can_float_p (GET_MODE (to), DImode) != CODE_FOR_nothing | |
1206 | || can_float_p (DFmode, DImode) != CODE_FOR_nothing)) | |
1207 | { | |
1208 | register rtx tem = gen_reg_rtx (DImode); | |
1209 | convert_move (tem, from, unsignedp); | |
1210 | from = tem; | |
1211 | /* If we extend FROM then we don't need to correct | |
1212 | the final value for unsignedness. */ | |
1213 | unsignedp = 0; | |
1214 | ||
1215 | if ((icode = can_float_p (GET_MODE (to), GET_MODE (from))) | |
1216 | != CODE_FOR_nothing) | |
1217 | { | |
1218 | emit_unop_insn (icode, to, from, FLOAT); | |
1219 | } | |
1220 | else if ((icode = can_float_p (DFmode, DImode)) | |
1221 | != CODE_FOR_nothing) | |
1222 | { | |
1223 | to = gen_reg_rtx (DFmode); | |
1224 | emit_unop_insn (icode, to, from, FLOAT); | |
1225 | } | |
1226 | } | |
1227 | /* No hardware instruction available; call a library | |
1228 | to convert from SImode or DImode into DFmode. */ | |
1229 | else | |
1230 | { | |
1231 | if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode)) | |
1232 | { | |
1233 | from = convert_to_mode (SImode, from, unsignedp); | |
1234 | unsignedp = 0; | |
1235 | } | |
1236 | emit_library_call (gen_rtx (SYMBOL_REF, Pmode, | |
1237 | (GET_MODE (from) == SImode ? "__floatsidf" | |
1238 | : "__floatdidf")), | |
1239 | 0, DFmode, 1, from, GET_MODE (from)); | |
1240 | to = copy_to_reg (hard_libcall_value (DFmode)); | |
1241 | } | |
1242 | ||
1243 | /* If FROM was unsigned but we treated it as signed, | |
1244 | then in the case where it is negative (and therefore TO is negative), | |
1245 | correct its value by 2**bitwidth. */ | |
1246 | ||
1247 | if (unsignedp) | |
1248 | { | |
1249 | rtx label = gen_label_rtx (); | |
1250 | rtx temp; | |
1251 | REAL_VALUE_TYPE offset; | |
1252 | ||
1253 | do_pending_stack_adjust (); | |
1254 | emit_cmp_insn (to, GET_MODE (to) == DFmode ? dconst0_rtx : fconst0_rtx, | |
1255 | 0, 0, 0); | |
1256 | emit_jump_insn (gen_bge (label)); | |
1257 | offset = REAL_VALUE_LDEXP (1.0, GET_MODE_BITSIZE (GET_MODE (from))); | |
1258 | temp = expand_binop (GET_MODE (to), add_optab, to, | |
1259 | immed_real_const_1 (offset, GET_MODE (to)), | |
1260 | to, 0, OPTAB_LIB_WIDEN); | |
1261 | if (temp != to) | |
1262 | emit_move_insn (to, temp); | |
1263 | do_pending_stack_adjust (); | |
1264 | emit_label (label); | |
1265 | } | |
1266 | ||
1267 | /* Copy result to requested destination | |
1268 | if we have been computing in a temp location. */ | |
1269 | ||
1270 | if (to != real_to) | |
1271 | { | |
1272 | if (GET_MODE (real_to) == GET_MODE (to)) | |
1273 | emit_move_insn (real_to, to); | |
1274 | else | |
1275 | convert_move (real_to, to, 0); | |
1276 | } | |
1277 | } | |
1278 | \f | |
1279 | /* expand_fix: generate code to convert FROM to fixed point | |
1280 | and store in TO. FROM must be floating point. */ | |
1281 | ||
1282 | static rtx | |
1283 | ftruncify (x) | |
1284 | rtx x; | |
1285 | { | |
1286 | rtx temp = gen_reg_rtx (GET_MODE (x)); | |
1287 | return expand_unop (GET_MODE (x), ftrunc_optab, x, temp, 0); | |
1288 | } | |
1289 | ||
1290 | void | |
1291 | expand_fix (to, from, unsignedp) | |
1292 | register rtx to, from; | |
1293 | int unsignedp; | |
1294 | { | |
1295 | enum insn_code icode; | |
1296 | register rtx target; | |
1297 | int must_trunc = 0; | |
1298 | ||
1299 | while (1) | |
1300 | { | |
1301 | icode = can_fix_p (GET_MODE (to), GET_MODE (from), unsignedp, &must_trunc); | |
1302 | if (icode != CODE_FOR_nothing) | |
1303 | { | |
1304 | if (must_trunc) | |
1305 | from = ftruncify (from); | |
1306 | ||
1307 | emit_unop_insn (icode, to, from, FIX); | |
1308 | return; | |
1309 | } | |
1310 | ||
1311 | #if 0 /* Turned off. It fails because the positive numbers | |
1312 | that become temporarily negative are rounded up instead of down. */ | |
1313 | ||
1314 | /* If no insns for unsigned conversion, | |
1315 | we can go via a signed number. | |
1316 | But make sure we won't overflow in the compiler. */ | |
1317 | if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_INT | |
1318 | /* Make sure we won't lose significant bits doing this. */ | |
1319 | && GET_MODE_BITSIZE (GET_MODE (from)) > GET_MODE_BITSIZE (GET_MODE (to))) | |
1320 | { | |
1321 | icode = can_fix_p (GET_MODE (to), GET_MODE (from), | |
1322 | 0, &must_trunc); | |
1323 | ||
1324 | if (icode != CODE_FOR_nothing) | |
1325 | { | |
1326 | REAL_VALUE_TYPE offset; | |
1327 | rtx temp, temp1; | |
1328 | int bitsize = GET_MODE_BITSIZE (GET_MODE (to)); | |
1329 | ||
1330 | if (must_trunc) | |
1331 | from = ftruncify (from); | |
1332 | ||
1333 | /* Subtract 2**(N-1), convert to signed number, | |
1334 | then add 2**(N-1). */ | |
1335 | offset = REAL_VALUE_LDEXP (1.0, bitsize - 1); | |
1336 | temp = expand_binop (GET_MODE (from), sub_optab, from, | |
1337 | immed_real_const_1 (offset, GET_MODE (from)), | |
1338 | 0, 0, OPTAB_LIB_WIDEN); | |
1339 | ||
1340 | temp1 = gen_reg_rtx (GET_MODE (to)); | |
1341 | emit_unop_insn (icode, temp1, temp, FIX); | |
1342 | temp = expand_binop (GET_MODE (to), add_optab, temp1, | |
1343 | gen_rtx (CONST_INT, VOIDmode, | |
1344 | 1 << (bitsize - 1)), | |
1345 | to, 1, OPTAB_LIB_WIDEN); | |
1346 | if (temp != to) | |
1347 | emit_move_insn (to, temp); | |
1348 | return; | |
1349 | } | |
1350 | } | |
1351 | #endif | |
1352 | icode = can_fix_p (DImode, GET_MODE (from), unsignedp, &must_trunc); | |
1353 | ||
1354 | if (GET_MODE (to) != DImode && icode != CODE_FOR_nothing) | |
1355 | { | |
1356 | register rtx temp = gen_reg_rtx (DImode); | |
1357 | ||
1358 | if (must_trunc) | |
1359 | from = ftruncify (from); | |
1360 | emit_unop_insn (icode, temp, from, FIX); | |
1361 | convert_move (to, temp, unsignedp); | |
1362 | return; | |
1363 | } | |
1364 | ||
1365 | /* If FROM is not DFmode, convert to DFmode and try again from there. */ | |
1366 | if (GET_MODE (from) == DFmode) | |
1367 | break; | |
1368 | ||
1369 | from = convert_to_mode (DFmode, from, 0); | |
1370 | } | |
1371 | ||
1372 | /* We can't do it with an insn, so use a library call. | |
1373 | The mode of FROM is known to be DFmode. */ | |
1374 | ||
1375 | to = protect_from_queue (to, 1); | |
1376 | from = protect_from_queue (from, 0); | |
1377 | ||
1378 | if (flag_force_mem) | |
1379 | from = force_not_mem (from); | |
1380 | ||
1381 | if (GET_MODE (to) != DImode) | |
1382 | { | |
1383 | emit_library_call (gen_rtx (SYMBOL_REF, Pmode, | |
1384 | unsignedp ? "__fixunsdfsi" | |
1385 | : "__fixdfsi"), | |
1386 | 0, SImode, 1, from, DFmode); | |
1387 | target = hard_libcall_value (SImode); | |
1388 | } | |
1389 | else | |
1390 | { | |
1391 | emit_library_call (gen_rtx (SYMBOL_REF, Pmode, | |
1392 | unsignedp ? "__fixunsdfdi" | |
1393 | : "__fixdfdi"), | |
1394 | 0, DImode, 1, from, DFmode); | |
1395 | target = hard_libcall_value (DImode); | |
1396 | } | |
1397 | ||
1398 | if (GET_MODE (to) == GET_MODE (target)) | |
1399 | emit_move_insn (to, target); | |
1400 | else | |
1401 | convert_move (to, target, 0); | |
1402 | } | |
1403 | \f | |
1404 | static optab | |
1405 | init_optab (code) | |
1406 | enum rtx_code code; | |
1407 | { | |
1408 | int i; | |
1409 | optab op = (optab) malloc (sizeof (struct optab)); | |
1410 | op->code = code; | |
1411 | for (i = 0; i < NUM_MACHINE_MODES; i++) | |
1412 | { | |
1413 | op->handlers[i].insn_code = CODE_FOR_nothing; | |
1414 | op->handlers[i].lib_call = 0; | |
1415 | } | |
1416 | return op; | |
1417 | } | |
1418 | ||
1419 | /* Call this once to initialize the contents of the optabs | |
1420 | appropriately for the current target machine. */ | |
1421 | ||
1422 | void | |
1423 | init_optabs () | |
1424 | { | |
1425 | init_fixtab (); | |
1426 | init_floattab (); | |
1427 | init_comparisons (); | |
1428 | /* init_extends (); */ | |
1429 | ||
1430 | add_optab = init_optab (PLUS); | |
1431 | sub_optab = init_optab (MINUS); | |
1432 | smul_optab = init_optab (MULT); | |
1433 | umul_optab = init_optab (UMULT); | |
1434 | smul_widen_optab = init_optab (MULT); | |
1435 | umul_widen_optab = init_optab (UMULT); | |
1436 | sdiv_optab = init_optab (DIV); | |
1437 | sdivmod_optab = init_optab (UNKNOWN); | |
1438 | udiv_optab = init_optab (UDIV); | |
1439 | udivmod_optab = init_optab (UNKNOWN); | |
1440 | smod_optab = init_optab (MOD); | |
1441 | umod_optab = init_optab (UMOD); | |
1442 | flodiv_optab = init_optab (DIV); | |
1443 | ftrunc_optab = init_optab (UNKNOWN); | |
1444 | and_optab = init_optab (AND); | |
1445 | andcb_optab = init_optab (UNKNOWN); | |
1446 | ior_optab = init_optab (IOR); | |
1447 | xor_optab = init_optab (XOR); | |
1448 | ashl_optab = init_optab (ASHIFT); | |
1449 | ashr_optab = init_optab (ASHIFTRT); | |
1450 | lshl_optab = init_optab (LSHIFT); | |
1451 | lshr_optab = init_optab (LSHIFTRT); | |
1452 | rotl_optab = init_optab (ROTATE); | |
1453 | rotr_optab = init_optab (ROTATERT); | |
1454 | mov_optab = init_optab (UNKNOWN); | |
1455 | movstrict_optab = init_optab (UNKNOWN); | |
1456 | cmp_optab = init_optab (UNKNOWN); | |
1457 | ucmp_optab = init_optab (UNKNOWN); | |
1458 | tst_optab = init_optab (UNKNOWN); | |
1459 | neg_optab = init_optab (NEG); | |
1460 | abs_optab = init_optab (ABS); | |
1461 | one_cmpl_optab = init_optab (NOT); | |
1462 | ffs_optab = init_optab (FFS); | |
1463 | ||
1464 | #ifdef HAVE_addqi3 | |
1465 | if (HAVE_addqi3) | |
1466 | add_optab->handlers[(int) QImode].insn_code = CODE_FOR_addqi3; | |
1467 | #endif | |
1468 | #ifdef HAVE_addhi3 | |
1469 | if (HAVE_addhi3) | |
1470 | add_optab->handlers[(int) HImode].insn_code = CODE_FOR_addhi3; | |
1471 | #endif | |
1472 | #ifdef HAVE_addsi3 | |
1473 | if (HAVE_addsi3) | |
1474 | add_optab->handlers[(int) SImode].insn_code = CODE_FOR_addsi3; | |
1475 | #endif | |
1476 | #ifdef HAVE_adddi3 | |
1477 | if (HAVE_adddi3) | |
1478 | add_optab->handlers[(int) DImode].insn_code = CODE_FOR_adddi3; | |
1479 | #endif | |
1480 | #ifdef HAVE_addsf3 | |
1481 | if (HAVE_addsf3) | |
1482 | add_optab->handlers[(int) SFmode].insn_code = CODE_FOR_addsf3; | |
1483 | #endif | |
1484 | #ifdef HAVE_adddf3 | |
1485 | if (HAVE_adddf3) | |
1486 | add_optab->handlers[(int) DFmode].insn_code = CODE_FOR_adddf3; | |
1487 | #endif | |
1488 | add_optab->handlers[(int) DImode].lib_call = "__adddi3"; | |
1489 | add_optab->handlers[(int) SFmode].lib_call = "__addsf3"; | |
1490 | add_optab->handlers[(int) DFmode].lib_call = "__adddf3"; | |
1491 | ||
1492 | #ifdef HAVE_subqi3 | |
1493 | if (HAVE_subqi3) | |
1494 | sub_optab->handlers[(int) QImode].insn_code = CODE_FOR_subqi3; | |
1495 | #endif | |
1496 | #ifdef HAVE_subhi3 | |
1497 | if (HAVE_subhi3) | |
1498 | sub_optab->handlers[(int) HImode].insn_code = CODE_FOR_subhi3; | |
1499 | #endif | |
1500 | #ifdef HAVE_subsi3 | |
1501 | if (HAVE_subsi3) | |
1502 | sub_optab->handlers[(int) SImode].insn_code = CODE_FOR_subsi3; | |
1503 | #endif | |
1504 | #ifdef HAVE_subdi3 | |
1505 | if (HAVE_subdi3) | |
1506 | sub_optab->handlers[(int) DImode].insn_code = CODE_FOR_subdi3; | |
1507 | #endif | |
1508 | #ifdef HAVE_subsf3 | |
1509 | if (HAVE_subsf3) | |
1510 | sub_optab->handlers[(int) SFmode].insn_code = CODE_FOR_subsf3; | |
1511 | #endif | |
1512 | #ifdef HAVE_subdf3 | |
1513 | if (HAVE_subdf3) | |
1514 | sub_optab->handlers[(int) DFmode].insn_code = CODE_FOR_subdf3; | |
1515 | #endif | |
1516 | sub_optab->handlers[(int) DImode].lib_call = "__subdi3"; | |
1517 | sub_optab->handlers[(int) SFmode].lib_call = "__subsf3"; | |
1518 | sub_optab->handlers[(int) DFmode].lib_call = "__subdf3"; | |
1519 | ||
1520 | #ifdef HAVE_mulqi3 | |
1521 | if (HAVE_mulqi3) | |
1522 | smul_optab->handlers[(int) QImode].insn_code = CODE_FOR_mulqi3; | |
1523 | #endif | |
1524 | #ifdef HAVE_mulhi3 | |
1525 | if (HAVE_mulhi3) | |
1526 | smul_optab->handlers[(int) HImode].insn_code = CODE_FOR_mulhi3; | |
1527 | #endif | |
1528 | #ifdef HAVE_mulsi3 | |
1529 | if (HAVE_mulsi3) | |
1530 | smul_optab->handlers[(int) SImode].insn_code = CODE_FOR_mulsi3; | |
1531 | #endif | |
1532 | #ifdef HAVE_muldi3 | |
1533 | if (HAVE_muldi3) | |
1534 | smul_optab->handlers[(int) DImode].insn_code = CODE_FOR_muldi3; | |
1535 | #endif | |
1536 | #ifdef HAVE_mulsf3 | |
1537 | if (HAVE_mulsf3) | |
1538 | smul_optab->handlers[(int) SFmode].insn_code = CODE_FOR_mulsf3; | |
1539 | #endif | |
1540 | #ifdef HAVE_muldf3 | |
1541 | if (HAVE_muldf3) | |
1542 | smul_optab->handlers[(int) DFmode].insn_code = CODE_FOR_muldf3; | |
1543 | #endif | |
1544 | ||
1545 | #ifdef MULSI3_LIBCALL | |
1546 | smul_optab->handlers[(int) SImode].lib_call = MULSI3_LIBCALL; | |
1547 | #else | |
1548 | smul_optab->handlers[(int) SImode].lib_call = "__mulsi3"; | |
1549 | #endif | |
1550 | smul_optab->handlers[(int) DImode].lib_call = "__muldi3"; | |
1551 | smul_optab->handlers[(int) SFmode].lib_call = "__mulsf3"; | |
1552 | smul_optab->handlers[(int) DFmode].lib_call = "__muldf3"; | |
1553 | ||
1554 | #ifdef HAVE_mulqihi3 | |
1555 | if (HAVE_mulqihi3) | |
1556 | smul_widen_optab->handlers[(int) HImode].insn_code = CODE_FOR_mulqihi3; | |
1557 | #endif | |
1558 | #ifdef HAVE_mulhisi3 | |
1559 | if (HAVE_mulhisi3) | |
1560 | smul_widen_optab->handlers[(int) SImode].insn_code = CODE_FOR_mulhisi3; | |
1561 | #endif | |
1562 | #ifdef HAVE_mulsidi3 | |
1563 | if (HAVE_mulsidi3) | |
1564 | smul_widen_optab->handlers[(int) DImode].insn_code = CODE_FOR_mulsidi3; | |
1565 | #endif | |
1566 | ||
1567 | #ifdef HAVE_umulqi3 | |
1568 | if (HAVE_umulqi3) | |
1569 | umul_optab->handlers[(int) QImode].insn_code = CODE_FOR_umulqi3; | |
1570 | #endif | |
1571 | #ifdef HAVE_umulhi3 | |
1572 | if (HAVE_umulhi3) | |
1573 | umul_optab->handlers[(int) HImode].insn_code = CODE_FOR_umulhi3; | |
1574 | #endif | |
1575 | #ifdef HAVE_umulsi3 | |
1576 | if (HAVE_umulsi3) | |
1577 | umul_optab->handlers[(int) SImode].insn_code = CODE_FOR_umulsi3; | |
1578 | #endif | |
1579 | #ifdef HAVE_umuldi3 | |
1580 | if (HAVE_umuldi3) | |
1581 | umul_optab->handlers[(int) DImode].insn_code = CODE_FOR_umuldi3; | |
1582 | #endif | |
1583 | #ifdef HAVE_umulsf3 | |
1584 | if (HAVE_umulsf3) | |
1585 | umul_optab->handlers[(int) SFmode].insn_code = CODE_FOR_umulsf3; | |
1586 | #endif | |
1587 | #ifdef HAVE_umuldf3 | |
1588 | if (HAVE_umuldf3) | |
1589 | umul_optab->handlers[(int) DFmode].insn_code = CODE_FOR_umuldf3; | |
1590 | #endif | |
1591 | ||
1592 | #ifdef UMULSI3_LIBCALL | |
1593 | umul_optab->handlers[(int) SImode].lib_call = UMULSI3_LIBCALL; | |
1594 | #else | |
1595 | umul_optab->handlers[(int) SImode].lib_call = "__umulsi3"; | |
1596 | #endif | |
1597 | umul_optab->handlers[(int) DImode].lib_call = "__umuldi3"; | |
1598 | umul_optab->handlers[(int) SFmode].lib_call = "__umulsf3"; | |
1599 | umul_optab->handlers[(int) DFmode].lib_call = "__umuldf3"; | |
1600 | ||
1601 | #ifdef HAVE_umulqihi3 | |
1602 | if (HAVE_umulqihi3) | |
1603 | umul_widen_optab->handlers[(int) HImode].insn_code = CODE_FOR_umulqihi3; | |
1604 | #endif | |
1605 | #ifdef HAVE_umulhisi3 | |
1606 | if (HAVE_umulhisi3) | |
1607 | umul_widen_optab->handlers[(int) SImode].insn_code = CODE_FOR_umulhisi3; | |
1608 | #endif | |
1609 | #ifdef HAVE_umulsidi3 | |
1610 | if (HAVE_umulsidi3) | |
1611 | umul_widen_optab->handlers[(int) DImode].insn_code = CODE_FOR_umulsidi3; | |
1612 | #endif | |
1613 | ||
1614 | #ifdef HAVE_divqi3 | |
1615 | if (HAVE_divqi3) | |
1616 | sdiv_optab->handlers[(int) QImode].insn_code = CODE_FOR_divqi3; | |
1617 | #endif | |
1618 | #ifdef HAVE_divhi3 | |
1619 | if (HAVE_divhi3) | |
1620 | sdiv_optab->handlers[(int) HImode].insn_code = CODE_FOR_divhi3; | |
1621 | #endif | |
1622 | #ifdef HAVE_divsi3 | |
1623 | if (HAVE_divsi3) | |
1624 | sdiv_optab->handlers[(int) SImode].insn_code = CODE_FOR_divsi3; | |
1625 | #endif | |
1626 | #ifdef HAVE_divdi3 | |
1627 | if (HAVE_divdi3) | |
1628 | sdiv_optab->handlers[(int) DImode].insn_code = CODE_FOR_divdi3; | |
1629 | #endif | |
1630 | ||
1631 | #ifdef DIVSI3_LIBCALL | |
1632 | sdiv_optab->handlers[(int) SImode].lib_call = DIVSI3_LIBCALL; | |
1633 | #else | |
1634 | sdiv_optab->handlers[(int) SImode].lib_call = "__divsi3"; | |
1635 | #endif | |
1636 | sdiv_optab->handlers[(int) DImode].lib_call = "__divdi3"; | |
1637 | ||
1638 | #ifdef HAVE_udivqi3 | |
1639 | if (HAVE_udivqi3) | |
1640 | udiv_optab->handlers[(int) QImode].insn_code = CODE_FOR_udivqi3; | |
1641 | #endif | |
1642 | #ifdef HAVE_udivhi3 | |
1643 | if (HAVE_udivhi3) | |
1644 | udiv_optab->handlers[(int) HImode].insn_code = CODE_FOR_udivhi3; | |
1645 | #endif | |
1646 | #ifdef HAVE_udivsi3 | |
1647 | if (HAVE_udivsi3) | |
1648 | udiv_optab->handlers[(int) SImode].insn_code = CODE_FOR_udivsi3; | |
1649 | #endif | |
1650 | #ifdef HAVE_udivdi3 | |
1651 | if (HAVE_udivdi3) | |
1652 | udiv_optab->handlers[(int) DImode].insn_code = CODE_FOR_udivdi3; | |
1653 | #endif | |
1654 | ||
1655 | #ifdef UDIVSI3_LIBCALL | |
1656 | udiv_optab->handlers[(int) SImode].lib_call = UDIVSI3_LIBCALL; | |
1657 | #else | |
1658 | udiv_optab->handlers[(int) SImode].lib_call = "__udivsi3"; | |
1659 | #endif | |
1660 | udiv_optab->handlers[(int) DImode].lib_call = "__udivdi3"; | |
1661 | ||
1662 | #ifdef HAVE_divmodqi4 | |
1663 | if (HAVE_divmodqi4) | |
1664 | sdivmod_optab->handlers[(int) QImode].insn_code = CODE_FOR_divmodqi4; | |
1665 | #endif | |
1666 | #ifdef HAVE_divmodhi4 | |
1667 | if (HAVE_divmodhi4) | |
1668 | sdivmod_optab->handlers[(int) HImode].insn_code = CODE_FOR_divmodhi4; | |
1669 | #endif | |
1670 | #ifdef HAVE_divmodsi4 | |
1671 | if (HAVE_divmodsi4) | |
1672 | sdivmod_optab->handlers[(int) SImode].insn_code = CODE_FOR_divmodsi4; | |
1673 | #endif | |
1674 | #ifdef HAVE_divmoddi4 | |
1675 | if (HAVE_divmoddi4) | |
1676 | sdivmod_optab->handlers[(int) DImode].insn_code = CODE_FOR_divmoddi4; | |
1677 | #endif | |
1678 | ||
1679 | #ifdef HAVE_udivmodqi4 | |
1680 | if (HAVE_udivmodqi4) | |
1681 | udivmod_optab->handlers[(int) QImode].insn_code = CODE_FOR_udivmodqi4; | |
1682 | #endif | |
1683 | #ifdef HAVE_udivmodhi4 | |
1684 | if (HAVE_udivmodhi4) | |
1685 | udivmod_optab->handlers[(int) HImode].insn_code = CODE_FOR_udivmodhi4; | |
1686 | #endif | |
1687 | #ifdef HAVE_udivmodsi4 | |
1688 | if (HAVE_udivmodsi4) | |
1689 | udivmod_optab->handlers[(int) SImode].insn_code = CODE_FOR_udivmodsi4; | |
1690 | #endif | |
1691 | #ifdef HAVE_udivmoddi4 | |
1692 | if (HAVE_udivmoddi4) | |
1693 | udivmod_optab->handlers[(int) DImode].insn_code = CODE_FOR_udivmoddi4; | |
1694 | #endif | |
1695 | ||
1696 | #ifdef HAVE_modqi3 | |
1697 | if (HAVE_modqi3) | |
1698 | smod_optab->handlers[(int) QImode].insn_code = CODE_FOR_modqi3; | |
1699 | #endif | |
1700 | #ifdef HAVE_modhi3 | |
1701 | if (HAVE_modhi3) | |
1702 | smod_optab->handlers[(int) HImode].insn_code = CODE_FOR_modhi3; | |
1703 | #endif | |
1704 | #ifdef HAVE_modsi3 | |
1705 | if (HAVE_modsi3) | |
1706 | smod_optab->handlers[(int) SImode].insn_code = CODE_FOR_modsi3; | |
1707 | #endif | |
1708 | #ifdef HAVE_moddi3 | |
1709 | if (HAVE_moddi3) | |
1710 | smod_optab->handlers[(int) DImode].insn_code = CODE_FOR_moddi3; | |
1711 | #endif | |
1712 | ||
1713 | #ifdef MODSI3_LIBCALL | |
1714 | smod_optab->handlers[(int) SImode].lib_call = MODSI3_LIBCALL; | |
1715 | #else | |
1716 | smod_optab->handlers[(int) SImode].lib_call = "__modsi3"; | |
1717 | #endif | |
1718 | smod_optab->handlers[(int) DImode].lib_call = "__moddi3"; | |
1719 | ||
1720 | #ifdef HAVE_umodqi3 | |
1721 | if (HAVE_umodqi3) | |
1722 | umod_optab->handlers[(int) QImode].insn_code = CODE_FOR_umodqi3; | |
1723 | #endif | |
1724 | #ifdef HAVE_umodhi3 | |
1725 | if (HAVE_umodhi3) | |
1726 | umod_optab->handlers[(int) HImode].insn_code = CODE_FOR_umodhi3; | |
1727 | #endif | |
1728 | #ifdef HAVE_umodsi3 | |
1729 | if (HAVE_umodsi3) | |
1730 | umod_optab->handlers[(int) SImode].insn_code = CODE_FOR_umodsi3; | |
1731 | #endif | |
1732 | #ifdef HAVE_umoddi3 | |
1733 | if (HAVE_umoddi3) | |
1734 | umod_optab->handlers[(int) DImode].insn_code = CODE_FOR_umoddi3; | |
1735 | #endif | |
1736 | ||
1737 | #ifdef UMODSI3_LIBCALL | |
1738 | umod_optab->handlers[(int) SImode].lib_call = UMODSI3_LIBCALL; | |
1739 | #else | |
1740 | umod_optab->handlers[(int) SImode].lib_call = "__umodsi3"; | |
1741 | #endif | |
1742 | umod_optab->handlers[(int) DImode].lib_call = "__umoddi3"; | |
1743 | ||
1744 | #ifdef HAVE_divsf3 | |
1745 | if (HAVE_divsf3) | |
1746 | flodiv_optab->handlers[(int) SFmode].insn_code = CODE_FOR_divsf3; | |
1747 | #endif | |
1748 | #ifdef HAVE_divdf3 | |
1749 | if (HAVE_divdf3) | |
1750 | flodiv_optab->handlers[(int) DFmode].insn_code = CODE_FOR_divdf3; | |
1751 | #endif | |
1752 | flodiv_optab->handlers[(int) SFmode].lib_call = "__divsf3"; | |
1753 | flodiv_optab->handlers[(int) DFmode].lib_call = "__divdf3"; | |
1754 | ||
1755 | #ifdef HAVE_ftruncsf2 | |
1756 | if (HAVE_ftruncsf2) | |
1757 | ftrunc_optab->handlers[(int) SFmode].insn_code = CODE_FOR_ftruncsf2; | |
1758 | #endif | |
1759 | #ifdef HAVE_ftruncdf2 | |
1760 | if (HAVE_ftruncdf2) | |
1761 | ftrunc_optab->handlers[(int) DFmode].insn_code = CODE_FOR_ftruncdf2; | |
1762 | #endif | |
1763 | ||
1764 | #ifdef HAVE_andqi3 | |
1765 | if (HAVE_andqi3) | |
1766 | and_optab->handlers[(int) QImode].insn_code = CODE_FOR_andqi3; | |
1767 | #endif | |
1768 | #ifdef HAVE_andhi3 | |
1769 | if (HAVE_andhi3) | |
1770 | and_optab->handlers[(int) HImode].insn_code = CODE_FOR_andhi3; | |
1771 | #endif | |
1772 | #ifdef HAVE_andsi3 | |
1773 | if (HAVE_andsi3) | |
1774 | and_optab->handlers[(int) SImode].insn_code = CODE_FOR_andsi3; | |
1775 | #endif | |
1776 | #ifdef HAVE_anddi3 | |
1777 | if (HAVE_anddi3) | |
1778 | and_optab->handlers[(int) DImode].insn_code = CODE_FOR_anddi3; | |
1779 | #endif | |
1780 | and_optab->handlers[(int) DImode].lib_call = "__anddi3"; | |
1781 | ||
1782 | #ifdef HAVE_andcbqi3 | |
1783 | if (HAVE_andcbqi3) | |
1784 | andcb_optab->handlers[(int) QImode].insn_code = CODE_FOR_andcbqi3; | |
1785 | #endif | |
1786 | #ifdef HAVE_andcbhi3 | |
1787 | if (HAVE_andcbhi3) | |
1788 | andcb_optab->handlers[(int) HImode].insn_code = CODE_FOR_andcbhi3; | |
1789 | #endif | |
1790 | #ifdef HAVE_andcbsi3 | |
1791 | if (HAVE_andcbsi3) | |
1792 | andcb_optab->handlers[(int) SImode].insn_code = CODE_FOR_andcbsi3; | |
1793 | #endif | |
1794 | #ifdef HAVE_andcbdi3 | |
1795 | if (HAVE_andcbdi3) | |
1796 | andcb_optab->handlers[(int) DImode].insn_code = CODE_FOR_andcbdi3; | |
1797 | #endif | |
1798 | andcb_optab->handlers[(int) DImode].lib_call = "__andcbdi3"; | |
1799 | ||
1800 | #ifdef HAVE_iorqi3 | |
1801 | if (HAVE_iorqi3) | |
1802 | ior_optab->handlers[(int) QImode].insn_code = CODE_FOR_iorqi3; | |
1803 | #endif | |
1804 | #ifdef HAVE_iorhi3 | |
1805 | if (HAVE_iorhi3) | |
1806 | ior_optab->handlers[(int) HImode].insn_code = CODE_FOR_iorhi3; | |
1807 | #endif | |
1808 | #ifdef HAVE_iorsi3 | |
1809 | if (HAVE_iorsi3) | |
1810 | ior_optab->handlers[(int) SImode].insn_code = CODE_FOR_iorsi3; | |
1811 | #endif | |
1812 | #ifdef HAVE_iordi3 | |
1813 | if (HAVE_iordi3) | |
1814 | ior_optab->handlers[(int) DImode].insn_code = CODE_FOR_iordi3; | |
1815 | #endif | |
1816 | ior_optab->handlers[(int) DImode].lib_call = "__iordi3"; | |
1817 | ||
1818 | #ifdef HAVE_xorqi3 | |
1819 | if (HAVE_xorqi3) | |
1820 | xor_optab->handlers[(int) QImode].insn_code = CODE_FOR_xorqi3; | |
1821 | #endif | |
1822 | #ifdef HAVE_xorhi3 | |
1823 | if (HAVE_xorhi3) | |
1824 | xor_optab->handlers[(int) HImode].insn_code = CODE_FOR_xorhi3; | |
1825 | #endif | |
1826 | #ifdef HAVE_xorsi3 | |
1827 | if (HAVE_xorsi3) | |
1828 | xor_optab->handlers[(int) SImode].insn_code = CODE_FOR_xorsi3; | |
1829 | #endif | |
1830 | #ifdef HAVE_xordi3 | |
1831 | if (HAVE_xordi3) | |
1832 | xor_optab->handlers[(int) DImode].insn_code = CODE_FOR_xordi3; | |
1833 | #endif | |
1834 | xor_optab->handlers[(int) DImode].lib_call = "__xordi3"; | |
1835 | ||
1836 | #ifdef HAVE_ashlqi3 | |
1837 | if (HAVE_ashlqi3) | |
1838 | ashl_optab->handlers[(int) QImode].insn_code = CODE_FOR_ashlqi3; | |
1839 | #endif | |
1840 | #ifdef HAVE_ashlhi3 | |
1841 | if (HAVE_ashlhi3) | |
1842 | ashl_optab->handlers[(int) HImode].insn_code = CODE_FOR_ashlhi3; | |
1843 | #endif | |
1844 | #ifdef HAVE_ashlsi3 | |
1845 | if (HAVE_ashlsi3) | |
1846 | ashl_optab->handlers[(int) SImode].insn_code = CODE_FOR_ashlsi3; | |
1847 | #endif | |
1848 | #ifdef HAVE_ashldi3 | |
1849 | if (HAVE_ashldi3) | |
1850 | ashl_optab->handlers[(int) DImode].insn_code = CODE_FOR_ashldi3; | |
1851 | #endif | |
1852 | ashl_optab->handlers[(int) SImode].lib_call = "__ashlsi3"; | |
1853 | ashl_optab->handlers[(int) DImode].lib_call = "__ashldi3"; | |
1854 | ||
1855 | #ifdef HAVE_ashrqi3 | |
1856 | if (HAVE_ashrqi3) | |
1857 | ashr_optab->handlers[(int) QImode].insn_code = CODE_FOR_ashrqi3; | |
1858 | #endif | |
1859 | #ifdef HAVE_ashrhi3 | |
1860 | if (HAVE_ashrhi3) | |
1861 | ashr_optab->handlers[(int) HImode].insn_code = CODE_FOR_ashrhi3; | |
1862 | #endif | |
1863 | #ifdef HAVE_ashrsi3 | |
1864 | if (HAVE_ashrsi3) | |
1865 | ashr_optab->handlers[(int) SImode].insn_code = CODE_FOR_ashrsi3; | |
1866 | #endif | |
1867 | #ifdef HAVE_ashrdi3 | |
1868 | if (HAVE_ashrdi3) | |
1869 | ashr_optab->handlers[(int) DImode].insn_code = CODE_FOR_ashrdi3; | |
1870 | #endif | |
1871 | ashr_optab->handlers[(int) SImode].lib_call = "__ashrsi3"; | |
1872 | ashr_optab->handlers[(int) DImode].lib_call = "__ashrdi3"; | |
1873 | ||
1874 | #ifdef HAVE_lshlqi3 | |
1875 | if (HAVE_lshlqi3) | |
1876 | lshl_optab->handlers[(int) QImode].insn_code = CODE_FOR_lshlqi3; | |
1877 | #endif | |
1878 | #ifdef HAVE_lshlhi3 | |
1879 | if (HAVE_lshlhi3) | |
1880 | lshl_optab->handlers[(int) HImode].insn_code = CODE_FOR_lshlhi3; | |
1881 | #endif | |
1882 | #ifdef HAVE_lshlsi3 | |
1883 | if (HAVE_lshlsi3) | |
1884 | lshl_optab->handlers[(int) SImode].insn_code = CODE_FOR_lshlsi3; | |
1885 | #endif | |
1886 | #ifdef HAVE_lshldi3 | |
1887 | if (HAVE_lshldi3) | |
1888 | lshl_optab->handlers[(int) DImode].insn_code = CODE_FOR_lshldi3; | |
1889 | #endif | |
1890 | lshl_optab->handlers[(int) SImode].lib_call = "__lshlsi3"; | |
1891 | lshl_optab->handlers[(int) DImode].lib_call = "__lshldi3"; | |
1892 | ||
1893 | #ifdef HAVE_lshrqi3 | |
1894 | if (HAVE_lshrqi3) | |
1895 | lshr_optab->handlers[(int) QImode].insn_code = CODE_FOR_lshrqi3; | |
1896 | #endif | |
1897 | #ifdef HAVE_lshrhi3 | |
1898 | if (HAVE_lshrhi3) | |
1899 | lshr_optab->handlers[(int) HImode].insn_code = CODE_FOR_lshrhi3; | |
1900 | #endif | |
1901 | #ifdef HAVE_lshrsi3 | |
1902 | if (HAVE_lshrsi3) | |
1903 | lshr_optab->handlers[(int) SImode].insn_code = CODE_FOR_lshrsi3; | |
1904 | #endif | |
1905 | #ifdef HAVE_lshrdi3 | |
1906 | if (HAVE_lshrdi3) | |
1907 | lshr_optab->handlers[(int) DImode].insn_code = CODE_FOR_lshrdi3; | |
1908 | #endif | |
1909 | lshr_optab->handlers[(int) SImode].lib_call = "__lshrsi3"; | |
1910 | lshr_optab->handlers[(int) DImode].lib_call = "__lshrdi3"; | |
1911 | ||
1912 | #ifdef HAVE_rotlqi3 | |
1913 | if (HAVE_rotlqi3) | |
1914 | rotl_optab->handlers[(int) QImode].insn_code = CODE_FOR_rotlqi3; | |
1915 | #endif | |
1916 | #ifdef HAVE_rotlhi3 | |
1917 | if (HAVE_rotlhi3) | |
1918 | rotl_optab->handlers[(int) HImode].insn_code = CODE_FOR_rotlhi3; | |
1919 | #endif | |
1920 | #ifdef HAVE_rotlsi3 | |
1921 | if (HAVE_rotlsi3) | |
1922 | rotl_optab->handlers[(int) SImode].insn_code = CODE_FOR_rotlsi3; | |
1923 | #endif | |
1924 | #ifdef HAVE_rotldi3 | |
1925 | if (HAVE_rotldi3) | |
1926 | rotl_optab->handlers[(int) DImode].insn_code = CODE_FOR_rotldi3; | |
1927 | #endif | |
1928 | rotl_optab->handlers[(int) SImode].lib_call = "__rotlsi3"; | |
1929 | rotl_optab->handlers[(int) DImode].lib_call = "__rotldi3"; | |
1930 | ||
1931 | #ifdef HAVE_rotrqi3 | |
1932 | if (HAVE_rotrqi3) | |
1933 | rotr_optab->handlers[(int) QImode].insn_code = CODE_FOR_rotrqi3; | |
1934 | #endif | |
1935 | #ifdef HAVE_rotrhi3 | |
1936 | if (HAVE_rotrhi3) | |
1937 | rotr_optab->handlers[(int) HImode].insn_code = CODE_FOR_rotrhi3; | |
1938 | #endif | |
1939 | #ifdef HAVE_rotrsi3 | |
1940 | if (HAVE_rotrsi3) | |
1941 | rotr_optab->handlers[(int) SImode].insn_code = CODE_FOR_rotrsi3; | |
1942 | #endif | |
1943 | #ifdef HAVE_rotrdi3 | |
1944 | if (HAVE_rotrdi3) | |
1945 | rotr_optab->handlers[(int) DImode].insn_code = CODE_FOR_rotrdi3; | |
1946 | #endif | |
1947 | rotr_optab->handlers[(int) SImode].lib_call = "__rotrsi3"; | |
1948 | rotr_optab->handlers[(int) DImode].lib_call = "__rotrdi3"; | |
1949 | ||
1950 | #ifdef HAVE_negqi2 | |
1951 | if (HAVE_negqi2) | |
1952 | neg_optab->handlers[(int) QImode].insn_code = CODE_FOR_negqi2; | |
1953 | #endif | |
1954 | #ifdef HAVE_neghi2 | |
1955 | if (HAVE_neghi2) | |
1956 | neg_optab->handlers[(int) HImode].insn_code = CODE_FOR_neghi2; | |
1957 | #endif | |
1958 | #ifdef HAVE_negsi2 | |
1959 | if (HAVE_negsi2) | |
1960 | neg_optab->handlers[(int) SImode].insn_code = CODE_FOR_negsi2; | |
1961 | #endif | |
1962 | #ifdef HAVE_negdi2 | |
1963 | if (HAVE_negdi2) | |
1964 | neg_optab->handlers[(int) DImode].insn_code = CODE_FOR_negdi2; | |
1965 | #endif | |
1966 | #ifdef HAVE_negsf2 | |
1967 | if (HAVE_negsf2) | |
1968 | neg_optab->handlers[(int) SFmode].insn_code = CODE_FOR_negsf2; | |
1969 | #endif | |
1970 | #ifdef HAVE_negdf2 | |
1971 | if (HAVE_negdf2) | |
1972 | neg_optab->handlers[(int) DFmode].insn_code = CODE_FOR_negdf2; | |
1973 | #endif | |
1974 | neg_optab->handlers[(int) SImode].lib_call = "__negsi2"; | |
1975 | neg_optab->handlers[(int) DImode].lib_call = "__negdi2"; | |
1976 | neg_optab->handlers[(int) SFmode].lib_call = "__negsf2"; | |
1977 | neg_optab->handlers[(int) DFmode].lib_call = "__negdf2"; | |
1978 | ||
1979 | #ifdef HAVE_absqi2 | |
1980 | if (HAVE_absqi2) | |
1981 | abs_optab->handlers[(int) QImode].insn_code = CODE_FOR_absqi2; | |
1982 | #endif | |
1983 | #ifdef HAVE_abshi2 | |
1984 | if (HAVE_abshi2) | |
1985 | abs_optab->handlers[(int) HImode].insn_code = CODE_FOR_abshi2; | |
1986 | #endif | |
1987 | #ifdef HAVE_abssi2 | |
1988 | if (HAVE_abssi2) | |
1989 | abs_optab->handlers[(int) SImode].insn_code = CODE_FOR_abssi2; | |
1990 | #endif | |
1991 | #ifdef HAVE_absdi2 | |
1992 | if (HAVE_absdi2) | |
1993 | abs_optab->handlers[(int) DImode].insn_code = CODE_FOR_absdi2; | |
1994 | #endif | |
1995 | #ifdef HAVE_abssf2 | |
1996 | if (HAVE_abssf2) | |
1997 | abs_optab->handlers[(int) SFmode].insn_code = CODE_FOR_abssf2; | |
1998 | #endif | |
1999 | #ifdef HAVE_absdf2 | |
2000 | if (HAVE_absdf2) | |
2001 | abs_optab->handlers[(int) DFmode].insn_code = CODE_FOR_absdf2; | |
2002 | #endif | |
2003 | /* No library calls here! If there is no abs instruction, | |
2004 | expand_expr will generate a conditional negation. */ | |
2005 | ||
2006 | #ifdef HAVE_one_cmplqi2 | |
2007 | if (HAVE_one_cmplqi2) | |
2008 | one_cmpl_optab->handlers[(int) QImode].insn_code = CODE_FOR_one_cmplqi2; | |
2009 | #endif | |
2010 | #ifdef HAVE_one_cmplhi2 | |
2011 | if (HAVE_one_cmplhi2) | |
2012 | one_cmpl_optab->handlers[(int) HImode].insn_code = CODE_FOR_one_cmplhi2; | |
2013 | #endif | |
2014 | #ifdef HAVE_one_cmplsi2 | |
2015 | if (HAVE_one_cmplsi2) | |
2016 | one_cmpl_optab->handlers[(int) SImode].insn_code = CODE_FOR_one_cmplsi2; | |
2017 | #endif | |
2018 | #ifdef HAVE_one_cmpldi2 | |
2019 | if (HAVE_one_cmpldi2) | |
2020 | one_cmpl_optab->handlers[(int) DImode].insn_code = CODE_FOR_one_cmpldi2; | |
2021 | #endif | |
2022 | one_cmpl_optab->handlers[(int) SImode].lib_call = "__one_cmplsi2"; | |
2023 | one_cmpl_optab->handlers[(int) DImode].lib_call = "__one_cmpldi2"; | |
2024 | ||
2025 | #ifdef HAVE_ffsqi2 | |
2026 | if (HAVE_ffsqi2) | |
2027 | ffs_optab->handlers[(int) QImode].insn_code = CODE_FOR_ffsqi2; | |
2028 | #endif | |
2029 | #ifdef HAVE_ffshi2 | |
2030 | if (HAVE_ffshi2) | |
2031 | ffs_optab->handlers[(int) HImode].insn_code = CODE_FOR_ffshi2; | |
2032 | #endif | |
2033 | #ifdef HAVE_ffssi2 | |
2034 | if (HAVE_ffssi2) | |
2035 | ffs_optab->handlers[(int) SImode].insn_code = CODE_FOR_ffssi2; | |
2036 | #endif | |
2037 | #ifdef HAVE_ffsdi2 | |
2038 | if (HAVE_ffsdi2) | |
2039 | ffs_optab->handlers[(int) DImode].insn_code = CODE_FOR_ffsdi2; | |
2040 | #endif | |
2041 | ffs_optab->handlers[(int) SImode].lib_call = "ffs"; | |
2042 | ||
2043 | #ifdef HAVE_movqi | |
2044 | if (HAVE_movqi) | |
2045 | mov_optab->handlers[(int) QImode].insn_code = CODE_FOR_movqi; | |
2046 | #endif | |
2047 | #ifdef HAVE_movhi | |
2048 | if (HAVE_movhi) | |
2049 | mov_optab->handlers[(int) HImode].insn_code = CODE_FOR_movhi; | |
2050 | #endif | |
2051 | #ifdef HAVE_movsi | |
2052 | if (HAVE_movsi) | |
2053 | mov_optab->handlers[(int) SImode].insn_code = CODE_FOR_movsi; | |
2054 | #endif | |
2055 | #ifdef HAVE_movdi | |
2056 | if (HAVE_movdi) | |
2057 | mov_optab->handlers[(int) DImode].insn_code = CODE_FOR_movdi; | |
2058 | #endif | |
2059 | #ifdef HAVE_movti | |
2060 | if (HAVE_movti) | |
2061 | mov_optab->handlers[(int) TImode].insn_code = CODE_FOR_movti; | |
2062 | #endif | |
2063 | #ifdef HAVE_movsf | |
2064 | if (HAVE_movsf) | |
2065 | mov_optab->handlers[(int) SFmode].insn_code = CODE_FOR_movsf; | |
2066 | #endif | |
2067 | #ifdef HAVE_movdf | |
2068 | if (HAVE_movdf) | |
2069 | mov_optab->handlers[(int) DFmode].insn_code = CODE_FOR_movdf; | |
2070 | #endif | |
2071 | #ifdef HAVE_movtf | |
2072 | if (HAVE_movtf) | |
2073 | mov_optab->handlers[(int) TFmode].insn_code = CODE_FOR_movtf; | |
2074 | #endif | |
2075 | ||
2076 | #ifdef HAVE_movstrictqi | |
2077 | if (HAVE_movstrictqi) | |
2078 | movstrict_optab->handlers[(int) QImode].insn_code = CODE_FOR_movstrictqi; | |
2079 | #endif | |
2080 | #ifdef HAVE_movstricthi | |
2081 | if (HAVE_movstricthi) | |
2082 | movstrict_optab->handlers[(int) HImode].insn_code = CODE_FOR_movstricthi; | |
2083 | #endif | |
2084 | #ifdef HAVE_movstrictsi | |
2085 | if (HAVE_movstrictsi) | |
2086 | movstrict_optab->handlers[(int) SImode].insn_code = CODE_FOR_movstrictsi; | |
2087 | #endif | |
2088 | #ifdef HAVE_movstrictdi | |
2089 | if (HAVE_movstrictdi) | |
2090 | movstrict_optab->handlers[(int) DImode].insn_code = CODE_FOR_movstrictdi; | |
2091 | #endif | |
2092 | ||
2093 | #ifdef HAVE_cmpqi | |
2094 | if (HAVE_cmpqi) | |
2095 | cmp_optab->handlers[(int) QImode].insn_code = CODE_FOR_cmpqi; | |
2096 | #endif | |
2097 | #ifdef HAVE_cmphi | |
2098 | if (HAVE_cmphi) | |
2099 | cmp_optab->handlers[(int) HImode].insn_code = CODE_FOR_cmphi; | |
2100 | #endif | |
2101 | #ifdef HAVE_cmpsi | |
2102 | if (HAVE_cmpsi) | |
2103 | cmp_optab->handlers[(int) SImode].insn_code = CODE_FOR_cmpsi; | |
2104 | #endif | |
2105 | #ifdef HAVE_cmpdi | |
2106 | if (HAVE_cmpdi) | |
2107 | cmp_optab->handlers[(int) DImode].insn_code = CODE_FOR_cmpdi; | |
2108 | #endif | |
2109 | #ifdef HAVE_cmpsf | |
2110 | if (HAVE_cmpsf) | |
2111 | cmp_optab->handlers[(int) SFmode].insn_code = CODE_FOR_cmpsf; | |
2112 | #endif | |
2113 | #ifdef HAVE_cmpdf | |
2114 | if (HAVE_cmpdf) | |
2115 | cmp_optab->handlers[(int) DFmode].insn_code = CODE_FOR_cmpdf; | |
2116 | #endif | |
2117 | #ifdef HAVE_tstqi | |
2118 | if (HAVE_tstqi) | |
2119 | tst_optab->handlers[(int) QImode].insn_code = CODE_FOR_tstqi; | |
2120 | #endif | |
2121 | #ifdef HAVE_tsthi | |
2122 | if (HAVE_tsthi) | |
2123 | tst_optab->handlers[(int) HImode].insn_code = CODE_FOR_tsthi; | |
2124 | #endif | |
2125 | #ifdef HAVE_tstsi | |
2126 | if (HAVE_tstsi) | |
2127 | tst_optab->handlers[(int) SImode].insn_code = CODE_FOR_tstsi; | |
2128 | #endif | |
2129 | #ifdef HAVE_tstdi | |
2130 | if (HAVE_tstdi) | |
2131 | tst_optab->handlers[(int) DImode].insn_code = CODE_FOR_tstdi; | |
2132 | #endif | |
2133 | #ifdef HAVE_tstsf | |
2134 | if (HAVE_tstsf) | |
2135 | tst_optab->handlers[(int) SFmode].insn_code = CODE_FOR_tstsf; | |
2136 | #endif | |
2137 | #ifdef HAVE_tstdf | |
2138 | if (HAVE_tstdf) | |
2139 | tst_optab->handlers[(int) DFmode].insn_code = CODE_FOR_tstdf; | |
2140 | #endif | |
2141 | /* Comparison libcalls for integers MUST come in pairs, signed/unsigned. */ | |
2142 | cmp_optab->handlers[(int) DImode].lib_call = "__cmpdi2"; | |
2143 | ucmp_optab->handlers[(int) DImode].lib_call = "__ucmpdi2"; | |
2144 | cmp_optab->handlers[(int) SFmode].lib_call = "__cmpsf2"; | |
2145 | cmp_optab->handlers[(int) DFmode].lib_call = "__cmpdf2"; | |
2146 | ||
2147 | #if HAVE_beq | |
2148 | if (HAVE_beq) | |
2149 | bcc_gen_fctn[(int) EQ] = gen_beq; | |
2150 | #endif | |
2151 | #if HAVE_bne | |
2152 | if (HAVE_bne) | |
2153 | bcc_gen_fctn[(int) NE] = gen_bne; | |
2154 | #endif | |
2155 | #if HAVE_bgt | |
2156 | if (HAVE_bgt) | |
2157 | bcc_gen_fctn[(int) GT] = gen_bgt; | |
2158 | #endif | |
2159 | #if HAVE_bge | |
2160 | if (HAVE_bge) | |
2161 | bcc_gen_fctn[(int) GE] = gen_bge; | |
2162 | #endif | |
2163 | #if HAVE_bgtu | |
2164 | if (HAVE_bgtu) | |
2165 | bcc_gen_fctn[(int) GTU] = gen_bgtu; | |
2166 | #endif | |
2167 | #if HAVE_bgeu | |
2168 | if (HAVE_bgeu) | |
2169 | bcc_gen_fctn[(int) GEU] = gen_bgeu; | |
2170 | #endif | |
2171 | #if HAVE_blt | |
2172 | if (HAVE_blt) | |
2173 | bcc_gen_fctn[(int) LT] = gen_blt; | |
2174 | #endif | |
2175 | #if HAVE_ble | |
2176 | if (HAVE_ble) | |
2177 | bcc_gen_fctn[(int) LE] = gen_ble; | |
2178 | #endif | |
2179 | #if HAVE_bltu | |
2180 | if (HAVE_bltu) | |
2181 | bcc_gen_fctn[(int) LTU] = gen_bltu; | |
2182 | #endif | |
2183 | #if HAVE_bleu | |
2184 | if (HAVE_bleu) | |
2185 | bcc_gen_fctn[(int) LEU] = gen_bleu; | |
2186 | #endif | |
2187 | ||
2188 | #if HAVE_seq | |
2189 | if (HAVE_seq) | |
2190 | setcc_gen_fctn[(int) EQ] = gen_seq; | |
2191 | #endif | |
2192 | #if HAVE_sne | |
2193 | if (HAVE_sne) | |
2194 | setcc_gen_fctn[(int) NE] = gen_sne; | |
2195 | #endif | |
2196 | #if HAVE_sgt | |
2197 | if (HAVE_sgt) | |
2198 | setcc_gen_fctn[(int) GT] = gen_sgt; | |
2199 | #endif | |
2200 | #if HAVE_sge | |
2201 | if (HAVE_sge) | |
2202 | setcc_gen_fctn[(int) GE] = gen_sge; | |
2203 | #endif | |
2204 | #if HAVE_sgtu | |
2205 | if (HAVE_sgtu) | |
2206 | setcc_gen_fctn[(int) GTU] = gen_sgtu; | |
2207 | #endif | |
2208 | #if HAVE_sgeu | |
2209 | if (HAVE_sgeu) | |
2210 | setcc_gen_fctn[(int) GEU] = gen_sgeu; | |
2211 | #endif | |
2212 | #if HAVE_slt | |
2213 | if (HAVE_slt) | |
2214 | setcc_gen_fctn[(int) LT] = gen_slt; | |
2215 | #endif | |
2216 | #if HAVE_sle | |
2217 | if (HAVE_sle) | |
2218 | setcc_gen_fctn[(int) LE] = gen_sle; | |
2219 | #endif | |
2220 | #if HAVE_sltu | |
2221 | if (HAVE_sltu) | |
2222 | setcc_gen_fctn[(int) LTU] = gen_sltu; | |
2223 | #endif | |
2224 | #if HAVE_sleu | |
2225 | if (HAVE_sleu) | |
2226 | setcc_gen_fctn[(int) LEU] = gen_sleu; | |
2227 | #endif | |
2228 | } |