Rev 2 | Blame | Compare with Previous | 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.
*/
/*
inst_fmt_2.c
This file contains a set of procedures to output assembler
instructions in both binary and symbolic formats and to call
the code scheduler at appropriate points.
*/
/*
$Log: inst_fmt.c,v $
* Revision 1.1.1.1 1998/01/17 15:56:00 release
* First version to be checked into rolling release.
*
* Revision 1.17 1997/09/05 12:22:47 john
* Change to jmp
*
* Revision 1.16 1996/02/15 09:53:16 john
* Changed integer_jump_fn
*
* Revision 1.15 1995/12/04 09:12:33 john
* Portability fixes
*
* Revision 1.14 1995/11/13 12:43:30 john
* Minor change
*
* Revision 1.13 1995/10/16 12:07:46 john
* Change to alignment calculation
*
* Revision 1.12 1995/09/04 16:23:37 john
* Fix to general procs
*
* Revision 1.11 1995/08/30 16:14:51 john
* Fix for use of AT register
*
* Revision 1.10 1995/08/21 08:44:49 john
* Changed include files
*
* Revision 1.9 1995/05/25 15:33:10 john
* Cosmetic changes
*
* Revision 1.8 1995/05/23 10:56:51 john
* Changes for 64 bit support
*
* Revision 1.7 1995/05/16 10:52:34 john
* Now uses correct register names (where supported by the assembler).
*
* Revision 1.6 1995/04/10 14:13:18 john
* Minor changes
*
* Revision 1.5 1995/04/07 11:03:45 john
* Changes to assembler output, plus change to floating point operations.
*
* Revision 1.4 1995/03/29 14:07:36 john
* Fixed error in noat block handling
*
* Revision 1.3 1995/03/29 10:30:51 john
* Added resources for scheduler
*
* Revision 1.2 1995/03/28 12:44:30 john
* Changed resources for scheduler
*
* Revision 1.1.1.1 1995/03/23 10:39:11 john
* Entered into CVS
*
* Revision 1.1 1995/03/23 10:06:32 john
* Initial revision
*
*/
#include "config.h"
#include "inst_fmt.h"
#include "main.h"
#include "fail.h"
#include "reg_defs.h"
#include "cross.h"
#include "regexps.h"
#include "alpha_ins.h"
#include "xalloc.h"
#include "bool.h"
#include "ibinasm.h"
#include "out_ba.h"
#include "syms.h"
#include "fail.h"
#include "instypes.h"
#if DO_SCHEDULE
#include "scheduler.h"
#include "common.h"
#endif
#include "procrectypes.h"
#include "locate.h"
#include "getregs.h"
#include "code_here.h"
#include "maxminmacs.h"
#include "pseudo.h"
#if DO_SCHEDULE
static int instruction_number=0;
#endif
int andpeep = 0;
extern int extended_comments;
bool in_noat_block=FALSE;
static char *reg_name[]=
{"$0","$1","$2","$3","$4","$5","$6","$7","$8","$9","$10","$11","$12","$13"
,"$14","$fp","$16","$17","$18","$19","$20","$21","$22","$23","$24","$25"
,"$26","$27","$at","$gp","$sp","$31"
};
#define instruction_block_size 500
#define schedule_leniency 0
#define is_32bit_load_store(X) (ins_equal(X,i_ldl)||ins_equal(X,i_stl)\
|| ins_equal(X,i_ldl_l)||ins_equal(X,i_stl_c))
#define is_32bit_fload_fstore(X) (ins_equal(X,i_lds)||ins_equal(X,i_sts)\
|| ins_equal(X,i_ldf)||ins_equal(X,i_stf))
#define is_unaligned_access_instruction(X) (ins_equal(X,i_ldq_u) ||\
ins_equal(X,i_stq_u))
/*
If the instruction ins has an equivalent which causes the OS to
successfully handle a trap then return it, otherwise return ins.
*/
instruction trap_ins
PROTO_N ( ( ins,traps ) )
PROTO_T ( instruction ins X bool *traps )
{
*traps = TRUE;
if (ins_equal(ins,i_adds))
return i_addssu;
if (ins_equal(ins,i_addt))
return i_addtsu;
if (ins_equal(ins,i_divs))
return i_divssu;
if (ins_equal(ins,i_divt))
return i_divtsu;
if (ins_equal(ins,i_muls))
return i_mulssu;
if (ins_equal(ins,i_mult))
return i_multsu;
if (ins_equal(ins,i_subs))
return i_subssu;
if (ins_equal(ins,i_subt))
return i_subtsu;
*traps = FALSE;
return ins;
}
#if DO_SCHEDULE
Instruction get_new_instruction
PROTO_Z ()
{
Instruction new_ins = getinst();
if(in_noat_block) setuses(new_ins,resource_noat,class_null);
return new_ins;
}
#endif
/*
Construct a new statement from the two representations and send
to the scheduler.
*/
#if DO_SCHEDULE
void output_instruction
PROTO_N ( ( cl,ins_text,ins_bindata ) )
PROTO_T ( Class cl X char *ins_text X char *ins_bindata )
{
Instruction new_ins = getinst();
Instruction_data ins_dat = get_new_ins_data();
if(ins_text){
if(!strcmp(ins_text,"\t.set\tat\n") ||
!strcmp(ins_text,"\t.set\tnoat\n")){
setsets(new_ins,resource_noat,class_null);
setsets(new_ins,R28,class_null);
}
}
setclass(new_ins,cl);
set_instruction_text(ins_dat,ins_text);
set_instruction_binasm(ins_dat,ins_bindata);
setdata(new_ins,ins_dat);
process_instruction(new_ins);
return;
}
#if SEPARATE_DATA
void output_data
PROTO_N ( ( data_txt,data_binasm ) )
PROTO_T ( char *data_txt X char * data_binasm )
{
Instruction_data ins_d = get_new_ins_data();
set_instruction_binasm(ins_d,data_binasm);
set_instruction_text(ins_d,data_txt);
out_code(ins_d);
return;
}
#else
void output_data
PROTO_N ( ( data_txt,data_binasm ) )
PROTO_T ( char *data_txt X char *data_binasm )
{
output_instruction(class_null,data_txt,data_binasm);
return;
}
#endif
#endif
#if DO_SCHEDULE
static String *init_String
PROTO_Z ()
{
String *res = (String*)xcalloc(1,sizeof(String));
res->head = res->tail = (StringData*)NULL;
return res;
}
static void add_char_to_string
PROTO_N ( ( ch,dest ) )
PROTO_T ( char ch X String **dest )
{
StringData *new = (StringData*)xcalloc(1,sizeof(StringData));
new->data = ch;
new->next = (StringData*)NULL;
if((*dest)->head == (StringData*)NULL){
(*dest)->head = new;
}
if((*dest)->tail != (StringData*)NULL){
(*dest)->tail->next = new;
}
(*dest)->tail = new;
return ;
}
static void add_to_string
PROTO_N ( ( str,dest ) )
PROTO_T ( char *str X String **dest )
{
int i = 0;
if(*dest == (String*)NULL){
*dest = (String*)xcalloc(1,sizeof(String));
(*dest)->head = (*dest)->tail = (StringData*)NULL;
}
for(;i<strlen(str);++i){
add_char_to_string(str[i],dest);
}
return;
}
static char *copy_from_string
PROTO_N ( ( src ) )
PROTO_T ( String *src )
{
StringData *trav = src->head;
int str_size=0,element=0;
char * result;
while(trav){
++str_size;
trav = trav->next;
}
result = (char*)xcalloc(str_size+1,sizeof(char));
trav = src->head;
while(trav){
result[element] = trav->data;
trav = trav->next;
element ++;
}
return result;
}
static void free_string
PROTO_N ( ( str ) )
PROTO_T ( String **str )
{
StringData *trav = (*str)->head;
StringData *old;
while(trav){
old = trav;
trav = trav->next;
free(old);
}
free(*str);
return;
}
/*
accumulate strings for output. If the input is NULL then return
the current string and reset, otherwise return NULL.
*/
char * outass
PROTO_N ( ( str ) )
PROTO_T ( char *str )
{
static String *res;
char * tmp;
static int str_size = 0;
if(str){
str_size += strlen(str);
add_to_string(str,&res);
/*strcat(res,str);*/
return (char*)NULL;
}
str_size = 0;
if ( res == (String*)NULL ){
tmp = (char*)NULL;
}
else{
tmp = copy_from_string(res);
free_string(&res);
res = init_String();
}
/*strcpy(res,"");*/
return tmp;
}
#endif
/*
Increment the current instruction number and, if enough
instructions have been output, call the scheduler and reset
the count.
*/
#if DO_SCHEDULE
void add_instruction
PROTO_N ( ( ins ) )
PROTO_T ( Instruction ins )
{
process_instruction(ins);
++instruction_number;
if(instruction_number >= (instruction_block_size+schedule_leniency)){
instruction_number = 0;
schedule_block();
}
return;
}
Instruction_data get_new_ins_data
PROTO_Z ()
{
Instruction_data a;
a.text = (char*)NULL;
a.bindata = (char*)NULL;
return a;
}
#endif
/*
This function performs a load store operation.
*/
void load_store
PROTO_N ( ( ins,reg,a ) )
PROTO_T ( instruction ins X int reg X baseoff a )
{
char *reg_str,*base_reg_str;
char *ins_name = ins_symbolic_name(ins);
#if DO_SCHEDULE
char *outline = (char*)xcalloc(80,sizeof(char));
#endif
char *binasm_data;
#if DO_SCHEDULE
int mem_size = is_32bit_load_store(ins)?4:8+
(is_unaligned_access_instruction(ins)?UNALIGNED_ACCESS_SIZE_ADJUSTMENT
:0);
int offset = is_unaligned_access_instruction(ins)?
a.offset+UNALIGNED_ACCESS_OFFSET_ADJUSTMENT : a.offset;
#endif
int insid = ins_binid(ins);
#if DO_SCHEDULE
Instruction new_ins = get_new_instruction();
Instruction_data ins_dat = get_new_ins_data();
setclass(new_ins,ins_class(ins));
if(ins_equal(ins,i_ldgp)) {
setsets_pc(new_ins,true);
}
if(ins_class(ins) != class_store_data && ins_class(ins) != class_store_addr){
setsets(new_ins,reg,ins_class(ins));
}
else{
setuses(new_ins,reg,ins_class(ins));
}
if(ins_class(ins) == class_iarithmetic){
if(a.base>=0 && a.base <32){
setuses(new_ins,a.base,ins_class(ins));
}
if(a.base<0) setuses(new_ins,R29,ins_class(ins));
}
else{
if(a.base < 0){
if(ins_class(ins) == class_store_data){
setuses(new_ins,R29,class_store_addr);
setuses(new_ins,R28,ins_class(ins));
}
else{
setuses(new_ins,R29,ins_class(ins));
}
setindex_global(new_ins,-a.base-1);
setoffset_global(new_ins,offset);
setsize_global(new_ins,mem_size);
}
else if(a.base >31){
if(ins_class(ins) == class_store_data){
setuses(new_ins,R29,class_store_addr);
setuses(new_ins,R28,ins_class(ins));
}
else{
setuses(new_ins,R29,ins_class(ins));
}
setbase_label(new_ins,a.base);
setoffset_label(new_ins,offset);
setsize_label(new_ins,mem_size);
}
else{
setbase_stack(new_ins,a.base);
setoffset_stack(new_ins,offset);
setsize_stack(new_ins,mem_size);
}
}
#endif
reg_str=reg_name[reg];
if(a.base<0){
char *extname=main_globals[-a.base-1]->dec_u.dec_val.dec_id;
if(as_file){
if(a.offset==0){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s, %s\n",ins_name,reg_str,extname);
#else
(void)sprintf(outline,"\t%s\t%s, %s\n",ins_name,reg_str,extname);
set_instruction_text(ins_dat,outline);
#endif
}
else
if(a.offset>0){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s,%s+%ld\n",ins_name,reg_str,
extname,a.offset);
#else
(void)sprintf(outline,"\t%s\t%s,%s+%ld\n",ins_name,reg_str,
extname,a.offset);
set_instruction_text(ins_dat,outline);
#endif
}
else{
if(a.offset<0){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s,%s%ld\n",ins_name,reg_str,
extname, a.offset);
#else
(void)sprintf(outline,"\t%s\t%s,%s%ld\n",ins_name,reg_str,
extname, a.offset);
set_instruction_text(ins_dat,outline);
#endif
}
}
}
binasm_data = out_iinst(symnos[-a.base-1],insid,reg,xnoreg,FRA,0U,a.offset);
#if DO_SCHEDULE
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
(void)add_instruction(new_ins);
#endif
}
else{
if(a.base > 31) /* label */{
if(as_file){
if(a.offset==0){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s, $$%d\n",ins_name,reg_str,
a.base);
#else
(void)sprintf(outline,"\t%s\t%s, $$%d\n",ins_name,reg_str,
a.base);
set_instruction_text(ins_dat,outline);
#endif
}
else if(a.offset>0){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s, $$%d+%ld\n",ins_name,
reg_str,a.base,a.offset);
#else
(void)sprintf(outline,"\t%s\t%s, $$%d+%ld\n",ins_name,
reg_str,a.base,a.offset);
set_instruction_text(ins_dat,outline);
#endif
}
else if(a.offset<0){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s, $$%d-%ld\n",ins_name,
reg_str,a.base,a.offset);
#else
(void)sprintf(outline,"\t%s\t%s, $$%d-%ld\n",ins_name,
reg_str,a.base,a.offset);
set_instruction_text(ins_dat,outline);
#endif
}
}
binasm_data =
out_iinst(tempsnos[a.base-32],insid,reg,xnoreg,FROB,0,a.offset);
#if DO_SCHEDULE
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
(void)add_instruction(new_ins);
#endif
}
else{
#if DO_SCHEDULE
if(ins_class(ins) == class_store_data){
setuses(new_ins,a.base,class_store_addr);
}
else if(ins_class(ins) == class_load){
setuses(new_ins,a.base,ins_class(ins));
}
#endif
base_reg_str=reg_name[a.base];
if(as_file){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s, %ld(%s)\n",ins_name,
reg_str,a.offset,base_reg_str);
#else
(void)sprintf(outline,"\t%s\t%s, %ld(%s)\n",ins_name,
reg_str,a.offset,base_reg_str);
set_instruction_text(ins_dat,outline);
#endif
}
if(ins_equal(ins,i_lda) || ins_equal(ins,i_ldq)){
if((a.base == SP) || ((regexps[a.base].alignment == 8) &&
(a.offset%8 == 0))){
regexps[reg].alignment = 8;
}
else if((a.base == SP || regexps[a.base].alignment == 4) && (a.offset %4 == 0)){
regexps[reg].alignment = 4;
}
else{
regexps[reg].alignment = 0;
}
}
binasm_data = out_iinst(0,insid,reg,a.base,FROB,0,a.offset);
#if DO_SCHEDULE
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
(void)add_instruction(new_ins);
#endif
}
}
clear_reg(reg);
return;
}
void load_store_immediate
PROTO_N ( ( ins,reg,val ) )
PROTO_T ( instruction ins X int reg X INT64 val )
{
#if DO_SCHEDULE
Instruction new_ins = get_new_instruction();
Instruction_data ins_dat = get_new_ins_data();
char * outline = (char*)xcalloc(80,sizeof(char));
#endif
char * binasm_data;
#if DO_SCHEDULE
setclass(new_ins,ins_class(ins));
setsets(new_ins,reg,ins_class(ins));
#endif
if(as_file){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s,",ins_symbolic_name(ins),reg_name[reg]);
#else
(void)sprintf(outline,"\t%s\t%s,%d\n",ins_symbolic_name(ins),
reg_name[reg],val);
set_instruction_text(ins_dat,outline);
#endif
/*setdata(new_ins,outline);*/
#if !DO_SCHEDULE
out_INT64(val);
(void)outstring("\n");
#endif
}
binasm_data = out_biinst(0,ins_binid(ins),reg,xnoreg,FRI,0,val);
#if DO_SCHEDULE
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
add_instruction(new_ins);
#endif
clear_reg(reg);
}
void load_store_label
PROTO_N ( ( ins,reg,lab ) )
PROTO_T ( instruction ins X int reg X int lab )
{
#if DO_SCHEDULE
Instruction new_ins = get_new_instruction();
Instruction_data ins_dat = get_new_ins_data();
char *outline = (char*)xcalloc(80,sizeof(char));
#endif
char *binasm_data;
#if DO_SCHEDULE
setclass(new_ins,ins_class(ins));
if(ins_class(ins) == class_load){
setsets(new_ins,reg,ins_class(ins));
}
else{
setuses(new_ins,reg,ins_class(ins));
}
setlabel(new_ins,lab);
#endif
if(as_file){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s, $%d\n",ins_symbolic_name(ins),
reg_name[reg],lab);
#else
(void)sprintf(outline,"\t%s\t%s, $%d\n",ins_symbolic_name(ins),
reg_name[reg],lab);
set_instruction_text(ins_dat,outline);
#endif
/*setdata(new_ins,outline);*/
}
binasm_data = out_linst(-lab,ins_binid(ins),reg,xnoreg,FRL,0);
#if DO_SCHEDULE
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
add_instruction(new_ins);
#endif
return;
}
/*
These functions output assembler for integer control instructions
*/
void integer_branch
PROTO_N ( ( ins,reg,dest ) )
PROTO_T ( instruction ins X int reg X int dest )
{
#if DO_SCHEDULE
Instruction new_ins = get_new_instruction();
Instruction_data ins_dat = get_new_ins_data();
char *outline = (char*)xcalloc(80,sizeof(char));
#endif
char *binasm_data = (char*)xcalloc(binasm_record_length+1,sizeof(char));
#if DO_SCHEDULE
setclass(new_ins,ins_class(ins));
if(ins_equal(ins,i_br)){
setsets(new_ins,reg,ins_class(ins));
}
else{
setuses(new_ins,reg,ins_class(ins));
}
setsets_pc(new_ins,true);
setlabel(new_ins,dest);
#endif
if(as_file){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s,$%d\n",ins_symbolic_name(ins),
reg_name[reg],dest);
#else
(void)sprintf(outline,"\t%s\t%s,$%d\n",ins_symbolic_name(ins),
reg_name[reg],dest);
set_instruction_text(ins_dat,outline);
#endif
}
binasm_data = out_linst(-dest,ins_binid(ins),reg,xnoreg,FRL,0);
#if DO_SCHEDULE
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
add_instruction(new_ins);
#endif
return;
}
void integer_jump
PROTO_N ( ( ins,dest_reg,source_reg,hint ) )
PROTO_T ( instruction ins X int dest_reg X int source_reg X int hint )
{
#if DO_SCHEDULE
Instruction new_ins = get_new_instruction();
Instruction_data ins_dat = get_new_ins_data();
char *outline = (char*)xcalloc(80,sizeof(char));
#endif
char *binasm_data;
#if DO_SCHEDULE
setclass(new_ins,ins_class(ins));
setsets(new_ins,dest_reg,ins_class(ins));
setuses(new_ins,source_reg,ins_class(ins));
setsets_pc(new_ins,true);
#endif
if(as_file){
if(hint<0){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s,(%s),$%d\n",
ins_symbolic_name(ins),reg_name[dest_reg],
reg_name[source_reg],-hint);
#else
(void)sprintf(outline,"\t%s\t%s,(%s),$%d\n",
ins_symbolic_name(ins),reg_name[dest_reg],
reg_name[source_reg],-hint);
#endif
}
else{
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s,(%s),%d\n",ins_symbolic_name(ins),
reg_name[dest_reg],reg_name[source_reg],hint);
#else
(void)sprintf(outline,"\t%s\t%s,(%s),%d\n",ins_symbolic_name(ins),
reg_name[dest_reg],reg_name[source_reg],hint);
#endif
}
}
binasm_data = out_iinst(0,ins_binid(ins),dest_reg,source_reg,FRR,0,hint);
#if DO_SCHEDULE
set_instruction_text(ins_dat,outline);
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
process_instruction(new_ins);
schedule_block();
instruction_number = 0;
#endif
return;
}
void integer_jump_fn
PROTO_N ( ( ins,ra,fn,sp ) )
PROTO_T ( instruction ins X int ra X exp fn X space sp )
{
baseoff b = boff(fn);
if(b.base<0) {
integer_jump_external(ins,ra,b);
}
else {
int rt;
if(ra != AT) {
rt = AT;
}
else {
rt = getreg(sp.fixed & 0x03f0000);/*leaves out parameter registers*/
}
rt = reg_operand(fn,sp);
operate_fmt(i_bis,rt,rt,PV);
integer_jump(i_jsr,26,rt,0);
}
return;
}
void integer_jump_external
PROTO_N ( ( ins,ra,b ) )
PROTO_T ( instruction ins X int ra X baseoff b )
{
char *extname = main_globals[-b.base-1]->dec_u.dec_val.dec_id;
char *binasm_data;
#if DO_SCHEDULE
char *outline = (char*)xcalloc(80,sizeof(char));
Instruction new_ins = get_new_instruction();
Instruction_data ins_dat = get_new_ins_data();
setclass(new_ins,ins_class(ins));
setsets(new_ins,ra,ins_class(ins));
setsets_pc(new_ins,true);
if(b.base < 0){
/* setindex_global(new_ins,-b.base-1);*/
/* setoffset_global(new_ins,b.offset);
setsize_global(new_ins,4);*/
}
else if (b.base>31){
/* setbase_label(new_ins,b.base);
setoffset_label(new_ins,b.offset);
setsize_label(new_ins,4);*/
}
else{
setbase_stack(new_ins,b.base);
setoffset_stack(new_ins,b.offset);
setsize_stack(new_ins,4);
}
#endif
clear_all();
andpeep=0;
if(as_file){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s,%s\n",ins_symbolic_name(ins),
reg_name[ra],extname);
#else
(void)sprintf(outline,"\t%s\t%s,%s\n",ins_symbolic_name(ins),
reg_name[ra],extname);
set_instruction_text(ins_dat,outline);
#endif
}
binasm_data = out_iinst(symnos[-b.base-1],ins_binid(ins),ra,xnoreg,FRR,0,0);
#if DO_SCHEDULE
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
add_instruction(new_ins);
#endif
return;
}
/*
3 register operations : instr $src1, [$src2|#src2], dest.
integer arithmetic, logic and shift, byte manipulation.
*/
void operate_fmt
PROTO_N ( ( ins,src1,src2,dest ) )
PROTO_T ( instruction ins X int src1 X int src2 X int dest )
{
char *binasm_data;
#if DO_SCHEDULE
char *outline = (char*)xcalloc(80,sizeof(char));
Instruction new_ins = get_new_instruction();
Instruction_data ins_dat = get_new_ins_data();
setclass(new_ins,ins_class(ins));
setsets(new_ins,dest,ins_class(ins));
setuses(new_ins,src1,ins_class(ins));
if(src1 != src2){
setuses(new_ins,src2,ins_class(ins));
}
if(ins_class(ins) == class_subroutine){
setuses(new_ins,R28,ins_class(ins));
setuses(new_ins,R28,ins_class(ins));
setsets_pc(new_ins,true);
}
#endif
if(dest!=NO_REG){
if(as_file){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s,%s,%s\n",ins_symbolic_name(ins),
reg_name[src1],reg_name[src2],reg_name[dest]);
#else
(void)sprintf(outline,"\t%s\t%s,%s,%s\n",ins_symbolic_name(ins),
reg_name[src1],reg_name[src2],reg_name[dest]);
#endif
}
clear_reg(dest);
binasm_data = out_rinst(0,ins_binid(ins),src1,src2,FRRR,dest);
#if DO_SCHEDULE
set_instruction_text(ins_dat,outline);
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
add_instruction(new_ins);
#endif
}
return;
}
/*
Output an operation where the second paramter is an immediate
value. If the immediate value is larger than 8 bits then it
needs to be loaded into a register
*/
void operate_fmt_immediate
PROTO_N ( ( ins,src1,src2,dest ) )
PROTO_T ( instruction ins X int src1 X int src2 X int dest )
{
char *binasm_data;
#if DO_SCHEDULE
char *outline = (char*)xcalloc(40,sizeof(char));
Instruction new_ins = get_new_instruction();
Instruction_data ins_dat = get_new_ins_data();
setclass(new_ins,ins_class(ins));
setsets(new_ins,(Register)dest,ins_class(ins));
setuses(new_ins,(Register)src1,ins_class(ins));
if(ins_class(ins) == class_subroutine){
setuses(new_ins,R28,ins_class(ins));
setsets_pc(new_ins,true);
}
#endif
if(abs(src2) > 255){
bool block_status = in_noat_block;
if (!block_status) setnoat();
if(src2<0) {
load_store_immediate(i_ldiq,AT,make_INT64(-1,(unsigned)src2));
}
else {
load_store_immediate(i_ldiq,AT,make_INT64(0,(unsigned)src2));
}
operate_fmt(ins,src1,AT,dest);
if (!block_status) setat();
return ;
}
if(dest!=NO_REG){
if(as_file){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s,%d,%s\n",ins_symbolic_name(ins),
reg_name[src1],src2,reg_name[dest]);
#else
(void)sprintf(outline,"\t%s\t%s,%d,%s\n",ins_symbolic_name(ins),
reg_name[src1],src2,reg_name[dest]);
#endif
}
clear_reg(dest);
binasm_data = out_iinst(0,ins_binid(ins),src1,dest,FRIR,0,src2);
#if DO_SCHEDULE
set_instruction_text(ins_dat,outline);
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
add_instruction(new_ins);
#endif
}
return;
}
void operate_fmt_big_immediate
PROTO_N ( ( ins,src1,src2,dest ) )
PROTO_T ( instruction ins X int src1 X INT64 src2 X int dest )
{
char * binasm_data;
#if DO_SCHEDULE
char * outline = (char*)xcalloc(80,sizeof(char));
Instruction new_ins = get_new_instruction();
Instruction_data ins_dat = get_new_ins_data();
setclass(new_ins,ins_class(ins));
setsets(new_ins,dest,ins_class(ins));
setuses(new_ins,src1,ins_class(ins));
#endif
if(as_file){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t%s,",ins_symbolic_name(ins),reg_name[src1]);
out_INT64(src2);
(void)fprintf(as_file,",%s\n",reg_name[dest]);
#else
(void)sprintf(outline,"\t%s\t%s,%d,%s\n",ins_symbolic_name(ins),
reg_name[src1],src2,reg_name[dest]);
#endif
}
clear_reg(dest);
binasm_data = out_biinst(0,ins_binid(ins),src1,dest,FRIR,0,src2);
#if DO_SCHEDULE
set_instruction_text(ins_dat,outline);
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
/*setdata(new_ins,outline);*/
add_instruction(new_ins);
#endif
return;
}
/*
floating point load/store
*/
void float_load_store
PROTO_N ( ( ins,reg,a ) )
PROTO_T ( instruction ins X int reg X baseoff a )
{
char * ins_name = ins_symbolic_name(ins);
char * binasm_data;
int ins_id = ins_binid(ins);
#if DO_SCHEDULE
char * outline = (char*)xcalloc(80,sizeof(char));
Instruction new_ins = get_new_instruction();
Instruction_data ins_dat = get_new_ins_data();
setclass(new_ins,ins_class(ins));
if(ins_class(ins) == class_fload){
setsets(new_ins,reg+float_register,ins_class(ins));
}
else{
setuses(new_ins,reg+float_register,ins_class(ins));
}
if(a.base < 0){
setoffset_global(new_ins,a.offset);
setsize_global(new_ins,is_32bit_fload_fstore(ins)?4:8);
setuses(new_ins,AT,ins_class(ins));
}
else if(a.base > 31){
setbase_label(new_ins,a.base);
setoffset_label(new_ins,a.offset);
setsize_label(new_ins,is_32bit_fload_fstore(ins)?4:8);
setuses(new_ins,AT,ins_class(ins));
}
else{
setbase_stack(new_ins,a.base);
setoffset_stack(new_ins,a.offset);
setsize_stack(new_ins,is_32bit_fload_fstore(ins)?4:8);
}
#endif
if(a.base>=0 && a.base <=31){
char *basereg=reg_name[a.base];
#if DO_SCHEDULE
if(ins_class(ins) == class_fstore_data){
setuses(new_ins,a.base,class_fstore_addr);
}
else{
setuses(new_ins,a.base,ins_class(ins));
}
#endif
if(as_file){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t$f%d,%ld(%s)\n",ins_name,reg,a.offset,
basereg);
#else
(void)sprintf(outline,"\t%s\t$f%d,%ld(%s)\n",ins_name,reg,a.offset,
basereg);
#endif
}
binasm_data=out_iinst(0,ins_id,reg+float_register,a.base,FROB,0,a.offset);
}
else
if(a.base<0){
char *extname = main_globals[-a.base-1]->dec_u.dec_val.dec_id;
if(as_file){
if(a.offset==0){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t$f%d, %s\n",ins_name,reg,extname);
#else
(void)sprintf(outline,"\t%s\t$f%d, %s\n",ins_name,reg,extname);
#endif
}
else{
if(a.offset<0){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t$f%d, %s%ld\n",ins_name,reg,
extname,a.offset);
#else
(void)sprintf(outline,"\t%s\t$f%d, %s%ld\n",ins_name,reg,
extname,a.offset);
#endif
}
else{
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t$f%d, %s+%ld\n",ins_name,reg,
extname,a.offset);
#else
(void)sprintf(outline,"\t%s\t$f%d, %s+%ld\n",ins_name,reg,
extname,a.offset);
#endif
}
}
}
binasm_data =
out_iinst(symnos[-a.base-1],ins_id,reg+float_register,xnoreg,FROB,0,
a.offset);
}
else{
if(as_file){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t$f%d, $$%d\n",ins_name,reg,a.base);
#else
(void)sprintf(outline,"\t%s\t$f%d, $$%d\n",ins_name,reg,a.base);
#endif
}
binasm_data =
out_iinst(tempsnos[a.base-32],ins_id,reg+float_register,xnoreg,FROB,
0,0);
}
#if DO_SCHEDULE
set_instruction_text(ins_dat,outline);
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
add_instruction(new_ins);
#endif
clear_reg(reg);
return;
}
/*
floating point constants are passed as strings, with the
formatting being done elsewhere.
*/
void float_load_store_immediate
PROTO_N ( ( ins,reg,val ) )
PROTO_T ( instruction ins X int reg X char* val )
{
#if DO_SCHEDULE
char *outline = (char*)xcalloc(80,sizeof(char));
Instruction new_ins = get_new_instruction();
setclass(new_ins,ins_class(ins));
setsets(new_ins,reg+float_register,ins_class(ins));
#endif
if(as_file){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t$f%d,%s\n",ins_symbolic_name(ins),reg,val);
#else
(void)sprintf(outline,"\t%s\t$f%d,%s\n",ins_symbolic_name(ins),reg,val);
#endif
}
#if DO_SCHEDULE
add_instruction(new_ins);
#endif
return;
}
/*
floating point branch
*/
void float_branch
PROTO_N ( ( ins,reg,dest ) )
PROTO_T ( instruction ins X int reg X int dest )
{
char * binasm_data;
#if DO_SCHEDULE
char *outline = (char*)xcalloc(80,sizeof(char));
Instruction new_ins = get_new_instruction();
Instruction_data ins_dat = get_new_ins_data();
setclass(new_ins,ins_class(ins));
setsets_pc(new_ins,true);
setlabel(new_ins,dest);
setuses(new_ins,reg+float_register,ins_class(ins));
#endif
if(as_file){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t$f%d,$%d\n",ins_symbolic_name(ins),reg,
dest);
#else
(void)sprintf(outline,"\t%s\t$f%d,$%d\n",ins_symbolic_name(ins),reg,
dest);
#endif
}
binasm_data=out_linst(-dest,ins_binid(ins),reg+float_register,xnoreg,FRL,0);
#if DO_SCHEDULE
set_instruction_text(ins_dat,outline);
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
add_instruction(new_ins);
#endif
return;
}
/*
floating point operations (except conversions).
*/
void float_op
PROTO_N ( ( ins,src1,src2,dest ) )
PROTO_T ( instruction ins X int src1 X int src2 X int dest )
{
char * binasm_data;
bool special_trap_ins = FALSE;
instruction real_ins = trap_all_fops?trap_ins(ins,&special_trap_ins):ins;
#if DO_SCHEDULE
char *outline = (char*)xcalloc(80,sizeof(char));
Instruction new_ins = get_new_instruction();
Instruction_data ins_dat = get_new_ins_data();
setclass(new_ins,ins_class(real_ins));
setsets(new_ins,dest+float_register,ins_class(real_ins));
setuses(new_ins,src1+float_register,ins_class(real_ins));
if(src1 != src2){
setuses(new_ins,src2+float_register,ins_class(real_ins));
}
#endif
if(special_trap_ins) no_parameter_instructions(i_trapb);
if(as_file){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t$f%d,$f%d,$f%d\n",
ins_symbolic_name(real_ins),src1,src2,dest);
#else
(void)sprintf(outline,"\t%s\t$f%d,$f%d,$f%d\n",
ins_symbolic_name(real_ins),src1,src2,dest);
#endif
}
binasm_data = out_rinst(0,ins_binid(real_ins),src1+float_register,
src2+float_register,FRRR,dest+float_register);
if(special_trap_ins) no_parameter_instructions(i_trapb);
clear_freg(dest);
#if DO_SCHEDULE
set_instruction_text(ins_dat,outline);
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
add_instruction(new_ins);
#endif
return;
}
#if 0
void float_op_immediate
PROTO_N ( ( ins,src1,imm,dest ) )
PROTO_T ( instruction ins X int src1 X double imm X int dest )
{
Instruction new_ins = get_new_instruction();
char *outline = (char*)xcalloc(80,sizeof(char));
setclass(new_ins,ins_class(ins));
setsets(new_ins,dest+float_register,ins_class(ins));
setuses(new_ins,src1+float_register,ins_class(ins));
if(as_file){
(void)fprintf(as_file,"\t%s\t$f%d,%lf,$f%d\n",ins_symbolic_name(ins),
src1,imm,dest);
(void)sprintf(outline,"\t%s\t$f%d,%lf,$f%d\n",ins_symbolic_name(ins),
src1,imm,dest);
}
clear_freg(dest);
setdata(new_ins,outline);
add_instruction(new_ins);
return;
}
#endif
/*
floating point conversions.
*/
void float_convert
PROTO_N ( ( ins,src,dest ) )
PROTO_T ( instruction ins X int src X int dest )
{
char * binasm_data;
#if DO_SCHEDULE
char *outline = (char*)xcalloc(80,sizeof(char));
Instruction new_ins = get_new_instruction();
Instruction_data ins_dat = get_new_ins_data();
setclass(new_ins,ins_class(ins));
setsets(new_ins,dest+float_register,ins_class(ins));
setuses(new_ins,src+float_register,ins_class(ins));
#endif
if(as_file){
#if !DO_SCHEDULE
(void)fprintf(as_file,"\t%s\t$f%d,$f%d\n",ins_symbolic_name(ins),src,
dest);
#else
(void)sprintf(outline,"\t%s\t$f%d,$f%d\n",ins_symbolic_name(ins),src,
dest);
#endif
}
binasm_data = out_rinst(0,ins_binid(ins),src+float_register,
dest+float_register,FRR,xnoreg);
#if DO_SCHEDULE
set_instruction_text(ins_dat,outline);
set_instruction_binasm(ins_dat,binasm_data);
setdata(new_ins,ins_dat);
add_instruction(new_ins);
#endif
return;
}
/*
miscellaneous instructions
*/
void call_pal
PROTO_N ( ( ins,pal_ins ) )
PROTO_T ( instruction ins X instruction pal_ins )
{
if(as_file){
(void)fprintf(as_file,"\t%s\t%s\n",ins_symbolic_name(ins),
ins_symbolic_name(pal_ins));
}
return;
}
void fetch
PROTO_N ( ( ins,a ) )
PROTO_T ( instruction ins X baseoff a )
{
#if DO_SCHEDULE
Instruction new_ins = get_new_instruction();
setclass(new_ins,ins_class(ins));
setuses(new_ins,a.base,ins_class(ins));
#endif
/* setmemory_base(new_ins,a.base);
setmemory_offset(new_ins,a.offset);*/
if(a.offset!=0)
failer("fetch offset must be zero");
if(as_file){
(void)fprintf(as_file,"\t%s\t%ld($%d)\n",ins_symbolic_name(ins),
a.offset,a.base);
}
#if DO_SCHEDULE
add_instruction(new_ins);
#endif
return;
}
void no_parameter_instructions
PROTO_N ( ( ins ) )
PROTO_T ( instruction ins )
{
#if DO_SCHEDULE
Instruction new_ins = get_new_instruction();
Instruction_data ins_data = get_new_ins_data();
char * outline = (char*)xcalloc(strlen(ins_symbolic_name((ins)))+1,sizeof(char));
char * binasm_data;
setclass(new_ins,ins_class(ins));
#endif
if(as_file){
(void)fprintf(as_file,"\t%s\n",ins_symbolic_name(ins));
#if DO_SCHEDULE
(void)sprintf(outline,"\t%s\n",ins_symbolic_name(ins));
set_instruction_text(ins_data,outline);
#endif
}
#if DO_SCHEDULE
binasm_data = out_rinst(0,ins_binid(ins),xnoreg,xnoreg,xnoreg,xnoreg);
set_instruction_binasm(ins_data,binasm_data);
setdata(new_ins,ins_data);
add_instruction(new_ins);
#else
(void)out_rinst(0,ins_binid(ins),xnoreg,xnoreg,xnoreg,xnoreg);
#endif
return;
}
#if DO_SCHEDULE
static void out_as_string
PROTO_N ( ( fp,str ) )
PROTO_T ( FILE *fp X char *str )
{
int i;
int slen = strlen(str);
for(i=0;i<strlen(str);++i){
outchar(str[i]);
}
return;
}
#endif
#if DO_SCHEDULE
void out_code
PROTO_N ( ( ins_data ) )
PROTO_T ( Instruction_data ins_data )
{
int i;
char * bdata = instruction_binasm(ins_data);
if(as_file && instruction_text(ins_data)){
out_as_string(as_file,instruction_text(ins_data));
/* fprintf(as_file,instruction_text(ins_data));*/
}
for(i=0;i<binasm_record_length;++i){
putc(bdata[i],ba_file);
}
/*(void)out_one(instruction_binasm(ins_data));*/
return;
}
#endif