Blame | Last modification | View Log | RSS feed
/*
Crown Copyright (c) 1997
This TenDRA(r) Computer Program is subject to Copyright
owned by the United Kingdom Secretary of State for Defence
acting through the Defence Evaluation and Research Agency
(DERA). It is made available to Recipients with a
royalty-free licence for its use, reproduction, transfer
to other parties and amendment for any purpose not excluding
product development provided that any such use et cetera
shall be deemed to be acceptance of the following conditions:-
(1) Its Recipients shall ensure that this Notice is
reproduced upon any copies or amended versions of it;
(2) Any amended version of it shall be clearly marked to
show both the nature of and the organisation responsible
for the relevant amendment or amendments;
(3) Its onward transfer from a recipient to another
party shall be deemed to be that party's acceptance of
these conditions;
(4) DERA gives no warranty or assurance as to its
quality or suitability for any purpose and DERA accepts
no liability whatsoever in relation to any use to which
it may be put.
*/
/*
VERSION INFORMATION
===================
--------------------------------------------------------------------------
$Header: /u/g/release/CVSROOT/Source/src/installers/sparc/common/inst_fmt.c,v 1.1.1.1 1998/01/17 15:55:54 release Exp $
--------------------------------------------------------------------------
$Log: inst_fmt.c,v $
* Revision 1.1.1.1 1998/01/17 15:55:54 release
* First version to be checked into rolling release.
*
* Revision 1.12 1997/11/06 09:28:50 pwe
* ANDF-DE V1.8
*
* Revision 1.11 1997/10/10 18:32:25 pwe
* prep ANDF-DE revision
*
* Revision 1.10 1997/08/23 13:53:49 pwe
* initial ANDF-DE
*
* Revision 1.9 1997/04/17 11:59:39 pwe
* dwarf2 support
*
* Revision 1.8 1996/09/18 12:03:38 pwe
* fixed PIC_code
*
* Revision 1.7 1995/12/15 10:12:47 john
* Minor change
*
* Revision 1.6 1995/08/31 15:55:06 john
* Added function for calculation of floating_max
*
* Revision 1.5 1995/07/18 09:38:37 john
* New functions for return_to_label
*
* Revision 1.4 1995/07/14 16:30:59 john
* Minor fix
*
* Revision 1.3 1995/06/14 15:33:09 john
* Reformatting
*
* Revision 1.2 1995/05/26 12:58:38 john
* Reformatting
*
* Revision 1.1.1.1 1995/03/13 10:18:39 john
* Entered into CVS
*
* Revision 1.7 1995/01/24 16:56:34 john
* Added special regs to the register set
*
* Revision 1.6 1994/12/21 12:11:38 djch
* Added maxmin functions for int max/min. Uses the delay slot...
*
* Revision 1.5 1994/12/01 13:16:01 djch
* Added lr_ins to load a label address to a register
* Added lngjmp to code the long jump construct
* Added br_abs to get efficient jump in abs (except with SunOS as)
*
* Revision 1.4 1994/07/07 16:11:33 djch
* Jul94 tape
*
* Revision 1.3 1994/07/04 08:20:45 djch
* added asserts to spot uninitialized labels
*
* Revision 1.2 1994/05/13 12:31:14 djch
* Incorporates improvements from expt version
* Fixed printf strings to remove long, added CONST to extj_special_ins
*
* Revision 1.1 1994/05/03 14:49:38 djch
* Initial revision
*
* Revision 1.7 93/09/27 14:45:39 14:45:39 ra (Robert Andrews)
* The label prefix is now given by lab_prefix rather than by being
* hardwired in.
*
* Revision 1.6 93/08/27 11:27:19 11:27:19 ra (Robert Andrews)
* Added a couple of explicit integer casts, ext_name now takes a long.
*
* Revision 1.5 93/07/12 15:14:20 15:14:20 ra (Robert Andrews)
* A couple of things should have been CONST.
*
* Revision 1.4 93/07/08 18:21:11 18:21:11 ra (Robert Andrews)
* Reformatted.
*
* Revision 1.3 93/07/05 18:19:49 18:19:49 ra (Robert Andrews)
* Reformatted a couple of routines. Added support for Position Independent
* Code (PIC) in set_ins.
*
* Revision 1.2 93/06/29 14:26:39 14:26:39 ra (Robert Andrews)
* Included a couple of explicit casts.
*
* Revision 1.1 93/06/24 14:58:28 14:58:28 ra (Robert Andrews)
* Initial revision
*
--------------------------------------------------------------------------
*/
#define SPARCTRANS_CODE
/*
This file contains procedures for outputting various SPARC instruction
formats to the external file - as_file. Each procedure produces
assembler instructions for a family of SPARC operations, the actual
instruction being passed as the string understood by the assembler.
*/
#include "config.h"
#include "common_types.h"
#include "myassert.h"
#include "xalloc.h"
#include "addrtypes.h"
#include "regexps.h"
#include "regmacs.h"
#include "sparcins.h"
#include "maxminmacs.h"
#include "comment.h"
#include "translat.h"
#include "inst_fmt.h"
#include "out.h"
#include "flags.h"
#include "labels.h"
#ifdef NEWDWARF
#include "dw2_config.h"
#endif
/*
IS c A POWER OF 2?
*/
#define IS_POW2( c ) ( ( c ) != 0 && ( ( c ) & ( ( c ) - 1 ) ) == 0 )
/*
ARRAY OF REGISTER NAMES
*/
static CONST char reg_name_tab [66][5] = {
"%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7",
"%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7",
"%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7",
"%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7",
"%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
"%f8", "%f9", "%f10","%f11","%f12","%f13","%f14","%f15",
"%f16","%f17","%f18","%f19","%f20","%f21","%f22","%f23",
"%f24","%f25","%f26","%f27","%f28","%f29","%f30","%f31",
"%fsr","%y"
} ;
/*
MACRO FOR ACCESSING REGISTER NAMES
This converts a register number into the corresponding register
name.
*/
#define RN( reg ) reg_name_tab [ reg ]
#define FRN( reg ) reg_name_tab [ reg + 32 ]
/*
FIND AN EXTERNAL NAME
*/
char *ext_name
PROTO_N ( ( id ) )
PROTO_T ( int id )
{
if ( id < 0 ) {
/* Negative numbers refer to globals */
char *ext = main_globals [ -id - 1 ]->dec_u.dec_val.dec_id ;
return ( ext ) ;
} else {
/* Positive numbers refer to labels */
static char space [64] ;
sprintf ( space, "%sD%d", lab_prefix, id ) ;
return ( space ) ;
}
}
/*
OUTPUT A LOAD REGISTER-OFFSET INSTRUCTION
*/
void ld_ro_ins
PROTO_N ( ( ins, a, dest ) )
PROTO_T ( ins_p ins X baseoff a X int dest )
{
long off = a.offset ;
assert ( IS_FIXREG ( a.base ) ) ;
clear_reg ( dest ) ;
if ( SIMM13_SIZE ( off ) ) {
/* Small offset */
CONST char *ra = RN ( a.base ) ;
CONST char *rd = RN ( dest ) ;
if ( off == 0 ) {
fprintf ( as_file, "\t%s\t[%s],%s\n", ins, ra, rd ) ;
} else if ( off > 0 ) {
fprintf ( as_file, "\t%s\t[%s+%ld],%s\n", ins, ra, off, rd ) ;
} else /* if ( off < 0 ) */ {
fprintf ( as_file, "\t%s\t[%s-%ld],%s\n", ins, ra, -off, rd ) ;
}
#ifdef NEWDWARF
count_ins(1);
#endif
} else {
/* Large offset */
if ( a.base != dest ) {
/* Is this really a saving? */
ir_ins ( i_set, off, dest ) ;
ld_rr_ins ( ins, a.base, dest, dest ) ;
} else {
assert ( a.base != R_TMP ) ;
ir_ins ( i_set, off, R_TMP ) ;
ld_rr_ins ( ins, a.base, R_TMP, dest ) ;
}
#ifdef NEWDWARF
lost_count_ins();
#endif
}
return ;
}
/*
OUTPUT A LOAD REGISTER-REGISTER INSTRUCTION
*/
void ld_rr_ins
PROTO_N ( ( ins, reg1, reg2, dest ) )
PROTO_T ( ins_p ins X int reg1 X int reg2 X int dest )
{
clear_reg ( dest ) ;
fprintf ( as_file, "\t%s\t[%s+%s],%s\n", ins,
RN ( reg1 ), RN ( reg2 ), RN ( dest ) ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
return ;
}
/*
OUTPUT A SET INSTRUCTION
*/
void set_ins
PROTO_N ( ( a, dest ) )
PROTO_T ( baseoff a X int dest )
{
char *extname = ext_name ( a.base ) ;
long d = a.offset ;
clear_reg ( dest ) ;
if ( d == 0 || PIC_code ) {
fprintf ( as_file, "\tset\t%s,%s\n", extname, RN ( dest ) ) ;
} else if ( d > 0 ) {
fprintf ( as_file, "\tset\t%s+%ld,%s\n", extname, d, RN ( dest ) ) ;
} else {
fprintf ( as_file, "\tset\t%s-%ld,%s\n", extname, -d, RN ( dest ) ) ;
}
#ifdef NEWDWARF
lost_count_ins();
#endif
if ( PIC_code ) {
ld_rr_ins ( i_ld, R_L7, dest, dest ) ;
if ( d ) rir_ins ( i_add, dest, d, dest ) ;
}
return ;
}
/*
OUTPUT A LOAD INSTRUCTION
If baseoff is a global this may be two instructions and involve
a temporary register.
*/
void ld_ins
PROTO_N ( ( ins, a, dest ) )
PROTO_T ( ins_p ins X baseoff a X int dest )
{
if ( !IS_FIXREG ( a.base ) ) {
/* global */
baseoff tmp_off ;
tmp_off.base = R_TMP ;
tmp_off.offset = 0 ;
set_ins ( a, R_TMP ) ;
ld_ro_ins ( ins, tmp_off, dest ) ;
} else {
ld_ro_ins ( ins, a, dest ) ;
}
return ;
}
/*
OUTPUT A STORE REGISTER-OFFSET INSTRUCTION
*/
void st_ro_ins
PROTO_N ( ( ins, src, a ) )
PROTO_T ( ins_p ins X int src X baseoff a )
{
long off = a.offset ;
assert ( IS_FIXREG ( a.base ) ) ;
/* in general we cannot cope with store using temp reg, catch it always */
if ( ( src == R_TMP || a.base == R_TMP )
&& ABS_OF ( off ) > ( 16 + 1 + 6 ) * 4 /* leeway for mem_temp */ ) {
fail ( "Temporary register problem in st_ro_ins" ) ;
}
if ( SIMM13_SIZE ( off ) ) {
/* Small offset */
CONST char *rs = RN ( src ) ;
CONST char *ra = RN ( a.base ) ;
if ( off == 0 ) {
fprintf ( as_file, "\t%s\t%s,[%s]\n", ins, rs, ra ) ;
} else if ( off > 0 ) {
fprintf ( as_file, "\t%s\t%s,[%s+%ld]\n", ins, rs, ra, off ) ;
} else /* if ( off < 0 ) */ {
fprintf ( as_file, "\t%s\t%s,[%s-%ld]\n", ins, rs, ra, -off ) ;
}
#ifdef NEWDWARF
count_ins(1);
#endif
} else {
/* Large offset */
assert ( a.base != R_TMP ) ;
ir_ins ( i_set, off, R_TMP ) ;
#ifdef NEWDWARF
lost_count_ins();
#endif
st_rr_ins ( ins, src, a.base, R_TMP ) ;
}
return ;
}
/*
OUTPUT A STORE REGISTER-REGISTER INSTRUCTION
*/
void st_rr_ins
PROTO_N ( ( ins, src, reg1, reg2 ) )
PROTO_T ( ins_p ins X int src X int reg1 X int reg2 )
{
fprintf ( as_file, "\t%s\t%s,[%s+%s]\n", ins,
RN ( src ), RN ( reg1 ), RN ( reg2 ) ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
return ;
}
/*
OUTPUT A STORE INSTRUCTION
If baseoff is a global this may be two instructions and involve
a temporary register.
*/
void st_ins
PROTO_N ( ( ins, src, a ) )
PROTO_T ( ins_p ins X int src X baseoff a )
{
if ( !IS_FIXREG ( a.base ) ) {
/* global */
baseoff tmp_off ;
if ( src == R_TMP ) {
fail ( "Temporary register problem in st_ins" ) ;
}
tmp_off.base = R_TMP ;
tmp_off.offset = 0 ;
set_ins ( a, R_TMP ) ;
st_ro_ins ( ins, src, tmp_off ) ;
} else {
st_ro_ins ( ins, src, a ) ;
}
return ;
}
/*
OUTPUT A THREE REGISTER INSTRUCTION
*/
void rrr_ins
PROTO_N ( ( ins, src1, src2, dest ) )
PROTO_T ( ins_p ins X int src1 X int src2 X int dest )
{
clear_reg ( dest ) ;
fprintf ( as_file, "\t%s\t%s,%s,%s\n", ins,
RN ( src1 ), RN ( src2 ), RN ( dest ) ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
return ;
}
/*
OUTPUT A REGISTER, IMMEDIATE, REGISTER INSTRUCTION
*/
void rir_ins
PROTO_N ( ( ins, src1, imm, dest ) )
PROTO_T ( ins_p ins X int src1 X long imm X int dest )
{
clear_reg ( dest ) ;
if ( SIMM13_SIZE ( imm ) ) {
/* Small data */
fprintf ( as_file, "\t%s\t%s,%ld,%s\n", ins,
RN ( src1 ), imm, RN ( dest ) ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
} else if ( SIMM13_SIZE ( ~imm ) &&
( ins == i_and || ins == i_or || ins == i_xor ) ) {
/* Small data complemented */
ins_p n_ins ;
if ( ins == i_and ) {
n_ins = i_andn ;
} else if ( ins == i_or ) {
n_ins = i_orn ;
} else /* if ( ins == i_xor ) */ {
n_ins = i_xnor ;
}
fprintf ( as_file, "\t%s\t%s,%ld,%s\n", n_ins,
RN ( src1 ), ~imm, RN ( dest ) ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
} else if ( ins == i_and && IS_POW2 ( imm + 1 ) ) {
/* Can be done by shift left, shift right */
int nbits = 0, shift ;
unsigned long uimm = ( unsigned long ) imm ;
while ( uimm != 0 ) {
nbits++ ;
uimm = uimm >> 1 ;
}
shift = 32 - nbits ;
rir_ins ( i_sll, src1, ( long ) shift, dest ) ;
rir_ins ( i_srl, dest, ( long ) shift, dest ) ;
} else if ( ( ins == i_add || ins == i_sub ) &&
SIMM13_SIZE ( imm / 2 ) && dest != R_SP ) {
if ( imm == 4096 ) {
/* add 4096 => sub -4096 etc */
rir_ins ( ( ins == i_add ? i_sub : i_add ), src1, -imm, dest ) ;
} else {
/* use two adds or subs */
long half = imm / 2;
rir_ins ( ins, src1, half, dest ) ;
rir_ins ( ins, dest, ( long ) ( imm - half ), dest ) ;
}
} else {
/* use temporary register for large constant */
if ( src1 == R_TMP ) {
fail ( "Temporary register problem in rir_ins" ) ;
} else {
fprintf ( as_file, "\tset\t%ld,%s\n", imm, RN ( R_TMP ) ) ;
#ifdef NEWDWARF
lost_count_ins();
#endif
rrr_ins ( ins, src1, R_TMP, dest ) ;
}
}
return ;
}
/*
OUTPUT A REGISTER TO REGISTER PSEUDO INSTRUCTION
*/
void rr_ins
PROTO_N ( ( ins, src, dest ) )
PROTO_T ( ins_p ins X int src X int dest )
{
clear_reg ( dest ) ;
fprintf ( as_file, "\t%s\t%s,%s\n", ins, RN ( src ), RN ( dest ) ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
return ;
}
/*
OUTPUT AN IMMEDIATE TO REGISTER PSEUDO INSTRUCTION
*/
void ir_ins
PROTO_N ( ( ins, imm, dest ) )
PROTO_T ( ins_p ins X long imm X int dest )
{
clear_reg ( dest ) ;
if ( SIMM13_SIZE ( imm ) || ins == i_set ) {
fprintf ( as_file, "\t%s\t%ld,%s\n", ins, imm, RN ( dest ) ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
} else if ( ins == i_mov ) {
/* use a set instruction for move */
fprintf ( as_file, "\tset\t%ld,%s\n", imm, RN ( dest ) ) ;
#ifdef NEWDWARF
lost_count_ins();
#endif
} else {
/* use temporary register for large constant */
fprintf ( as_file, "\tset\t%ld,%s\n", imm, RN ( R_TMP ) ) ;
#ifdef NEWDWARF
lost_count_ins();
#endif
rr_ins ( ins, R_TMP, dest ) ;
}
return ;
}
/*
OUTPUT A LABEL TO REGISTER PSEUDO INSTRUCTION
*/
void lr_ins
PROTO_N ( ( imm, dest ) )
PROTO_T ( int imm X int dest )
{
clear_reg ( dest ) ;
/* use a set instruction to load the label */
fprintf ( as_file, "\tset\t%s%d,%s\n", lab_prefix, imm, RN ( dest ) ) ;
#ifdef NEWDWARF
lost_count_ins();
#endif
if ( PIC_code ) {
ld_rr_ins ( i_ld, R_L7, dest, dest ) ;
}
return ;
}
/*
OUTPUT A ZEROADIC INSTRUCTION
*/
void z_ins
PROTO_N ( ( ins ) )
PROTO_T ( ins_p ins )
{
fprintf ( as_file, "\t%s\n", ins ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
return ;
}
/*
OUTPUT AN UNCONDITIONAL BRANCH
*/
void uncond_ins
PROTO_N ( ( ins, lab ) )
PROTO_T ( ins_p ins X int lab )
{
fprintf ( as_file, "\t%s\t%s%d\n", ins, lab_prefix, lab ) ;
assert (lab > 100);
outs ( "\tnop\n" ) ; /* delay slot */
#ifdef NEWDWARF
count_ins(2);
#endif
return ;
}
/*
OUTPUT A RETURN INSTRUCTION
*/
void ret_ins
PROTO_N ( ( ins ) )
PROTO_T ( ins_p ins )
{
fprintf ( as_file, "\t%s\n", ins ) ;
outs ( "\tnop\n" ) ; /* delay slot */
#ifdef NEWDWARF
count_ins(2);
#endif
return ;
}
/*
OUTPUT A RETURN AND RESTORE INSTRUCTION
*/
void ret_restore_ins
PROTO_Z ()
{
fprintf ( as_file, "\t%s\n", i_ret ) ;
fprintf ( as_file, "\t%s\n", i_restore ) ; /* delay slot */
#ifdef NEWDWARF
count_ins(2);
#endif
return ;
}
/*
OUTPUT A LONGJMP (old sp, pc)
*/
/* offset from fp to saved i6 in the 16 word
reg save area. See rw_fp in <machine/reg.h> */
#define FP_OFFSET_IN_FRAME (8*4 + 6*4)
void lngjmp
PROTO_N ( ( o_fp_reg, pc_reg, r_new_sp ) )
PROTO_T ( int o_fp_reg X int pc_reg X int r_new_sp )
{
int lab = new_label();
baseoff frm;
frm.offset = FP_OFFSET_IN_FRAME;
#ifdef NOT_SUN_BUGGY_ASM
fprintf ( as_file, "\tta\t3\n" );
#else
fprintf ( as_file, "\t.word\t0x91d02003\n" ) ; /* ta 3, but SunOS as may
get ta wrong I'm told */
#endif
#ifdef NEWDWARF
lost_count_ins();
#endif
rr_ins ( i_mov, R_SP, r_new_sp);
rir_ins( i_sub, R_SP, 0x40, R_SP);
frm.base = r_new_sp;
set_label (lab);
ld_ro_ins (i_ld, frm, R_TMP);
fprintf ( as_file, "\tcmp\t%s,%s\n", RN (R_TMP ), RN(o_fp_reg));
fprintf ( as_file, "\tbne,a\t%s%d\n", lab_prefix, lab);
#ifdef NEWDWARF
count_ins(2);
#endif
rr_ins (i_mov, R_TMP, r_new_sp);
/* now r_new_sp holds the sp to a reg
save area whose fp is the fp we want...*/
rr_ins (i_mov, r_new_sp, R_FP);
fprintf ( as_file, "\tjmpl\t %s + 0, %%g0\n", RN(pc_reg)) ;
fprintf ( as_file, "\t%s\n", i_restore ) ; /* delay slot */
#ifdef NEWDWARF
count_ins(2);
#endif
}
/*
OUTPUT A STRUCTURE RESULT RETURN AND RESTORE INSTRUCTION
See section D.4 of the SPARC architecture manual.
*/
void stret_restore_ins
PROTO_Z ()
{
fprintf ( as_file, "\tjmp\t%%i7+12\n" ) ;
fprintf ( as_file, "\t%s\n", i_restore ) ; /* delay slot */
#ifdef NEWDWARF
count_ins(2);
#endif
return ;
}
/*
OUTPUT AN EXTERNAL JUMP OR CALL INSTRUCTION
*/
void extj_ins
PROTO_N ( ( ins, b, param_regs_used ) )
PROTO_T ( ins_p ins X baseoff b X int param_regs_used )
{
char *ext = ext_name ( b.base ) ;
if ( param_regs_used >= 0 ) {
/* print number of parameter registers if known */
assert ( param_regs_used <= 6 ) ; /* %o0..%o5 */
if(b.offset) {
fprintf(as_file,"\t%s\t%s+%ld,%d\n",ins,ext,b.offset,param_regs_used);
}
else {
fprintf ( as_file, "\t%s\t%s,%d\n", ins, ext, param_regs_used ) ;
}
}
else {
/* param_regs_used = -1 means it is not known */
if (b.offset) {
fprintf(as_file,"\t%s\t%s+%ld\n",ins,ext,b.offset);
}
else {
fprintf ( as_file, "\t%s\t%s\n", ins, ext ) ;
}
}
outs ( "\tnop\n" ) ; /* delay slot */
#ifdef NEWDWARF
count_ins(2);
#endif
return ;
}
/*
don't fill up the delay slot: the caller of this functions must
provide its own delay slot filler
*/
void extj_ins_without_delay
PROTO_N ( ( ins, b, param_regs_used ) )
PROTO_T ( ins_p ins X baseoff b X int param_regs_used ){
char *ext = ext_name ( b.base ) ;
if ( param_regs_used >= 0 ) {
/* print number of parameter registers if known */
assert ( param_regs_used <= 6 ) ; /* %o0..%o5 */
fprintf ( as_file, "\t%s\t%s,%d\n", ins, ext, param_regs_used ) ;
}
else {
/* param_regs_used = -1 means it is not known */
fprintf ( as_file, "\t%s\t%s\n", ins, ext ) ;
}
#ifdef NEWDWARF
count_ins(1);
#endif
return ;
}
/*
OUTPUT AN EXTERNAL JUMP OR CALL INSTRUCTION (SPECIAL CASE)
This case is used to handle special calls like .muls where the
name is given by a string.
*/
void extj_special_ins
PROTO_N ( ( ins, ext, param_regs_used ) )
PROTO_T ( ins_p ins X CONST char * CONST ext X int param_regs_used ){
if ( param_regs_used >= 0 ) {
/* print number of parameter registers if known */
assert ( param_regs_used <= 6 ) ; /* %o0..%o5 */
fprintf ( as_file, "\t%s\t%s,%d\n", ins, ext, param_regs_used ) ;
}
else {
/* param_regs_used = -1 means it is not known */
fprintf ( as_file, "\t%s\t%s\n", ins, ext ) ;
}
outs ( "\tnop\n" ) ; /* delay slot */
#ifdef NEWDWARF
count_ins(2);
#endif
return ;
}
/* as above, but with allowing the calling function to fill in the
delay slot. */
void extj_special_ins_no_delay
PROTO_N ( ( ins, ext, param_regs_used ) )
PROTO_T ( ins_p ins X CONST char * CONST ext X int param_regs_used ){
if ( param_regs_used >= 0 ) {
/* print number of parameter registers if known */
assert ( param_regs_used <= 6 ) ; /* %o0..%o5 */
fprintf ( as_file, "\t%s\t%s,%d\n", ins, ext, param_regs_used ) ;
}
else {
/* param_regs_used = -1 means it is not known */
fprintf ( as_file, "\t%s\t%s\n", ins, ext ) ;
}
#ifdef NEWDWARF
count_ins(1);
#endif
/* delay slot */
return ;
}
/*
OUTPUT AN EXTERNAL JUMP TO REGISTER INSTRUCTION
*/
void extj_reg_ins
PROTO_N ( ( ins, reg, param_regs_used ) )
PROTO_T ( ins_p ins X int reg X int param_regs_used ){
assert ( IS_FIXREG ( reg ) ) ;
if ( sysV_assembler ) {
/* The SysV assembler likes reg to be R_G1 for calls */
if ( ins == i_call && reg != R_G1 ) {
rr_ins ( i_mov, reg, R_G1 ) ;
reg = R_G1 ;
}
}
extj_special_ins ( ins, RN ( reg ), param_regs_used ) ;
return ;
}
void extj_reg_ins_no_delay
PROTO_N ( ( ins, reg, param_regs_used ) )
PROTO_T ( ins_p ins X int reg X int param_regs_used ){
assert ( IS_FIXREG ( reg ) ) ;
if ( sysV_assembler ) {
/* The SysV assembler likes reg to be R_G1 for calls */
if ( ins == i_call && reg != R_G1 ) {
rr_ins ( i_mov, reg, R_G1 ) ;
reg = R_G1 ;
}
}
extj_special_ins_no_delay ( ins, RN ( reg ), param_regs_used ) ;
return ;
}
/*
OUTPUT AN UNIMP INSTRUCTION
*/
void unimp_ins
PROTO_N ( ( imm ) )
PROTO_T ( long imm ){
fprintf ( as_file, "\tunimp\t%ld\n", imm ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
return ;
}
/*
OUTPUT A CONDITIONAL INTEGER TEST JUMP
*/
void br_ins
PROTO_N ( ( ins, dest ) )
PROTO_T ( ins_p ins X int dest ){
fprintf ( as_file, "\t%s\t%s%d\n", ins, lab_prefix, dest ) ;
assert (dest > 100);
outs ( "\tnop\n" ) ; /* delay slot */
#ifdef NEWDWARF
count_ins(2);
#endif
return ;
}
/*
OUTPUT int branch for abs
*/
void br_abs
PROTO_N ( ( lab ) )
PROTO_T ( int lab ){
#ifdef NOT_SUN_BUGGY_ASM
fprintf ( as_file, "\t%s\t%s%s\n", "bpos,a", lab_prefix, lab);
#ifdef NEWDWARF
count_ins(1);
#endif
/* No nop, delay slot used!!! */
#else
fprintf ( as_file, "\t%s\t%s%d\n", "bneg", lab_prefix, lab);
fprintf ( as_file, "\tnop\n");
#ifdef NEWDWARF
count_ins(2);
#endif
#endif
return ;
}
/*
OUTPUT A CONDITIONAL FLOATING POINT TEST JUMP
The instruction before a floating point test jump instruction
cannot be another floating point instruction.
*/
void fbr_ins
PROTO_N ( ( ins, dest ) )
PROTO_T ( ins_p ins X int dest ){
outs ( "\tnop\n" ) ;
fprintf ( as_file, "\t%s\t%s%d\n", ins, lab_prefix, dest ) ;
assert (dest > 100);
outs ( "\tnop\n" ) ; /* delay slot */
#ifdef NEWDWARF
count_ins(2);
#endif
return ;
}
/*
OUTPUT A REGISTER, REGISTER COMPARISON
*/
void condrr_ins
PROTO_N ( ( ins, src1, src2, lab ) )
PROTO_T ( ins_p ins X int src1 X int src2 X int lab ){
if(src2 == R_G0){
fprintf ( as_file, "\ttst\t%s\n",RN(src1) );
}
else{
fprintf ( as_file, "\tcmp\t%s,%s\n", RN ( src1 ), RN ( src2 ) ) ;
}
#ifdef NEWDWARF
count_ins(1);
#endif
br_ins ( ins, lab ) ;
return ;
}
/*
OUTPUT A REGISTER, IMMEDIATE COMPARISON
*/
void condri_ins
PROTO_N ( ( ins, src1, imm, lab ) )
PROTO_T ( ins_p ins X int src1 X long imm X int lab ){
if ( SIMM13_SIZE(imm) ) {
/* Small constant */
fprintf ( as_file, "\tcmp\t%s,%ld\n", RN ( src1 ), imm ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
br_ins ( ins, lab ) ;
}
else {
/* Large constant */
if ( src1 == R_TMP ) {
fail ( "Temporary register problem in condri_ins" ) ;
}
fprintf ( as_file, "\tset\t%ld,%s\n", imm, RN ( R_TMP ) ) ;
#ifdef NEWDWARF
lost_count_ins();
#endif
condrr_ins ( ins, src1, R_TMP, lab ) ;
}
return ;
}
/*
OUTPUT A REGISTER, REGISTER MAX/MIN
*/
void fmaxminrr_ins
PROTO_N ( ( ins, src1, src2, dest, ftype ) )
PROTO_T ( ins_p ins X int src1 X int src2 X int dest X int ftype ) {
ins_p fcmp_ins;
int lab = new_label() ;
fcmp_ins = i_fcmps;
fprintf ( as_file, "\t%s\t%s,%s\n", fcmp_ins,RN ( src1 ), RN ( src2 ) ) ;
fprintf ( as_file, "\t%s\t%s%d\n", ins, lab_prefix, lab ) ;
/* USE the delay slot */
fprintf ( as_file, "\tfmovs %s, %s\n", RN(src1), RN(dest));
fprintf ( as_file, "\tfmovs %s, %s\n", RN(src2), RN(dest));
#ifdef NEWDWARF
count_ins(4);
#endif
set_label(lab);
return ;
}
void maxminrr_ins
PROTO_N ( ( ins, src1, src2, dest ) )
PROTO_T ( ins_p ins X int src1 X int src2 X int dest ){
int lab = new_label() ;
fprintf ( as_file, "\tcmp\t%s,%s\n", RN ( src1 ), RN ( src2 ) ) ;
fprintf ( as_file, "\t%s\t%s%d\n", ins, lab_prefix, lab ) ;
/* USE the delay slot */
fprintf ( as_file, "\tmov %s, %s\n", RN(src1), RN(dest));
fprintf ( as_file, "\tmov %s, %s\n", RN(src2), RN(dest));
#ifdef NEWDWARF
count_ins(4);
#endif
set_label(lab);
return ;
}
/*
OUTPUT A REGISTER, IMMEDIATE MAX/MIN
*/
void maxminri_ins
PROTO_N ( ( ins, src1, val, dest ) )
PROTO_T ( ins_p ins X int src1 X long val X int dest ){
int lab = new_label() ;
if (!SIMM13_SIZE ( val )) {
fprintf ( as_file, "\tset\t%ld,%s\n", val, RN ( R_TMP ) ) ;
fprintf ( as_file, "\tcmp\t%s,%s\n", RN ( src1 ), RN ( R_TMP) ) ;
fprintf ( as_file, "\t%s\t%s%d\n", ins, lab_prefix, lab ) ;
/* USE the delay slot */
fprintf ( as_file, "\tmov %s, %s\n", RN(src1), RN(dest));
/* note set is two instruction, and
must not go in the delay slot... */
fprintf ( as_file, "\tset %ld, %s\n", val, RN(dest));
#ifdef NEWDWARF
lost_count_ins();
#endif
}
else{
fprintf ( as_file, "\tcmp\t%s,%ld\n", RN ( src1 ), val ) ;
fprintf ( as_file, "\t%s\t%s%d\n", ins, lab_prefix, lab ) ;
/* USE the delay slot */
fprintf ( as_file, "\tmov %s, %s\n", RN(src1), RN(dest));
fprintf ( as_file, "\tmov %ld, %s\n", val, RN(dest));
#ifdef NEWDWARF
count_ins(4);
#endif
}
set_label(lab);
return ;
}
/*
OUTPUT A LOAD FLOATING REGISTER-OFFSET INSTRUCTION
*/
void ldf_ro_ins
PROTO_N ( ( ins, a, dest ) )
PROTO_T ( ins_p ins X baseoff a X int dest ){
long off = a.offset ;
assert ( IS_FIXREG ( a.base ) ) ;
clear_freg ( dest ) ;
if ( SIMM13_SIZE ( off ) ) {
/* Small offset */
CONST char *rn = RN ( a.base ) ;
if ( off == 0 ) {
fprintf ( as_file, "\t%s\t[%s],%s\n", ins, rn, FRN(dest) ) ;
}
else if ( off > 0 ) {
fprintf ( as_file, "\t%s\t[%s+%ld],%s\n", ins, rn, off, FRN(dest) ) ;
}
else /* if ( off < 0 ) */ {
fprintf ( as_file, "\t%s\t[%s-%ld],%s\n", ins, rn, -off, FRN(dest) ) ;
}
#ifdef NEWDWARF
count_ins(1);
#endif
}
else {
/* Large offset */
assert ( a.base != R_TMP ) ;
ir_ins ( i_set, off, R_TMP ) ;
#ifdef NEWDWARF
lost_count_ins();
#endif
ldf_rr_ins ( ins, a.base, R_TMP, dest ) ;
}
return ;
}
/*
OUTPUT A LOAD FLOATING REGISTER-REGISTER INSTRUCTION
*/
void ldf_rr_ins
PROTO_N ( ( ins, reg1, reg2, dest ) )
PROTO_T ( ins_p ins X int reg1 X int reg2 X int dest ){
clear_freg ( dest ) ;
fprintf ( as_file, "\t%s\t[%s+%s],%s\n", ins,
RN ( reg1 ), RN ( reg2 ), FRN(dest) ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
return ;
}
/*
OUTPUT A LOAD FLOATING INSTRUCTION
If baseoff is a global this may be two instructions and involve
a temporary register.
*/
void ldf_ins
PROTO_N ( ( ins, a, dest ) )
PROTO_T ( ins_p ins X baseoff a X int dest ){
if ( !IS_FIXREG ( a.base ) ) {
/* global */
baseoff tmp_off ;
tmp_off.base = R_TMP ;
tmp_off.offset = 0 ;
set_ins ( a, R_TMP ) ;
ldf_ro_ins ( ins, tmp_off, dest ) ;
}
else {
ldf_ro_ins ( ins, a, dest ) ;
}
return ;
}
/*
OUTPUT A STORE FLOATING REGISTER-OFFSET INSTRUCTION
*/
void stf_ro_ins
PROTO_N ( ( ins, src, a ) )
PROTO_T ( ins_p ins X int src X baseoff a ){
long off = a.offset ;
assert ( IS_FIXREG ( a.base ) ) ;
if ( a.base == R_TMP && ABS_OF ( off ) > ( 16 + 1 + 6 ) * 4 ) {
fail ( "Temporary register problem in stf_ro_ins" ) ;
}
if ( SIMM13_SIZE ( off ) ) {
/* Small offset */
CONST char *rn = RN ( a.base ) ;
if ( off == 0 ) {
fprintf ( as_file, "\t%s\t%s,[%s]\n", ins, FRN(src), rn ) ;
}
else if ( off > 0 ) {
fprintf ( as_file, "\t%s\t%s,[%s+%ld]\n", ins, FRN(src), rn, off ) ;
}
else /* if ( off < 0 ) */ {
fprintf ( as_file, "\t%s\t%s,[%s-%ld]\n", ins, FRN(src), rn, -off ) ;
}
#ifdef NEWDWARF
count_ins(1);
#endif
}
else {
/* Large offset */
assert ( a.base != R_TMP ) ;
ir_ins ( i_set, off, R_TMP ) ;
#ifdef NEWDWARF
lost_count_ins();
#endif
stf_rr_ins ( ins, src, a.base, R_TMP ) ;
}
return ;
}
/*
OUTPUT A STORE FLOATING REGISTER-REGISTER INSTRUCTION
*/
void stf_rr_ins
PROTO_N ( ( ins, src, reg1, reg2 ) )
PROTO_T ( ins_p ins X int src X int reg1 X int reg2 ){
fprintf ( as_file, "\t%s\t%s,[%s+%s]\n", ins, FRN(src),
RN ( reg1 ), RN ( reg2 ) ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
return ;
}
/*
OUTPUT A STORE FLOATING INSTRUCTION
If baseoff is a global this may be two instructions and involve
a temporary register.
*/
void stf_ins
PROTO_N ( ( ins, src, a ) )
PROTO_T ( ins_p ins X int src X baseoff a ){
if ( !IS_FIXREG ( a.base ) ) {
/* global */
baseoff tmp_off ;
tmp_off.base = R_TMP ;
tmp_off.offset = 0 ;
set_ins ( a, R_TMP ) ;
stf_ro_ins ( ins, src, tmp_off ) ;
}
else {
stf_ro_ins ( ins, src, a ) ;
}
return ;
}
/*
OUTPUT A FLOATING REGISTER, FLOATING REGISTER COMPARISON
*/
void rrf_cmp_ins
PROTO_N ( ( ins, src1, src2 ) )
PROTO_T ( ins_p ins X int src1 X int src2 ){
fprintf ( as_file, "\t%s\t%s,%s\n", ins, FRN(src1), FRN(src2) ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
return ;
}
/*
OUTPUT A FLOATING REGISTER, FLOATING REGISTER INSTRUCTION
*/
void rrf_ins
PROTO_N ( ( ins, src, dest ) )
PROTO_T ( ins_p ins X int src X int dest ){
clear_freg ( dest ) ;
fprintf ( as_file, "\t%s\t%s,%s\n", ins, FRN(src), FRN(dest) ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
return ;
}
/*
OUTPUT A THREE FLOATING REGISTER INSTRUCTION
*/
void rrrf_ins
PROTO_N ( ( ins, src1, src2, dest ) )
PROTO_T ( ins_p ins X int src1 X int src2 X int dest ){
clear_freg ( dest ) ;
fprintf ( as_file, "\t%s\t%s,%s,%s\n", ins, FRN(src1),
FRN(src2), FRN(dest) ) ;
#ifdef NEWDWARF
count_ins(1);
#endif
return ;
}
/*
OUTPUT AN OPERAND, AS PART OF AN ASM SEQUENCE
*/
void out_asm_reg
PROTO_N ( ( r, fp ) )
PROTO_T ( int r X int fp ){
outs ((fp ? FRN(r) : RN(r)));
return ;
}
void out_asm_boff
PROTO_N ( ( b, o2 ) )
PROTO_T ( baseoff b X long o2 ){
long off = b.offset + o2;
if ( off == 0 )
fprintf ( as_file, "[%s]", RN(b.base));
else if ( off > 0 )
fprintf ( as_file, "[%s+%ld]", RN(b.base), off);
else /* if ( off < 0 ) */
fprintf ( as_file, "[%s-%ld]", RN(b.base), -off);
return ;
}