Subversion Repositories tendra.SVN

Rev

Rev 5 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
6 7u83 2
 * Copyright (c) 2002-2005 The TenDRA Project <http://www.tendra.org/>.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright notice,
11
 *    this list of conditions and the following disclaimer in the documentation
12
 *    and/or other materials provided with the distribution.
13
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific, prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
18
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * $Id$
30
 */
31
/*
2 7u83 32
    Copyright (c) 1993 Open Software Foundation, Inc.
33
 
34
 
35
    All Rights Reserved
36
 
37
 
38
    Permission to use, copy, modify, and distribute this software
39
    and its documentation for any purpose and without fee is hereby
40
    granted, provided that the above copyright notice appears in all
41
    copies and that both the copyright notice and this permission
42
    notice appear in supporting documentation.
43
 
44
 
45
    OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING
46
    ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
47
    PARTICULAR PURPOSE.
48
 
49
 
50
    IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
51
    CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
52
    LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
53
    NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
54
    WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
55
*/
56
 
57
/*
58
    		 Crown Copyright (c) 1997
6 7u83 59
 
2 7u83 60
    This TenDRA(r) Computer Program is subject to Copyright
61
    owned by the United Kingdom Secretary of State for Defence
62
    acting through the Defence Evaluation and Research Agency
63
    (DERA).  It is made available to Recipients with a
64
    royalty-free licence for its use, reproduction, transfer
65
    to other parties and amendment for any purpose not excluding
66
    product development provided that any such use et cetera
67
    shall be deemed to be acceptance of the following conditions:-
6 7u83 68
 
2 7u83 69
        (1) Its Recipients shall ensure that this Notice is
70
        reproduced upon any copies or amended versions of it;
6 7u83 71
 
2 7u83 72
        (2) Any amended version of it shall be clearly marked to
73
        show both the nature of and the organisation responsible
74
        for the relevant amendment or amendments;
6 7u83 75
 
2 7u83 76
        (3) Its onward transfer from a recipient to another
77
        party shall be deemed to be that party's acceptance of
78
        these conditions;
6 7u83 79
 
2 7u83 80
        (4) DERA gives no warranty or assurance as to its
81
        quality or suitability for any purpose and DERA accepts
82
        no liability whatsoever in relation to any use to which
83
        it may be put.
84
*/
85
 
86
 
87
 
88
/**********************************************************************
89
$Author: release $
90
$Date: 1998/02/04 15:49:00 $
91
$Revision: 1.2 $
92
$Log: muldvrem.c,v $
93
 * Revision 1.2  1998/02/04  15:49:00  release
94
 * Added OSF copyright message.
95
 *
96
 * Revision 1.1.1.1  1998/01/17  15:55:57  release
97
 * First version to be checked into rolling release.
98
 *
99
 * Revision 1.2  1996/10/04  16:02:52  pwe
100
 * add banners and mod for PWE ownership
101
 *
102
**********************************************************************/
103
 
104
 
105
#include "config.h"
106
#include "memtdf.h"
107
#include "codegen.h"
108
#include "geninst.h"
109
 
110
#include "myassert.h"
111
#include "needscan.h"
112
#include "comment.h"
113
 
114
#include "muldvrem.h"
115
#include "translat.h"
116
#include "error.h"
117
#define BITS_PER_WORD		32
118
 
119
#define MAX_MUL_POW2_OFFSET	2	/* max permissable X in 2**n +- X for
120
					 * constant multiply */
121
 
122
#define NOT_MUL_CONST_SIMPLE	(MAX_MUL_POW2_OFFSET+1)
123
 /* any constant larger than permissable X offset in 2**n +- X */
124
 
6 7u83 125
#define IS_POW2(c)		((c)!= 0 && ((c) & ((c) -1)) == 0)
2 7u83 126
 
127
 
128
 
129
 
130
/*
131
 * Utility functions.
132
 */
133
 
134
/* return bit number 0..31 from right of word of 'c' which has one bit set */
6 7u83 135
static int bit_no(unsigned long c)
2 7u83 136
{
137
  int shift_const;
138
  unsigned long mask;
139
 
140
  ASSERT(IS_POW2(c));
141
 
142
  for (mask = 1, shift_const = 0; mask != c; mask = mask << 1)
143
  {
144
    shift_const++;
145
  }
146
 
147
  return shift_const;
148
}
149
 
150
 
151
 
152
 
153
/*
154
 * Multiply.
155
 */
156
 
157
 
158
/* is constval +ve const 2**n or 2**(n +- X) where abs(X) <= MAX_MUL_POW2_OFFSET */
6 7u83 159
static int offset_mul_const_simple(long constval, bool sgned)
2 7u83 160
{
161
  int i;
162
 
163
  FULLCOMMENT1("offset_mul_const_simple: %ld", constval);
164
 
165
  if (constval < 0)
166
  {
167
    if (sgned)
168
      constval = -constval;
169
    else
170
      return NOT_MUL_CONST_SIMPLE;	/* very rare case */
171
  }
172
 
173
  for (i = 0; i <= MAX_MUL_POW2_OFFSET; i++)
174
  {
175
    long c;			/* power of two close to constval */
176
 
177
    /* check for add offsets, avoiding overflow confusion */
178
    c = constval - i;
179
    if (IS_POW2(c) && c+i == constval)
180
      return i;
181
 
182
    /* check for sub offset of 1 only, avoiding overflow confusion */
183
    if (i == 1)
184
    {
185
      c = constval + i;
186
      if (IS_POW2(c) && c-i == constval)
187
	return -i;
188
    }
189
  }
190
 
191
  return NOT_MUL_CONST_SIMPLE;
192
}
193
 
194
 
195
/* generate code for multiply by constant */
6 7u83 196
static void mul_const_simple(int src, long constval, int dest, bool sgned)
2 7u83 197
{
198
  int shift_const;
199
  long c;			/* power of two close to constval */
200
  int add_sub;			/* difference from power of two: +N add, 0
201
				 * nop, -N sub */
202
 
203
  if (sgned && constval < 0)
204
  {
205
    if (constval == -1)
206
    {
207
      /* X * -1 => -X */
208
      rr_ins(i_neg, src, dest);
209
      return;
210
    }
211
    constval = -constval;
212
    rr_ins(i_neg, src, R_TMP0);	/* incorrect to modify source */
213
    src = R_TMP0;
214
  }
215
 
216
  if (constval == 0)
217
  {
218
    ld_const_ins(0, dest);	/* rare case not handled by mul_const_X() */
219
    return;
220
  }
221
  else if (constval == 1)
222
  {
223
    if (src != dest)
224
    {
225
      mov_rr_ins(src, dest);comment(NIL);
226
    }
227
    return;
228
  }
229
  else if (constval == 2)
230
  {
231
    /* use add, which can be peep-hole optimised to addcc later */
232
    rrr_ins(i_a, src, src, dest);
233
    return;
234
  }
235
 
236
  add_sub = offset_mul_const_simple(constval, sgned);
237
  c = constval - add_sub;
238
 
239
  ASSERT(constval == c + add_sub);
240
 
241
  shift_const = bit_no(c);
242
 
243
  FULLCOMMENT3("mul_const_simple: constval=%#lx shift_const=%d add_sub=%d", constval, shift_const, add_sub);
244
  ASSERT(constval == (1 << shift_const) + add_sub);
245
 
246
  if (add_sub == 0)
247
  {
248
    rir_ins(i_sl, src, shift_const, dest);
249
  }
250
  else
251
  {
252
    /* add_sub != 0 */
253
    Instruction_P i_add_sub;
254
    int n;			/* number of add_sub instructions */
255
    int inter_reg;		/* for partial result */
256
    int i;
257
 
258
    if (add_sub > 0)
259
    {
260
      i_add_sub = i_a;
261
      n = add_sub;
262
    }
263
    else
264
    {
265
      i_add_sub = i_s;
266
      n = -add_sub;
267
    }
268
 
269
    if (src == dest)
270
    {
271
      inter_reg = R_TMP0;	/* must preserve src for add/sub */
272
    }
273
    else
274
    {
275
      inter_reg = dest;
276
    }
277
 
278
    ASSERT(src != inter_reg);
279
 
280
    rir_ins(i_sl, src, shift_const, inter_reg);
281
 
282
    /* all but final add_sub */
283
    for (i = 1; i < n; i++)
284
    {
285
      rrr_ins(i_add_sub, inter_reg, src, inter_reg);
286
    }
287
 
288
    /* final add_sub to dest reg */
289
    rrr_ins(i_add_sub, inter_reg, src, dest);
290
  }
291
}
292
 
293
 
294
 
295
/* generate code for multiply using i_muls unless simple constant */
6 7u83 296
static int do_mul_comm_const(exp seq, space sp, int final_reg, bool sgned)
2 7u83 297
{
298
  exp arg2 = bro(seq);
299
  int lhs_reg = reg_operand(seq, sp);
300
 
6 7u83 301
  ASSERT(name(arg2) == val_tag && offset_mul_const_simple(no(arg2), sgned)!= NOT_MUL_CONST_SIMPLE);
2 7u83 302
 
303
 
304
  sp = guardreg(lhs_reg, sp);
305
 
306
  ASSERT(last(arg2));			/* check() & scan() should move const to last */
307
 
308
  if (final_reg == R_NO_REG)
309
    final_reg = getreg(sp.fixed);	/* better code from mul_const if src != dest reg */
310
 
311
  mul_const_simple(lhs_reg, no(arg2), final_reg, sgned);
312
 
313
  return final_reg;
314
}
315
 
316
 
317
/* generate code for divide using i_divs/i_div unless simple constant */
6 7u83 318
static int do_div(exp seq, space sp, int final_reg, bool sgned)
2 7u83 319
{
320
  exp lhs = seq;
321
  exp rhs = bro(lhs);
322
  exp e = bro(rhs);
6 7u83 323
 
2 7u83 324
  int div_type=name(bro(rhs));
6 7u83 325
 
2 7u83 326
  int lhs_reg = reg_operand(lhs, sp);
327
  int rhs_reg;
6 7u83 328
 
2 7u83 329
  sp = guardreg(lhs_reg, sp);
330
 
331
  if (final_reg == R_NO_REG)
332
  {
333
    final_reg = getreg(sp.fixed);
334
    sp = guardreg(final_reg, sp);
335
  }
336
 
337
  ASSERT(last(rhs));
6 7u83 338
 
339
  if (name(rhs) == val_tag && IS_POW2(no(rhs)))
2 7u83 340
  {
6 7u83 341
    /*
2 7u83 342
     * OPTIMISATION: Division by power of 2 can be done as a shift
343
     */
344
    long constval = no(rhs);
345
    if (!optop(e) && constval == 0)
346
    {
347
      /* division by zero goto error jump */
348
      uncond_ins(i_b,no(son(pt(e))));
349
      return final_reg;
350
    }
351
    if (constval>0 && IS_POW2(constval))
352
    {
353
      /* const optim, replace div by 2**n by shift right */
6 7u83 354
 
2 7u83 355
      int shift_const = bit_no(constval);
6 7u83 356
 
2 7u83 357
      if (constval==1)
358
      {
359
	/* result always lhs */
360
	mov_rr_ins(lhs_reg, final_reg);comment(NIL);
361
      }
362
      else if (sgned && div_type!=div1_tag)
363
      {
364
	/* signed, adjust lhs before shift */
6 7u83 365
 
2 7u83 366
	/* +++ the divide instructions rounds to zero, but the shift
367
	 * instruction sets the carry bit if the result is negative so a
368
	 * shift follwed by an add-with-carry instruction is equivalent to
369
	 * a round-to-zero divide.
370
	 */
371
 
372
	int tmp_reg = R_TMP0;
6 7u83 373
 
2 7u83 374
	ASSERT(shift_const>0);			/* assumed below */
375
 
376
	if (shift_const-1 != 0)
377
	{
378
	  rir_ins(i_sra, lhs_reg, shift_const-1, tmp_reg);
379
	  rir_ins(i_sr, tmp_reg, 32-shift_const, tmp_reg);
380
	}
381
	else
382
	{
383
	  rir_ins(i_sr, lhs_reg, 32-shift_const, tmp_reg);
384
	}
385
	rrr_ins(i_a, lhs_reg, tmp_reg, tmp_reg);
386
	rir_ins(i_sra, tmp_reg, shift_const, final_reg);
387
      }
388
      else
389
      {
390
	/* div1_tag and unsigned */
391
	if (sgned)
392
	{
393
	  rir_ins(i_sra, lhs_reg, shift_const, final_reg);
394
	}
395
	else
396
	{
397
	  rir_ins(i_sr, lhs_reg, shift_const, final_reg);
398
	}
399
      }
400
      return final_reg;
401
    }
402
  }
6 7u83 403
 
2 7u83 404
  rhs_reg = reg_operand(rhs,sp);
405
  if (ERROR_TREATMENT(e))
406
  {
6 7u83 407
    div_error_treatment(lhs_reg, rhs_reg, e);
2 7u83 408
  }
409
 
410
  if (architecture==POWERPC_CODE)
411
  {
412
    /* PowerPC has nicer divide instructions */
413
    if (div_type !=div1_tag || !sgned)
414
    {
415
      rrr_ins(sgned?i_divw:i_divwu,lhs_reg,rhs_reg,final_reg);
416
    }
417
    else
418
    {
419
      int creg = next_creg();
420
      int creg2 = next_creg();
421
      int lab =new_label();
6 7u83 422
 
2 7u83 423
      /* signed div1_tag needs special care */
424
      rrr_ins(i_xor,lhs_reg,rhs_reg,R_TMP0);
425
      rir_ins(i_and,R_TMP0,0x80000000,R_TMP0);
426
      cmp_ri_ins(i_cmp,R_TMP0,0,creg);
427
      rrr_ins(i_divw,lhs_reg,rhs_reg,final_reg);
428
      bc_ins(i_beq,creg,lab,LIKELY_TO_JUMP); /* both the same sign same as div2 so jump over*/
429
      rrr_ins(i_muls,rhs_reg,final_reg,R_TMP0);
430
      rrr_ins(i_sf,R_TMP0,lhs_reg,R_TMP0);
431
      cmp_ri_ins(i_cmp,R_TMP0,0,creg2);
432
      bc_ins(i_beq,creg2,lab,UNLIKELY_TO_JUMP); /* 0 remainder jump over */
433
      rir_ins(i_a,final_reg,-1,final_reg); /* subtract one from answer */
434
      set_label(lab);
435
    }
6 7u83 436
 
2 7u83 437
  }
438
  else
439
  {
440
    /* RS/6000 and Common code */
441
    if (sgned)
442
    {
443
      if (div_type==div1_tag)
444
      {
445
	int creg = next_creg();
446
	int creg2 = next_creg();
447
	int lab =new_label();
6 7u83 448
 
2 7u83 449
	/* signed div1_tag needs special care */
450
	rrr_ins(i_xor,lhs_reg,rhs_reg,R_TMP0);
451
	rir_ins(i_and,R_TMP0,0x80000000,R_TMP0);
452
	cmp_ri_ins(i_cmp,R_TMP0,0,creg);
453
	rrr_ins(i_divs,lhs_reg,rhs_reg,final_reg);
454
	bc_ins(i_beq,creg,lab,LIKELY_TO_JUMP); /* both the same sign same as div2 so jump over*/
455
	rrr_ins(i_muls,rhs_reg,final_reg,R_TMP0);
456
	rrr_ins(i_sf,R_TMP0,lhs_reg,R_TMP0);
457
	cmp_ri_ins(i_cmp,R_TMP0,0,creg2);
458
	bc_ins(i_beq,creg2,lab,UNLIKELY_TO_JUMP); /* 0 remainder jump over */
459
	rir_ins(i_a,final_reg,-1,final_reg); /* subtract one from answer */
460
	set_label(lab);
461
      }
462
      else
463
      {
464
	/* signed divide is easy */
465
	rrr_ins(i_divs, lhs_reg, rhs_reg, final_reg);
466
      }
467
    }
468
    else
469
    {
470
      /* unsigned divide */
471
      int safe_rhs_reg;
472
      int creg1 = next_creg();
473
      int creg2 = next_creg();
474
      int endlab = new_label();
6 7u83 475
 
2 7u83 476
      ASSERT(creg1 != creg2);
6 7u83 477
 
2 7u83 478
      if (final_reg != rhs_reg)
479
      {
480
	safe_rhs_reg = rhs_reg;
481
      }
482
      else
483
      {
484
	/* early setting of final_reg will clobber rhs_reg so make safe copy */
485
	safe_rhs_reg = getreg(sp.fixed);
486
	mov_rr_ins(rhs_reg, safe_rhs_reg);comment(NIL);
487
      }
6 7u83 488
 
2 7u83 489
      /* compares as early as possible to minimise cr def-use delay */
490
      cmp_rr_ins(i_cmpl, rhs_reg, lhs_reg, creg1);
491
      cmp_ri_ins(i_cmp, rhs_reg, 0, creg2);
6 7u83 492
 
2 7u83 493
      /* maximise cr def-use delay by loading mq early for following div */
494
      mt_ins(i_mtmq, lhs_reg);
6 7u83 495
 
2 7u83 496
      /* if rhs > lhs then result is 0 */
497
      ld_const_ins(0, final_reg);
498
      bc_ins(i_bgt, creg1, endlab,LIKELY_TO_JUMP);
6 7u83 499
 
2 7u83 500
      /* otherwise if rhs has top bit set then result is 1 */
501
      ld_const_ins(1, final_reg);
502
      bc_ins(i_blt, creg2, endlab,LIKELY_TO_JUMP);
6 7u83 503
 
2 7u83 504
      /* do the extended div */
505
      ld_const_ins(0, R_TMP0);
506
      rrr_ins(i_div, R_TMP0, safe_rhs_reg, final_reg);
6 7u83 507
 
2 7u83 508
      set_label(endlab);
509
    }
510
  }
6 7u83 511
 
2 7u83 512
  return final_reg;
513
}
514
 
