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.