📄 pa.c
字号:
if (GET_CODE (operands[0]) == REG) { rtx xoperands[3]; xoperands[2] = operands[1]; xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); xoperands[0] = operands[0]; output_asm_insn ("fstds %2,-16(0,30)\n\tldw -12(0,30),%1\n\tldw -16(0,30),%0", xoperands); } else output_asm_insn ("fstds%F0 %1,%0", operands); } else abort (); return "";}/* Return a REG that occurs in ADDR with coefficient 1. ADDR can be effectively incremented by incrementing REG. */static rtxfind_addr_reg (addr) rtx addr;{ while (GET_CODE (addr) == PLUS) { if (GET_CODE (XEXP (addr, 0)) == REG) 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 ();}/* Emit code to perform a block move. Restriction: If the length argument is non-constant, alignment must be 4. OPERANDS[0] is the destination pointer as a REG, clobbered. OPERANDS[1] is the source pointer as a REG, clobbered. if SIZE_IS_CONSTANT OPERANDS[2] is a register for temporary storage. OPERANDS[4] is the size as a CONST_INT else OPERANDS[2] is a REG which will contain the size, clobbered. OPERANDS[3] is a register for temporary storage. OPERANDS[5] is the alignment safe to use, as a CONST_INT. */char *output_block_move (operands, size_is_constant) rtx *operands; int size_is_constant;{ int align = INTVAL (operands[5]); unsigned long n_bytes; /* We can't move more than four bytes at a time because the PA has no longer integer move insns. (Could use fp mem ops?) */ if (align > 4) align = 4; if (size_is_constant) { unsigned long n_items; unsigned long offset; rtx temp; n_bytes = INTVAL (operands[4]); if (n_bytes == 0) return ""; if (align >= 4) { /* Don't unroll too large blocks. */ if (n_bytes > 64) goto copy_with_loop; /* Read and store using two registers, and hide latency by deferring the stores until three instructions after the corresponding load. The last load insn will read the entire word were the last bytes are, possibly past the end of the source block, but since loads are aligned, this is harmless. */ output_asm_insn ("ldws,ma 4(0,%1),%2", operands); for (offset = 4; offset < n_bytes; offset += 4) { output_asm_insn ("ldws,ma 4(0,%1),%3", operands); output_asm_insn ("stws,ma %2,4(0,%0)", operands); temp = operands[2]; operands[2] = operands[3]; operands[3] = temp; } if (n_bytes % 4 == 0) /* Store the last word. */ output_asm_insn ("stw %2,0(0,%0)", operands); else { /* Store the last, partial word. */ operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes % 4); output_asm_insn ("stbys,e %2,%4(0,%0)", operands); } return ""; } if (align >= 2 && n_bytes >= 2) { output_asm_insn ("ldhs,ma 2(0,%1),%2", operands); for (offset = 2; offset + 2 <= n_bytes; offset += 2) { output_asm_insn ("ldhs,ma 2(0,%1),%3", operands); output_asm_insn ("sths,ma %2,2(0,%0)", operands); temp = operands[2]; operands[2] = operands[3]; operands[3] = temp; } if (n_bytes % 2 != 0) output_asm_insn ("ldb 0(0,%1),%3", operands); output_asm_insn ("sths,ma %2,2(0,%0)", operands); if (n_bytes % 2 != 0) output_asm_insn ("stb %3,0(0,%0)", operands); return ""; } output_asm_insn ("ldbs,ma 1(0,%1),%2", operands); for (offset = 1; offset + 1 <= n_bytes; offset += 1) { output_asm_insn ("ldbs,ma 1(0,%1),%3", operands); output_asm_insn ("stbs,ma %2,1(0,%0)", operands); temp = operands[2]; operands[2] = operands[3]; operands[3] = temp; } output_asm_insn ("stb %2,0(0,%0)", operands); return ""; } if (align != 4) abort(); copy_with_loop: if (size_is_constant) { /* Size is compile-time determined, and also not very small (such small cases are handled above). */ operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes - 4); output_asm_insn ("ldo %4(0),%2", operands); } else { /* Decrement counter by 4, and if it becomes negative, jump past the word copying loop. */ output_asm_insn ("addib,<,n -4,%2,.+16", operands); } /* Copying loop. Note that the first load is in the annulled delay slot of addib. Is it OK on PA to have a load in a delay slot, i.e. is a possible page fault stopped in time? */ output_asm_insn ("ldws,ma 4(0,%1),%3", operands); output_asm_insn ("addib,>= -4,%2,.-4", operands); output_asm_insn ("stws,ma %3,4(0,%0)", operands); /* The counter is negative, >= -4. The remaining number of bytes are determined by the two least significant bits. */ if (size_is_constant) { if (n_bytes % 4 != 0) { /* Read the entire word of the source block tail. */ output_asm_insn ("ldw 0(0,%1),%3", operands); operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes % 4); output_asm_insn ("stbys,e %3,%4(0,%0)", operands); } } else { /* Add 4 to counter. If it becomes zero, we're done. */ output_asm_insn ("addib,=,n 4,%2,.+16", operands); /* Read the entire word of the source block tail. (Also this load is in an annulled delay slot.) */ output_asm_insn ("ldw 0(0,%1),%3", operands); /* Make %0 point at the first byte after the destination block. */ output_asm_insn ("add %2,%0,%0", operands); /* Store the leftmost bytes, up to, but not including, the address in %0. */ output_asm_insn ("stbys,e %3,0(0,%0)", operands); } return "";}char *output_and (operands) rtx *operands;{ if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0) { unsigned mask = INTVAL (operands[2]); int ls0, ls1, ms0, p, len; for (ls0 = 0; ls0 < 32; ls0++) if ((mask & (1 << ls0)) == 0) break; for (ls1 = ls0; ls1 < 32; ls1++) if ((mask & (1 << ls1)) != 0) break; for (ms0 = ls1; ms0 < 32; ms0++) if ((mask & (1 << ms0)) == 0) break; if (ms0 != 32) abort(); if (ls1 == 32) { len = ls0; if (len == 0) abort (); operands[2] = gen_rtx (CONST_INT, VOIDmode, len); return "extru %1,31,%2,%0"; } else { /* We could use this `depi' for the case above as well, but `depi' requires one more register file access than an `extru'. */ p = 31 - ls0; len = ls1 - ls0; operands[2] = gen_rtx (CONST_INT, VOIDmode, p); operands[3] = gen_rtx (CONST_INT, VOIDmode, len); return "depi 0,%2,%3,%0"; } } else return "and %1,%2,%0";}char *output_ior (operands) rtx *operands;{ if (GET_CODE (operands[2]) == CONST_INT) { unsigned mask = INTVAL (operands[2]); int bs0, bs1, bs2, p, len; if (INTVAL (operands[2]) == 0) return "copy %1,%0"; for (bs0 = 0; bs0 < 32; bs0++) if ((mask & (1 << bs0)) != 0) break; for (bs1 = bs0; bs1 < 32; bs1++) if ((mask & (1 << bs1)) == 0) break; if (bs1 != 32 && ((unsigned) 1 << bs1) <= mask) abort(); p = 31 - bs0; len = bs1 - bs0; operands[2] = gen_rtx (CONST_INT, VOIDmode, p); operands[3] = gen_rtx (CONST_INT, VOIDmode, len); return "depi -1,%2,%3,%0"; } else return "or %1,%2,%0";}/* Output an ascii string. */output_ascii (file, p, size) FILE *file; unsigned char *p; int size;{ int i; int chars_output; unsigned char partial_output[16]; /* Max space 4 chars can occupy. */ /* The HP assembler can only take strings of 256 characters at one time. This is a limitation on input line length, *not* the length of the string. Sigh. Even worse, it seems that the restriction is in number of input characters (see \xnn & \whatever). So we have to do this very carefully. */ fprintf (file, "\t.STRING \""); chars_output = 0; for (i = 0; i < size; i += 4) { int co = 0; int io = 0; for (io = 0, co = 0; io < MIN (4, size - i); io++) { register unsigned int c = p[i + io]; if (c == '\"' || c == '\\') partial_output[co++] = '\\'; if (c >= ' ' && c < 0177) partial_output[co++] = c; else { unsigned int hexd; partial_output[co++] = '\\'; partial_output[co++] = 'x'; hexd = c / 16 - 0 + '0'; if (hexd > '9') hexd -= '9' - 'a' + 1; partial_output[co++] = hexd; hexd = c % 16 - 0 + '0'; if (hexd > '9') hexd -= '9' - 'a' + 1; partial_output[co++] = hexd; } } if (chars_output + co > 243) { fprintf (file, "\"\n\t.STRING \""); chars_output = 0; } fwrite (partial_output, 1, co, file); chars_output += co; co = 0; } fprintf (file, "\"\n");}/* You may have trouble believing this, but this is the HP825 stack layout. Wow. Offset Contents Variable arguments (optional; any number may be allocated) SP-(4*(N+9)) arg word N : : SP-56 arg word 5 SP-52 arg word 4 Fixed arguments (must be allocated; may remain unused) SP-48 arg word 3 SP-44 arg word 2 SP-40 arg word 1 SP-36 arg word 0 Frame Marker SP-32 External Data Pointer (DP) SP-28 External sr4 SP-24 External/stub RP (RP') SP-20 Current RP SP-16 Static Link SP-12 Clean up SP-8 Calling Stub RP (RP'') SP-4 Previous SP Top of Frame SP-0 Stack Pointer (points to next available address)*//* This function saves registers as follows. Registers marked with ' are this function's registers (as opposed to the previous function's). If a frame_pointer isn't needed, r4 is saved as a general register; the space for the frame pointer is still allocated, though, to keep things simple. Top of Frame SP (FP') Previous FP SP + 4 Alignment filler (sigh) SP + 8 Space for locals reserved here. . . . SP + n All call saved register used. . . . SP + o All call saved fp registers used. . . . SP + p (SP') points to next available address. *//* Helper functions */voidprint_stw (file, r, disp, base) FILE *file; int r, disp, base;{ if (VAL_14_BITS_P (disp)) fprintf (file, "\tstw %d,%d(0,%d)\n", r, disp, base); else fprintf (file, "\taddil L'%d,%d\n\tstw %d,R'%d(0,1)\n", disp, base, r, disp);}voidprint_ldw (file, r, disp, base) FILE *file; int r, disp, base;{ if (VAL_14_BITS_P (disp)) fprintf (file, "\tldw %d(0,%d),%d\n", disp, base, r); else fprintf (file, "\taddil L'%d,%d\n\tldw R'%d(0,1),%d\n", disp, base, disp, r);}/* Global variables set by FUNCTION_PROLOGUE. *//* Size of frame. Need to know this to emit return insns from leaf procedures. */int apparent_fsize;int actual_fsize;int local_fsize, save_fregs;intcompute_frame_size (size, leaf_function, fregs_live) int size; int leaf_function; int *fregs_live;{ extern int current_function_outgoing_args_size; int i; /* 8 is space for frame pointer + filler */ local_fsize = actual_fsize = size + 8; /* fp is stored in a special place. */ for (i = 18; i >= 5; i--) if (regs_ever_live[i]) actual_fsize += 4; if (regs_ever_live[3]) actual_fsize += 4; actual_fsize = (actual_fsize + 7) & ~7; if (!TARGET_SNAKE) { for (i = 47; i >= 44; i--) if (regs_ever_live[i]) { actual_fsize += 8; if (fregs_live) *fregs_live = 1; } } else { for (i = 90; i >= 72; i -= 2) if (regs_ever_live[i] || regs_ever_live[i + 1]) { actual_fsize += 8; if (fregs_live) *fregs_live = 1; } } return actual_fsize + current_function_outgoing_args_size;} voidoutput_function_prologue (file, size, leaf_function) FILE *file; int size; int leaf_function;{ extern char call_used_regs[]; extern int frame_pointer_needed; extern int current_function_returns_struct; int i, offset; save_fregs = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -