📄 s390.c
字号:
case CODE_LABEL: case SYMBOL_REF: output_addr_const (file, x); break; case UNSPEC: if (XVECLEN (x, 0) != 1) output_operand_lossage ("invalid UNSPEC as operand (1)"); switch (XINT (x, 1)) { case 100: s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); fprintf (file, "-.LT%X", s390_function_count); break; case 110: s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); fprintf (file, "@GOT12"); break; case 111: s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); fprintf (file, "@GOTENT"); break; case 112: s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); fprintf (file, "@GOT"); break; case 113: s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); fprintf (file, "@PLT"); break; case 114: s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); fprintf (file, "@PLT-.LT%X", s390_function_count); break; default: output_operand_lossage ("invalid UNSPEC as operand (2)"); break; } break; default: fatal_insn ("UNKNOWN in s390_output_symbolic_const !?", x); break; }}/* Output address operand ADDR in assembler syntax to stdio stream FILE. */voidprint_operand_address (file, addr) FILE *file; rtx addr;{ struct s390_address ad; if (!s390_decompose_address (addr, &ad, TRUE)) output_operand_lossage ("Cannot decompose address."); if (ad.disp) s390_output_symbolic_const (file, ad.disp); else fprintf (file, "0"); if (ad.base && ad.indx) fprintf (file, "(%s,%s)", reg_names[REGNO (ad.indx)], reg_names[REGNO (ad.base)]); else if (ad.base) fprintf (file, "(%s)", reg_names[REGNO (ad.base)]);}/* Output operand X in assembler syntax to stdio stream FILE. CODE specified the format flag. The following format flags are recognized: 'C': print opcode suffix for branch condition. 'D': print opcode suffix for inverse branch condition. 'O': print only the displacement of a memory reference. 'R': print only the base register of a memory reference. 'N': print the second word of a DImode operand. 'M': print the second word of a TImode operand. 'b': print integer X as if it's an unsigned byte. 'x': print integer X as if it's an unsigned word. 'h': print integer X as if it's a signed word. */voidprint_operand (file, x, code) FILE *file; rtx x; int code;{ switch (code) { case 'C': fprintf (file, s390_branch_condition_mnemonic (x, FALSE)); return; case 'D': fprintf (file, s390_branch_condition_mnemonic (x, TRUE)); return; case 'O': { struct s390_address ad; if (GET_CODE (x) != MEM || !s390_decompose_address (XEXP (x, 0), &ad, TRUE) || ad.indx) abort (); if (ad.disp) s390_output_symbolic_const (file, ad.disp); else fprintf (file, "0"); } return; case 'R': { struct s390_address ad; if (GET_CODE (x) != MEM || !s390_decompose_address (XEXP (x, 0), &ad, TRUE) || ad.indx) abort (); if (ad.base) fprintf (file, "%s", reg_names[REGNO (ad.base)]); else fprintf (file, "0"); } return; case 'N': if (GET_CODE (x) == REG) x = gen_rtx_REG (GET_MODE (x), REGNO (x) + 1); else if (GET_CODE (x) == MEM) x = change_address (x, VOIDmode, plus_constant (XEXP (x, 0), 4)); else abort (); break; case 'M': if (GET_CODE (x) == REG) x = gen_rtx_REG (GET_MODE (x), REGNO (x) + 1); else if (GET_CODE (x) == MEM) x = change_address (x, VOIDmode, plus_constant (XEXP (x, 0), 8)); else abort (); break; } switch (GET_CODE (x)) { case REG: fprintf (file, "%s", reg_names[REGNO (x)]); break; case MEM: output_address (XEXP (x, 0)); break; case CONST: case CODE_LABEL: case LABEL_REF: case SYMBOL_REF: s390_output_symbolic_const (file, x); break; case CONST_INT: if (code == 'b') fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xff); else if (code == 'x') fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xffff); else if (code == 'h') fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((INTVAL (x) & 0xffff) ^ 0x8000) - 0x8000); else fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); break; case CONST_DOUBLE: if (GET_MODE (x) != VOIDmode) abort (); if (code == 'b') fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x) & 0xff); else if (code == 'x') fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x) & 0xffff); else if (code == 'h') fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((CONST_DOUBLE_LOW (x) & 0xffff) ^ 0x8000) - 0x8000); else abort (); break; default: fatal_insn ("UNKNOWN in print_operand !?", x); break; }}/* Target hook for assembling integer objects. We need to define it here to work a round a bug in some versions of GAS, which couldn't handle values smaller than INT_MIN when printed in decimal. */static bools390_assemble_integer (x, size, aligned_p) rtx x; unsigned int size; int aligned_p;{ if (size == 8 && aligned_p && GET_CODE (x) == CONST_INT && INTVAL (x) < INT_MIN) { fputs ("\t.quad\t", asm_out_file); fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, INTVAL (x)); putc ('\n', asm_out_file); return true; } return default_assemble_integer (x, size, aligned_p);}#define DEBUG_SCHED 0/* Returns true if register REGNO is used for forming a memory address in expression X. */static intreg_used_in_mem_p (regno, x) int regno; rtx x;{ enum rtx_code code = GET_CODE (x); int i, j; const char *fmt; if (code == MEM) { if (refers_to_regno_p (regno, regno+1, XEXP (x, 0), 0)) return 1; } else if (code == SET && GET_CODE (SET_DEST (x)) == PC) { if (refers_to_regno_p (regno, regno+1, SET_SRC (x), 0)) return 1; } fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e' && reg_used_in_mem_p (regno, XEXP (x, i))) return 1; else if (fmt[i] == 'E') for (j = 0; j < XVECLEN (x, i); j++) if (reg_used_in_mem_p (regno, XVECEXP (x, i, j))) return 1; } return 0;}/* Returns true if expression DEP_RTX sets an address register used by instruction INSN to address memory. */static int addr_generation_dependency_p (dep_rtx, insn) rtx dep_rtx; rtx insn;{ rtx target, pat; if (GET_CODE (dep_rtx) == SET) { target = SET_DEST (dep_rtx); if (GET_CODE (target) == REG) { int regno = REGNO (target); if (get_attr_type (insn) == TYPE_LA) { pat = PATTERN (insn); if (GET_CODE (pat) == PARALLEL) { if (XVECLEN (pat, 0) != 2) abort(); pat = XVECEXP (pat, 0, 0); } if (GET_CODE (pat) == SET) return refers_to_regno_p (regno, regno+1, SET_SRC (pat), 0); else abort(); } else if (get_attr_atype (insn) == ATYPE_MEM) return reg_used_in_mem_p (regno, PATTERN (insn)); } } return 0;}/* Return the modified cost of the dependency of instruction INSN on instruction DEP_INSN through the link LINK. COST is the default cost of that dependency. Data dependencies are all handled without delay. However, if a register is modified and subsequently used as base or index register of a memory reference, at least 4 cycles need to pass between setting and using the register to avoid pipeline stalls. An exception is the LA instruction. An address generated by LA can be used by introducing only a one cycle stall on the pipeline. */static ints390_adjust_cost (insn, link, dep_insn, cost) rtx insn; rtx link; rtx dep_insn; int cost;{ rtx dep_rtx; int i; /* If the dependence is an anti-dependence, there is no cost. For an output dependence, there is sometimes a cost, but it doesn't seem worth handling those few cases. */ if (REG_NOTE_KIND (link) != 0) return 0; /* If we can't recognize the insns, we can't really do anything. */ if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0) return cost; dep_rtx = PATTERN (dep_insn); if (GET_CODE (dep_rtx) == SET) { if (addr_generation_dependency_p (dep_rtx, insn)) { cost += (get_attr_type (dep_insn) == TYPE_LA) ? 1 : 4; if (DEBUG_SCHED) { fprintf (stderr, "\n\nAddress dependency detected: cost %d\n", cost); debug_rtx (dep_insn); debug_rtx (insn); } } } else if (GET_CODE (dep_rtx) == PARALLEL) { for (i = 0; i < XVECLEN (dep_rtx, 0); i++) { if (addr_generation_dependency_p (XVECEXP (dep_rtx, 0, i), insn)) { cost += (get_attr_type (dep_insn) == TYPE_LA) ? 1 : 4; if (DEBUG_SCHED) { fprintf (stderr, "\n\nAddress dependency detected: cost %d\n" ,cost); debug_rtx (dep_insn); debug_rtx (insn); } } } } return cost;}/* A C statement (sans semicolon) to update the integer scheduling priority INSN_PRIORITY (INSN). Reduce the priority to execute the INSN earlier, increase the priority to execute INSN later. Do not define this macro if you do not need to adjust the scheduling priorities of insns. A LA instruction maybe scheduled later, since the pipeline bypasses the calculated value. */static ints390_adjust_priority (insn, priority) rtx insn ATTRIBUTE_UNUSED; int priority;{ if (! INSN_P (insn)) return priority; if (GET_CODE (PATTERN (insn)) == USE || GET_CODE (PATTERN (insn)) == CLOBBER) return priority; switch (get_attr_type (insn)) { default: break; case TYPE_LA: if (priority >= 0 && priority < 0x01000000) priority <<= 3; break; case TYPE_LM: /* LM in epilogue should never be scheduled. This is due to literal access done in function body. The usage of register 13 is not mentioned explicitly, leading to scheduling 'LM' accross this instructions. */ priority = 0x7fffffff; break; } return priority;}/* Split all branches that exceed the maximum distance. */static void s390_split_branches (void){ rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM); rtx insn, pat, label, target, jump, tmp; /* In 64-bit mode we can jump +- 4GB. */ if (TARGET_64BIT) return; /* Find all branches that exceed 64KB, and split them. */ for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { if (GET_CODE (insn) != JUMP_INSN) continue; pat = PATTERN (insn); if (GET_CODE (pat) != SET) continue; if (GET_CODE (SET_SRC (pat)) == LABEL_REF) { label = SET_SRC (pat); } else if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE) { if (GET_CODE (XEXP (SET_SRC (pat), 1)) == LABEL_REF) label = XEXP (SET_SRC (pat), 1); else if (GET_CODE (XEXP (SET_SRC (pat), 2)) == LABEL_REF) label = XEXP (SET_SRC (pat), 2); else continue; } else continue; if (get_attr_length (insn) == 4) continue; if (flag_pic) { target = gen_rtx_UNSPEC (SImode, gen_rtvec (1, label), 100); target = gen_rtx_CONST (SImode, target); target = force_const_mem (SImode, target); jump = gen_rtx_REG (Pmode, BASE_REGISTER); jump = gen_rtx_PLUS (Pmode, jump, temp_reg); } else { target = force_const_mem (Pmode, label); jump = temp_reg; } if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE) { if (GET_CODE (XEXP (SET_SRC (pat), 1)) == LABEL_REF) jump = gen_rtx_IF_THEN_ELSE (VOIDmode, XEXP (SET_SRC (pat), 0), jump, pc_rtx); else jump = gen_rtx_IF_THEN_ELSE (VOIDmode, XEXP (SET_SRC (pat), 0), pc_rtx, jump); } tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, target), insn); INSN_ADDRESSES_NEW (tmp, -1); tmp = emit_jump_insn_before (gen_rtx_SET (VOIDmode, pc_rtx, jump), insn); INSN_ADDRESSES_NEW (tmp, -1); remove_ins
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -