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
    		 Crown Copyright (c) 1996
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
			    VERSION INFORMATION
31
			    ===================
32
 
33
--------------------------------------------------------------------------
34
$Header: /u/g/release/CVSROOT/Source/src/installers/680x0/common/ops_logic.c,v 1.1.1.1 1998/01/17 15:55:49 release Exp $
35
--------------------------------------------------------------------------
36
$Log: ops_logic.c,v $
37
 * Revision 1.1.1.1  1998/01/17  15:55:49  release
38
 * First version to be checked into rolling release.
39
 *
40
Revision 1.2  1997/11/09 14:23:43  ma
41
Now is_signed is used instead of issigned.
42
 
43
Revision 1.1.1.1  1997/10/13 12:42:57  ma
44
First version.
45
 
46
Revision 1.2  1997/09/25 06:45:26  ma
47
All general_proc tests passed
48
 
49
Revision 1.1.1.1  1997/03/14 07:50:15  ma
50
Imported from DRA
51
 
52
 * Revision 1.1.1.1  1996/09/20  10:57:00  john
53
 *
54
 * Revision 1.2  1996/07/05  14:24:36  john
55
 * Changes for spec 3.1
56
 *
57
 * Revision 1.1.1.1  1996/03/26  15:45:16  john
58
 *
59
 * Revision 1.6  94/06/29  14:23:47  14:23:47  ra (Robert Andrews)
60
 * Changed a few moves to change_varieties (consequent to changes in
61
 * bitfields).
62
 *
63
 * Revision 1.5  94/02/21  16:01:48  16:01:48  ra (Robert Andrews)
64
 * A couple of arguments should be int, not long.
65
 *
66
 * Revision 1.4  93/11/19  16:22:37  16:22:37  ra (Robert Andrews)
67
 * Minor correction to bitfields of complex operands.
68
 *
69
 * Revision 1.3  93/03/08  15:30:22  15:30:22  ra (Robert Andrews)
70
 * Emulate cc by mapping ( a << b ) to ( a << ( b % 64 ) ) when b is
71
 * a constant.
72
 *
73
 * Revision 1.2  93/03/03  14:49:37  14:49:37  ra (Robert Andrews)
74
 * Started adding support for error treatments.
75
 *
76
 * Revision 1.1  93/02/22  17:16:23  17:16:23  ra (Robert Andrews)
77
 * Initial revision
78
 *
79
--------------------------------------------------------------------------
80
*/
81
 
82
 
83
#include "config.h"
84
#include "common_types.h"
85
#include "assembler.h"
86
#include "basicread.h"
87
#include "check.h"
88
#include "exp.h"
89
#include "expmacs.h"
90
#include "externs.h"
91
#include "install_fns.h"
92
#include "shapemacs.h"
93
#include "tags.h"
94
#include "mach.h"
95
#include "mach_ins.h"
96
#include "where.h"
97
#include "mach_op.h"
98
#include "instr.h"
99
#include "codex.h"
100
#include "instrs.h"
101
#include "coder.h"
102
#include "tests.h"
103
#include "operations.h"
104
#include "evaluate.h"
105
#include "utility.h"
106
#include "translate.h"
107
#include "ops_shared.h"
108
 
109
 
110
/*
111
    MARKERS FOR AND, OR AND XOR
112
 
113
    The logical operations, and, or and xor are handled by a single
114
    routine with a flag to indicate which is meant.  The flag can take
115
    the following values.
116
*/
117
 
118
#define  AND		0
119
#define  OR		1
120
#define  XOR		2
121
 
122
 
123
/*
124
    AND/OR/XOR BY A CONSTANT
125
 
126
    The value a of shape sha and size sz has the logical operator indicated
127
    by logop applied to it and the constant c.  The result is stored in
128
    dest.  instr is one of m_andl, m_orl, eorl.
129
*/
130
 
131
static void andetc_const
132
    PROTO_N ( ( instr, sha, sz, c, a, dest, logop ) )
133
    PROTO_T ( int instr X shape sha X long sz X long c X where a X where dest X int logop )
134
{
135
    long whd ;
136
 
137
    /* First check that a is not a constant */
138
    if ( whereis ( a ) == Value ) {
139
	long ca = nw ( a ) ;
140
	switch ( logop ) {
141
	    case AND : ca &= c ; break ;
142
	    case OR  : ca |= c ; break ;
143
	    case XOR : ca ^= c ; break ;
144
	}
145
	move ( sha, mnw ( ca ), dest ) ;
146
	return ;
147
    }
148
 
149
    /* Now look for some special values of c */
150
    switch ( logop ) {
151
 
152
	case AND : {
153
	    long cc ;
154
	    if ( c == 0 ) {
155
		move ( sha, zero, dest ) ;
156
		return ;
157
	    }
158
	    cc = ~c ;
159
	    if ( sz == 32 ) {
160
		if ( cc == 0 ) {
161
		    change_var ( sha, a, dest ) ;
162
		    return ;
163
		}
164
		if ( is_pow2 ( cc ) ) {
165
		    long p = log2 ( cc ) ;
166
		    if ( whereis ( dest ) == Dreg ) {
167
			change_var ( sha, a, dest ) ;
168
			ins2n ( m_bclr, p, sz, dest, 1 ) ;
169
			have_cond = 0 ;
170
			return ;
171
		    }
172
		}
173
	    }
174
	    break ;
175
	}
176
 
177
	case OR : {
178
	    if ( c == 0 ) {
179
		change_var ( sha, a, dest ) ;
180
		return ;
181
	    }
182
	    if ( is_pow2 ( c ) ) {
183
		long p = log2 ( c ) ;
184
		if ( whereis ( dest ) == Dreg ) {
185
		    change_var ( sha, a, dest ) ;
186
		    ins2n ( m_bset, p, sz, dest, 1 ) ;
187
		    have_cond = 0 ;
188
		    return ;
189
		}
190
	    }
191
	    break ;
192
	}
193
 
194
	case XOR : {
195
	    if ( c == 0 ) {
196
		change_var ( sha, a, dest ) ;
197
		return ;
198
	    }
199
	    break ;
200
	}
201
    }
202
 
203
    whd = whereis ( dest ) ;
204
    if ( whd != Areg && eq_where ( a, dest ) ) {
205
	ins2h ( instr, c, sz, dest, 1 ) ;
206
	set_cond ( dest, sz ) ;
207
	return ;
208
    }
209
    if ( whd == Dreg ) {
210
	change_var ( sha, a, dest ) ;
211
	ins2h ( instr, c, sz, dest, 1 ) ;
212
	set_cond ( dest, sz ) ;
213
	return ;
214
    }
215
    if ( whereis ( a ) == Dreg && last_use ( a ) ) {
216
	ins2h ( instr, c, sz, a, 1 ) ;
217
	change_var ( sha, a, dest ) ;
218
	set_cond ( dest, sz ) ;
219
	return ;
220
    }
221
    change_var ( sha, a, D0 ) ;
222
    ins2h ( instr, c, sz, D0, 1 ) ;
223
    move ( sha, D0, dest ) ;
224
    set_cond ( dest, sz ) ;
225
    return ;
226
}
227
 
228
 
229
/*
230
    AUXILLARY ROUTINE FOR AND/OR/XOR
231
 
232
    The values a1 and a2 of shape sha have the logical operation indicated
233
    by logop applied to them and the result is stored in dest.  ( opb,
234
    opw, opl ) is an ordered triple giving the byte, word and long forms of
235
    the appropriate machine instruction.
236
*/
237
 
238
static void andetc
239
    PROTO_N ( ( opb, opw, opl, sha, a1, a2, dest, logop ) )
240
    PROTO_T ( int opb X int opw X int opl X shape sha X where a1 X where a2 X where dest X int logop )
241
{
242
    int instr ;
243
    long wha, whb, whd ;
244
    long sz = shape_size ( sha ) ;
245
 
246
    if ( eq_where ( a1, a2 ) ) {
247
	switch ( logop ) {
248
	    case AND : move ( sha, a1, dest ) ; return ;
249
	    case OR  : move ( sha, a1, dest ) ; return ;
250
	    case XOR : move ( sha, zero, dest ) ; return ;
251
	}
252
    }
253
 
254
    instr = ins ( sz, opb, opw, opl ) ;
255
 
256
    wha = whereis ( a1 ) ;
257
    whb = whereis ( a2 ) ;
258
 
259
    if ( wha == Freg ) {
260
	move ( sha, a1, D0 ) ;
261
	andetc ( opb, opw, opl, sha, D0, a2, dest, logop ) ;
262
	return ;
263
    }
264
 
265
    if ( whb == Freg ) {
266
	move ( sha, a2, D0 ) ;
267
	andetc ( opb, opw, opl, sha, a1, D0, dest, logop ) ;
268
	return ;
269
    }
270
 
271
    if ( wha == Value ) {
272
	long c = nw ( a1 ) ;
273
	andetc_const ( instr, sha, sz, c, a2, dest, logop ) ;
274
	return ;
275
    }
276
 
277
    if ( whb == Value ) {
278
	long c = nw ( a2 ) ;
279
	andetc_const ( instr, sha, sz, c, a1, dest, logop ) ;
280
	return ;
281
    }
282
 
283
    whd = whereis ( dest ) ;
284
 
285
    if ( eq_where ( a1, dest ) && whd != Areg ) {
286
	if ( whb == Dreg ) {
287
	    ins2 ( instr, sz, sz, a2, dest, 1 ) ;
288
	    return ;
289
	}
290
	if ( whd == Dreg ) {
291
	    if ( logop == XOR || whb == Areg ) {
292
		if ( eq_where ( dest, D0 ) ) {
293
		    regsinproc |= regmsk ( REG_D1 ) ;
294
		    move ( sha, a2, D1 ) ;
295
		    ins2 ( instr, sz, sz, D1, dest, 1 ) ;
296
		    set_cond ( dest, sz ) ;
297
		    return ;
298
		} else {
299
		    move ( sha, a2, D0 ) ;
300
		    ins2 ( instr, sz, sz, D0, dest, 1 ) ;
301
		    set_cond ( dest, sz ) ;
302
		    return ;
303
		}
304
	    } else {
305
		ins2 ( instr, sz, sz, a2, dest, 1 ) ;
306
		set_cond ( dest, sz ) ;
307
		return ;
308
	    }
309
	} else {
310
	    move ( sha, a2, D0 ) ;
311
	    ins2 ( instr, sz, sz, D0, dest, 1 ) ;
312
	    set_cond ( dest, sz ) ;
313
	    return ;
314
	}
315
    }
316
 
317
    if ( eq_where ( a2, dest ) && whd != Areg ) {
318
	if ( wha == Dreg ) {
319
	    ins2 ( instr, sz, sz, a1, dest, 1 ) ;
320
	    set_cond ( dest, sz ) ;
321
	    return ;
322
	}
323
	if ( whd == Dreg ) {
324
	    if ( logop == XOR || wha == Areg || wha == Freg ) {
325
		if ( eq_where ( dest, D0 ) ) {
326
		    regsinproc |= regmsk ( REG_D1 ) ;
327
		    move ( sha, a1, D1 ) ;
328
		    ins2 ( instr, sz, sz, D1, dest, 1 ) ;
329
		} else {
330
		    move ( sha, a1, D0 ) ;
331
		    ins2 ( instr, sz, sz, D0, dest, 1 ) ;
332
		}
333
	    } else {
334
		ins2 ( instr, sz, sz, a1, dest, 1 ) ;
335
	    }
336
	} else {
337
	    move ( sha, a1, D0 ) ;
338
	    ins2 ( instr, sz, sz, D0, dest, 1 ) ;
339
	}
340
	set_cond ( dest, sz ) ;
341
	return ;
342
    }
343
 
344
    if ( whd == Dreg ) {
345
	if ( !interfere ( a2, dest ) ) {
346
	    move ( sha, a1, dest ) ;
347
	    andetc ( opb, opw, opl, sha, a2, dest, dest, logop ) ;
348
	    return ;
349
	}
350
	if ( !interfere ( a1, dest ) ) {
351
	    move ( sha, a2, dest ) ;
352
	    andetc ( opb, opw, opl, sha, a1, dest, dest, logop ) ;
353
	    return ;
354
	}
355
    }
356
 
357
    move ( sha, a1, D0 ) ;
358
    andetc ( opb, opw, opl, sha, a2, D0, D0, logop ) ;
359
    move ( sha, D0, dest ) ;
360
    return ;
361
}
362
 
363
 
364
/*
365
    AND INSTRUCTION
366
 
367
    The values a1 and a2 of shape sha are anded and the result is stored
368
    in dested.
369
*/
370
 
371
void and
372
    PROTO_N ( ( sha, a1, a2, dest ) )
373
    PROTO_T ( shape sha X where a1 X where a2 X where dest )
374
{
375
    andetc ( ml_and, sha, a1, a2, dest, AND ) ;
376
    return ;
377
}
378
 
379
 
380
/*
381
    OR INSTRUCTION
382
 
383
    The values a1 and a2 of shape sha are ored and the result is stored
384
    in dested.
385
*/
386
 
387
void or
388
    PROTO_N ( ( sha, a1, a2, dest ) )
389
    PROTO_T ( shape sha X where a1 X where a2 X where dest )
390
{
391
    andetc ( ml_or, sha, a1, a2, dest, OR ) ;
392
    return ;
393
}
394
 
395
 
396
/*
397
    XOR INSTRUCTION
398
 
399
    The values a1 and a2 of shape sha are xored and the result is stored
400
    in dested.
401
*/
402
 
403
void xor
404
    PROTO_N ( ( sha, a1, a2, dest ) )
405
    PROTO_T ( shape sha X where a1 X where a2 X where dest )
406
{
407
    andetc ( ml_eor, sha, a1, a2, dest, XOR ) ;
408
    return ;
409
}
410
 
411
 
412
/*
413
    LOGICAL NEGATION INSTRUCTION
414
 
415
    The value a of shape sha is logically negated and the result is stored
416
    in dest.
417
*/
418
 
419
void not
420
    PROTO_N ( ( sha, a, dest ) )
421
    PROTO_T ( shape sha X where a X where dest )
422
{
423
    int instr ;
424
    long sz = shape_size ( sha ) ;
425
    long wha = whereis ( a ) ;
426
    long whd = whereis ( dest ) ;
427
 
428
    if ( wha == Value ) {
429
	long c = nw ( a ) ;
430
	move ( sha, mnw ( ~c ), dest ) ;
431
	return ;
432
    }
433
 
434
    if ( eq_where ( a, dest ) && whd != Areg ) {
435
	instr = ins ( sz, ml_not ) ;
436
	ins1 ( instr, sz, dest, 1 ) ;
437
	set_cond ( dest, sz ) ;
438
	return ;
439
    }
440
 
441
    if ( whd == Dreg ) {
442
	move ( sha, a, dest ) ;
443
	not ( sha, dest, dest ) ;
444
	return ;
445
    }
446
 
447
    if ( wha == Dreg && last_use ( a ) ) {
448
	not ( sha, a, a ) ;
449
	move ( sha, a, dest ) ;
450
	return ;
451
    }
452
 
453
    move ( sha, a, D0 ) ;
454
    not ( sha, D0, D0 ) ;
455
    move ( sha, D0, dest ) ;
456
    return ;
457
}
458
 
459
 
460
/*
461
    LOW LEVEL SHIFT
462
 
463
    This routine outputs a simple shift instruction, taking overflow
464
    into account if necessary (not right yet).
465
*/
466
 
467
static void shift_it
468
    PROTO_N ( ( sha, shb, instr, by, to ) )
469
    PROTO_T ( shape sha X shape shb X int instr X where by X where to )
470
{
471
    long sz = shape_size ( sha ) ;
472
    ins2 ( instr, L8, sz, by, to, 1 ) ;
473
    have_cond = 0 ;
474
    test_overflow( ON_OVERFLOW ) ;
475
    return ;
476
}
477
 
478
 
479
/*
480
    AUXILIARY SHIFT ROUTINE
481
 
482
    The value from of shape sha is shifted, either left if sw is 0, or
483
    right otherwise, by the value by.  The result is stored in to.
484
    The dont_use_D1 flag indicates that register D1 should not be used.
485
    It is always false for simple shifts, but may be true for certain
486
    multiplications which are done by shifts.
487
*/
488
 
489
void shift_aux
490
    PROTO_N ( ( sha, by, from, to, sw, dont_use_D1 ) )
491
    PROTO_T ( shape sha X where by X where from X where to X int sw X int dont_use_D1 )
492
{
493
    where w ;
494
    long whb, wht ;
495
    int instr, shift_plus, shift_minus ;
496
 
497
    shape shb = sh ( by.wh_exp ) ;
498
    long sz = shape_size ( sha ) ;
499
    bool sig = is_signed ( sha ) ;
500
 
501
    switch ( sz ) {
502
	case 8 : {
503
	    shift_plus = ( sig ? m_aslb : m_lslb ) ;
504
	    shift_minus = ( sig ? m_asrb : m_lsrb ) ;
505
	    break ;
506
	}
507
	case 16 : {
508
	    shift_plus = ( sig ? m_aslw : m_lslw ) ;
509
	    shift_minus = ( sig ? m_asrw : m_lsrw ) ;
510
	    break ;
511
	}
512
	default : {
513
	    shift_plus = ( sig ? m_asll : m_lsll ) ;
514
	    shift_minus = ( sig ? m_asrl : m_lsrl ) ;
515
	    break ;
516
	}
517
    }
518
 
519
    if ( sw ) {
520
	/* Switch shift_plus and shift_minus for right shifts */
521
	instr = shift_plus ;
522
	shift_plus = shift_minus ;
523
	shift_minus = instr ;
524
    }
525
 
526
    whb = whereis ( by ) ;
527
    wht = whereis ( to ) ;
528
 
529
    if ( whb == Value && !have_overflow () ) {
530
	long p = nw ( by ) ;
531
	if ( p == 0 ) {
532
	    /* A shift by 0 is a move */
533
	    move ( sha, from, to ) ;
534
	    return ;
535
	}
536
	/* Reduce mod 64 to emulate instruction */
537
	p &= 0x3f ;
538
	instr = shift_plus ;
539
	/* Do the shift, at most eight at a time */
540
	if ( p <= 8 || D1_is_special || dont_use_D1 ) {
541
	    w = ( wht == Dreg ? to : D0 ) ;
542
	    move ( sha, from, w ) ;
543
	    while ( p ) {
544
		long q = ( p > 8 ? 7 : p ) ;
545
		ins2n ( instr, q, sz, w, 1 ) ;
546
		p -= q ;
547
	    }
548
	    have_cond = 0 ;
549
	    move ( sha, w, to ) ;
550
	    return ;
551
	}
552
	/* Fall through otherwise */
553
	shb = slongsh ;
554
    }
555
 
556
    if ( wht == Dreg ) {
557
	if ( whb == Dreg && !eq_where ( by, to ) ) {
558
	    move ( sha, from, to ) ;
559
	    shift_it ( sha, shb, shift_plus, by, to ) ;
560
	    return ;
561
	}
562
	if ( eq_where ( D0, to ) ) {
563
	    w = D1 ;
564
	    regsinproc |= regmsk ( REG_D1 ) ;
565
	} else {
566
	    w = D0 ;
567
	}
568
	move ( shb, by, w ) ;
569
	move ( sha, from, to ) ;
570
	shift_it ( sha, shb, shift_plus, w, to ) ;
571
	return ;
572
    }
573
 
574
    if ( whb == Dreg ) {
575
	if ( eq_where ( D0, by ) ) {
576
	    w = D1 ;
577
	    regsinproc |= regmsk ( REG_D1 ) ;
578
	} else {
579
	    w = D0 ;
580
	}
581
	move ( sha, from, w ) ;
582
	shift_it ( sha, shb, shift_plus, by, w ) ;
583
	move ( sha, w, to ) ;
584
	return ;
585
    }
586
 
587
    regsinproc |= regmsk ( REG_D1 ) ;
588
    move ( shb, by, D0 ) ;
589
    move ( sha, from, D1 ) ;
590
    shift_it ( sha, shb, shift_plus, D0, D1 ) ;
591
    move ( sha, D1, to ) ;
592
    return ;
593
}
594
 
595
 
596
/*
597
    MAIN LEFT SHIFT ROUTINE
598
 
599
    The value from of shape sha is shifted left by the value by.  The
600
    result is stored in to.
601
*/
602
 
603
void shift
604
    PROTO_N ( ( sha, by, from, to ) )
605
    PROTO_T ( shape sha X where by X where from X where to )
606
{
607
    shift_aux ( sha, by, from, to, 0, 0 ) ;
608
    return ;
609
}
610
 
611
 
612
/*
613
    MAIN RIGHT SHIFT ROUTINE
614
 
615
    The value from of shape sha is shifted right by the value by.  The
616
    result is stored in to.
617
*/
618
 
619
void rshift
620
    PROTO_N ( ( sha, by, from, to ) )
621
    PROTO_T ( shape sha X where by X where from X where to )
622
{
623
    shift_aux ( sha, by, from, to, 1, 0 ) ;
624
    return ;
625
}
626
 
627
 
628
/*
629
    ADJUST AN EXPRESSION READY FOR A BITFIELD OPERATION
630
 
631
    The value in the no field of e is rounded down to a multiple of 32.
632
    The remainder is the bitfield offset and is returned.
633
*/
634
 
635
static long adjust_bitf
636
    PROTO_N ( ( e ) )
637
    PROTO_T ( exp e )
638
{
639
    long boff = no ( e ) % 32 ;
640
    no ( e ) -= boff ;
641
    return ( boff ) ;
642
}
643
 
644
 
645
/*
646
    FIND POSITION OF A CONTENTS BITFIELD
647
*/
648
 
649
static long contents_bitf
650
    PROTO_N ( ( e ) )
651
    PROTO_T ( exp e )
652
{
653
    char n = name ( e ) ;
654
    if ( n == name_tag || n == reff_tag ) return ( adjust_bitf ( e ) ) ;
655
    if ( n == ident_tag ) {
656
	exp s = son ( e ) ;
657
	exp b = bro ( s ) ;
658
	if ( name ( b ) == reff_tag ) return ( adjust_bitf ( b ) ) ;
659
	if ( name ( b ) == ident_tag ) return ( contents_bitf ( b ) ) ;
660
	if ( name ( b ) == name_tag && son ( b ) == e &&
661
	     name ( s ) == name_tag ) {
662
	    return ( contents_bitf ( son ( s ) ) ) ;
663
	}
664
	if ( name ( s ) == name_tag ) return ( adjust_bitf ( s ) ) ;
665
    }
666
    error ( "Illegal bitfield operation" ) ;
667
    return ( 0 ) ;
668
}
669
 
670
 
671
/*
672
    FIND POSITION OF A BITFIELD OPERATION
673
*/
674
 
675
static long bitf_posn
676
    PROTO_N ( ( e ) )
677
    PROTO_T ( exp e )
678
{
679
    char n = name ( e ) ;
680
    if ( n == name_tag ) return ( adjust_bitf ( e ) ) ;
681
    if ( n == cont_tag || n == ass_tag ) {
682
	return ( bitf_posn ( son ( e ) ) ) ;
683
    }
684
    if ( n == ident_tag ) return ( 0 ) ;
685
    error ( "Illegal bitfield operation" ) ;
686
    return ( 0 ) ;
687
}
688
 
689
 
690
/*
691
    EXTRACT A BITFIELD
692
 
693
    The bitfield e of shape sha is extracted into dest.  The current state
694
    of the stack is also given.
695
*/
696
 
697
void bitf_to_int
698
    PROTO_N ( ( e, sha, dest, stack ) )
699
    PROTO_T ( exp e X shape sha X where dest X ash stack )
700
{
701
    where bf, d ;
702
    exp t = dest.wh_exp ;
703
    shape dsha = sh ( t ) ;
704
 
705
    int extend = ( is_signed ( sha ) ? 1 : 0 ) ;
706
    int instr = ( extend ? m_bfexts : m_bfextu ) ;
707
 
708
    long off, sz, bstart ;
709
    bitpattern pmask ;
710
    long nbits = shape_size ( sha ) ;
711
    long boff = bitf_posn ( e ) ;
712
 
713
    off = 8 * ( boff / 8 ) ;
714
    sz = 8 * ( ( boff + nbits - 1 ) / 8 ) + 8 - off ;
715
    if ( sz == 24 ) { sz = 32 ; off -= 8 ; }
716
    bstart = boff - off ;
717
 
718
    pmask = ( ( hi_bits [ nbits ] ) >> bstart ) >> ( 32 - sz ) ;
719
 
720
    switch ( name ( t ) ) {
721
	case ident_tag : dsha = sh ( son ( t ) ) ; break ;
722
	case ass_tag : dsha = sh ( bro ( son ( t ) ) ) ; break ;
723
    }
724
    if ( name ( dsha ) == bitfhd ) dsha = ( extend ? slongsh : ulongsh ) ;
725
    if ( name ( dsha ) == tophd ) warning ( "Top in bitfield assignment" ) ;
726
 
727
    bf = mw ( e, off ) ;
728
 
729
    if ( bstart == 0 && nbits == sz ) {
730
	shape bsha ;
731
	switch ( sz ) {
732
	    case 8 : bsha = scharsh ; break ;
733
	    case 16 : bsha = swordsh ; break ;
734
	    case 32 : bsha = slongsh ; break ;
735
	}
736
	change_var_sh ( dsha, bsha, bf, dest ) ;
737
	return ;
738
    }
739
 
740
    if ( whereis ( bf ) == Dreg ) {
741
	bitpattern m = ( lo_bits [ nbits ] <<  boff ) ;
742
	d = ( whereis ( dest ) == Dreg ? dest : D0 ) ;
743
	and ( slongsh, bf, mnw ( m ), d ) ;
744
	if ( extend ) {
745
	    long r = 32 - nbits - boff ;
746
	    if ( r ) {
747
		if ( r <= 8 ) {
748
		    ins2n ( m_lsll, r, L32, d, 1 ) ;
749
		    ins2n ( m_asrl, r, L32, d, 1 ) ;
750
		} else {
751
		    regsinproc |= regmsk ( REG_D1 ) ;
752
		    ins2n ( m_moveq, r, L32, D1, 1 ) ;
753
		    ins2 ( m_lsll, L32, L32, D1, d, 1 ) ;
754
		    ins2 ( m_asrl, L32, L32, D1, d, 1 ) ;
755
		}
756
	    }
757
	}
758
	have_cond = 0 ;
759
	change_var_sh ( dsha, slongsh, d, dest ) ;
760
	return ;
761
    } else {
762
	mach_op *op1, *op2 ;
763
	d = ( whereis ( dest ) == Dreg ? dest : D0 ) ;
764
	op1 = operand ( L32, bf ) ;
765
	op1 = make_bitfield_op ( op1, ( int ) bstart, ( int ) nbits ) ;
766
	op2 = operand ( L32, d ) ;
767
	make_instr ( instr, op1, op2, regs_changed ( op2, 1 ) ) ;
768
	have_cond = 0 ;
769
	change_var_sh ( dsha, slongsh, d, dest ) ;
770
	return ;
771
    }
772
}
773
 
774
 
775
/*
776
    INSERT A BITFIELD
777
 
778
    The value e is inserted into the bitfield d.  The state of the stack
779
    is also given.
780
*/
781
 
782
void int_to_bitf
783
    PROTO_N ( ( e, d, stack ) )
784
    PROTO_T ( exp e X exp d X ash stack )
785
{
786
    shape sha ;
787
    where dest, f ;
788
 
789
    long off, sz, bstart, bend ;
790
    bitpattern pmask, nmask, v ;
791
    long nbits = shape_size ( sh ( e ) ) ;
792
    long boff = bitf_posn ( d ) ;
793
 
794
    off = 8 * ( boff / 8 ) ;
795
    sz = 8 * ( ( boff + nbits - 1 ) / 8 ) + 8 - off ;
796
    if ( sz == 24 ) { sz = 32 ; off -= 8 ; }
797
    bstart = boff - off ;
798
    bend = sz - nbits - bstart ;
799
 
800
    pmask = ( ( hi_bits [ nbits ] ) >> bstart ) >> ( 32 - sz ) ;
801
    nmask = ~pmask ;
802
 
803
    switch ( sz ) {
804
	case 8 : nmask &= 0xff ; sha = scharsh ; break ;
805
	case 16 : nmask &= 0xffff ; sha = swordsh ; break ;
806
	default : sha = slongsh ; break ;
807
    }
808
 
809
    if ( name ( e ) == int_to_bitf_tag ) {
810
	exp s = son ( e ) ;
811
	if ( is_o ( name ( s ) ) ) {
812
	    e = s ;
813
	} else {
814
	    regsinproc |= regmsk ( REG_D1 ) ;
815
	    coder ( D1, stack, s ) ;
816
	    if ( shape_size ( sh ( s ) ) < 32 ) warning ( "Think again!" ) ;
817
	    e = D1.wh_exp ;
818
	}
819
    }
820
 
821
    dest = mw ( d, off ) ;
822
 
823
    if ( bstart == 0 && nbits == sz ) {
824
	change_var_sh ( sha, sh ( e ), zw ( e ), dest ) ;
825
	return ;
826
    }
827
 
828
    if ( ( bstart + nbits > 32 ) || ( name ( e ) != val_tag ) ) {
829
	where dd ;
830
	bitpattern ch ;
831
	mach_op *op1, *op2 ;
832
	dd = zw ( e ) ;
833
	if ( whereis ( dd ) != Dreg || shape_size ( sh ( e ) ) != 32 ) {
834
	    change_var_sh ( slongsh, sh ( e ), dd, D0 ) ;
835
	    dd = D0 ;
836
	}
837
	op1 = operand ( L32, dd ) ;
838
	op2 = operand ( L32, dest ) ;
839
	ch = regs_changed ( op2, 1 ) ;
840
	op2 = make_bitfield_op ( op2, ( int ) bstart, ( int ) nbits ) ;
841
	make_instr ( m_bfins, op1, op2, ch ) ;
842
	have_cond = 0 ;
843
	return ;
844
    }
845
 
846
    v = ( bitpattern ) no ( e ) ;
847
    v = ( ( v << bend ) & pmask ) ;
848
 
849
    if ( v == 0 ) {
850
	and ( sha, mnw ( nmask ), dest, dest ) ;
851
	return ;
852
    }
853
 
854
    if ( v == pmask ) {
855
	or ( sha, mnw ( pmask ), dest, dest ) ;
856
	return ;
857
    }
858
 
859
    f = ( ( whereis ( dest ) == Dreg ) ? dest : D0 ) ;
860
    and ( sha, mnw ( nmask ), dest, f ) ;
861
    or ( sha, mnw ( v ), f, dest ) ;
862
    return ;
863
}
864
 
865
 
866
/*
867
    TEST A NUMBER OF BITS
868
 
869
    The value a1 of shape sha is tested to see if the bits indicated by
870
    the value a2 are set.  If a2 is a constant power of 2 then a bit
871
    test operation is used.  Otherwise a1 is anded with a2 and the
872
    result is stored in an unwanted D-register.
873
*/
874
 
875
void bit_test
876
    PROTO_N ( ( sha, a1, a2 ) )
877
    PROTO_T ( shape sha X where a1 X where a2 )
878
{
879
    long sz = shape_size ( sha ) ;
880
    long wh1 = whereis ( a1 ) ;
881
    long wh2 = whereis ( a2 ) ;
882
    if ( wh2 == Value ) {
883
	if ( wh1 == External || wh1 == Parameter || wh1 == RegInd ) {
884
	    long v = nw ( a2 ) ;
885
	    if ( is_pow2 ( v ) ) {
886
		where w ;
887
		long n = log2 ( v ) ;
888
		long off = sz - 8 * ( 1 + ( n / 8 ) ) ;
889
		w = mw ( a1.wh_exp, a1.wh_off + off ) ;
890
		ins2n ( m_btstb, n % 8, 8, w, 1 ) ;
891
		have_cond = 0 ;
892
		return ;
893
	    }
894
	}
895
	if ( wh1 == Dreg ) {
896
	    long v = nw ( a2 ) ;
897
	    if ( last_use ( a1 ) ) {
898
		and ( sha, a2, a1, a1 ) ;
899
		return ;
900
	    }
901
	    if ( is_pow2 ( v ) && sz == 32 ) {
902
		long n = log2 ( v ) ;
903
		ins2n ( m_btstl, n, sz, a1, 1 ) ;
904
		have_cond = 0 ;
905
		return ;
906
	    }
907
	}
908
    }
909
    if ( wh1 == Dreg && last_use ( a1 ) ) {
910
	and ( sha, a2, a1, a1 ) ;
911
	return ;
912
    }
913
    if ( wh2 == Dreg && last_use ( a2 ) ) {
914
	and ( sha, a1, a2, a2 ) ;
915
	return ;
916
    }
917
    move ( sha, a1, D0 ) ;
918
    and ( sha, a2, D0, D0 ) ;
919
    return ;
920
}