⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pdp11.c

📁 Mac OS X 10.4.9 for x86 Source Code gcc 实现源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
     such overlap can't happen in memory unless the user explicitly     sets it up, and that is an undefined circumstance.  */  if (optype0 == PUSHOP || optype1 == PUSHOP      || (optype0 == REGOP && optype1 == REGOP	  && REGNO (operands[0]) == REGNO (latehalf[1])))    {      /* Make any unoffsettable addresses point at high-numbered word.  */      if (addreg0)	output_asm_insn ("add $2,%0", &addreg0);      if (addreg1)	output_asm_insn ("add $2,%0", &addreg1);      /* Do that word.  */      output_asm_insn (singlemove_string (latehalf), latehalf);      /* Undo the adds we just did.  */      if (addreg0)	output_asm_insn ("sub $2,%0", &addreg0);      if (addreg1)	output_asm_insn ("sub $2,%0", &addreg1);      /* Do low-numbered word.  */      return singlemove_string (operands);    }  /* Normal case: do the two words, low-numbered first.  */  output_asm_insn (singlemove_string (operands), operands);  /* Make any unoffsettable addresses point at high-numbered word.  */  if (addreg0)    output_asm_insn ("add $2,%0", &addreg0);  if (addreg1)    output_asm_insn ("add $2,%0", &addreg1);  /* Do that word.  */  output_asm_insn (singlemove_string (latehalf), latehalf);  /* Undo the adds we just did.  */  if (addreg0)    output_asm_insn ("sub $2,%0", &addreg0);  if (addreg1)    output_asm_insn ("sub $2,%0", &addreg1);  return "";}/* Output assembler code to perform a quadword move insn   with operands OPERANDS.  */const char *output_move_quad (rtx *operands){  enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;  rtx latehalf[2];  rtx addreg0 = 0, addreg1 = 0;  output_asm_insn(";/* movdi/df: %1 -> %0 */", operands);    if (REG_P (operands[0]))    optype0 = REGOP;  else if (offsettable_memref_p (operands[0]))    optype0 = OFFSOP;  else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)    optype0 = POPOP;  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)    optype0 = PUSHOP;  else if (GET_CODE (operands[0]) == MEM)    optype0 = MEMOP;  else    optype0 = RNDOP;  if (REG_P (operands[1]))    optype1 = REGOP;  else if (CONSTANT_P (operands[1])	   || GET_CODE (operands[1]) == CONST_DOUBLE)    optype1 = CNSTOP;  else if (offsettable_memref_p (operands[1]))    optype1 = OFFSOP;  else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)    optype1 = POPOP;  else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)    optype1 = PUSHOP;  else if (GET_CODE (operands[1]) == MEM)    optype1 = MEMOP;  else    optype1 = RNDOP;  /* Check for the cases that the operand constraints are not     supposed to allow to happen.  Abort if we get one,     because generating code for these cases is painful.  */  if (optype0 == RNDOP || optype1 == RNDOP)    abort ();    /* check if we move a CPU reg to an FPU reg, or vice versa! */  if (optype0 == REGOP && optype1 == REGOP)      /* bogus - 64 bit cannot reside in CPU! */      if (CPU_REG_P(REGNO(operands[0]))	  || CPU_REG_P (REGNO(operands[1])))	  abort();    if (optype0 == REGOP || optype1 == REGOP)  {      /* check for use of clrd????          if you ever allow ac4 and ac5 (now we require secondary load) 	 you must check whether 	 you want to load into them or store from them - 	 then dump ac0 into $help$ movce ac4/5 to ac0, do the 	 store from ac0, and restore ac0 - if you can find 	 an unused ac[0-3], use that and you save a store and a load!*/      if (FPU_REG_P(REGNO(operands[0])))      {	  if (GET_CODE(operands[1]) == CONST_DOUBLE)	  {	      REAL_VALUE_TYPE r;	      REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);	      if (REAL_VALUES_EQUAL (r, dconst0))		  return "{clrd|clrf} %0";	  }	      	  return "{ldd|movf} %1, %0";      }            if (FPU_REG_P(REGNO(operands[1])))	  return "{std|movf} %1, %0";  }        /* If one operand is decrementing and one is incrementing     decrement the former register explicitly     and change that operand into ordinary indexing.  */  if (optype0 == PUSHOP && optype1 == POPOP)    {      operands[0] = XEXP (XEXP (operands[0], 0), 0);      output_asm_insn ("sub $8,%0", operands);      operands[0] = gen_rtx_MEM (DImode, operands[0]);      optype0 = OFFSOP;    }  if (optype0 == POPOP && optype1 == PUSHOP)    {      operands[1] = XEXP (XEXP (operands[1], 0), 0);      output_asm_insn ("sub $8,%1", operands);      operands[1] = gen_rtx_MEM (SImode, operands[1]);      optype1 = OFFSOP;    }  /* If an operand is an unoffsettable memory ref, find a register     we can increment temporarily to make it refer to the second word.  */  if (optype0 == MEMOP)    addreg0 = find_addr_reg (XEXP (operands[0], 0));  if (optype1 == MEMOP)    addreg1 = find_addr_reg (XEXP (operands[1], 0));  /* Ok, we can do one word at a time.     Normally we do the low-numbered word first,     but if either operand is autodecrementing then we     do the high-numbered word first.     In either case, set up in LATEHALF the operands to use     for the high-numbered word and in some cases alter the     operands in OPERANDS to be suitable for the low-numbered word.  */  if (optype0 == REGOP)    latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);  else if (optype0 == OFFSOP)    latehalf[0] = adjust_address (operands[0], SImode, 4);  else    latehalf[0] = operands[0];  if (optype1 == REGOP)    latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);  else if (optype1 == OFFSOP)    latehalf[1] = adjust_address (operands[1], SImode, 4);  else if (optype1 == CNSTOP)    {      if (GET_CODE (operands[1]) == CONST_DOUBLE)	{	  REAL_VALUE_TYPE r;	  long dval[2];	  REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);	  REAL_VALUE_TO_TARGET_DOUBLE (r, dval);	  latehalf[1] = GEN_INT (dval[1]);	  operands[1] = GEN_INT	(dval[0]);	}      else if (GET_CODE(operands[1]) == CONST_INT)	{	  latehalf[1] = const0_rtx;	}      else	abort();    }  else    latehalf[1] = operands[1];  /* If insn is effectively movd N(sp),-(sp) then we will do the     high word first.  We should use the adjusted operand 1 (which is N+4(sp))     for the low word as well, to compensate for the first decrement of sp.  */  if (optype0 == PUSHOP      && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM      && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))    operands[1] = latehalf[1];  /* If one or both operands autodecrementing,     do the two words, high-numbered first.  */  /* Likewise,  the first move would clobber the source of the second one,     do them in the other order.  This happens only for registers;     such overlap can't happen in memory unless the user explicitly     sets it up, and that is an undefined circumstance.  */  if (optype0 == PUSHOP || optype1 == PUSHOP      || (optype0 == REGOP && optype1 == REGOP	  && REGNO (operands[0]) == REGNO (latehalf[1])))    {      /* Make any unoffsettable addresses point at high-numbered word.  */      if (addreg0)	output_asm_insn ("add $4,%0", &addreg0);      if (addreg1)	output_asm_insn ("add $4,%0", &addreg1);      /* Do that word.  */      output_asm_insn(output_move_double(latehalf), latehalf);      /* Undo the adds we just did.  */      if (addreg0)	output_asm_insn ("sub $4,%0", &addreg0);      if (addreg1)	output_asm_insn ("sub $4,%0", &addreg1);      /* Do low-numbered word.  */      return output_move_double (operands);    }  /* Normal case: do the two words, low-numbered first.  */  output_asm_insn (output_move_double (operands), operands);  /* Make any unoffsettable addresses point at high-numbered word.  */  if (addreg0)    output_asm_insn ("add $4,%0", &addreg0);  if (addreg1)    output_asm_insn ("add $4,%0", &addreg1);  /* Do that word.  */  output_asm_insn (output_move_double (latehalf), latehalf);  /* Undo the adds we just did.  */  if (addreg0)    output_asm_insn ("sub $4,%0", &addreg0);  if (addreg1)    output_asm_insn ("sub $4,%0", &addreg1);  return "";}/* Return a REG that occurs in ADDR with coefficient 1.   ADDR can be effectively incremented by incrementing REG.  */static rtxfind_addr_reg (rtx addr){  while (GET_CODE (addr) == PLUS)    {      if (GET_CODE (XEXP (addr, 0)) == REG)	addr = XEXP (addr, 0);      if (GET_CODE (XEXP (addr, 1)) == REG)	addr = XEXP (addr, 1);      if (CONSTANT_P (XEXP (addr, 0)))	addr = XEXP (addr, 1);      if (CONSTANT_P (XEXP (addr, 1)))	addr = XEXP (addr, 0);    }  if (GET_CODE (addr) == REG)    return addr;  return 0;}/* Output an ascii string.  */voidoutput_ascii (FILE *file, const char *p, int size){  int i;  /* This used to output .byte "string", which doesn't work with the UNIX     assembler and I think not with DEC ones either.  */  fprintf (file, "\t.byte ");  for (i = 0; i < size; i++)    {      register int c = p[i];      if (c < 0)	c += 256;      fprintf (file, "%#o", c);      if (i < size - 1)	putc (',', file);    }  putc ('\n', file);}/* --- stole from out-vax, needs changes */voidprint_operand_address (FILE *file, register rtx addr){  register rtx reg1, reg2, breg, ireg;  rtx offset; retry:  switch (GET_CODE (addr))    {    case MEM:      if (TARGET_UNIX_ASM)	fprintf (file, "*");      else	fprintf (file, "@");      addr = XEXP (addr, 0);      goto retry;    case REG:      fprintf (file, "(%s)", reg_names[REGNO (addr)]);      break;    case PRE_MODIFY:    case PRE_DEC:      fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);      break;    case POST_MODIFY:    case POST_INC:      fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);      break;    case PLUS:      reg1 = 0;	reg2 = 0;      ireg = 0;	breg = 0;      offset = 0;      if (CONSTANT_ADDRESS_P (XEXP (addr, 0))	  || GET_CODE (XEXP (addr, 0)) == MEM)	{	  offset = XEXP (addr, 0);	  addr = XEXP (addr, 1);	}      else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))	       || GET_CODE (XEXP (addr, 1)) == MEM)	{	  offset = XEXP (addr, 1);	  addr = XEXP (addr, 0);	}      if (GET_CODE (addr) != PLUS)	;      else if (GET_CODE (XEXP (addr, 0)) == MULT)	{	  reg1 = XEXP (addr, 0);	  addr = XEXP (addr, 1);	}      else if (GET_CODE (XEXP (addr, 1)) == MULT)	{	  reg1 = XEXP (addr, 1);	  addr = XEXP (addr, 0);	}      else if (GET_CODE (XEXP (addr, 0)) == REG)	{	  reg1 = XEXP (addr, 0);	  addr = XEXP (addr, 1);	}      else if (GET_CODE (XEXP (addr, 1)) == REG)	{	  reg1 = XEXP (addr, 1);	  addr = XEXP (addr, 0);	}      if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)	{	  if (reg1 == 0)	    reg1 = addr;	  else	    reg2 = addr;	  addr = 0;	}      if (offset != 0)	{	  if (addr != 0) abort ();	  addr = offset;	}      if (reg1 != 0 && GET_CODE (reg1) == MULT)	{	  breg = reg2;	  ireg = reg1;	}      else if (reg2 != 0 && GET_CODE (reg2) == MULT)	{	  breg = reg1;	  ireg = reg2;	}      else if (reg2 != 0 || GET_CODE (addr) == MEM)	{	  breg = reg2;	  ireg = reg1;	}      else	{	  breg = reg1;	  ireg = reg2;	}      if (addr != 0)	output_address (addr);      if (breg != 0)	{	  if (GET_CODE (breg) != REG)	    abort ();	  fprintf (file, "(%s)", reg_names[REGNO (breg)]);	}      if (ireg != 0)	{	  if (GET_CODE (ireg) == MULT)	    ireg = XEXP (ireg, 0);	  if (GET_CODE (ireg) != REG)	    abort ();	  abort();	  fprintf (file, "[%s]", reg_names[REGNO (ireg)]);	}      break;    default:      output_addr_const_pdp11 (file, addr);    }}/* Target hook to assemble integer objects.  We need to use the   pdp-specific version of output_addr_const.  */static boolpdp11_assemble_integer (rtx x, unsigned int size, int aligned_p){  if (aligned_p)    switch (size)      {      case 1:	fprintf (asm_out_file, "\t.byte\t");	output_addr_const_pdp11 (asm_out_file, x);	fprintf (asm_out_file, " /* char */\n");	return true;      case 2:	fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t");	output_addr_const_pdp11 (asm_out_file, x);	fprintf (asm_out_file, " /* short */\n");	return true;      }  return default_assemble_integer (x, size, aligned_p);}/* register move costs, indexed by regs */static const int move_costs[N_REG_CLASSES][N_REG_CLASSES] = {             /* NO  MUL  GEN  LFPU  NLFPU FPU ALL *//* NO */     {  0,   0,   0,    0,    0,    0,   0},/* MUL */    {  0,   2,   2,   10,   22,   22,  22},/* GEN */    {  0,   2,   2,   10,   22,   22,  22},/* LFPU */   {  0,  10,  10,    2,    2,    2,  10},/* NLFPU */  {  0,  22,  22,    2,    2,    2,  22},/* FPU */    {  0,  22,  22,    2,    2,    2,  22},/* ALL */    {  0,  22,  22,   10,   22,   22,  22}}  ;/* -- note that some moves are tremendously expensive,    because they require lots of tricks! do we have to    charge the costs incurred by secondary reload class    -- as we do here with 22 -- or not ? */int register_move_cost(c1, c2)  enum reg_class c1, c2;{    return move_costs[(int)c1][(int)c2];}static boolpdp11_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total){  switch (code)    {    case CONST_INT:      if (INTVAL (x) == 0 || INTVAL (x) == -1 || INTVAL (x) == 1)	{	  *total = 0;	  return true;	}      /* FALLTHRU */    case CONST:    case LABEL_REF:    case SYMBOL_REF:      /* Twice as expensive as REG.  */      *total = 2;      return true;    case CONST_DOUBLE:      /* Twice (or 4 times) as expensive as 16 bit.  */      *total = 4;      return true;    case MULT:      /* ??? There is something wrong in MULT because MULT is not          as cheap as total = 2 even if we can shift!  */      /* If optimizing for size make mult etc cheap, but not 1, so when          in doubt the faster insn is chosen.  */      if (optimize_size)        *total = COSTS_N_INSNS (2);      else        *total = COSTS_N_INSNS (11);      return false;    case DIV:      if (optimize_size)        *total = COSTS_N_INSNS (2);      else        *total = COSTS_N_INSNS (25);      return false;    case MOD:      if (optimize_size)        *total = COSTS_N_INSNS (2);      else        *total = COSTS_N_INSNS (26);      return false;    case ABS:      /* Equivalent to length, so same for optimize_size.  */      *total = COSTS_N_INSNS (3);      return false;    case ZERO_EXTEND:      /* Only used for qi->hi.  */      *total = COSTS_N_INSNS (1);      return false;    case SIGN_EXTEND:      if (GET_MODE (x) == HImode)      	*total = COSTS_N_INSNS (1);      else if (GET_MODE (x) == SImode)	*total = COSTS_N_INSNS (6);      else	*total = COSTS_N_INSNS (2);      return false;    case ASHIFT:    case LSHIFTRT:    case ASHIFTRT:      if (optimize_size)        *total = COSTS_N_INSNS (1);      else if (GET_MODE (x) ==  QImode)        {          if (GET_CODE (XEXP (x, 1)) != CONST_INT)   	    *total = COSTS_N_INSNS (8); /* worst case */          else	    *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1)));        }      else if (GET_MODE (x) == HImode)        {          if (GET_CODE (XEXP (x, 1)) == CONST_INT)            {	      if (abs (INTVAL (XEXP (x, 1))) == 1)                *total = COSTS_N_INSNS (1);              else	        *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));            }          else            *total = COSTS_N_INSNS (10); /* worst case */        }      else if (GET_MODE (x) == SImode)        {          if (GET_CODE (XEXP (x, 1)) == CONST_INT)	    *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -