Subversion Repositories tendra.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
2
    		 Crown Copyright (c) 1997
3
 
4
    This TenDRA(r) Computer Program is subject to Copyright
5
    owned by the United Kingdom Secretary of State for Defence
6
    acting through the Defence Evaluation and Research Agency
7
    (DERA).  It is made available to Recipients with a
8
    royalty-free licence for its use, reproduction, transfer
9
    to other parties and amendment for any purpose not excluding
10
    product development provided that any such use et cetera
11
    shall be deemed to be acceptance of the following conditions:-
12
 
13
        (1) Its Recipients shall ensure that this Notice is
14
        reproduced upon any copies or amended versions of it;
15
 
16
        (2) Any amended version of it shall be clearly marked to
17
        show both the nature of and the organisation responsible
18
        for the relevant amendment or amendments;
19
 
20
        (3) Its onward transfer from a recipient to another
21
        party shall be deemed to be that party's acceptance of
22
        these conditions;
23
 
24
        (4) DERA gives no warranty or assurance as to its
25
        quality or suitability for any purpose and DERA accepts
26
        no liability whatsoever in relation to any use to which
27
        it may be put.
28
*/
29
 
30
 
31
 
32
 
33
/*
34
			    VERSION INFORMATION
35
			    ===================
36
 
37
--------------------------------------------------------------------------
38
$Header: /u/g/release/CVSROOT/Source/src/installers/sparc/common/oprators.c,v 1.1.1.1 1998/01/17 15:55:55 release Exp $
39
--------------------------------------------------------------------------
40
$Log: oprators.c,v $
41
 * Revision 1.1.1.1  1998/01/17  15:55:55  release
42
 * First version to be checked into rolling release.
43
 *
44
 * Revision 1.9  1997/10/10  18:32:50  pwe
45
 * prep ANDF-DE revision
46
 *
47
 * Revision 1.8  1997/08/23  13:54:24  pwe
48
 * initial ANDF-DE
49
 *
50
 * Revision 1.7  1997/02/18  11:48:13  pwe
51
 * NEWDIAGS for debugging optimised code
52
 *
53
 * Revision 1.6  1996/08/27  14:54:38  pwe
54
 * Q_functions destroy flpt regs
55
 *
56
 * Revision 1.5  1996/03/20  16:12:37  john
57
 * Reformatting
58
 *
59
 * Revision 1.4  1995/07/27  16:32:04  john
60
 * Fix for quad op
61
 *
62
 * Revision 1.3  1995/07/14  16:33:04  john
63
 * Changes for new error handling
64
 *
65
 * Revision 1.2  1995/05/26  13:00:16  john
66
 * Reformatting
67
 *
68
 * Revision 1.1.1.1  1995/03/13  10:18:50  john
69
 * Entered into CVS
70
 *
71
 * Revision 1.5  1994/12/21  11:47:13  djch
72
 * added labeldecs.h to declare set_label
73
 *
74
 * Revision 1.4  1994/12/01  13:18:59  djch
75
 * Altered abs code to generate a label, and pass to br_abs. .+8 is allowed by
76
 * the SPARC asm manual, not by /bin/as...
77
 *
78
 * Revision 1.3  1994/11/28  16:55:06  djch
79
 * added code for absop to generate efficient abs code
80
 *
81
 * Revision 1.2  1994/07/07  16:11:33  djch
82
 * Jul94 tape
83
 *
84
 * Revision 1.1  1994/05/03  14:49:47  djch
85
 * Initial revision
86
 *
87
 * Revision 1.5  93/09/27  14:52:20  14:52:20  ra (Robert Andrews)
88
 * Added quad_op, the main routine for dealing with long double
89
 * operations.  Modified fop to allow for long doubles.
90
 * 
91
 * Revision 1.4  93/08/27  11:34:44  11:34:44  ra (Robert Andrews)
92
 * A couple of lint-like changes.
93
 * 
94
 * Revision 1.3  93/07/08  18:22:32  18:22:32  ra (Robert Andrews)
95
 * Reformatted.
96
 * 
97
 * Revision 1.2  93/06/29  14:30:03  14:30:03  ra (Robert Andrews)
98
 * Now use ins_p to represent instructions.
99
 * 
100
 * Revision 1.1  93/06/24  14:58:57  14:58:57  ra (Robert Andrews)
101
 * Initial revision
102
 * 
103
--------------------------------------------------------------------------
104
*/
105
 
106
 
107
#define SPARCTRANS_CODE
108
#include "config.h"
109
#include "common_types.h"
110
#include "codehere.h"
111
#include "expmacs.h"
112
#include "addrtypes.h"
113
#include "inst_fmt.h"
114
#include "move.h"
115
#include "maxminmacs.h"
116
#include "getregs.h"
117
#include "guard.h"
118
#include "tags.h"
119
#include "shapemacs.h"
120
#include "bitsmacs.h"
121
#include "myassert.h"
122
#include "externs.h"
123
#include "install_fns.h"
124
#include "regmacs.h"
125
#include "regexps.h"
126
#include "exp.h"
127
#include "out.h"
128
#include "locate.h"
129
#include "eval.h"
130
#include "muldvrem.h"
131
#include "proc.h"
132
#include "labels.h"
133
#include "oprators.h"
134
 
135
/*
136
    CORRECT POSSIBLE OVERFLOWS IN REGISTER r
137
*/
138
 
139
void tidyshort 
140
    PROTO_N ( ( r, s ) )
141
    PROTO_T ( int r X shape s ){
142
  if ( name ( s ) == ucharhd ) {
143
    rir_ins ( i_and, r, 0xff, r ) ;
144
  } else if ( name ( s ) == uwordhd ) {
145
    rir_ins ( i_and, r, 0xffff, r ) ;
146
  }
147
  return ;
148
}
149
 
150
 
151
/*
152
  REMOVE AN EXPRESSION CONTAINING A REGISTER
153
  Given a list of expressions, seq, find one whose value is in 
154
  register reg.  If this is found, it is removed from seq and 1 
155
  is returned.  Otherwise 0 is returned.
156
*/
157
bool regremoved 
158
    PROTO_N ( ( seq, reg ) )
159
    PROTO_T ( exp * seq X int reg ){
160
  exp s = *seq ;
161
  exp t = bro ( s ) ;
162
  if ( ABS_OF ( regofval ( s ) ) == reg ) {
163
    ( *seq ) = t ;
164
    return ( 1 ) ;
165
  }
166
  for ( ; ; ) {
167
    if ( ABS_OF ( regofval ( t ) ) == reg ) {
168
      bro ( s ) = bro ( t ) ;
169
      if ( last ( t ) ) setlast ( s ) ;
170
      return ( 1 ) ;
171
    }
172
    if ( last ( t ) ) return ( 0 ) ;
173
    s = t ;
174
    t = bro ( t ) ;
175
  }
176
  /* NOT REACHED */
177
}
178
 
179
 
180
/*
181
  EVALUATE A COMMUTATIVE OPERATION
182
  Evaluates reg = seq_1 @ seq_2 @ ... where @ is a binary commutative
183
  operation given by rins.  sp may be used for free t-registers.
184
*/
185
void do_comm 
186
    PROTO_N ( ( seq, sp, final, rins ) )
187
    PROTO_T ( exp seq X space sp X int final X ins_p rins ){
188
  int r = 0 ;
189
  space nsp ;
190
  int a1, a2 ;
191
  /* should have been optimised in scan... */
192
  assert ( !( rins == i_add && name ( seq ) == neg_tag &&
193
	      name ( bro ( seq ) ) != val_tag ) ) ;
194
  /* evaluate first operand into a1 */
195
  a1 = reg_operand ( seq, sp ) ;
196
  for ( ; ; ) {
197
    nsp = guardreg ( a1, sp ) ;
198
    seq = bro ( seq ) ;
199
    if ( name ( seq ) == val_tag ) {
200
      /* next operand is a constant */
201
      if ( last ( seq ) ) {
202
	rir_ins ( rins, a1, ( long ) no ( seq ), final ) ;
203
	return ;
204
      } 
205
      else {
206
	if ( r == 0 ) r = getreg ( sp.fixed ) ;
207
	rir_ins ( rins, a1, ( long ) no ( seq ), r ) ;
208
      }
209
    } 
210
    else {
211
      /* evaluate next operand */
212
      exp sq = seq ;
213
      ins_p ins = rins ;
214
      a2 = reg_operand ( sq, nsp ) ;
215
      if ( last ( seq ) ) {
216
	rrr_ins ( ins, a1, a2, final ) ;
217
	return ;
218
      } 
219
      else {
220
	if ( r == 0 ) r = getreg ( sp.fixed ) ;
221
	rrr_ins ( ins, a1, a2, r ) ;
222
      }
223
    }
224
    a1 = r ;
225
  }
226
  /* NOT REACHED */
227
}
228
 
229
 
230
/*
231
  EVALUATE A COMMUTATIVE OPERATION
232
  The commutative operation, rrins, given by e is evaluated into d,
233
  using sp to get free t-registers.
234
*/
235
 
236
int comm_op 
237
    PROTO_N ( ( e, sp, d, rrins ) )
238
    PROTO_T ( exp e X space sp X where d X ins_p rrins ){
239
  ins_p rins = rrins ;
240
  switch ( discrim ( d.answhere ) ) {
241
    case inreg : {
242
      int dest = regalt ( d.answhere ) ;
243
      bool usesdest = regremoved ( &son ( e ), dest ) ;
244
      exp seq = son ( e ) ;
245
      if(dest == R_G0) {
246
	dest = getreg(sp.fixed);
247
      }
248
 
249
      /* the destination is in a register, take care that we don't
250
	 alter it before possible use as an operand ... */
251
      if ( usesdest && last ( seq ) ) {
252
	/* used, but there is only one other operand */
253
	if ( name ( seq ) == val_tag ) {
254
	  rir_ins ( rins, dest, ( long ) no ( seq ), dest ) ;
255
	} 
256
        else {
257
	  rrr_ins ( rins, dest, reg_operand ( seq, sp ), dest ) ;
258
	}
259
	if(optop(e)) tidyshort ( dest, sh ( e ) ) ;
260
	return ( dest ) ;
261
      } 
262
      else if ( usesdest ) {
263
	/* dest used, use temp */
264
	int r = getreg ( sp.fixed ) ;
265
	do_comm ( seq, sp, r, rins ) ;
266
	rrr_ins ( rins, dest, r, dest ) ;
267
	if (optop(e)) tidyshort ( dest, sh ( e ) ) ;
268
	return ( dest ) ;
269
      } 
270
      else {
271
	/* dest not used, evaluate into dest */
272
	do_comm ( seq, sp, dest, rins ) ;
273
	if (optop(e)) tidyshort ( dest, sh ( e ) ) ;
274
	return ( dest ) ;
275
      }
276
    }
277
    default : {
278
      ans a ;
279
      space nsp ;
280
      int r = getreg ( sp.fixed ) ;
281
      setregalt ( a, r ) ;
282
      /* evaluate the expression into r ... */
283
      do_comm ( son ( e ), sp, r, rins ) ;
284
      if(optop(e)) tidyshort ( r, sh ( e ) ) ;
285
      nsp = guardreg ( r, sp ) ;
286
      /* ... and move into a */
287
      ( void ) move ( a, d, nsp.fixed, 1 ) ;
288
      return ( r ) ;
289
    }
290
  }
291
  /* NOT REACHED */
292
}
293
 
294
 
295
/*
296
  EVALUATE A NON-COMMUTATIVE OPERATION
297
  The non-commutative operation, rins, given by e is evaluated 
298
  into dest, using sp to get free t-registers.
299
*/
300
int non_comm_op 
301
    PROTO_N ( ( e, sp, dest, rins ) )
302
    PROTO_T ( exp e X space sp X where dest X ins_p rins ){
303
  exp l = son ( e ) ;
304
  exp r = bro ( l ) ;
305
  int a1 = reg_operand ( l, sp ), a2 ;
306
  space nsp ;
307
  nsp = guardreg ( a1, sp ) ;
308
  a2 = reg_operand ( r, nsp ) ;
309
  switch ( discrim ( dest.answhere ) ) {
310
    case inreg : {
311
      int d = regalt ( dest.answhere ) ;
312
      if(d == R_G0) {
313
	d = getreg(sp.fixed);
314
      }
315
      rrr_ins ( rins, a1, a2, d ) ;
316
      if(optop(e)) tidyshort ( d, sh ( e ) ) ;
317
      return ( d ) ;
318
    }
319
    default : {
320
      ans a ;
321
      int r1 = getreg ( nsp.fixed ) ;
322
      setregalt ( a, r1 ) ;
323
      rrr_ins ( rins, a1, a2, r1 ) ;
324
      if(optop(e)) tidyshort ( r1, sh ( e ) ) ;
325
      nsp = guardreg ( r1, sp ) ;
326
      ( void ) move ( a, dest, nsp.fixed, 1 ) ;
327
      return ( r1 ) ;
328
    }
329
  }
330
  /* NOT REACHED */
331
}
332
 
333
 
334
/*
335
  EVALUATE A MONADIC OPERATION
336
  The monadic operation, ins, given by e is evaluated into dest, 
337
  using sp to get free t-registers.
338
*/
339
int monop 
340
    PROTO_N ( ( e, sp, dest, ins ) )
341
    PROTO_T ( exp e X space sp X where dest X ins_p ins ){
342
  int r1 = getreg ( sp.fixed ) ;
343
  int a1 = reg_operand ( son ( e ), sp ) ;
344
  switch ( discrim ( dest.answhere ) ) {
345
    case inreg : {
346
      int d = regalt ( dest.answhere ) ;
347
      if (d == R_G0) d = getreg(sp.fixed);
348
      rr_ins ( ins, a1, d ) ;
349
      if(optop(e)) tidyshort ( d, sh ( e ) ) ;
350
      return ( d ) ;
351
    }
352
    default : {
353
      ans a ;
354
      space nsp ;
355
      setregalt ( a, r1 ) ;
356
      rr_ins ( ins, a1, r1 ) ;
357
      if(optop(e)) tidyshort ( r1, sh ( e ) ) ;
358
      nsp = guardreg ( r1, sp ) ;
359
      ( void ) move ( a, dest, nsp.fixed, 1 ) ;
360
      return ( r1 ) ;
361
    }
362
  }
363
  /* NOT REACHED */
364
}
365
 
366
/*
367
    EVALUATE abs OPERATION as
368
    move a1 -> d
369
    subcc %g0, a1 -> R_TMP
370
    bpos,a L
371
    move R_TMP -> d
372
L:
373
 
374
*/
375
int absop 
376
    PROTO_N ( ( e, sp, dest ) )
377
    PROTO_T ( exp e X space sp X where dest ){
378
  int r1 = getreg ( sp.fixed ) ;
379
  int a1 = reg_operand ( son ( e ), sp ) ;
380
  int lab = new_label();
381
 
382
  switch ( discrim ( dest.answhere ) ) {
383
    case inreg : {
384
      int d = regalt ( dest.answhere ) ;
385
      if (d == R_G0) {
386
	d = getreg(sp.fixed);
387
      }
388
      rr_ins ( i_mov, a1, d ) ;
389
      rrr_ins ( i_subcc, R_G0, a1, R_TMP);
390
      br_abs(lab);
391
      rr_ins( i_mov, R_TMP, d);
392
      set_label(lab);
393
      if(optop(e)) tidyshort ( d, sh ( e ) ) ;
394
      return ( d ) ;
395
    }
396
    default : {
397
      ans a ;
398
      space nsp ;
399
      setregalt ( a, r1 ) ;
400
      rr_ins ( i_mov, a1, r1 ) ;
401
      rrr_ins ( i_subcc, R_G0, a1, R_TMP);
402
      br_abs(lab);
403
      rr_ins( i_mov, R_TMP, r1);
404
      set_label(lab);
405
      if(optop(e)) tidyshort ( r1, sh ( e ) ) ;
406
      nsp = guardreg ( r1, sp ) ;
407
      ( void ) move ( a, dest, nsp.fixed, 1 ) ;
408
      return ( r1 ) ;
409
    }
410
  }
411
  /* NOT REACHED */
412
}
413
 
414
 
415
/*
416
  GET THE ADDRESS OF A LONG DOUBLE
417
*/
418
static void quad_addr 
419
    PROTO_N ( ( e, r, sp ) )
420
    PROTO_T ( exp e X int r X space sp ){
421
  instore is ;
422
  if ( name ( e ) == real_tag ) {
423
    is = evaluated ( e, 0, 1 ) ;
424
  } 
425
  else {
426
    where w ;
427
    w = locate1 ( e, sp, sh ( e ), 0 ) ;
428
    if ( discrim ( w.answhere ) != notinreg ) {
429
      fail ( "Illegal expression in quad_addr" ) ;
430
    }
431
    is = insalt ( w.answhere ) ;
432
  }
433
  if ( is.adval ) {
434
    fail ( "Illegal expression in quad_addr" ) ;
435
  }
436
  if ( IS_FIXREG ( is.b.base ) ) {
437
    if ( is.b.offset == 0 ) {
438
      if ( is.b.base != r ) rr_ins ( i_mov, is.b.base, r ) ;
439
    } 
440
    else {
441
      rir_ins ( i_add, is.b.base, is.b.offset, r ) ;
442
    }
443
  } 
444
  else {
445
    set_ins ( is.b, r ) ;
446
  }
447
  return ;
448
}
449
 
450
 
451
/*
452
  DO A LONG DOUBLE OPERATION
453
*/
454
void quad_op 
455
    PROTO_N ( ( a1, a2, sp, dest, op ) )
456
    PROTO_T ( exp a1 X exp a2 X space sp X where dest X int op ){
457
  char *s ;
458
  bool quad_ret = 1 ;
459
  if ( op < 0 ) {
460
    /* Test operations */
461
    quad_ret = 0 ;
462
    switch ( -op ) {
463
      case 1 : s = "_Q_fle,2" ; break ;
464
      case 2 : s = "_Q_flt,2" ; break ;
465
      case 3 : s = "_Q_fge,2" ; break ;
466
      case 4 : s = "_Q_fgt,2" ; break ;
467
      case 5 : s = "_Q_fne,2" ; break ;
468
      case 6 : s = "_Q_feq,2" ; break ;
469
      default : fail ( "Illegal floating-point test" ) ;
470
    }
471
  } 
472
  else {
473
    /* Binary operations */
474
    switch ( op ) {
475
      case fplus_tag : s = "_Q_add,2" ; break ;
476
      case fminus_tag : s = "_Q_sub,2" ; break ;
477
      case fmult_tag : s = "_Q_mul,2" ; break ;
478
      case fdiv_tag : s = "_Q_div,2" ; break ;
479
      case fneg_tag : s = "_Q_neg,1" ; break ;
480
      case chfl_tag : s = "_Q_stoq,1" ; break ;
481
      case float_tag : s = "_Q_itoq,1" ; break ;
482
      case 100 : s = "_Q_qtod,1" ; quad_ret = 0 ; break ;
483
      case 101 : s = "_Q_qtos,1" ; quad_ret = 0 ; break ;
484
      case fabs_tag : 
485
      /* special case: there is no special operation for 
486
	 this, so it has to be performed by a code sequence*/
487
      fail("No operation for fabs( long double )");
488
      s = "_Q_abs,1" ; 
489
      break ;
490
      default : fail ( "Illegal floating-point operation" ) ;
491
    }
492
  }
493
  if ( quad_ret ) {
494
    instore is ;
495
    baseoff ret_addr ;
496
    ret_addr.base = R_SP ;
497
    ret_addr.offset = ( 16 * 4 ) ;
498
    is = insalt ( dest.answhere ) ;
499
    if ( discrim ( dest.answhere ) != notinreg ) {
500
      is.b = mem_temp(0);
501
      is.adval = 1;
502
      /*fail ( "Illegal expression in quad_op" ) ;*/
503
    }
504
    if ( is.adval ) {
505
      if ( IS_FIXREG ( is.b.base ) ) {
506
	if ( is.b.offset == 0 ) {
507
	  st_ro_ins ( i_st, is.b.base, ret_addr ) ;
508
	} 
509
	else {
510
	  rir_ins ( i_add, is.b.base, is.b.offset, R_TMP ) ;
511
	  st_ro_ins ( i_st, R_TMP, ret_addr ) ;
512
	}
513
      } 
514
      else {
515
	set_ins ( is.b, R_TMP ) ;
516
	st_ro_ins ( i_st, R_TMP, ret_addr ) ;
517
      }
518
    } 
519
    else {
520
      ld_ins ( i_ld, is.b, R_TMP ) ;
521
      st_ro_ins ( i_st, R_TMP, ret_addr ) ;
522
    }
523
  }
524
  /* hack for float integer */
525
  if ( op == float_tag ) {
526
    int r = reg_operand ( a1, sp ) ;
527
    if ( name ( sh ( a1 ) ) == ulonghd ) s = "_Q_utoq,1" ;
528
    if ( r != R_O0 ) rr_ins ( i_mov, r, R_O0 ) ;
529
    a1 = nilexp ;
530
  }
531
  /* hack for change floating variety */
532
  if ( op == chfl_tag ) {
533
    ans aa ;
534
    where w ;
535
    freg frg ;
536
    frg.fr = getfreg ( sp.flt ) ;
537
    if ( name ( sh ( a1 ) ) == realhd ) {
538
      s = "_Q_dtoq,1" ;
539
      frg.dble = 1 ;
540
    } 
541
    else {
542
      frg.dble = 0 ;
543
    }
544
    setfregalt ( aa, frg ) ;
545
    w.answhere = aa ;
546
    w.ashwhere = ashof ( sh ( a1 ) ) ;
547
    ( void ) code_here ( a1, sp, w ) ;
548
    if ( frg.dble ) {
549
      stf_ins ( i_std, frg.fr << 1, mem_temp ( 0 ) ) ;
550
      ld_ro_ins ( i_ld, mem_temp ( 0 ), R_O0 ) ;
551
      ld_ro_ins ( i_ld, mem_temp ( 4 ), R_O1 ) ;
552
    } 
553
    else {
554
      stf_ins ( i_st, frg.fr << 1, mem_temp ( 0 ) ) ;
555
      ld_ro_ins ( i_ld, mem_temp ( 0 ), R_O0 ) ;
556
    }
557
    a1 = nilexp ;
558
  }
559
  /* put the arguments into the call registers */
560
  if ( a1 != nilexp ) {
561
    quad_addr ( a1, R_O0, sp ) ;
562
    if ( a2 != nilexp ) {
563
      sp = needreg ( R_O0, sp ) ;
564
      quad_addr ( a2, R_O1, sp ) ;
565
    }
566
  }
567
  /* output the actual call */
568
  outs ( "\tcall\t" ) ;
569
  outs ( s ) ;
570
  outs ( "\n\tnop\n" ) ;
571
  if ( quad_ret ) outs ( "\tunimp\t16\n" ) ;
572
  clear_all () ;
573
  return ;
574
}
575
 
576
 
577
/*
578
  EVALUATE A FLOATING POINT OPERATION
579
  The floating point operation, ins, given by e is evaluated 
580
  into dest, using sp to get free t-registers.
581
*/
582
int fop 
583
    PROTO_N ( ( e, sp, dest, ins ) )
584
    PROTO_T ( exp e X space sp X where dest X ins_p ins ){
585
  exp l = son ( e ) ;
586
  exp r = bro ( l ) ;
587
  space nsp ;
588
  int a1, a2 ;
589
 
590
#if use_long_double
591
  if ( name ( sh ( e ) ) == doublehd ) {
592
    if ( IsRev ( e ) ) {
593
      quad_op ( r, l, sp, dest, ( int ) name ( e ) ) ;
594
    } 
595
    else {
596
      quad_op ( l, r, sp, dest, ( int ) name ( e ) ) ;
597
    }
598
    return ( NOREG ) ;
599
  }
600
#endif
601
  if ( IsRev ( e ) ) {
602
    /* reverse operands */
603
    a2 = freg_operand ( r, sp, getfreg ( sp.flt ) ) ;
604
    nsp = guardfreg ( a2, sp ) ;
605
    a1 = freg_operand ( l, nsp, getfreg ( nsp.flt ) ) ;
606
    } 
607
  else {
608
    a1 = freg_operand ( l, sp, getfreg ( sp.flt ) ) ;
609
    nsp = guardfreg ( a1, sp ) ;
610
    a2 = freg_operand ( r, nsp, getfreg ( nsp.flt ) ) ;
611
  }
612
  switch ( discrim ( dest.answhere ) ) {
613
    case infreg : {
614
      freg fr ;
615
      fr = fregalt ( dest.answhere ) ;
616
      rrrf_ins ( ins, a1 << 1, a2 << 1, fr.fr << 1 ) ;
617
      return ( ( fr.dble ) ? -( fr.fr + 32 ) : ( fr.fr + 32 ) ) ;
618
    }
619
    default : {
620
      ans a ;
621
      freg fr ;
622
      int r1 = getfreg ( nsp.flt ) ;
623
      fr.fr = r1 ;
624
      fr.dble = ( bool ) ( ( dest.ashwhere.ashsize == 64 ) ? 1 : 0 ) ;
625
      setfregalt ( a, fr ) ;
626
      rrrf_ins ( ins, a1 << 1, a2 << 1, r1 << 1 ) ;
627
      ( void ) move ( a, dest, sp.fixed, 1 ) ;
628
      return ( ( fr.dble ) ? -( fr.fr + 32 ) : ( fr.fr + 32 ) ) ;
629
    }
630
  }
631
    /* NOT REACHED */
632
}