This is out-dsp56k.c in view mode; [Download] [Up]
/*
GCC56K -- GCC 1.40 machine description for DSP56000/1 processor
Copyright (C) 1991 Andrew Sterian and Bell-Northern Research
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the GCC distribution; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Contact the author at 'asterian@bnr.ca' or post to the 'comp.dsp'
newsgroup.
*/
#include <stdio.h>
#include <ctype.h>
#include "tree.h"
#include "flags.h"
void print_operand_address(FILE *, rtx, int);
void extendReg(rtx op);
static int regValid[FIRST_PSEUDO_REGISTER];
int
hard_regno_mode_ok(int regnum, enum machine_mode mode)
{
if ((mode == DFmode) || (mode == DImode)) {
switch(regnum) {
case 0: /* X1 */
case 2: /* Y1 */
case 5: /* A1 */
case 8: /* B1 */
return 1; /* All of the above are OK */
default:
return 0;
}
}
/* Ensure A2, B2 don't get allocated */
if ((regnum==4) || (regnum==7))
return 0;
/* A0, B0, and AGU registers can't hold SFmode or SImode */
if ((mode == SFmode) || (mode == SImode)) {
if ((regnum >= 10) && (regnum <= 26))
return 0;
if ((regnum == 6) || (regnum == 9))
return 0;
return 1;
}
if ((mode == QImode) || (mode == VOIDmode) || (mode == HImode)) {
return 1; /* All regs OK */
}
error("aux-output: Mode %u unknown",mode);
return 0; /* No other modes accepted */
}
int
regno_reg_class(int regnum)
{
switch (regnum) {
case 0: case 2: /* X1, Y1 */
return ALU_DATA_REGS1;
case 1: case 3: /* X0, Y0 */
return ALU_DATA_REGS0;
/* A0 and B0 have to be included because of address arithmetic */
/* e.g. (set (reg:HI 8) (subreg:HI (reg:DI 5) 1)) */
/* transforms into (set (reg:HI 8) (reg:HI 6)) */
case 5: case 8: /* A1, B1 */
return ACC_REGS_HI;
case 6: case 9: /* A0, B0 */
return ACC_REGS_LO;
case 10: case 11: case 12: case 13: /* R0..R7 */
case 14: case 15: case 16: case 17:
return ADDRESS_REGS;
case 18: case 19: case 20: case 21: /* N0..N7 */
case 22: case 23: case 24: case 25:
return INDEX_REGS;
default: /* A2, B2, Possibly pseudo-regs */
return NO_REGS;
}
}
int
reg_class_from_letter(int c)
{
/* May not use the letters m o < > r i n I J K F G H s g p */
switch(c) {
case 'A': /* A1, A0, B1, B0, X1, X0, Y1, Y0 */
return ALU_REGS;
case 'C': /* A1, B1, X1, X0, Y1, Y0 */
return MATHOP_REGS;
case 'a': /* R0..R7 */
return ADDRESS_REGS;
case 'd': /* X1, X0, Y1, Y0 */
return ALU_DATA_REGS;
/* Used for multiply instructions where mpy X1,X1,A is illegal */
case 'e': /* X0, Y0 */
return ALU_DATA_REGS0;
/* Not used */
case 'x': /* N0..N7 */
return INDEX_REGS;
case 'l': /* A1, B1 */
return ACC_REGS_HI;
case 'u': /* A1, A0, B1, B0 */
return ACC_REGS;
default:
return NO_REGS;
}
}
void
function_prologue(FILE *file, int size)
{
int i;
fprintf(file,"\tmove R0,%c:-(R6)\n",StackSpace);
fprintf(file,"\tmove SSH,%c:-(R6)\n",StackSpace);
if (size > 1)
fprintf(file,"\tmove #%u,N6\n",size);
fprintf(file,"\tlua (R6)-,R0\n");
if (size > 1)
fprintf(file,"\tmove (R6)-N6\n");
else if (size == 1)
fprintf(file,"\tmove (R6)-\n");
for (i=10; i<26; i++) {
if (regs_ever_live[i] && !call_used_regs[i]) {
fprintf(file,"\tmove %s,%c:-(R6)\n",reg_names[i],StackSpace);
}
}
}
void
function_epilogue(FILE *file, int size)
{
int i;
int any_regs_used=0;
for (i=10; i<26; i++) {
if (regs_ever_live[i] && !call_used_regs[i]) {
any_regs_used = 1;
break;
}
}
if ((size > 1) && any_regs_used)
fprintf(file, "\tmove #%u,N0\n",size);
fprintf(file, "\tlua (R0)+,R6\n");
if (any_regs_used) {
if (size > 1)
fprintf(file, "\tmove (R0)-N0\n");
else if (size == 1)
fprintf(file, "\tmove (R0)-\n");
for (i=10; i<26; i++) {
if (regs_ever_live[i] && !call_used_regs[i]) {
fprintf(file,"\tmove %c:(R0)-,%s\n", StackSpace, reg_names[i]);
}
}
} else {
fprintf(file,"\tnop\n");
}
fprintf(file,"\tmove %c:(R6)+,SSH\n", StackSpace);
fprintf(file,"\tmove %c:(R6)+,R0\n", StackSpace);
fprintf(file,"\trts\n");
}
/*
* Codes:
* w -- For A and B, output A1 and B1 (or A10, B10)
* x -- lower part of 48-bit DFmode or DImode value (X0 instead of X)
* or Y: part of a long-mode memory reference
* y -- upper part of 48-bit DFmode or DImode value (X1 instead of X)
* or X: part of a long-mode memory reference
* z -- Extension part of 56-bit reg. (A2 instead of A)
* p -- Address or (Reg)+ -- first word of a DI/DF mode
* q -- Address+1 of (Reg)- -- second word of a DI/DF mode
* r -- Don't output size information
* s -- Destination is N-register (different from GCC5616)
* Z -- Don't output memory space
*/
void
print_operand(FILE *filePtr, rtx operand, int code)
{
enum machine_mode mode=GET_MODE(operand);
char *p;
int c;
int outval;
int modeIsLong, modeIsInt, isAcc;
rtx memop;
modeIsLong = ((mode==DFmode) || (mode==DImode));
modeIsInt = ((mode==QImode) || (mode==HImode) || (mode==SImode));
switch(GET_CODE(operand)) {
case REG:
p = reg_names[REGNO(operand)];
c = *p;
isAcc = ((REGNO(operand)==5) || (REGNO(operand)==8));
if (REGNO(operand)==6) {
fprintf(filePtr,"A0");
} else if (REGNO(operand)==9) {
fprintf(filePtr,"B0");
} else if ((mode==DImode) && isAcc && (code == 'w')) {
fprintf(filePtr,"%c10",c);
} else if (code=='x') {
fprintf(filePtr,"%c0",c);
} else if (code=='y') {
fprintf(filePtr,"%c1",c);
} else if ((code=='z') && isAcc) {
fprintf(filePtr,"%c2",c);
} else if (modeIsLong) {
fprintf(filePtr,"%c",c);
} else if (isAcc) {
/* Changed from 'if (modeIsInt && code=='w')' */
/* 21Oct91 */
if (code=='w')
fprintf(filePtr,"%c1",c);
else
fprintf(filePtr,"%c",c);
} else {
fprintf(filePtr, "%s", p);
}
break;
case MEM:
memop = XEXP(operand,0);
if (code != 'Z') {
/* If this a reference to R0 or R6, use StackSpace */
do { int memcode=GET_CODE(memop);
if (modeIsLong && !TARGET_NOLSPACE) {
if (code=='x')
fprintf(filePtr,"Y:");
else if (code=='y')
fprintf(filePtr,"X:");
else
fprintf(filePtr,"L:"); break;
}
if ((memcode==REG) || (memcode==PRE_DEC) ||
(memcode==POST_INC) || (memcode==POST_DEC)) {
if ((REGNO(memop) == 10) || (REGNO(memop)==16)) {
fprintf(filePtr,"%c:",StackSpace); break;
}
}
if (memcode==PLUS) {
rtx opB=XEXP(memop, 0);
rtx opIx=XEXP(memop, 1);
if (GET_CODE(opIx)==REG && REGNO(opIx)>=10) {
opB=opIx; opIx=XEXP(memop, 0);
}
if ((REGNO(opB) == 10) || (REGNO(opB)==16)) {
fprintf(filePtr,"%c:",StackSpace); break;
}
}
fprintf(filePtr,"%c:", DataSpace);
} while(0);
}
print_operand_address(filePtr, memop, code);
break;
case CONST_INT:
outval = INTVAL(operand);
if (code=='s') {
if (outval & 0xFFFFFF00)
p = "#%d";
else
p = "#<%d";
if (!(outval & 0x80000000))
outval &= 0xFFFF;
else
outval |= 0x7FFF0000;
} else {
outval &= 0xFFFFFF;
if (mode == HImode) outval &= 0xFFFF;
if (mode == QImode) outval &= 0xFFFF;
if (code=='r')
p = "#$%X";
else
if (! (outval & 0xFFFF) ) {
p = "#<$%X";
outval >>= 16;
} else
p = "#>$%X";
}
fprintf(filePtr, p, outval);
break;
case CONST_DOUBLE:
putc('#', filePtr);
output_addr_const(filePtr, operand);
break;
case LABEL_REF:
case CONST:
fprintf(filePtr, "#>");
output_addr_const(filePtr, operand);
break;
case SYMBOL_REF:
p = XSTR(operand,0);
fprintf(filePtr, "#>");
assemble_name(filePtr, p);
break;
default:
fprintf(stderr,"%s:%u Unknown code %s:%u\n",__FILE__,__LINE__,
rtx_name[GET_CODE(operand)], GET_MODE(operand));
/* fall-through */
case CODE_LABEL:
output_addr_const(filePtr, operand);
break;
}
}
extern FILE *asm_out_file;
void
output_preloadN(rtx operand)
{
rtx op0,op1;
if (GET_CODE(operand) != MEM) return;
operand = XEXP(operand,0);
if (GET_CODE(operand) != PLUS) return;
op0=XEXP(operand,0); op1=XEXP(operand,1);
if (GET_CODE(op1)==REG && REGNO(op1)>=10) {
op1=op0; op0=XEXP(operand,1);
}
fprintf(asm_out_file,"\tmove ");
print_operand(asm_out_file, op1, 's');
fprintf(asm_out_file,",N%u\n",REGNO(op0)-10);
}
void
print_operand_address(FILE *filePtr, rtx operand, int code)
{
char *p;
int digit;
int opval;
rtx op0,op1;
switch(GET_CODE(operand)) {
case REG:
p = reg_names[REGNO(operand)];
digit = *(p+1);
switch(code) {
case 'p':
fprintf(filePtr, "(%s)+", p);
break;
case 'q':
fprintf(filePtr, "(%s)-", p);
break;
default:
fprintf(filePtr, "(%s)", p);
}
break;
case PRE_DEC:
p = reg_names[REGNO(XEXP(operand,0))];
fprintf(filePtr, "-(%s)", p);
break;
case POST_DEC:
p = reg_names[REGNO(XEXP(operand,0))];
fprintf(filePtr, "(%s)-", p);
break;
case POST_INC:
p = reg_names[REGNO(XEXP(operand,0))];
fprintf(filePtr, "(%s)+", p);
break;
case PLUS:
op0=XEXP(operand,0); op1=XEXP(operand,1);
if (GET_CODE(op1)==REG && REGNO(op1)>=10) {
op0=op1; op1=XEXP(operand,0);
}
p = reg_names[REGNO(op0)];
digit = *(p+1);
fprintf(filePtr, "(%s+N%c)", p, digit);
break;
case SYMBOL_REF:
p = XSTR(operand, 0);
assemble_name(filePtr, p);
if (code=='q') fprintf(filePtr, "+1");
break;
case CONST_INT:
opval = INTVAL(operand) & 0xFFFF;
if (code=='q') opval++;
if (opval < 256)
p = "<$%X";
else
p = ">$%X";
fprintf(filePtr, p, opval);
break;
case CONST:
output_addr_const(filePtr, operand);
if (code=='q') fprintf(filePtr, "+1");
break;
default:
fprintf(filePtr, "%s:%u Unknown code %u", __FILE__, __LINE__,
GET_CODE(operand));
break;
}
}
/* Sometime in the future */
int
legitimize_address(rtx x, rtx oldx, enum machine_mode mode)
{
return 0;
}
void
select_rtx_section(enum machine_mode mode, rtx exp)
{
switch(mode) {
case DFmode: case DImode:
if (!TARGET_NOLSPACE) {
l_const_section();
break;
}
/* else fall-through */
case QImode: case HImode: case SImode: case SFmode:
case BLKmode:
if (TARGET_DATAX)
x_const_section();
else
y_const_section();
break;
default:
error("%s:%c Don't know how to handle mode %s\n",__FILE__,__LINE__,
GET_MODE_NAME(mode));
}
}
/* Given a tree which is a VAR_DECL, find the largest element in the */
/* type of the tree. Since sizes are either 1 or 2, stop whenever */
/* we've found something of size 2. This means that the data */
/* structure will reside in L-space. If all elements of the structure */
/* are of size 1, the structure will reside in DataSpace */
int
find_longest_field(tree x)
{
int code = TREE_CODE(x);
if (!x) return 0;
while ((code==RECORD_TYPE) || (code==UNION_TYPE) || (code==ARRAY_TYPE) ||
(code==FIELD_DECL)) {
if (code==ARRAY_TYPE) {
x = TREE_TYPE(x);
code = TREE_CODE(x);
continue;
}
if (code==FIELD_DECL) {
if (find_longest_field(TREE_TYPE(x))) {
return 1;
} else {
x = TREE_CHAIN(x);
if (!x) return 0;
code = TREE_CODE(x);
continue;
}
}
return find_longest_field(TYPE_FIELDS(x));
}
switch(code) {
case INTEGER_TYPE:
return (DECL_MODE(x) == DImode);
case REAL_TYPE:
return (DECL_MODE(x) == DFmode);
case ENUMERAL_TYPE: case POINTER_TYPE:
return 0;
default:
fprintf(stderr,"%s:%u Unknown type\n",__FILE__,__LINE__);
debug_tree(x);
return 1;
}
}
void
select_section(tree x)
{
unsigned char code=TREE_CODE(x);
enum machine_mode mode=DECL_MODE(x);
int constant = 0;
int longtype = -1;
switch(code) {
case STRING_CST:
if (flag_writable_strings) {
if (TARGET_DATAX)
x_data_section();
else
y_data_section();
} else {
if (TARGET_DATAX)
x_const_section();
else
y_const_section();
}
break;
case INTEGER_CST:
case REAL_CST:
mode = DECL_MODE(TREE_TYPE(x));
switch(mode) {
case DFmode: case DImode:
if (!TARGET_NOLSPACE) {
l_const_section();
break;
}
/* else fall-through */
case QImode: case HImode: case SImode: case SFmode:
case BLKmode:
if (TARGET_DATAX)
x_const_section();
else
y_const_section();
break;
default:
fprintf(stderr,"%s:%u Unknown mode %d/%s\n",__FILE__,__LINE__,
mode,GET_MODE_NAME(mode));
debug_tree(x);
break;
}
break;
case VAR_DECL:
/* No storage allocated for external references */
if (TREE_EXTERNAL(x)) return;
if (TREE_STATIC(x) && TREE_READONLY(x)) constant=1;
if (TARGET_NOLSPACE)
longtype = 0;
else
longtype = find_longest_field(TREE_TYPE(x));
if (constant)
if (longtype)
l_const_section();
else if (TARGET_DATAX)
x_const_section();
else
y_const_section();
else
if (longtype)
l_data_section();
else if (TARGET_DATAX)
x_data_section();
else
y_data_section();
break;
default:
fprintf(stderr,"%s:%u Unknown code %u\n",__FILE__,__LINE__,code);
debug_tree(x);
break;
}
}
typedef union { double d; int i[2]; } float_u;
double ints_to_double(rtx op)
{
float_u u;
u.i[0] = CONST_DOUBLE_LOW(op);
u.i[1] = CONST_DOUBLE_HIGH(op);
return u.d;
}
int
const_double_to_SF(rtx op, int *intVal)
{
register int i, outval;
double inval, mask;
inval = ints_to_double(op);
if ((inval < -1.0) || (inval >= 1.0)) return 0;
outval = 0;
if (inval < 0) {
outval = 1;
inval += 1.0;
}
for (i=0, mask=0.5; i<23; i++, mask /= 2.0) {
outval <<= 1;
if (inval >= mask) {
outval |= 1;
inval -= mask;
}
}
*intVal = outval;
return 1;
}
int
const_inval_to_DF(double inval, int *intHigh, int *intLow)
{
register int i, outval1, outval2;
double mask;
if ((inval < -1.0) || (inval >= 1.0)) return 0;
outval1 = 0;
if (inval < 0) {
outval1 = 1;
inval += 1.0;
}
for (i=0, mask=0.5; i<23; i++, mask /= 2.0) {
outval1 <<= 1;
if (inval >= mask) {
outval1 |= 1;
inval -= mask;
}
}
for (i=0, outval2=0; i<24; i++, mask /= 2.0) {
outval2 <<= 1;
if (inval >= mask) {
outval2 |= 1;
inval -= mask;
}
}
*intHigh = outval1;
*intLow = outval2;
return 1;
}
int
const_double_to_DF(rtx op, int *intHigh, int *intLow)
{
return const_inval_to_DF(ints_to_double(op), intHigh, intLow);
}
int
const_double_ok_for_letter_p(rtx op, int c)
{
double f;
if ((c=='F' || c=='G')) {
f = ints_to_double(op);
if ((f >= -1.0) && (f < 1.0))
return 1;
}
return 0;
}
int
constant_address_p(rtx op)
{
int code = GET_CODE(op);
return (code==LABEL_REF) || (code==SYMBOL_REF) || (code==CONST_INT) ||
(code==CONST);
}
void
asm_output_ascii(FILE *filePtr, char *name, int len)
{
int i,j,k;
while (len) {
fprintf(filePtr, "\tdc\t");
for (i=0; (i<10) && (len); i++,len--) {
if (i) fprintf(filePtr, ",$%02X", *name++); else
fprintf(filePtr, "$%02X", *name++);
}
for (k=i; k<10; k++)
fprintf(filePtr, " ");
fprintf(filePtr, " ;\'");
for (j=0; j<i; j++) {
if (isprint(name[j-i])) fprintf(filePtr,"%c",name[j-i]);
else fprintf(filePtr,".");
}
fprintf(filePtr,"\'\n");
}
}
char *
remove_punct(char *name)
{
static char outname[40];
int i;
/* Skip over leading punctuation */
while (!isalnum(*name)) name++;
for (i=0; (i<39) && *name; name++) {
outname[i++] = (isalnum(*name) ? *name : '_');
}
outname[i] = 0;
return outname;
}
/*
This routine returns the output string for general math ops. which
match the following pattern:
(set (match_operand:mode 0 "general_operand" "=l")
(mathop:mode (match_operand:mode 1 "general_operand" "0")
(match_operand:mode 2 "general_operand" "dl")))
*/
#define ADD_56K 0
#define SUB_56K 1
char *
mathOpInsn(rtx *operands, int code)
{
int reg0 = REGNO(operands[0]);
int reg1 = REGNO(operands[2]);
switch(code) {
case ADD_56K:
if (reg0==reg1) {
extendReg(operands[0]);
regValid[reg0] = 0;
return "asl %0";
} else {
return "add %2,%0";
}
case SUB_56K:
if (reg0==reg1) {
regValid[reg0] = 1;
return "clr %0";
} else {
return "sub %2,%0";
}
}
}
int
class_max_nregs(enum reg_class class, enum machine_mode mode)
{
switch(class) {
case ALU_DATA_REGS0: case ALU_DATA_REGS1:
case ACC_REGS_HI: case ACC_REGS:
case ALU_DATA_REGS: case MATHOP_REGS:
case ALU_REGS: case GENERAL_REGS: case GENERAL_REGS2:
case ALL_REGS:
return (((mode==DImode) || (mode==DFmode)) ? 2 : 1);
case ACC_REGS_LO: case ADDRESS_REGS: case INDEX_REGS: case AGU_REGS:
return 1;
default:
fprintf(stderr,"%s:%u Unexpected class %u\n",__FILE__,__LINE__,
class);
error("Internal error");
return 2;
}
}
/* We use this to clobber A0 or B0 for every INSN that writes to A or B */
/* Too pessimistic, perhaps make A0 and B0 actually usable in the future */
int
insn_clobbers_regno_p(rtx insn, int regnum)
{
rtx op=PATTERN(insn);
int regdest;
/* Only real INSN's clobber A0/B0 mysteriously */
if (GET_CODE(insn) != INSN) return 0;
/* Check for an assignment to register A1 (5) or B1 (8) */
if (GET_CODE(op) != SET) return 0;
if (GET_CODE(XEXP(op,0)) != REG) return 0;
regdest=REGNO(XEXP(op,0));
if ((regdest != 5) && (regdest != 8)) return 0;
/* Is reg-to-check related to our destination register ? */
if (regnum != (regdest+1)) return 0;
/* Assume all assignments to A or B clobber A0 or B0 */
return 1;
}
void
asm_output_double(FILE *filePtr, double value)
{
int intHigh, intLow;
if (const_inval_to_DF(value, &intHigh, &intLow)) {
if (TARGET_NOLSPACE) {
fprintf(filePtr,"\tdc\t$%06X\n",intHigh);
fprintf(filePtr,"\tdc\t$%06X\n",intLow);
} else {
fprintf(filePtr,"\tdc\t%1.20lf\n",value);
}
} else {
error("Floating point constant out of bounds");
}
}
void
asm_output_float(FILE *filePtr, double value)
{
if (value < 1.0 && value >= -1.0) {
fprintf(filePtr,"\tdc\t%1.12lf\n",value);
} else {
error("Floating point constant out of bounds");
}
}
void
double_reg_to_memory(rtx operands[])
{
int reg0;
rtx op1 = XEXP(operands[0],0);
rtx opB, opIx;
rtx xoperands[2];
int code = GET_CODE(op1);
int intVal;
output_preloadN(operands[0]);
switch(code) {
case REG:
case POST_INC:
if (TARGET_NOLSPACE) {
output_asm_insn( "move %y1,%p0", operands);
output_asm_insn( "move %x1,%q0", operands);
} else {
output_asm_insn( "move %w1,%0", operands);
}
return;
case POST_DEC:
reg0 = REGNO(XEXP(op1,0));
if (TARGET_NOLSPACE) {
fprintf(asm_out_file, "\tmove (%s)+\n", reg_names[reg0]);
output_asm_insn( "move %x1,%p0", operands);
output_asm_insn( "move %y1,%q0", operands);
fprintf(asm_out_file, "\tmove (%s)-\n", reg_names[reg0]);
} else {
output_asm_insn( "move %w1,%0", operands);
}
return;
case PRE_DEC:
if (TARGET_NOLSPACE) {
output_asm_insn( "move %x1,%p0", operands);
output_asm_insn( "move %y1,%q0", operands);
} else {
output_asm_insn( "move %w1,%0", operands);
}
return;
case PLUS:
if (!TARGET_NOLSPACE) {
output_asm_insn( "move %w1,%0", operands);
return;
}
output_asm_insn( "move %y1,%p0", operands);
opIx = XEXP(op1, 1); /* The index */
opB = XEXP(op1, 0); /* The base */
if (GET_CODE(opIx)==REG && REGNO(opIx)>=10) {
opB=opIx; opIx=XEXP(op1, 0);
}
reg0 = REGNO(opB);
fprintf(asm_out_file, "\tmove (%s)+\n", reg_names[reg0]);
output_asm_insn( "move %x1,%q0", operands);
fprintf(asm_out_file, "\tmove (%s)-\n", reg_names[reg0]);
return;
case SYMBOL_REF:
case CONST_INT:
case CONST:
if (TARGET_NOLSPACE) {
output_asm_insn( "move %y1,%p0", operands);
output_asm_insn( "move %x1,%q0", operands);
} else {
output_asm_insn( "move %w1,%0", operands);
}
return;
default:
fprintf(stderr,"%s:%u Unknown code %d\n",__FILE__,__LINE__,code);
error("Internal error");
}
return;
}
/* This routine must also take care of the move subreg:DI->SI RTL */
/* It is assumed that if the destination reg is not longmode, it */
/* is a result of this kind of RTL and only the low word of the DI */
/* is required. */
void
double_reg_from_memory(rtx operands[])
{
int reg0,reg1;
rtx op1=XEXP(operands[1],0);
rtx opIx, opB;
int code = GET_CODE(op1);
enum machine_mode destMode = GET_MODE(operands[0]);
int destModeIsLong;
destModeIsLong = ((destMode==DImode) || (destMode==DFmode));
reg0 = REGNO(operands[0]);
switch(code) {
case REG:
case POST_INC:
if (TARGET_NOLSPACE) {
if (destModeIsLong) {
if (reg0 < 4)
output_asm_insn( "move %p1,%y0", operands);
else
output_asm_insn( "move %p1,%0", operands);
output_asm_insn( "move %q1,%x0", operands);
} else {
/* Special subreg RTL case */
output_asm_insn( "move %p1,%0 ;dummy", operands);
output_asm_insn( "move %q1,%0", operands);
}
} else {
if (destModeIsLong) {
output_asm_insn( "move %1,%0", operands);
} else {
output_asm_insn( "move %x1,%0", operands);
}
}
return;
case POST_DEC:
reg1 = REGNO(XEXP(op1,0));
if (!TARGET_NOLSPACE) {
if (destModeIsLong) {
output_asm_insn( "move %1,%0", operands);
} else {
output_asm_insn( "move %x1,%0", operands);
}
return;
}
fprintf(asm_out_file, "\tmove (%s)+\n", reg_names[reg1]);
if (destModeIsLong) {
if (reg0 < 4)
output_asm_insn( "move %p1,%y0", operands);
else
output_asm_insn( "move %p1,%0", operands);
output_asm_insn( "move %q1,%x0", operands);
} else {
/* Special subreg RTL case */
output_asm_insn( "move %p1,%0", operands);
fprintf(asm_out_file, "\tmove (%s)- ;dummy\n", reg_names[reg1]);
}
fprintf(asm_out_file, "\tmove (%s)-\n", reg_names[reg1]);
return;
case PRE_DEC:
reg1 = REGNO(XEXP(op1,0));
if (TARGET_NOLSPACE) {
if (destModeIsLong) {
output_asm_insn( "move %p1,%x0", operands);
output_asm_insn( "move %q1,%y0", operands);
regValid[reg0] = 0;
} else {
/* Special subreg RTL case */
output_asm_insn( "move %p1,%0", operands);
fprintf(asm_out_file, "\tmove (%s)- ;dummy\n", reg_names[reg1]);
}
} else {
if (destModeIsLong) {
output_asm_insn( "move %1,%0", operands);
} else {
output_asm_insn( "move %x1,%0", operands);
}
}
return;
case PLUS:
if (!TARGET_NOLSPACE) {
output_preloadN(operands[1]);
if (destModeIsLong) {
output_asm_insn( "move %1,%0", operands);
} else {
output_asm_insn( "move %x1,%0", operands);
}
return;
}
if (destModeIsLong) {
output_preloadN(operands[1]);
if (reg0 < 4)
output_asm_insn( "move %p1,%y0", operands);
else
output_asm_insn( "move %p1,%0", operands);
}
opIx = XEXP(op1, 1); /* The index */
opB = XEXP(op1, 0); /* The base */
if (GET_CODE(opIx)==REG && REGNO(opIx)>=10) {
opB=opIx; opIx=XEXP(op1,0);
}
reg0 = REGNO(opB);
if (!destModeIsLong && GET_CODE(opIx)==CONST_INT) {
/* Special subreg RTL case */
INTVAL(opIx)++;
output_preloadN(operands[1]);
output_asm_insn( "move %1,%0", operands);
return;
}
if (!destModeIsLong)
output_preloadN(operands[1]);
fprintf(asm_out_file, "\tmove (%s)+\n", reg_names[reg0]);
if (destModeIsLong)
output_asm_insn( "move %q1,%x0", operands);
else
/* Special subreg RTL case */
output_asm_insn( "move %q1,%0", operands);
fprintf(asm_out_file, "\tmove (%s)-\n", reg_names[reg0]);
return;
case SYMBOL_REF:
case CONST_INT:
case CONST:
if (TARGET_NOLSPACE) {
if (destModeIsLong) {
if (reg0 < 4)
output_asm_insn( "move %p1,%y0", operands);
else
output_asm_insn( "move %p1,%0", operands);
output_asm_insn( "move %q1,%x0", operands);
} else {
/* Special subreg RTL case */
output_asm_insn( "move %q1,%0", operands);
}
} else {
if (destModeIsLong) {
output_asm_insn( "move %1,%0", operands);
} else {
output_asm_insn( "move %x1,%0", operands);
}
}
return;
default:
fprintf(stderr,"%s:%u Unknown code %d\n",__FILE__,__LINE__,code);
error("Internal error");
}
return;
}
void
asm_output_double_int(FILE *filePtr, rtx exp)
{
int intHigh, intLow;
if (GET_CODE(exp) == CONST_DOUBLE) {
intHigh = CONST_DOUBLE_HIGH(exp);
intLow = CONST_DOUBLE_LOW(exp);
} else {
intLow = INTVAL(exp);
intHigh = 0;
}
intHigh = ((intHigh << 8) | ((intLow >> 24)&0xFF)) & 0xFFFFFF;
intLow &= 0xFFFFFF;
if (TARGET_NOLSPACE) {
fprintf(filePtr,"\tdc\t$%06X\n",intHigh);
fprintf(filePtr,"\tdc\t$%06X\n",intLow);
} else {
fprintf(filePtr,"\tdc\t@LNG($%06X,$%06X)\n",intHigh,intLow);
}
}
#define ASHL_56K 0
#define ASHR_56K 1
#define LSHL_56K 2
#define LSHR_56K 3
#define ROTL_56K 4
#define ROTR_56K 5
char *
shiftOpInsn(rtx operands[], int op)
{
int plus1=0, plus2=0;
if (GET_CODE(operands[2]) == CONST_INT) {
int intVal=INTVAL(operands[2]);
if (!intVal) return "; shift 0";
plus1 = (intVal == 1);
plus2 = (intVal == 2);
}
if (operands[2] == const0_rtx) {
return "; shift 0";
}
extendReg(operands[0]);
regValid[REGNO(operands[0])] = 0;
switch(op) {
case ASHL_56K:
if (plus1) return "asl %0";
else if (plus2) return "asl %0\n\tasl %0";
else return "rep %r2\n\tasl %0";
case ASHR_56K:
if (plus1) return "asr %0";
else if (plus2) return "asr %0\n\tasr %0";
else return "rep %r2\n\tasr %0";
case LSHL_56K:
if (plus1) return "lsl %0";
else if (plus2) return "lsl %0\n\tlsl %0";
else return "rep %r2\n\tlsl %0";
case LSHR_56K:
if (plus1) return "lsr %0";
else if (plus2) return "lsr %0\n\tlsr %0";
else return "rep %r2\n\tlsr %0";
case ROTL_56K:
if (plus1) return "rol %0";
else if (plus2) return "rol %0\n\trol %0";
else return "rep %r2\n\trol %0";
case ROTR_56K:
if (plus1) return "ror %0";
else if (plus2) return "ror %0\n\tror %0";
else return "rep %r2\n\tror %0";
}
}
int
allRegsInvalid(void)
{
regValid[5] = regValid[8] = 0;
}
void
extendReg(rtx op)
{
int regnum = REGNO(op);
enum machine_mode mode=GET_MODE(op);
int modeIsLong=((mode==DImode) || (mode==DFmode));
if (!TARGET_SAFECOMPARE || ((regnum != 5) && (regnum != 8))) return;
if (!regValid[regnum]) {
if (modeIsLong) {
output_asm_insn("move %w0,L:-(R6)", &op);
output_asm_insn("move L:(R6)+,%0", &op);
} else {
output_asm_insn("move %w0,%0 ;sc", &op);
}
regValid[regnum]=1;
}
}
void
asm_output_labelref(FILE *filePtr, char *name)
{
while(*name && *name == '_') name++;
fprintf(filePtr,"%s",name);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.