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.