Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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