515
 
516
/* generate code for rem using i_divs/i_div unless simple constant */
6 7u83 517
static int do_rem(exp seq, space sp, int final_reg, bool sgned)
2 7u83 518
{
519
  exp lhs = seq;
520
  exp rhs = bro(lhs);
521
  exp e = bro(rhs);
522
  int lhs_reg;
523
  int rem_type=name(bro(rhs));
6 7u83 524
  int rhs_reg;
2 7u83 525
  ASSERT(last(rhs));
526
 
527
  lhs_reg = reg_operand(lhs, sp);
528
 
529
  sp = guardreg(lhs_reg, sp);
530
 
531
  if (final_reg == R_NO_REG)
532
  {
533
    final_reg = getreg(sp.fixed);
534
  }
535
 
536
  if (name(rhs) == val_tag && IS_POW2(no(rhs)))
537
  {
538
    long constval = no(rhs);
539
 
540
    if (constval>0 && IS_POW2(constval))
541
    {
542
      /* const optim, replace rem by 2**n by and with mask */
543
 
544
      if (constval==1)
545
      {
546
	/* result always 0 */
547
	ld_const_ins(0, final_reg);
548
      }
549
      else if (sgned && rem_type!=mod_tag)
550
      {
551
	/*
552
	 * signed, need to allow for negative lhs.
553
	 * Treat l%c as l-(l/c)*c
554
	 */
555
 
556
	int tmp_reg = R_TMP0;
557
	int shift_const = bit_no(constval);
558
 
559
	ASSERT(shift_const>0);			/* assumed below */
560
 
561
	/* do the divide, as in do_div */
562
	if (shift_const-1 != 0)
563
	{
564
	  rir_ins(i_sra, lhs_reg, shift_const-1, tmp_reg);
565
	  rir_ins(i_sr, tmp_reg, 32-shift_const, tmp_reg);
566
	}
567
	else
568
	{
569
	  rir_ins(i_sr, lhs_reg, 32-shift_const, tmp_reg);
570
	}
571
	rrr_ins(i_a, lhs_reg, tmp_reg, tmp_reg);
572
	rir_ins(i_sra, tmp_reg, shift_const, tmp_reg);
573
 
574
	/* multiply */
575
	rir_ins(i_sl, tmp_reg, shift_const, tmp_reg);
576
 
577
	/* subtract */
578
	rrr_ins(i_s, lhs_reg, tmp_reg, final_reg);
579
      }
6 7u83 580
      else
2 7u83 581
      {
582
	/* mod_tag and unsigned */
583
	rir_ins(i_and, lhs_reg, constval-1, final_reg);
584
      }
585
      return final_reg;
586
    }
587
  }
588
  rhs_reg = reg_operand(rhs,sp);
6 7u83 589
  if (ERROR_TREATMENT(e))
2 7u83 590
  {
591
    rem_error_treatment(lhs_reg,rhs_reg,e);
592
  }
6 7u83 593
  if (architecture==POWERPC_CODE)
2 7u83 594
  {
595
    if (!sgned || rem_type !=mod_tag)
596
    {
597
 
598
      rrr_ins(sgned?i_divw:i_divwu,lhs_reg,rhs_reg,R_TMP0);
599
      rrr_ins(i_muls,R_TMP0,rhs_reg,R_TMP0);
600
      rrr_ins(i_sf,R_TMP0,lhs_reg,final_reg);
601
    }
602
    else
603
    {
604
      /* signed and rem1 */
605
      int creg = next_creg();
606
      int creg2 = next_creg();
607
      int lab =new_label();
6 7u83 608
 
2 7u83 609
      /* signed div1_tag needs special care */
610
      rrr_ins(i_xor,lhs_reg,rhs_reg,R_TMP0);
611
      rir_ins(i_and,R_TMP0,0x80000000,R_TMP0);
612
      cmp_ri_ins(i_cmp,R_TMP0,0,creg);
613
      rrr_ins(i_divw,lhs_reg,rhs_reg,R_TMP0);
614
      rrr_ins(i_muls,rhs_reg,R_TMP0,final_reg);
615
      rrr_ins(i_sf,final_reg,lhs_reg,final_reg);
616
      bc_ins(i_beq,creg,lab,LIKELY_TO_JUMP); /* both the same sign same as div2 so jump over*/
617
      cmp_ri_ins(i_cmp,final_reg,0,creg2);
618
      bc_ins(i_beq,creg2,lab,UNLIKELY_TO_JUMP); /* 0 remainder jump over */
619
      rrr_ins(i_a,final_reg,rhs_reg,final_reg); /* add quotinent to answer */
620
      set_label(lab);
621
    }
622
  }
623
  else
624
  {
625
    if (sgned)
626
    {
627
      if (rem_type==mod_tag)
628
      {
629
	int creg = next_creg();
630
	int creg2 = next_creg();
631
	int lab =new_label();
6 7u83 632
 
2 7u83 633
	/* signed div1_tag needs special care */
634
	rrr_ins(i_xor,lhs_reg,rhs_reg,R_TMP0);
635
	rir_ins(i_and,R_TMP0,0x80000000,R_TMP0);
636
	cmp_ri_ins(i_cmp,R_TMP0,0,creg);
637
	rrr_ins(i_divs,lhs_reg,rhs_reg,R_TMP0);
638
	rrr_ins(i_muls,rhs_reg,R_TMP0,final_reg);
639
	rrr_ins(i_sf,final_reg,lhs_reg,final_reg);
640
	bc_ins(i_beq,creg,lab,LIKELY_TO_JUMP); /* both the same sign same as div2 so jump over*/
641
	cmp_ri_ins(i_cmp,final_reg,0,creg2);
642
	bc_ins(i_beq,creg2,lab,UNLIKELY_TO_JUMP); /* 0 remainder jump over */
643
	rrr_ins(i_a,final_reg,rhs_reg,final_reg); /* add quotinent to answer */
644
	set_label(lab);
645
      }
646
      else
647
      {
648
	rrr_ins(i_divs, lhs_reg, rhs_reg, R_TMP0);
649
	mf_ins(i_mfmq, final_reg);
650
      }
651
    }
652
    else
653
    {
654
      int safe_rhs_reg;
655
      int creg1 = next_creg();
656
      int creg2 = next_creg();
657
      int endlab = new_label();
6 7u83 658
 
2 7u83 659
      ASSERT(creg1 != creg2);
6 7u83 660
 
2 7u83 661
      if (final_reg != rhs_reg)
662
      {
663
	safe_rhs_reg = rhs_reg;
664
      }
665
      else
666
      {
667
	/* early setting of final_reg will clobber rhs_reg so make safe copy */
668
	safe_rhs_reg = getreg(sp.fixed);
669
	mov_rr_ins(rhs_reg, safe_rhs_reg);comment(NIL);
670
      }
6 7u83 671
 
2 7u83 672
      /* compares as early as possible to minimise cr def-use delay */
673
      cmp_rr_ins(i_cmpl, rhs_reg, lhs_reg, creg1);
674
      cmp_ri_ins(i_cmp, rhs_reg, 0, creg2);
6 7u83 675
 
2 7u83 676
      /* maximise cr def-use delay by loading mq early for following div */
677
      mt_ins(i_mtmq, lhs_reg);
6 7u83 678
 
2 7u83 679
      /* if rhs > lhs then result is lhs */
680
      mov_rr_ins(lhs_reg, final_reg);comment(NIL);
681
      bc_ins(i_bgt, creg1, endlab,LIKELY_TO_JUMP);
6 7u83 682
 
2 7u83 683
      /* otherwise if rhs has top bit set then result is lhs - rhs */
684
      if (lhs_reg == final_reg)
685
      {
686
	/* lhs has been clobbered, recover from MQ */
687
	mf_ins(i_mfmq, lhs_reg);
688
      }
689
      rrr_ins(i_s, lhs_reg, safe_rhs_reg, final_reg);
690
      bc_ins(i_blt, creg2, endlab,LIKELY_TO_JUMP);
6 7u83 691
 
2 7u83 692
      /* do the extended div */
693
      ld_const_ins(0, R_TMP0);
694
      rrr_ins(i_div, R_TMP0, safe_rhs_reg, R_TMP0);
695
      mf_ins(i_mfmq, final_reg);
6 7u83 696
 
2 7u83 697
      set_label(endlab);
698
    }
699
  }
6 7u83 700
 
2 7u83 701
  return final_reg;
702
}
703
 
704
 
705
 
706
/* choose regs and generate code using do_fn */
707
static int find_reg_and_apply
6 7u83 708
(exp e, space sp, where dest, bool sgned,	     int(*do_fn)PROTO_S((exp, space, int, bool)))
2 7u83 709
{
710
  exp seq = son(e);
711
  ans a;
712
  int dest_reg;
713
 
714
  switch (dest.answhere.discrim)
715
  {
716
  case inreg:
717
    dest_reg = (*do_fn)(seq, sp, regalt(dest.answhere), sgned);
718
    break;
719
 
720
  case insomereg:
721
    {
722
      int *dr = someregalt(dest.answhere);
723
 
724
      *dr = (*do_fn)(seq, sp, R_NO_REG, sgned);		/* leave (*do_fn)() to allocate reg */
725
      return *dr;		/* no need for move */
726
    }
727
 
728
  default:
729
    dest_reg = (*do_fn)(seq, sp, R_NO_REG, sgned);	/* leave (*do_fn)() to allocate reg */
730
  }
731
 
732
  ASSERT(dest_reg != R_NO_REG);
733
 
734
  setregalt(a, dest_reg);
735
  sp = guardreg(dest_reg, sp);
736
  move(a, dest, sp.fixed, sgned);
737
 
738
  return dest_reg;
739
}
740
 
741
 
742
 
743
/* choose regs and generate code for multiply */
6 7u83 744
int do_mul_comm_op(exp e, space sp, where dest, bool sgned)
2 7u83 745
{
746
  exp arg2 = bro(son(e));
747
 
748
  if (name(arg2) == val_tag &&
6 7u83 749
      offset_mul_const_simple(no(arg2), sgned)!= NOT_MUL_CONST_SIMPLE)
2 7u83 750
  {
751
    return find_reg_and_apply(e, sp, dest, sgned, do_mul_comm_const);
752
  }
753
  else
754
  {
6 7u83 755
    return comm_op(e, sp, dest, i_muls);
2 7u83 756
    /* i_muls for both signed and unsigned with no error treatment */
757
  }
758
}
759
 
760
 
761
/* choose regs and generate code for divide */
6 7u83 762
int do_div_op(exp e, space sp, where dest, bool sgned)
2 7u83 763
{
764
  return find_reg_and_apply(e, sp, dest, sgned, do_div);
765
}
766
 
767
 
768
/* choose regs and generate code for rem */
6 7u83 769
int do_rem_op(exp e, space sp, where dest, bool sgned)
2 7u83 770
{
771
  return find_reg_and_apply(e, sp, dest, sgned, do_rem);
772
}
773
 
