?? out-sparc.c
字號:
addr = XEXP (addr, 0); else if (GET_CODE (XEXP (addr, 1)) == REG) addr = XEXP (addr, 1); else if (CONSTANT_P (XEXP (addr, 0))) addr = XEXP (addr, 1); else if (CONSTANT_P (XEXP (addr, 1))) addr = XEXP (addr, 0); else abort (); } if (GET_CODE (addr) == REG) return addr; abort ();}voidoutput_sized_memop (opname, mode) char *opname; enum machine_mode mode;{ extern struct _iobuf *asm_out_file; static char *ld_size_suffix[] = { "ub", "uh", "", "?", "d" }; static char *st_size_suffix[] = { "b", "h", "", "?", "d" }; char *modename = (opname[0] == 'l' ? ld_size_suffix : st_size_suffix)[GET_MODE_SIZE (mode) >> 1]; fprintf (asm_out_file, "\t%s%s", opname, modename);}/* Output a store-in-memory whose operands are OPERANDS[0,1]. OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero. */char *output_store (operands) rtx *operands;{ enum machine_mode mode = GET_MODE (operands[0]); rtx address = XEXP (operands[0], 0); cc_status.flags |= CC_KNOW_HI_G1; cc_status.mdep = address; if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) && address == cc_prev_status.mdep)) { output_asm_insn ("sethi %%hi(%m0),%%g1", operands); cc_prev_status.mdep = address; } /* Store zero in two parts when appropriate. */ if (mode == DFmode && operands[1] == dconst0_rtx) { /* We can't cross a page boundary here because the SYMBOL_REF must be double word aligned, and for this to be the case, SYMBOL_REF+4 cannot cross. */ output_sized_memop ("st", SImode); output_asm_insn ("%r1,[%%g1+%%lo(%m0)]", operands); output_sized_memop ("st", SImode); return "%r1,[%%g1+%%lo(%m0)+4]"; } /* Code below isn't smart enough to move a doubleword in two parts, so use output_move_double to do that in the cases that require it. */ if ((mode == DImode || mode == DFmode) && (GET_CODE (operands[1]) == REG && (REGNO (operands[1]) & 1))) return output_move_double (operands); output_sized_memop ("st", mode); return "%r1,[%%g1+%%lo(%m0)]";}/* Output a fixed-point load-from-memory whose operands are OPERANDS[0,1]. OPERANDS[0] is a reg, and OPERANDS[1] is a mem. */char *output_load_fixed (operands) rtx *operands;{ enum machine_mode mode = GET_MODE (operands[0]); rtx address = XEXP (operands[1], 0); /* We don't bother trying to see if we know %hi(address). This is because we are doing a load, and if we know the %hi value, we probably also know that value in memory. */ cc_status.flags |= CC_KNOW_HI_G1; cc_status.mdep = address; if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) && address == cc_prev_status.mdep && cc_prev_status.mdep == cc_status.mdep)) { output_asm_insn ("sethi %%hi(%m1),%%g1", operands); cc_prev_status.mdep = address; } /* Code below isn't smart enough to do a doubleword in two parts. So handle that case the slow way. */ if (mode == DImode && GET_CODE (operands[0]) == REG /* Moving to nonaligned reg pair */ && (REGNO (operands[0]) & 1)) return output_move_double (operands); output_sized_memop ("ld", mode); if (GET_CODE (operands[0]) == REG) return "[%%g1+%%lo(%m1)],%0"; abort ();}/* Output a floating-point load-from-memory whose operands are OPERANDS[0,1]. OPERANDS[0] is a reg, and OPERANDS[1] is a mem. We also handle the case where OPERANDS[0] is a mem. */char *output_load_floating (operands) rtx *operands;{ enum machine_mode mode = GET_MODE (operands[0]); rtx address = XEXP (operands[1], 0); /* We don't bother trying to see if we know %hi(address). This is because we are doing a load, and if we know the %hi value, we probably also know that value in memory. */ cc_status.flags |= CC_KNOW_HI_G1; cc_status.mdep = address; if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) && address == cc_prev_status.mdep && cc_prev_status.mdep == cc_status.mdep)) { output_asm_insn ("sethi %%hi(%m1),%%g1", operands); cc_prev_status.mdep = address; } if (mode == DFmode) { if (REG_P (operands[0])) { if (REGNO (operands[0]) & 1) return output_move_double (operands); else return "ldd [%%g1+%%lo(%m1)],%0"; } cc_status.flags &= ~(CC_F0_IS_0|CC_F1_IS_0); output_asm_insn ("ldd [%%g1+%%lo(%m1)],%%f0", operands); operands[1] = gen_rtx (REG, DFmode, 32); return output_fp_move_double (operands); } if (GET_CODE (operands[0]) == MEM) { cc_status.flags &= ~CC_F1_IS_0; output_asm_insn ("ld [%%g1+%%lo(%1)],%%f1", operands); if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) { cc_status.mdep = XEXP (operands[0], 0); return "sethi %%hi(%m0),%%g1\n\tst %%f1,[%%g1+%%lo(%m0)]"; } else return "st %%f1,%0"; } return "ld [%%g1+%%lo(%m1)],%0";}/* Load the address specified by OPERANDS[3] into the register specified by OPERANDS[0]. OPERANDS[3] may be the result of a sum, hence it could either be: (1) CONST (2) REG (2) REG + CONST_INT (3) REG + REG + CONST_INT (4) REG + REG (special case of 3). Note that (3) is not a legitimate address. All cases are handled here. */voidoutput_load_address (operands) rtx *operands;{ rtx base, offset; if (CONSTANT_P (operands[3])) { output_asm_insn ("set %3,%0", operands); return; } if (REG_P (operands[3])) { if (REGNO (operands[0]) != REGNO (operands[3])) output_asm_insn ("mov %3,%0", operands); return; } if (GET_CODE (operands[3]) != PLUS) abort (); base = XEXP (operands[3], 0); offset = XEXP (operands[3], 1); if (GET_CODE (base) == CONST_INT) { rtx tmp = base; base = offset; offset = tmp; } if (GET_CODE (offset) != CONST_INT) { /* Operand is (PLUS (REG) (REG)). */ base = operands[3]; offset = const0_rtx; } if (REG_P (base)) { operands[6] = base; operands[7] = offset; if (SMALL_INT (offset)) output_asm_insn ("add %6,%7,%0", operands); else output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands); } else if (GET_CODE (base) == PLUS) { operands[6] = XEXP (base, 0); operands[7] = XEXP (base, 1); operands[8] = offset; if (SMALL_INT (offset)) output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands); else output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands); } else abort ();}/* Output code to place a size count SIZE in register REG. ALIGN is the size of the unit of transfer. Because block moves are pipelined, we don't include the first element in the transfer of SIZE to REG. */static voidoutput_size_for_block_move (size, reg, align) rtx size, reg; rtx align;{ rtx xoperands[3]; xoperands[0] = reg; xoperands[1] = size; xoperands[2] = align; if (GET_CODE (size) == REG) output_asm_insn ("sub %1,%2,%0", xoperands); else { xoperands[1] = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align)); cc_status.flags &= ~ CC_KNOW_HI_G1; output_asm_insn ("set %1,%0", xoperands); }}/* Emit code to perform a block move. OPERANDS[0] is the destination. OPERANDS[1] is the source. OPERANDS[2] is the size. OPERANDS[3] is the alignment safe to use. OPERANDS[4] is a register we can safely clobber as a temp. */char *output_block_move (operands) rtx *operands;{ /* A vector for our computed operands. Note that load_output_address makes use of (and can clobber) up to the 8th element of this vector. */ rtx xoperands[10]; rtx zoperands[10]; static int movstrsi_label = 0; int i, j; rtx temp1 = operands[4]; rtx alignrtx = operands[3]; int align = INTVAL (alignrtx); xoperands[0] = operands[0]; xoperands[1] = operands[1]; xoperands[2] = temp1; /* We can't move more than four bytes at a time because we have only one register to move them through. */ if (align > 4) { align = 4; alignrtx = gen_rtx (CONST_INT, VOIDmode, 4); } /* Since we clobber untold things, nix the condition codes. */ CC_STATUS_INIT; /* Recognize special cases of block moves. These occur when GNU C++ is forced to treat something as BLKmode to keep it in memory, when its mode could be represented with something smaller. We cannot do this for global variables, since we don't know what pages they don't cross. Sigh. */ if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) <= 16 && ! CONSTANT_ADDRESS_P (operands[0]) && ! CONSTANT_ADDRESS_P (operands[1])) { int size = INTVAL (operands[2]); cc_status.flags &= ~CC_KNOW_HI_G1; if (align == 1) { if (memory_address_p (QImode, plus_constant (xoperands[0], size)) && memory_address_p (QImode, plus_constant (xoperands[1], size))) { /* We will store different integers into this particular RTX. */ xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); for (i = size-1; i >= 0; i--) { INTVAL (xoperands[2]) = i; output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]", xoperands); } return ""; } } else if (align == 2) { if (memory_address_p (HImode, plus_constant (xoperands[0], size)) && memory_address_p (HImode, plus_constant (xoperands[1], size))) { /* We will store different integers into this particular RTX. */ xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); for (i = (size>>1)-1; i >= 0; i--) { INTVAL (xoperands[2]) = i<<1; output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]", xoperands); } return ""; } } else { if (memory_address_p (SImode, plus_constant (xoperands[0], size)) && memory_address_p (SImode, plus_constant (xoperands[1], size))) { /* We will store different integers into this particular RTX. */ xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); for (i = (size>>2)-1; i >= 0; i--) { INTVAL (xoperands[2]) = i<<2; output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]", xoperands); } return ""; } } } /* This is the size of the transfer. Either use the register which already contains the size, or use a free register (used by no operands). Also emit code to decrement the size value by ALIGN. */ output_size_for_block_move (operands[2], temp1, alignrtx); zoperands[0] = operands[0]; zoperands[3] = plus_constant (operands[0], align); output_load_address (zoperands); xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align);#ifdef NO_UNDERSCORES if (align == 1) output_asm_insn ("\n.Lm%3:\n\tldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tstb %%g1,[%0+%2]", xoperands); else if (align == 2) output_asm_insn ("\n.Lm%3:\n\tlduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tsth %%g1,[%0+%2]", xoperands); else output_asm_insn ("\n.Lm%3:\n\tld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tst %%g1,[%0+%2]", xoperands);#else if (align == 1) output_asm_insn ("\nLm%3:\n\tldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tstb %%g1,[%0+%2]", xoperands); else if (align == 2) output_asm_insn ("\nLm%3:\n\tlduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tsth %%g1,[%0+%2]", xoperands); else output_asm_insn ("\nLm%3:\n\tld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tst %%g1,[%0+%2]", xoperands);#endif return "";}/* What the sparc lacks in hardware, make up for in software. Compute a fairly good sequence of shift and add insns to make a multiply happen. */#define ABS(x) ((x) < 0 ? -(x) : x)char *output_mul_by_constant (insn, operands, unsignedp) rtx insn; rtx *operands; int unsignedp;{ int c; /* Size of constant */ int shifts[BITS_PER_WORD]; /* Table of shifts */ unsigned int p, log; /* A power of two, and its log */ int d1, d2; /* Differences of c and p */ int first = 1; /* True if dst has unknown data in it */ int i; CC_STATUS_INIT; c = INTVAL (operands[2]); if (c == 0) { /* Does happen, at least when not optimizing. */ if (GET_CODE (operands[0]) == MEM) return "st %%g0,%0"; return "mov %%g0,%0"; } output_asm_insn ("! start open coded multiply"); /* Clear out the table of shifts. */ for (i = 0; i < BITS_PER_WORD; ++i) shifts[i] = 0; while (c) { /* Find the power of two nearest ABS(c) */ p = 1, log = 0; do { d1 = ABS(c) - p; p *= 2; ++log; } while (p < ABS(c)); d2 = p - ABS(c); /* Make an appropriate entry in shifts for p. */ if (d2 < d1) { shifts[log] = c < 0 ? -1 : 1; c = c < 0 ? d2 : -d2; } else { shifts[log - 1] = c < 0 ? -1 : 1; c = c < 0 ? -d1 : d1; } } /* Take care of the first insn in sequence. We know we have at least one. */ /* A value of -1 in shifts says to subtract that power of two, and a value of 1 says to add that power of two. */ for (i = 0; ; i++) if (shifts[i]) { if (i) { operands[2] = gen_rtx (CONST_INT, VOIDmode, i); output_asm_insn ("sll %1,%2,%%g1", operands); } else output_asm_insn ("mov %1,%%g1", operands); log = i; if (shifts[i] < 0) output_asm_insn ("sub %%g0,%%g1,%0", operands); else output_asm_insn ("mov %%g1,%0", operands); break; } /* A value of -1 in shifts says to subtract that power of two, and a value of 1 says to add that power of two--continued. */ for (i += 1; i < BITS_PER_WORD; ++i) if (shifts[i]) { if (i - log > 0) { operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log); output_asm_insn ("sll %%g1,%2,%%g1", operands); } else { operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i); output_asm_insn ("sra %%g1,%2,%%g1", operands); } log = i; if (shifts[i] < 0) output_asm_insn ("sub %0,%%g1,%0", operands); else output_asm_insn ("add %0,%%g1,%0", operands); } output_asm_insn ("! end open coded multiply"); return "";}char *output_mul_insn (operands, unsignedp) rtx *operands; int unsignedp;{ int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1; int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1; CC_STATUS_INIT; if (lucky1) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -