Subversion Repositories tendra.SVN

Rev

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

Rev Author Line No. Line
2 7u83 1
/*
7 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
    		 Crown Copyright (c) 1997
33
 
34
    This TenDRA(r) Computer Program is subject to Copyright
35
    owned by the United Kingdom Secretary of State for Defence
36
    acting through the Defence Evaluation and Research Agency
37
    (DERA).  It is made available to Recipients with a
38
    royalty-free licence for its use, reproduction, transfer
39
    to other parties and amendment for any purpose not excluding
40
    product development provided that any such use et cetera
41
    shall be deemed to be acceptance of the following conditions:-
42
 
43
        (1) Its Recipients shall ensure that this Notice is
44
        reproduced upon any copies or amended versions of it;
45
 
46
        (2) Any amended version of it shall be clearly marked to
47
        show both the nature of and the organisation responsible
48
        for the relevant amendment or amendments;
49
 
50
        (3) Its onward transfer from a recipient to another
51
        party shall be deemed to be that party's acceptance of
52
        these conditions;
53
 
54
        (4) DERA gives no warranty or assurance as to its
55
        quality or suitability for any purpose and DERA accepts
56
        no liability whatsoever in relation to any use to which
57
        it may be put.
58
*/
59
/*
60
			    VERSION INFORMATION
61
			    ===================
62
 
63
--------------------------------------------------------------------------
64
$Header: /u/g/release/CVSROOT/Source/src/installers/680x0/common/ops_float.c,v 1.1.1.1 1998/01/17 15:55:49 release Exp $
65
--------------------------------------------------------------------------
66
$Log: ops_float.c,v $
67
 * Revision 1.1.1.1  1998/01/17  15:55:49  release
68
 * First version to be checked into rolling release.
69
 *
70
Revision 1.3  1997/11/09 14:04:53  ma
71
round_with_mode rewritten.
72
 
73
Revision 1.2  1997/10/29 10:22:24  ma
74
Replaced use_alloca with has_alloca.
75
 
76
Revision 1.1.1.1  1997/10/13 12:42:56  ma
77
First version.
78
 
79
Revision 1.4  1997/10/13 08:49:44  ma
80
Made all pl_tests for general proc & exception handling pass.
81
 
82
Revision 1.3  1997/09/25 06:45:23  ma
83
All general_proc tests passed
84
 
85
Revision 1.2  1997/06/18 12:04:55  ma
86
Merged with Input Baseline changes.
87
 
88
 * Revision 1.3  1997/06/06  14:36:26  john
89
 * Fixed rounding modes
90
 *
91
 * Revision 1.2  1997/06/05  10:55:48  john
92
 * Fix to unsigned conversion
93
 *
94
 * Revision 1.1.1.1  1997/04/25  12:32:40  john
95
 *
96
 * Revision 1.2  1996/07/05  14:23:53  john
97
 * Changes for spec 3.1
98
 *
99
 * Revision 1.1.1.1  1996/03/26  15:45:15  john
100
 *
101
 * Revision 1.2  93/03/03  14:48:21  14:48:21  ra (Robert Andrews)
102
 * Started adding support for error treatments.
103
 *
104
 * Revision 1.1  93/02/22  17:16:17  17:16:17  ra (Robert Andrews)
105
 * Initial revision
106
 *
107
--------------------------------------------------------------------------
108
*/
109
 
110
 
111
#include "config.h"
112
#include "common_types.h"
113
#include "assembler.h"
114
#include "basicread.h"
115
#include "check.h"
116
#include "exp.h"
117
#include "expmacs.h"
118
#include "externs.h"
119
#include "install_fns.h"
120
#include "fbase.h"
121
#include "flpt.h"
122
#include "flpttypes.h"
123
#include "shapemacs.h"
124
#include "tags.h"
125
#include "mach.h"
126
#include "mach_ins.h"
127
#include "where.h"
128
#include "mach_op.h"
129
#include "instr.h"
130
#include "codex.h"
131
#include "instrs.h"
132
#include "coder.h"
133
#include "tests.h"
134
#include "operations.h"
135
#include "evaluate.h"
136
#include "utility.h"
137
#include "translate.h"
138
#include "ops_shared.h"
139
 
140
/*
141
    GIVE PROTOTYPE FOR MFW
142
*/
143
 
7 7u83 144
#if (FBASE == 10)
145
extern where mfw(int, char *, int);
2 7u83 146
#define FBASE_10
147
#else
7 7u83 148
extern where mfw(int, long *, int);
2 7u83 149
#undef FBASE_10
150
#endif
151
 
152
extern int need_dummy_double;
153
/************************************************************************
154
  Test for overflow.
155
 
156
  freg is a Freg which is moved to a dummy memory location to force the
157
  overflow (if any) before the test.
158
 ************************************************************************/
159
 
160
void test_float_overflow_reg
7 7u83 161
(where freg, long sz)
2 7u83 162
{
163
   if (have_overflow()) {
7 7u83 164
      ins2(insf(sz, ml_fmove), sz, sz, freg, dummy_double_dest, 1);
165
      test_overflow(ON_FP_OVERFLOW);
166
      need_dummy_double = 1;
2 7u83 167
   }
168
}
169
 
170
/************************************************************************
171
  Test for overflow.
172
 
173
  If dest is zero, freg is moved to a memory location to force the
174
  overflow (if any) before the test.
175
  ************************************************************************/
176
 
177
void test_float_overflow
7 7u83 178
(where freg, where dest, long sz)
2 7u83 179
{
180
   if (have_overflow()) {
181
      if (eq_where(dest, zero)) {
7 7u83 182
         ins2(insf(sz, ml_fmove), sz, sz, freg, dummy_double_dest, 1);
183
         need_dummy_double = 1;
2 7u83 184
      }
7 7u83 185
      test_overflow(ON_FP_OVERFLOW);
2 7u83 186
   }
187
}
188
 
189
 
190
/*
191
    GENERAL PURPOSE FLOATING POINT ROUTINE
192
 
193
    The values a1 and a2 of shape sha have the binary floating-point
194
    operation indicated by the tag t applied to them and the result is
195
    stored in dest.
196
*/
197
 
198
void fl_binop
7 7u83 199
(int t, shape sha, where a1, where a2, where dest)
2 7u83 200
{
7 7u83 201
    int op, op1, op2;
202
    bool commutes = 0;
203
    int err = ON_FP_OVERFLOW;
204
    long sz = shape_size(sha);
2 7u83 205
 
7 7u83 206
    switch (t) {
207
	case fplus_tag: {
208
	    commutes = 1;
209
	    op1 = insf(sz, ml_fadd);
210
	    op2 = m_faddx;
211
	    break;
2 7u83 212
	}
7 7u83 213
	case fminus_tag: {
214
	    op1 = insf(sz, ml_fsub);
215
	    op2 = m_fsubx;
216
	    break;
2 7u83 217
	}
7 7u83 218
	case fmult_tag: {
219
	    commutes = 1;
220
	    op1 = insf(sz, ml_fmul);
221
	    op2 = m_fmulx;
222
	    break;
2 7u83 223
	}
7 7u83 224
	case fdiv_tag: {
225
	    op1 = insf(sz, ml_fdiv);
226
	    op2 = m_fdivx;
227
	    err = ON_FP_CARRY;
228
	    break;
2 7u83 229
	}
230
	default : {
7 7u83 231
	    error("Illegal floating operation");
232
	    return;
2 7u83 233
	}
234
    }
235
 
7 7u83 236
    if (whereis(dest) == Freg) {
237
       if (eq_where(a1, dest)) {
238
          if (commutes) {
239
             op = (whereis(a2) == Freg ? op2 : op1);
240
             ins2(op, sz, sz, a2, dest, 1);
2 7u83 241
             if (t == fdiv_tag) test_overflow(ON_FP_OVERFLOW) ; /* divided by 0 ? */
7 7u83 242
             test_float_overflow_reg(dest, sz);
2 7u83 243
          }
244
          else {
7 7u83 245
             move(sha, a2, FP0);
246
             ins2(op2, sz, sz, a1, FP0, 1);
2 7u83 247
             if (t == fdiv_tag) test_overflow(ON_FP_OVERFLOW) ; /* divided by 0 ? */
7 7u83 248
             move(sha, FP0, dest);
2 7u83 249
          }
250
       } else {
7 7u83 251
          move(sha, a2, dest);
252
          op = (whereis(a1) == Freg ? op2 : op1);
253
          ins2(op, sz, sz, a1, dest, 1);
2 7u83 254
          if (t == fdiv_tag) test_overflow(ON_FP_OVERFLOW) ; /* divided by 0 ? */
7 7u83 255
          test_float_overflow_reg(dest, sz);
2 7u83 256
       }
257
    }
258
    else {
7 7u83 259
       move(sha, a2, FP0);
260
       op = (whereis(a1) == Freg ? op2 : op1);
261
       ins2(op, sz, sz, a1, FP0, 1);
2 7u83 262
       if (t == fdiv_tag) test_overflow(ON_FP_OVERFLOW) ; /* divided by 0 ? */
7 7u83 263
       move(sha, FP0, dest);
264
       test_float_overflow(FP0, dest, sz);
2 7u83 265
    }
7 7u83 266
    have_cond = 0;
267
    return;
2 7u83 268
}
269
 
