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
/*
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/special.c,v 1.1.1.1 1998/01/17 15:55:55 release Exp $
39
--------------------------------------------------------------------------
40
$Log: special.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.10  1996/08/28  17:36:21  pwe
45
 * fixed local_alloc_check use of registers
46
 *
47
 * Revision 1.9  1996/03/29  14:41:54  john
48
 * Fixed for zero-sized alloca
49
 *
50
 * Revision 1.8  1996/01/17  12:04:41  john
51
 * Fix to local_alloc check
52
 *
53
 * Revision 1.7  1995/12/15  10:28:02  john
54
 * Changes local_alloc stack check
55
 *
56
 * Revision 1.6  1995/11/15  16:57:21  john
57
 * Stack check now uses unsigned test
58
 *
59
 * Revision 1.5  1995/09/22  15:58:42  john
60
 * Fix to stack check
61
 *
62
 * Revision 1.4  1995/09/20  12:40:28  john
63
 * Portability fix
64
 *
65
 * Revision 1.3  1995/09/19  14:32:37  john
66
 * Added checkstack to alloca_tag
67
 *
68
 * Revision 1.2  1995/09/15  16:18:43  john
69
 * New exception handling
70
 *
71
 * Revision 1.1.1.1  1995/03/13  10:18:58  john
72
 * Entered into CVS
73
 *
74
 * Revision 1.2  1994/07/07  16:11:33  djch
75
 * Jul94 tape
76
 *
77
 * Revision 1.2  1994/07/07  16:11:33  djch
78
 * Jul94 tape
79
 *
80
 * Revision 1.1  1994/05/03  14:49:58  djch
81
 * Initial revision
82
 *
83
 * Revision 1.8  93/09/27  14:56:39  14:56:39  ra (Robert Andrews)
84
 * Changed the names of a couple of my built-in functions.
85
 * 
86
 * Revision 1.7  93/08/27  11:39:21  11:39:21  ra (Robert Andrews)
87
 * A couple of lint-like changes.
88
 * 
89
 * Revision 1.6  93/08/13  14:47:14  14:47:14  ra (Robert Andrews)
90
 * Reformatted.
91
 * 
92
 * Revision 1.5  93/07/14  11:22:35  11:22:35  ra (Robert Andrews)
93
 * Add library_key to determine presence of TDF support library.
94
 * 
95
 * Revision 1.4  93/07/12  15:18:57  15:18:57  ra (Robert Andrews)
96
 * Added support for special_routines, which is used to handle built-in
97
 * system calls like .mul and TDF library calls like L.div1 (used to
98
 * implement div1).
99
 * 
100
 * Revision 1.3  93/07/05  18:28:48  18:28:48  ra (Robert Andrews)
101
 * Made distinction between the System V assembler and the System V ABI.
102
 * 
103
 * Revision 1.2  93/06/29  14:35:30  14:35:30  ra (Robert Andrews)
104
 * Have to include regexps.h.
105
 * 
106
 * Revision 1.1  93/06/24  14:59:27  14:59:27  ra (Robert Andrews)
107
 * Initial revision
108
 * 
109
--------------------------------------------------------------------------
110
*/
111
 
112
 
113
#define SPARCTRANS_CODE
114
#include "config.h"
115
#include "common_types.h"
116
#include "exptypes.h"
117
#include "expmacs.h"
118
#include "codetypes.h"
119
#include "const.h"
120
#include "installtypes.h"
121
#include "exp.h"
122
#include "translat.h"
123
#include "addrtypes.h"
124
#include "shapemacs.h"
125
#include "move.h"
126
#include "regmacs.h"
127
#include "getregs.h"
128
#include "guard.h"
129
#include "codehere.h"
130
#include "inst_fmt.h"
131
#include "sparcins.h"
132
#include "labels.h"
133
#include "tags.h"
134
#include "proctypes.h"
135
#include "bitsmacs.h"
136
#include "comment.h"
137
#include "machine.h"
138
#include "proc.h"
139
#include "myassert.h"
140
#include "out.h"
141
#include "regexps.h"
142
#include "special.h"
143
#include "makecode.h"
144
 
145
/*
146
    LOOK FOR SPECIAL FUNCTIONS
147
*/
148
 
149
/* ARGSUSED */ speci special_fn 
150
    PROTO_N ( ( a1, a2, s ) )
151
    PROTO_T ( exp a1 X exp a2 X shape s )
152
{
153
    speci spr ;
154
    spr.is_special = 0 ;
155
    spr.special_exp = nilexp ;
156
    return ( spr ) ;
157
}
158
 