774
 
775
#if 0
776
/*
777
 * Needs estimation
778
 */
779
 
780
 
6 7u83 781
needs multneeds(exp *e, exp **at)
2 7u83 782
{
783
  needs n = likeplus(e, at);	/* has had comm_ass() treatment */
784
  exp arg1 = son(*e);
785
  exp arg2 = bro(arg1);
786
 
787
  /* remember that mult may have more than two args after optimisation */
788
 
789
  if (last(arg2) && name(arg2) == val_tag)
790
  {
791
    /*
792
     * const optim, additional reg only needed where src and dest are same reg,
793
     * in which case it has already been allowed for.
794
     */
795
    return n;
796
  }
797
 
798
  return n;
799
}
800
 
801
 
6 7u83 802
needs divneeds(exp *e, exp **at)
2 7u83 803
{
804
  needs n = likeminus(e, at);
805
  exp lhs = son(*e);
806
  exp rhs = bro(lhs);
807
  bool sgned = name(sh(*e)) & 1;
808
 
809
  ASSERT(last(rhs));
810
 
6 7u83 811
  if (name(rhs) ==val_tag)
2 7u83 812
  {
813
    long constval = no(rhs);
814
 
815
    if (constval>0 && IS_POW2(constval))
816
    {
817
      /* const optim, replace div by positive, non-zero, 2**n by shift right */
818
 
819
      return n;
820
    }
821
  }
822
 
823
  /* need extra reg for unsigned div */
824
  if (!sgned && n.fixneeds < 2)
825
    n.fixneeds = 2;
826
 
827
  return n;
828
}
829
 
830
 
6 7u83 831
needs remneeds(exp *e, exp **at)
2 7u83 832
{
833
  needs n = likeminus(e, at);
834
  exp lhs = son(*e);
835
  exp rhs = bro(lhs);
836
  bool sgned = name(sh(*e)) & 1;
837
 
838
  ASSERT(last(rhs));
839
 
6 7u83 840
  if (name(rhs) ==val_tag)
2 7u83 841
  {
842
    long constval = no(rhs);
843
 
844
    if (constval>0 && IS_POW2(constval))
845
    {
846
      /* const optim of rem by positive, non-zero, 2**n */
847
 
848
      return n;
849
    }
850
  }
851
 
852
  /* need extra reg for unsigned rem */
853
  if (!sgned && n.fixneeds < 2)
854
    n.fixneeds = 2;
855
 
856
  return n;
857
}
858
#endif