270
 
271
/*
272
    NEGATE A FLOATING-POINT NUMBER
273
 
274
    The floating-point value a of shape sha is negated and stored in dest.
275
*/
276
 
277
void negate_float
7 7u83 278
(shape sha, where a, where dest)
2 7u83 279
{
7 7u83 280
   if (whereis(a) == Freg) {
281
      if (whereis(dest) == Freg) {
282
         ins2(m_fnegx, L64, L64, a, dest, 1);
283
         test_float_overflow_reg(dest, L64);
2 7u83 284
      } else {
7 7u83 285
         negate_float(sha, a, FP0);
286
         move(sha, FP0, dest);
2 7u83 287
      }
288
   }
289
   else {
7 7u83 290
      move(sha, a, FP0);
291
      negate_float(sha, FP0, FP0);
292
      move(sha, FP0, dest);
293
      test_float_overflow(FP0, dest, shape_size(sha));
2 7u83 294
   }
7 7u83 295
   have_cond = 0;
2 7u83 296
}
297
 
298
 
299
/*
300
    FIND THE ABSOLUTE VALUE OF A FLOATING-POINT NUMBER
301
 
302
    The floating-point value a of shape sha is has its absolute value
303
    stored in dest.
304
*/
305
 
306
void abs_float
7 7u83 307
(shape sha, where a, where dest)
2 7u83 308
{
7 7u83 309
    if (whereis(a) == Freg) {
310
	if (whereis(dest) == Freg) {
311
	    ins2(m_fabsx, L64, L64, a, dest, 1);
312
            test_float_overflow_reg(dest, L64);
2 7u83 313
	} else {
7 7u83 314
	    abs_float(sha, a, FP0);
315
	    move(sha, FP0, dest);
2 7u83 316
	}
317
    } else {
7 7u83 318
	move(sha, a, FP0);
319
	abs_float(sha, FP0, FP0);
320
	move(sha, FP0, dest);
2 7u83 321
    }
7 7u83 322
    have_cond = 0;
2 7u83 323
}
324
 
325
 
326
/*
327
    CHANGE FLOATING VARIETY
328
 
329
    The floating-point value from is converted to a value of shape sha
330
    and stored in to.
331
*/
332
 
333
void change_flvar
7 7u83 334
(shape sha, where from, where to)
2 7u83 335
{
7 7u83 336
    shape shf = sh(from.wh_exp);
337
    if (whereis(to) == Freg) {
338
	if (whereis(from) == Freg) {
339
	    move(realsh, from, to);
340
	    return;
2 7u83 341
	}
7 7u83 342
	if (shape_size(shf) > shape_size(sha)) {
343
	    move(shf, from, to);
344
	    move(sha, to, D0);
345
	    move(sha, D0, to);
346
	    return;
2 7u83 347
	}
7 7u83 348
	move(shf, from, to);
349
	return;
2 7u83 350
    }
7 7u83 351
    if (whereis(from) == Freg) {
352
	move(sha, from, to);
353
        test_float_overflow_reg(to, shape_size(sha));
354
	return;
2 7u83 355
    }
7 7u83 356
    move(shf, from, FP0);
357
    move(sha, FP0, to);
358
    test_float_overflow(FP0, to, shape_size(sha));
2 7u83 359
}
360
 
361
 
362
/*
363
    CURRENT ROUNDING MODE
364
 
365
    This gives the rounding mode for round_float.
366
*/
367
 
7 7u83 368
int crt_rmode = R2NEAR;
2 7u83 369
 
370
 
371
/* Make floating point representing range_min(sha) - adjustment
372
Where Adjustment(adj) is 0,1,0.5 when adj is 0,1,2
373
*/
374
 
375
where get_min_limit
7 7u83 376
(shape sha, int adj)
2 7u83 377
{
378
   long fmd[4], min;
379
 
7 7u83 380
   if (name(sha) ==ulonghd) {
2 7u83 381
      switch (adj) {
382
      case 0:
383
         /* res = 0 */
384
         fmd[0] = 0;
385
         fmd[1] = -1;
386
         return mfw(0,fmd,0);
387
      case 1:
388
         /* res = -1 */
389
         fmd[0] = 1;
390
         fmd[1] = -1;
391
         return mfw(-1,fmd,1);
392
      case 2:
393
         /* res = - 0.5 */
394
         fmd[0] = 0x8000;
395
         fmd[1] = -1;
396
         return mfw(-1,fmd,-1);
397
      }
398
   }
7 7u83 399
   if (name(sha) ==slonghd) {
2 7u83 400
      switch (adj) {
401
      case 0:
7 7u83 402
         break;
2 7u83 403
      case 1:
404
         /* res = - 2**31 - 1 */
405
         fmd[0] = 0x8000;
406
         fmd[1] = 0x0001;
407
         fmd[2] = -1;
408
         return mfw(-1,fmd,1);
409
 
410
      case 2:
411
         /* res = - 2**31 - 0.5 */
412
         fmd[0] = 0x8000;
413
         fmd[1] = 0x0000;
414
         fmd[2] = 0x8000;
415
         fmd[3] = -1;
416
         return mfw(-1,fmd,-1);
417
      }
418
   }
419
 
7 7u83 420
   min = range_min(sha);
2 7u83 421
   switch (adj) {
422
   case 0:
423
   case 1:
424
      /* min - (0|1) */
7 7u83 425
      min -= adj;
2 7u83 426
      fmd[0] = (min>>16) & 0xffff;
427
      fmd[1] = min & 0xffff;
428
      fmd[2] = -1;
7 7u83 429
      return mfw((is_signed(sha) ||adj)? -1 : 0,fmd,1);
2 7u83 430
   case 2:
431
      /* min - 0.5 */
7 7u83 432
      min -= 1;
2 7u83 433
      fmd[0] = (min>>16) & 0xffff;
434
      fmd[1] = min & 0xffff;
435
      fmd[2] = 0x8000;
436
      fmd[3] = -1;
437
      return mfw(-1,fmd,-1);
438
   }
439
 
440
   /* Shouldn't happen */
441
   fmd[0] = 0;
442
   fmd[1] = -1;
443
   return mfw(0,fmd,0);
444
}
445
 
446
/* Make floating point representing range_max(sha) + adjustment
447
Where Adjustment(adj) is 0,1,0.5 when adj is 0,1,2
448
*/
449
 
450
where get_max_limit
7 7u83 451
(shape sha, int adj)
2 7u83 452
{
453
   long fmd[6];
7 7u83 454
   long max = range_max(sha);
455
   if (name(sha) ==ulonghd) {
2 7u83 456
      switch (adj) {
457
      case 0:
458
         /* max */
459
         fmd[0] = 0xffff;
460
         fmd[1] = 0xffff;
461
         fmd[2] = -1;
462
         return mfw(1,fmd,1);
463
      case 1:
464
         /* max + 1 */
465
         fmd[0] = 1;
466
         fmd[1] = 0;
467
         fmd[2] = 0;
468
         fmd[3] = -1;
469
         return mfw(1,fmd,2);
470
      case 2:
471
         /* max + 0.5 */
472
         fmd[0] = 1;
473
         fmd[1] = 0;
474
         fmd[2] = 0;
475
         fmd[3] = 0;
476
         fmd[4] = 0x8000;
477
         fmd[5] = -1;
478
         return mfw(1,fmd,-1);
479
      }
480
   }
481
   else {
482
      switch (adj) {
483
      case 0:
484
      case 1:
485
         /* max + (0|1) */
7 7u83 486
         max += adj;
2 7u83 487
         fmd[0] = (max>>16) & 0xffff;
488
         fmd[1] = max & 0xffff;
489
         fmd[2] = -1;
490
         return mfw(1,fmd,1);
491
      case 2:
492
         /* max + 0.5 */
493
         fmd[0] = (max>>16) & 0xffff;
494
         fmd[1] = max & 0xffff;
495
         fmd[2] = 0x8000;
496
         fmd[3] = -1;
497
         return mfw(1,fmd,-1);
498
      }
499
   }
500
 
501
   /* Shouldn't happen */
502
   fmd[0] = 0xffff;
503
   fmd[1] = 0xffff;
504
   fmd[2] = -1;
505
   return mfw(1,fmd,1);
506
}
507
 
508
/* Test number against limit */
509
void check_limit
7 7u83 510
(where number, where limit, int tst)
2 7u83 511
{
7 7u83 512
   int sw, instr;
2 7u83 513
   move(realsh,limit,FP1);
514
   sw = cmp(realsh,number,FP1,tst);
515
   instr = branch_ins(tst,sw,1,1);
516
   test_overflow2(instr);
517
}
518
 
519
/*
520
  Check that the floating point value in 'from' will, when rounded, fall
521
  within the range of the integer variety given by 'sha'.
522
*/
523
static void check_float_round_overflow
7 7u83 524
(shape sha, where from, int mode)
2 7u83 525
{
526
  if (overflow_jump == -1) {
527
     make_comment("error_teatment is trap");
528
     return;
529
  }
530
 
531
  make_comment("check_float_round_overflow ...");
532
 
533
  /* Setup min and max limits & decide tests */
534
  switch (mode) {
535
  case R2PINF:
536
     make_comment(" (toward larger) min-1 < x <= max");
537
     /* error if x <= min-1 or x > max */
7 7u83 538
     check_limit(from, get_min_limit(sha,1),tst_le);
539
     check_limit(from, get_max_limit(sha,0),tst_gr);
2 7u83 540
     break;
541
  case R2NINF:
542
     make_comment(" (toward smaller) min <= x < max+1");
543
     /* error if x < min or x >= max+1 */
7 7u83 544
     check_limit(from, get_min_limit(sha,0),tst_ls);
545
     check_limit(from, get_max_limit(sha,1),tst_ge);
2 7u83 546
     break;
547
  case R2ZERO:
7 7u83 548
     make_comment(" (toward zero) min-1 < x < max+1");
2 7u83 549
     /* error if x <= min-1 or x >= max+1 */
7 7u83 550
     check_limit(from, get_min_limit(sha,1),tst_le);
551
     check_limit(from, get_max_limit(sha,1),tst_ge);
2 7u83 552
     break;
553
  case R2NEAR:
554
     make_comment(" (to nearest) min-0.5 <= x < max+0.5");
555
     /* error if x < min-0.5 or x >= max+0.5 */
7 7u83 556
     check_limit(from, get_min_limit(sha,2),tst_le);
557
     check_limit(from, get_max_limit(sha,2),tst_gr);
2 7u83 558
     break;
559
  case 4:
560
     make_comment(" (internal mode) min <= x <= max");
561
     /* error if x < min or x > max */
7 7u83 562
     check_limit(from, get_min_limit(sha,0),tst_ls);
563
     check_limit(from, get_max_limit(sha,0),tst_gr);
2 7u83 564
     break;
565
  default:
566
     error("check_float_round_overflow: wrong rounding mode");
567
  }
568
 
569
  make_comment("check_float_round_overflow done");
570
}
571
 
572
 
573
/*
574
   SET_ROUND_MODE
575
 
576
   Changes the default floating point rounding mode.
577
   Set bits 4 & 5 of fpcr (floating point control register)
578
   according to rounding mode.
579
 
580
   The global flag changed_round_mode is set to TRUE.
581
*/
582
 
7 7u83 583
bool changed_round_mode = 0;
2 7u83 584
 
585
void set_round_mode
7 7u83 586
(int mode)
2 7u83 587
{
588
/*
589
   if (mode == f_to_nearest && ! changed_round_mode ) return ;
590
*/
7 7u83 591
   changed_round_mode = 1;
2 7u83 592
 
593
   ins2(m_fmovel,32,32,RW[REG_FPCR],D0,1);
594
 
7 7u83 595
   switch (mode) {
2 7u83 596
   case R2NEAR:
597
      make_comment("round mode to nearest");
598
      /* to nearest => bit 4 = 0, bit 5 = 0 */
599
      ins2n(m_bclr,4,32,D0,1);
600
      ins2n(m_bclr,5,32,D0,1);
601
      break;
602
   case R2PINF:
603
      make_comment("round mode to larger");
604
      /* to + INF  => bit 4 =1, bit5 = 1 */
605
      ins2n(m_bset,4,32,D0,1);
606
      ins2n(m_bset,5,32,D0,1);
607
      break;
608
   case R2NINF:
609
      make_comment("round mode to smaller");
610
      /* to - INF => bit 4 = 0, bit 5 = 1 */
611
      ins2n(m_bclr,4,32,D0,1);
612
      ins2n(m_bset,5,32,D0,1);
613
      break;
614
   case R2ZERO:
615
      make_comment("round mode to zero");
616
      /* to zero => bit 4 = 1, bit 5 = 0
617
         This should never occur, as fintrz is always used
618
         for round to zero */
619
      ins2n(m_bset,4,32,D0,1);
620
      ins2n(m_bclr,5,32,D0,1);
621
      break;
622
   default:
623
      error("wrong rounding mode");
624
   }
625
   ins2(m_fmovel,32,32,D0,RW[REG_FPCR],1);
626
}
627
 
628
void reset_round_mode
7 7u83 629
(void)
2 7u83 630
{
7 7u83 631
   if (changed_round_mode) {
632
      set_round_mode(f_to_nearest);
2 7u83 633
      changed_round_mode = 0;
634
   }
635
}
636
 
637
 
638
/*
639
    ROUND A FLOATING POINT NUMBER TO AN INTEGER
640
 
641
    The floating-point value from is rounded to an integer value of shape
642
    sha and stored in to.  The rounding mode is given by crt_rmode.
643
*/
644
 
645
void round_float
7 7u83 646
(shape sha, where from, where to)
2 7u83 647
{
7 7u83 648
    where fr;
649
    where dest;
650
    int mode = crt_rmode;
2 7u83 651
 
7 7u83 652
    if (name(sha) == ulonghd) {
653
        if (have_overflow()) {
2 7u83 654
            /* This must be checked before a round operation is attempted
655
               because out-of-range values can cause an exception */
656
            check_float_round_overflow(sha,from,mode);
657
        }
658
 
7 7u83 659
	if (mode == f_toward_zero|| mode == 4) {
2 7u83 660
 
661
#ifdef float_to_unsigned
7 7u83 662
	    change_flvar(realsh, from, FP0);
663
	    push_float(L64, FP0);
2 7u83 664
#ifdef float_to_unsigned_uses_fp1
7 7u83 665
	    if (mode == 4 && eq_where(from, FP1) {
666
		push_float(L64, FP1);
667
		libcall(float_to_unsigned);
668
		pop_float(L64, FP1);
2 7u83 669
	    } else
670
#endif
7 7u83 671
	    libcall(float_to_unsigned);
672
	    dec_stack(-64);
673
	    have_cond = 0;
674
	    move(ulongsh, D0, to);
2 7u83 675
#else
7 7u83 676
	    where fm;
677
	    long lab1 = next_lab();
678
	    long lab2 = next_lab();
679
	    exp jt = simple_exp(0);
680
	    ptno(jt) = lab1;
681
	    regsinproc |= regmsk(REG_FP1);
2 7u83 682
#ifdef FBASE_10
7 7u83 683
	    fm = mfw(1, "2147483648", 9);
2 7u83 684
#else
685
	    {
7 7u83 686
		static long fmd[] = { 32768, 0, -1 };
687
		fm = mfw(1, fmd, 1);
2 7u83 688
	    }
689
#endif
7 7u83 690
	    change_flvar(realsh, from, FP0);
691
	    move(realsh, fm, FP1);
692
	    regsinproc |= regmsk(REG_FP1);
693
	    ins2_cmp(m_fcmpx, L64, L64, FP0, FP1, 0);
694
	    branch(tst_gr, jt, 1, 1, 1);
695
	    ins2(m_fsubx, L64, L64, FP1, FP0, regmsk(REG_FP0));
696
	    if (whereis(to) == Dreg) {
697
	      ins2(m_fintrzx,L32,L32,FP0,FP0,1);
698
	      ins2(m_fmovel, L32, L32, FP0, to, 1);
699
	      or(ulongsh, to, mnw((long)2147483648UL), to);
2 7u83 700
	    } else {
7 7u83 701
	       ins2(m_fintrzx,L32,L32,FP0,FP0,1);
702
	       ins2(m_fmovel, L32, L32, FP0, D0, 1);
703
	       or(ulongsh, D0, mnw((long)2147483648UL), D0);
704
	       move(ulongsh, D0, to);
2 7u83 705
	    }
7 7u83 706
	    make_jump(m_bra, lab2);
707
	    make_label(lab1);
708
	    if (whereis(to) == Dreg) {
709
	      ins2(m_fintrzx,L32,L32,FP0,FP0,1);
710
	      ins2(m_fmovel, L32, L32, FP0, to, 1);
2 7u83 711
	    } else {
7 7u83 712
	      ins2(m_fintrzx,L32,L32,FP0,FP0,1);
713
	      ins2(m_fmovel, L32, L32, FP0, D0, 1);
714
	      move(ulongsh, D0, to);
2 7u83 715
	    }
7 7u83 716
	    make_label(lab2);
717
	    have_cond = 0;
2 7u83 718
#endif
7 7u83 719
	    return;
2 7u83 720
	}
721
 
722
    } else {
723
 
724
 
7 7u83 725
	if (mode == 4) {
2 7u83 726
	    /* Special case - move FP0 into the register to */
7 7u83 727
	    ins2(m_fmovel, L32, L32, FP0, to, 1);
2 7u83 728
 
729
            /* This might generate operand error */
730
            test_overflow(ON_FP_OPERAND_ERROR);
731
 
7 7u83 732
	    have_cond = 0;
733
	    change_var_sh(sha, slongsh, to, to);
734
	    return;
2 7u83 735
	}
736
 
7 7u83 737
	if (have_overflow()) {
2 7u83 738
	  /* This must be checked before a round operation is attempted
739
	     because out-of-range values can cause an exception */
740
	  check_float_round_overflow(sha,from,mode);
741
	}
742
 
7 7u83 743
	if (mode == f_toward_zero || mode == f_to_nearest) {
2 7u83 744
	    /* Rounding to nearest or towards zero are easy */
7 7u83 745
	    int instr;
746
	    shape shf = sh(from.wh_exp);
747
	    long szf = shape_size(shf);
748
	    if (mode == f_toward_zero) {
749
		instr = m_fintrzx;
750
		if (whereis(from)!= Freg) {
751
		    instr = insf(szf, ml_fint);
2 7u83 752
		}
753
	    } else {
754
                set_round_mode(mode);
7 7u83 755
		instr = m_fintx;
756
		if (whereis(from)!= Freg) {
757
		    instr = insf(szf, ml_fintrz);
2 7u83 758
		}
759
	    }
7 7u83 760
	    ins2(instr, szf, szf, from, FP0, 1);
761
	    if (whereis(to) == Dreg) {
762
		dest = to;
2 7u83 763
	    } else {
7 7u83 764
		dest = D0;
2 7u83 765
	    }
7 7u83 766
	    ins2(m_fmovel, L32, L32, FP0, dest, 1);
767
	    have_cond = 0;
768
	    change_var_sh(sha, slongsh, dest, to);
769
	    return;
2 7u83 770
	}
771
    }
772
 
773
    /* Other modes : firstly find some registers */
7 7u83 774
    if (whereis(to) == Dreg) {
775
	dest = to;
2 7u83 776
    } else {
7 7u83 777
	dest = D0;
2 7u83 778
    }
7 7u83 779
    if (whereis(from) == Freg && !eq_where(from, FP0)) {
780
	fr = from;
2 7u83 781
    } else {
7 7u83 782
	shape shf = sh(from.wh_exp);
783
	fr = FP1;
784
	regsinproc |= regmsk(REG_FP1);
785
	move(shf, from, fr);
2 7u83 786
    }
787
 
788
    /* Round fr into FP0 */
7 7u83 789
    if (mode == f_toward_zero) {
790
       ins2(m_fintrzx, 64, 64, fr, FP0, 1);
2 7u83 791
    }
792
    else {
793
       set_round_mode(mode);
7 7u83 794
       ins2(m_fintx, 64, 64, fr, FP0, 1);
2 7u83 795
    }
796
 
797
    /* Move FP0 into dest */
7 7u83 798
    crt_rmode = 4;
799
    round_float(sha, FP0, dest);
800
    crt_rmode = mode;
2 7u83 801
 
802
    /* Move result into place */
7 7u83 803
    have_cond = 0;
804
    move(sha, dest, to);
805
    return;
2 7u83 806
}
807
 
808
 
809
/*
810
    CONVERT AN INTEGER TO A FLOATING POINT NUMBER
811
 
812
    The integer value from is converted to a floating-point value of
813
    shape sha and stored in to.  Unsigned longs are difficult.  Error
814
    treatments are ignored (they cannot occur at present).
815
*/
816
 
817
void int_to_float
7 7u83 818
(shape sha, where from, where to)
2 7u83 819
{
7 7u83 820
    where fpr;
821
    shape shf = sh(from.wh_exp);
2 7u83 822
#ifdef REJECT
7 7u83 823
    fpr = (whereis(to) == Freg ? to : FP0);
2 7u83 824
#else
7 7u83 825
    fpr = FP0;
2 7u83 826
#endif
7 7u83 827
    if (name(shf) == ulonghd) {
2 7u83 828
#ifdef unsigned_to_float
7 7u83 829
	if (whereis(from) == Dreg) {
830
	    push(slongsh, L32, from);
2 7u83 831
	} else {
7 7u83 832
	    move(shf, from, D0);
833
	    push(slongsh, L32, D0);
2 7u83 834
	}
7 7u83 835
	libcall(unsigned_to_float);
836
	dec_stack(-32);
837
	have_cond = 0;
838
	move(realsh, D0_D1, fpr);
839
	move(sha, fpr, to);
840
	return;
2 7u83 841
#else
7 7u83 842
	where fm;
843
	long lab = next_lab();
844
	exp jt = simple_exp(0);
845
	ptno(jt) = lab;
2 7u83 846
#ifdef FBASE_10
7 7u83 847
	fm = mfw(1, "4294967296", 9);
2 7u83 848
#else
849
	{
7 7u83 850
	    static long fmd[] = { 1, 0, 0, -1 };
851
	    fm = mfw(1, fmd, 2);
2 7u83 852
	}
853
#endif
7 7u83 854
	if (whereis(from) == Dreg) {
855
	    ins2(m_fmovel, L32, L64, from, fpr, 1);
2 7u83 856
	} else {
7 7u83 857
	    move(slongsh, from, D0);
858
	    ins2(m_fmovel, L32, L64, D0, fpr, 1);
2 7u83 859
	}
7 7u83 860
	branch(tst_ge, jt, 1, 1, 1);
861
	add(sha, fpr, fm, fpr);
862
	make_label(lab);
863
	have_cond = 0;
864
	move(sha, fpr, to);
865
	return;
2 7u83 866
#endif
867
    }
7 7u83 868
    if (name(shf) == slonghd && whereis(from) == Dreg) {
869
	ins2(m_fmovel, L32, L64, from, fpr, 1);
2 7u83 870
    } else {
7 7u83 871
	change_var_sh(slongsh, shf, from, D0);
872
	ins2(m_fmovel, L32, L64, D0, fpr, 1);
2 7u83 873
    }
7 7u83 874
    move(sha, fpr, to);
875
    have_cond = 0;
876
    return;
2 7u83 877
}