159
 
160
/*
161
    FIND SPECIAL PROCEDURE NUMBER
162
 
163
    A value of 0 indicates that the procedure name n is not special.  A
164
    value > 0 indicates a special procedure handled by specialmake.  A
165
    value < 0 indicates a special procedure handled bu specialneeds.
166
*/
167
 
168
static int specno 
169
    PROTO_N ( ( n ) )
170
    PROTO_T ( char * n )
171
{
172
    if ( strcmp ( n, "___builtin_strcpy" ) == 0 ||
173
	 strcmp ( n, "___TDF_builtin_strcpy" ) == 0 ) {
174
	return ( -1 ) ;
175
    }
176
 
177
    if ( strcmp ( n, "___builtin_asm" ) == 0 ||
178
	 strcmp ( n, "___TDF_builtin_asm" ) == 0 ) {
179
	return ( 4 ) ;
180
    }
181
 
182
    if ( strcmp ( n, "___builtin_alloca" ) == 0 ||
183
	 strcmp ( n, "___TDF_builtin_alloca" ) == 0 ) {
184
	return ( 5 ) ;
185
    }
186
 
187
#if 0
188
    /* Could be made special */
189
    if ( strcmp ( n, "strlen" ) == 0 ) return ( 2 ) ;
190
    if ( strcmp ( n, "strcmp" ) == 0 ) return ( -3 ) ;
191
#endif
192
 
193
    return ( 0 ) ;
194
}
195
 
196
 
197
/*
198
    FIND NAME OF A SPECIAL PROCEDURE
199
*/
200
 
201
char *special_call_name 
202
    PROTO_N ( ( i ) )
203
    PROTO_T ( int i )
204
{
205
    switch ( i ) {
206
 
207
	case -1 :
208
	case 1 : {
209
	    return ( sysV_assembler ? "strcpy" : "_strcpy" ) ;
210
	}
211
 
212
	case 5 : {
213
	    return ( sysV_assembler ? "alloca" : "_alloca" ) ;
214
	}
215
 
216
	default : {
217
	    fail ( "Attempting external call to builtin" ) ;
218
	    return ( "" ) ;
219
	}
220
    }
221
    /* NOT REACHED */
222
}
223
 
224
 
225
/*
226
    REGISTER REQUIREMENTS
227
 
228
    These indicate respectively needs of zero, one and two fixed register.
229
*/
230
 
231
static CONST needs zeroneeds = { 0, 0, 0, 0 } ;
232
#if 0
233
static CONST needs onefixneeds = { 1, 0, 0, 0 } ;
234
static CONST needs twofixneeds = { 2, 0, 0, 0 } ;
235
#endif
236
 
237
 
238
/*
239
    DEAL WITH THE NEEDS OF SPECIAL PROCEDURES
240
*/
241
 
242
/* ARGSUSED */ needs specialneeds 
243
    PROTO_N ( ( i, application, pars ) )
244
    PROTO_T ( int i X exp application X exp pars )
245
{
246
    switch ( i ) {
247
 
248
#if 0
249
	case -1 :
250
	case 1 : {
251
	    /* The library strcpy contains a number of tricks, so this
252
	       isn't really worthwhile */
253
	    exp par1 = pars ;
254
	    exp par2 = bro ( pars ) ;
255
 
256
	    if ( name ( par2 ) == eval_tag &&
257
		 name ( son ( par2 ) ) == pack_tag &&
258
		 name ( son ( son ( par2 ) ) ) == string_tag ) {
259
		/* strcpy of constant string */
260
		if ( no ( sh ( son ( son ( par2 ) ) ) ) > 7 ) {
261
		    break ;
262
		}
263
 
264
		/* apply_tag into ass_tag */
265
		setname ( application, ass_tag ) ;
266
 
267
		/* params of ass_tag as params of application */
268
		son ( application ) = pars ;
269
		bro ( bro ( pars ) ) = application ;	/* set father */
270
 
271
		/* loose pack_tag */
272
		son ( par2 ) = son ( son ( par2 ) ) ;
273
		bro ( son ( par2 ) ) = par2 ;		/* set father */
274
 
275
		/* shape of eval_tag from ptrhd to nofhd */
276
		sh ( par2 ) = sh ( son ( par2 ) ) ;
277
 
278
		return ( twofixneeds ) ;
279
	    }
280
 
281
	    /* otherwise leave TDF so strcpy is called */
282
	    return ( zeroneeds ) ;
283
	}
284
#endif
285
 
286
	case 4 : return ( zeroneeds ) ;	 /* asm */
287
	case 5 : return ( zeroneeds ) ;	 /* alloca */
288
 
289
	default : {
290
	    fail ( "Unimplemented builtin" ) ;
291
	    return ( zeroneeds ) ;
292
	}
293
    }
294
    /* NOT REACHED */
295
}
296
 
297
 
298
/*
299
    DOES fn REPRESENT A SPECIAL PROCEDURE?
300
*/
301
 
302
int specialfn 
303
    PROTO_N ( ( fn ) )
304
    PROTO_T ( exp fn )
305
{
306
    if ( name ( fn ) == name_tag && name ( son ( fn ) ) == ident_tag &&
307
	 isglob ( son ( fn ) ) && son ( son ( fn ) ) == nilexp ) {
308
	char *extname = brog ( son ( fn ) )->dec_u.dec_val.dec_id ;
309
	return ( specno ( extname ) ) ;
310
    }
311
    return ( 0 ) ;
312
}
313
 
314
/*
315
    IS A CALL TO fn REASON TO PROHIBIT OPTIMISATION OF THE CALLER?
316
 
317
    Some system calls have unexpected effects on the registers and should
318
    not be optimised.
319
*/
320
 
321
int specialopt 
322
    PROTO_N ( ( fn ) )
323
    PROTO_T ( exp fn )
324
{
325
    if ( name ( fn ) == name_tag && name ( son ( fn ) ) == ident_tag &&
326
	 isglob ( son ( fn ) ) && son ( son ( fn ) ) == nilexp ) {
327
	char *extname = brog ( son ( fn ) )->dec_u.dec_val.dec_id ;
328
	if ( extname == NULL ) return ( 0 ) ;
329
	extname += strlen ( name_prefix ) ;	/* get rid of any prefix */
330
 
331
	/* The following list corresponds to #pragma unknown_control_flow
332
	   in SunOS 4.1.1 /usr/include */
333
	if ( ( strcmp ( extname, "vfork" ) == 0 ) ||
334
	     ( strcmp ( extname, "setjmp" ) == 0 ) ||
335
	     ( strcmp ( extname, "_setjmp" ) == 0 ) ||
336
	     ( strcmp ( extname, "sigsetjmp" ) == 0 ) ) {
337
	    return ( 1 ) ;
338
	}
339
    }
340
    return ( 0 ) ;
341
}
342
extern int stackerr_lab;
343
extern int local_stackerr_lab;
344
 
345
/*
346
    INLINE SPECIAL FUNCTIONS
347
*/
348
 
349
int specialmake 
350
    PROTO_N ( ( i, par, sp, dest, exitlab ) )
351
    PROTO_T ( int i X exp par X space sp X where dest X int exitlab ){
352
  switch ( i ) {
353
    case 4 : {
354
      /* asm ( s ) - simply output s */
355
      exp e ;
356
      char *s ;
357
      e = son ( son ( par ) ) ;
358
      if ( name ( e ) != string_tag ) {
359
	fail ( "asm argument is not a string" ) ;
360
	return ( 0 ) ;
361
      }
362
      s = nostr ( e ) ;
363
      /* asm is dangerous : zap register tracking */
364
      clear_all () ;
365
      outs ( "! asm : \n" ) ;
366
      outs ( s ) ;
367
      outnl () ;
368
      break ;
369
    }
370
 
371
    case 5 :
372
    case 6 : {    
373
      /* 5 == alloca_tag, 6 = alloca_tag with checkstack */
374
      /* alloca ( n ) - grab n bytes from stack frame */
375
      int maxargbytes = ( int ) ( proc_state.maxargs / 8 ) ;
376
      int safety_below = 0 ;     /* safety zone in bytes */
377
      int safety_above = 0 ;     /* on each side of allocation */
378
      int dreg ;
379
      ans aa ;
380
      int rd ;
381
      /* Sparctrans does not use %sp relative temps, so we need not
382
	 move them to grow the stack frame in the middle for alloca.
383
	 %sp relative addresses may be used in building param lists,
384
	 but scan () brings forward alloca () as for function calls
385
	 so we will not be invoked during that sequence */
386
      if(i == 6) {
387
	rd =  getreg(sp.fixed); /* R_SP;*/
388
	sp = guardreg (rd, sp);	
389
      }
390
      else {
391
	rd = R_SP;
392
      }
393
      /* grow the stack frame */
394
      if ( name ( par ) == val_tag ) {
395
	/* n is a constant */
396
	int n = no ( par ) ;
397
	/* adjust n to be multiple of 8 */
398
	n = ( n + 8 - 1 ) & ~( 8 - 1 ) ;
399
	n += safety_below + safety_above ;
400
	if ( n != 0 ) {
401
	  rir_ins ( i_sub, R_SP, ( long ) n, rd ) ;
402
	}
403
	else {
404
	  rd = R_SP;
405
	}
406
      } 
407
      else {
408
	int nreg = reg_operand ( par, sp ) ;
409
	/* adjust nreg to be multiple of 8 */
410
	int m = ( 8 - 1 ) + ( safety_below + safety_above ) ;
411
	rir_ins ( i_add, nreg, ( long ) m, R_TMP ) ;
412
	rir_ins ( i_and, R_TMP, ~( 8 - 1 ), R_TMP ) ;
413
	rrr_ins ( i_sub, R_SP, R_TMP, rd ) ;
414
      }
415
 
416
      dreg = ( ( discrim ( dest.answhere ) == inreg ) ?
417
	       regalt ( dest.answhere ) : getreg ( sp.fixed ) ) ;
418
      sp = guardreg (dreg, sp);
419
 
420
      /* stack frame beyond reg dump area is the space to use */
421
      assert ( maxargbytes >= 16 * 4 ) ;
422
      rir_ins ( i_add, rd, ( long ) ( maxargbytes + safety_below ),
423
		dreg ) ;
424
      if (i == 6) {
425
	int rt = getreg(sp.fixed);
426
	/* checkalloc */
427
	baseoff b;
428
	b = find_tag(TDF_STACKLIM);
429
	if(stackerr_lab == 0) stackerr_lab = new_label();
430
	if(local_stackerr_lab == 0) local_stackerr_lab = new_label();
431
	ld_ins(i_ld,b,rt);
432
	condrr_ins(i_bgtu,rt,rd,local_stackerr_lab);
433
	if(rd != R_SP) {
434
	  rr_ins(i_mov,rd,R_SP);
435
	}
436
      }
437
      setregalt ( aa, dreg ) ;
438
      ( void ) move ( aa, dest, sp.fixed, 0 ) ;
439
      break ;
440
    }
441
 
442
    default : {
443
      fail ( "Unimplemented builtin" ) ;
444
      return ( 0 ) ;
445
    }
446
  }
447
  return ( exitlab ) ;
448
}
449
 
450
 
451
/*
452
    TDF LIBRARY KEY
453
 
454
    A value of 0 means that the library is not present, 1 that it is, and
455
    2 that it should be generated.
456
*/
457
 
458
int library_key = 0 ;
459
 
460
 
461
/*
462
    SPECIAL ROUTINES
463
*/
464
 
465
#define no_special_routines 8
466
 
467
static struct {
468
    char *proc_name ;
469
    int proc_regs ;
470
    bool proc_used ;
471
    bool in_library ;
472
} special_routine [ no_special_routines ] = {
473
    { ".mul", 2, 0, 1 },	/* SPECIAL_MUL */
474
    { ".umul", 2, 0, 1 },	/* SPECIAL_UMUL */
475
    { ".div", 2, 0, 1 },	/* SPECIAL_DIV2 */
476
    { ".udiv", 2, 0, 1 },	/* SPECIAL_UDIV2 */
477
    { ".rem", 2, 0, 1 },	/* SPECIAL_REM2 */
478
    { ".urem", 2, 0, 1 },	/* SPECIAL_UREM2 */
479
    { ".L.div1", 2, 0, 0 },	/* SPECIAL_DIV1 */
480
    { ".L.rem1", 2, 0, 0 }	/* SPECIAL_REM1 */
481
} ;
482
 
483
 
484
/*
485
    OUTPUT A CALL TO A SPECIAL ROUTINE
486
*/
487
 
488
void call_special_routine 
489
    PROTO_N ( ( n ) )
490
    PROTO_T ( int n )
491
{
492
    char *nm = special_routine [n].proc_name ;
493
    int r = special_routine [n].proc_regs ;
494
    special_routine [n].proc_used = 1 ;
495
    if ( library_key && nm [1] == 'L' ) nm += 2 ;
496
    extj_special_ins ( i_call, nm, r ) ;
497
    return ;
498
}
499
 
500
 
501
/*
502
    OUTPUT ALL SPECIAL ROUTINES
503
*/
504
 
505
void output_special_routines 
506
    PROTO_Z ()
507
{
508
    int i ;
509
    if ( library_key == 1 ) return ;
510
    for ( i = 0 ; i < no_special_routines ; i++ ) {
511
	if ( special_routine [i].proc_used || library_key == 2 ) {
512
	    if ( !special_routine [i].in_library ) {
513
		char *nm = special_routine [i].proc_name ;
514
		if ( library_key && nm [1] == 'L' ) nm += 2 ;
515
		insection ( text_section ) ;
516
		outs ( "!\tTDF support library routine\n" ) ;
517
		outs ( "\t.proc\t4\n" ) ;
518
		outs ( "\t.optim\t\"-O" ) ;
519
		outn ( optim_level ) ;
520
		outs ( "\"\n" ) ;
521
		outs ( nm ) ;
522
		outs ( ":\n" ) ;
523
		switch ( i ) {
524
 
525
		    case SPECIAL_DIV1 : {
526
			outs ( "\tsave\t%sp,-96,%sp\n" ) ;
527
			outs ( "\tmov\t%i0,%o0\n" ) ;
528
			outs ( "\tmov\t%i1,%o1\n" ) ;
529
			outs ( "\tcall\t.div,2\n" ) ;
530
			outs ( "\tnop\n" ) ;
531
			outs ( "\tmov\t%o0,%i2\n" ) ;
532
			outs ( "\tmov\t%i0,%o0\n" ) ;
533
			outs ( "\tmov\t%i1,%o1\n" ) ;
534
			outs ( "\tcall\t.rem,2\n" ) ;
535
			outs ( "\tnop\n" ) ;
536
			outs ( "\tcmp\t%o0,0\n" ) ;
537
			outs ( "\tbe\tLS.101\n" ) ;
538
			outs ( "\tnop\n" ) ;
539
			outs ( "LS.102:\n" ) ;
540
			outs ( "\tcmp\t%o0,0\n" ) ;
541
			outs ( "\tble\tLS.103\n" ) ;
542
			outs ( "\tnop\n" ) ;
543
			outs ( "\tcmp\t%i1,0\n" ) ;
544
			outs ( "\tbge\tLS.101\n" ) ;
545
			outs ( "\tnop\n" ) ;
546
			outs ( "\tadd\t%i2,-1,%i2\n" ) ;
547
			outs ( "\tb\tLS.101\n" ) ;
548
			outs ( "\tnop\n" ) ;
549
			outs ( "LS.103:\n" ) ;
550
			outs ( "\tcmp\t%i1,0\n" ) ;
551
			outs ( "\tble\tLS.101\n" ) ;
552
			outs ( "\tnop\n" ) ;
553
			outs ( "\tadd\t%i2,-1,%i2\n" ) ;
554
			outs ( "LS.101:\n" ) ;
555
			outs ( "\tmov\t%i2,%i0\n" ) ;
556
			break ;
557
		    }
558
 
559
		    case SPECIAL_REM1 : {
560
			outs ( "\tsave\t%sp,-96,%sp\n" ) ;
561
			outs ( "\tmov\t%i0,%o0\n" ) ;
562
			outs ( "\tmov\t%i1,%o1\n" ) ;
563
			outs ( "\tcall\t.rem,2\n" ) ;
564
			outs ( "\tnop\n" ) ;
565
			outs ( "\tcmp\t%o0,0\n" ) ;
566
			outs ( "\tbe\tLS.201\n" ) ;
567
			outs ( "\tnop\n" ) ;
568
			outs ( "LS.202:\n" ) ;
569
			outs ( "\tcmp\t%o0,0\n" ) ;
570
			outs ( "\tble\tLS.203\n" ) ;
571
			outs ( "\tnop\n" ) ;
572
			outs ( "\tcmp\t%i1,0\n" ) ;
573
			outs ( "\tbge\tLS.201\n" ) ;
574
			outs ( "\tnop\n" ) ;
575
			outs ( "\tadd\t%o0,%i1,%o0\n" ) ;
576
			outs ( "\tb\tLS.201\n" ) ;
577
			outs ( "\tnop\n" ) ;
578
			outs ( "LS.203:\n" ) ;
579
			outs ( "\tcmp\t%i1,0\n" ) ;
580
			outs ( "\tble\tLS.201\n" ) ;
581
			outs ( "\tnop\n" ) ;
582
			outs ( "\tadd\t%o0,%i1,%o0\n" ) ;
583
			outs ( "LS.201:\n" ) ;
584
			outs ( "\tmov\t%o0,%i0\n" ) ;
585
			break ;
586
		    }
587
 
588
		    default : {
589
			fail ( "Unimplemented special routine" ) ;
590
			break ;
591
		    }
592
		}
593
		outs ( "\tret\n" ) ;
594
		outs ( "\trestore\n" ) ;
595
	    }
596
	}
597
    }
598
    return ;
599
}