This is out-dsp5616.c in view mode; [Download] [Up]
/*
GCC5616 -- GCC 1.40 machine description for DSP5616 processors
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;
if ((mode == QImode) || (mode == VOIDmode) || (mode == HImode) ||
(mode == SFmode) || (mode == SImode)) {
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..R3 */
return ADDRESS_REGS;
case 18: case 19: case 20: case 21: /* N0..N3 */
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': /* X1, X0, Y1, Y0, A1, B1 */
return MATHOP_REGS;
case 'a': /* R0..R3 */
return ADDRESS_REGS;
case 'b': /* R0..R3, A1, B1 */
return BASE_REGS;
/* For muldi operations -- not used */
case 'c': /* Y1, Y0 */
return ALU_DATA_REGSY;
case 'd': /* X1, X0, Y1, Y0 */
return ALU_DATA_REGS;
/* Used for multiply instructions where mpy X1,X1,A is illegal */
case 'e': /* X0, Y1, Y0 */
return ALU_DATA_REGS2;
/* Used for multiply instructions where mpy X1,X1,A is illegal */
case 'f': /* X0, X1 */
return ALU_DATA_REGSX;
/* 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)
{
fprintf(file,"\tmove R2,X:-(R3)\n");
fprintf(file,"\tmove R3,R2\n");
if (size > 1)
fprintf(file,"\tmove #%d,N3\n",-size);
fprintf(file,"\tmove SSH,X:-(R3)\n");
if (size > 1)
fprintf(file,"\tmove (R3)+N3\n");
else if (size==1)
fprintf(file,"\tmove (R3)-\n");
}
void
function_epilogue(FILE *file, int size)
{
fprintf(file,"\tmove R2,R3\n");
fprintf(file,"\tmove X:-(R2),SSH\n");
fprintf(file,"\tmove X:(R3)+,R2\n");
fprintf(file,"\trts\n");
}
/*
* Codes:
* w -- For A and B, output A1 and B1
* x -- lower part of 32-bit DFmode or DImode value (X0 instead of X)
* y -- upper part of 32-bit DFmode or DImode value (X1 instead of X)
* z -- Extension part of 40-bit reg. (A2 instead of A)
* p -- Address or (Reg)+ -- first word of a DI/DFmode
* q -- Address+1 or (Reg)- -- second word of a DI/DFmode
* r -- Don't output size information
* s -- Candidate for movei instruction (different from GCC56K)
* Z -- Don't output memory space and output R0 instead of (R0)
*/
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 (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') {
fprintf(filePtr,"X:");
}
print_operand_address(filePtr, memop, code);
break;
case CONST_INT:
outval = INTVAL(operand);
outval &= 0xFFFF;
if (code=='r')
p = "#$%X";
else if (code=='s' &&
(((outval & 0xFF80)==0xFF80) || (!(outval & 0xFF80)))) {
if (outval & 0xFF80)
outval |= 0xFFFF0000;
else
outval &= 0xFF;
p = "#<%d";
} 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)
{
int regnum, val;
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) {
op0 = op1; op1 = XEXP(operand,0);
}
regnum = REGNO(op0);
/* (R2+xx) is handled in print_operand_address, no need to preload */
if (GET_CODE(op1) == CONST_INT) {
val = INTVAL(op1);
if ((regnum==12) && (val >= -128) && (val < 128)) return;
}
fprintf(asm_out_file,"\tmove ");
print_operand(asm_out_file, op1, 'w');
fprintf(asm_out_file,",N%u\n",regnum-10);
}
/* In the machine description, code=='p' *must* be followed by a */
/* statement with code=='q' since this routine modifies the */
/* referred-to register */
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:
if (code=='Z')
fprintf(filePtr, "%s", p);
else
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);
if (GET_CODE(op1)!=CONST_INT) {
fprintf(filePtr,"(%s+N%c)", p, digit);
break;
}
opval = INTVAL(op1);
if ((code=='q') && (digit=='2') && (opval >= -128) && (opval < 127))
fprintf(filePtr,"(%s%+d)", p, opval+1);
else if ((digit=='2') && (opval >= -128) && (opval < 128))
fprintf(filePtr, "(%s%+d)", p, opval);
else
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++;
fprintf(filePtr, "$%04X", 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));
error("Internal error");
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 QImode: case HImode: case SImode: case SFmode:
case DFmode: case DImode:
case BLKmode:
x_const_section();
break;
default:
fprintf(stderr,"%s:%u Don\'t know how to handle mode %s\n",
__FILE__,__LINE__,GET_MODE_NAME(mode));
error("Internal error");
}
}
void
select_section(tree x)
{
unsigned char code=TREE_CODE(x);
enum machine_mode mode=DECL_MODE(x);
int constant = 0;
switch(code) {
case STRING_CST:
if (flag_writable_strings) {
x_data_section();
} else {
x_const_section();
}
break;
case INTEGER_CST:
case REAL_CST:
mode = DECL_MODE(TREE_TYPE(x));
switch(mode) {
case QImode: case HImode: case SImode: case SFmode:
case DFmode: case DImode:
case BLKmode:
x_const_section();
break;
default:
fprintf(stderr,"%s:%u Unknown mode %d/%s\n",__FILE__,__LINE__,
mode,GET_MODE_NAME(mode));
#ifdef DEBUG56
debug_tree(x);
#endif
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 (constant)
x_const_section();
else
x_data_section();
break;
default:
fprintf(stderr,"%s:%u Unknown code %u\n",__FILE__,__LINE__,code);
error("Internal error");
#ifdef DEBUG56
debug_tree(x);
#endif
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<15; 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<15; i++, mask /= 2.0) {
outval1 <<= 1;
if (inval >= mask) {
outval1 |= 1;
inval -= mask;
}
}
for (i=0, outval2=0; i<16; 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;
enum machine_mode mode=GET_MODE(operands[0]);
/* Must be a value of 1 or -1 and only for integer modes */
if (GET_CODE(operands[2]) == CONST_INT) {
int intVal = INTVAL(operands[2]);
if (!intVal) return "; +0";
if (code==ADD_56K && intVal==1 || code==SUB_56K && intVal==-1)
return ((mode==DImode) ? "inc %0" : "inc24 %0");
else if (code==ADD_56K && intVal==-1 || code==SUB_56K && intVal==1)
return ((mode==DImode) ? "dec %0" : "dec24 %0");
else {
#if DEBUG56
fprintf(stderr,"%s:%u Unknown combination\n",__FILE__,__LINE__);
#endif
error("Internal error");
return "???";
}
}
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) {
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 ALU_DATA_REGSX:
case ALU_DATA_REGSY: case ACC_REGS_HI: case ACC_REGS:
case ALU_DATA_REGS2: case ALU_DATA_REGS: case MATHOP_REGS:
case BASE_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 to clobber A0 or B0 for every INSN that writes to A or B */
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
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:
output_asm_insn( "move %y1,%p0", operands);
output_asm_insn( "move %x1,%q0", operands);
return;
case POST_DEC:
reg0 = REGNO(XEXP(op1,0));
fprintf(asm_out_file, "\tlea (%s)+,%s\n", reg_names[reg0],
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]);
return;
case PRE_DEC:
output_asm_insn( "move %x1,%p0", operands);
output_asm_insn( "move %y1,%q0", operands);
return;
case PLUS:
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);
if (GET_CODE(opIx)==CONST_INT) {
intVal = INTVAL(opIx);
if ((reg0==12) && (intVal >= -128) && (intVal < 127)) {
output_asm_insn( "move %x1,%q0", operands);
return;
}
}
fprintf(asm_out_file, "\tlea (%s)+,%s\n", reg_names[reg0],
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:
output_asm_insn( "move %y1,%p0", operands);
output_asm_insn( "move %x1,%q0", 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 opB, opIx;
int code = GET_CODE(op1);
int intVal;
enum machine_mode destMode = GET_MODE(operands[0]);
int destModeIsLong;
destModeIsLong = ((destMode==DImode) || (destMode==DFmode));
output_preloadN(operands[1]);
reg0 = REGNO(operands[0]);
switch(code) {
case REG:
case POST_INC:
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);
}
return;
case POST_DEC:
reg1 = REGNO(XEXP(op1,0));
fprintf(asm_out_file, "\tlea (%s)+,%s\n", reg_names[reg1],
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 (destModeIsLong) {
output_asm_insn( "move %p1,%x0", operands);
output_asm_insn( "move %q1,%y0", operands);
if (reg0 > 3)
output_asm_insn( "ext %0", operands);
} else {
/* Special subreg RTL case */
output_asm_insn( "move %p1,%0", operands);
fprintf(asm_out_file, "\tmove (%s)- ;dummy\n", reg_names[reg1]);
}
return;
case PLUS:
if (destModeIsLong)
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 (GET_CODE(opIx)==CONST_INT) {
intVal = INTVAL(opIx);
if ((reg0==12) && (intVal >= -128) && (intVal < 127)) {
if (destModeIsLong)
output_asm_insn( "move %q1,%x0", operands);
else
/* Special subreg RTL case */
output_asm_insn( "move %q1,%0", operands);
return;
}
}
/* This is inefficient if destModeIsLong is FALSE */
/* and opIx is CONST_INT...just add one to INTVAL */
fprintf(asm_out_file, "\tlea (%s)+,%s\n", reg_names[reg0],
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 (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);
return;
default:
fprintf(stderr,"%s:%u Unknown code %d\n",__FILE__,__LINE__,code);
error("Internal error");
}
return;
}
void
asm_output_double(FILE *filePtr, double value)
{
int intHigh, intLow;
if (const_inval_to_DF(value, &intHigh, &intLow)) {
fprintf(filePtr,"\tdc\t$%04X\n",intHigh);
fprintf(filePtr,"\tdc\t$%04X\n",intLow);
} 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.10lf\n",value);
} else {
error("Floating point constant out of bounds");
}
}
void
asm_output_double_int(FILE *filePtr, rtx exp)
{
int intHigh, intLow;
if (GET_CODE(exp) == CONST_DOUBLE)
intLow = CONST_DOUBLE_LOW(exp);
else
intLow = INTVAL(exp);
intHigh = (intLow >> 16) & 0xFFFF;
intLow &= 0xFFFF;
fprintf(filePtr,"\tdc\t$%04X\n",intHigh);
fprintf(filePtr,"\tdc\t$%04X\n",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, plus4=0, plus16=0;
if (GET_CODE(operands[2]) == CONST_INT) {
int intVal=INTVAL(operands[2]);
if (!intVal) return "; shift 0";
plus1 = (intVal == 1);
plus2 = (intVal == 2);
plus4 = (intVal == 4);
plus16 = (intVal == 16);
}
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 if (plus4) return "asl4 %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 if (plus4) return "asr4 %0";
else if (plus16) return "asr16 %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("ext %0 ;sc", &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.