📄 xtensa.c
字号:
emit_insn (gen_rtx_SET (VOIDmode, x, temp[phase])); offset_st += amount[phase]; } } while (active[next]); return 1;}voidxtensa_expand_nonlocal_goto (rtx *operands){ rtx goto_handler = operands[1]; rtx containing_fp = operands[3]; /* Generate a call to "__xtensa_nonlocal_goto" (in libgcc); the code is too big to generate in-line. */ if (GET_CODE (containing_fp) != REG) containing_fp = force_reg (Pmode, containing_fp); goto_handler = replace_rtx (copy_rtx (goto_handler), virtual_stack_vars_rtx, containing_fp); emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__xtensa_nonlocal_goto"), 0, VOIDmode, 2, containing_fp, Pmode, goto_handler, Pmode);}static struct machine_function *xtensa_init_machine_status (void){ return ggc_alloc_cleared (sizeof (struct machine_function));}voidxtensa_setup_frame_addresses (void){ /* Set flag to cause FRAME_POINTER_REQUIRED to be set. */ cfun->machine->accesses_prev_frame = 1; emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__xtensa_libgcc_window_spill"), 0, VOIDmode, 0);}/* Emit the assembly for the end of a zero-cost loop. Normally we just emit a comment showing where the end of the loop is. However, if there is a label or a branch at the end of the loop then we need to place a nop there. If the loop ends with a label we need the nop so that branches targeting that label will target the nop (and thus remain in the loop), instead of targeting the instruction after the loop (and thus exiting the loop). If the loop ends with a branch, we need the nop in case the branch is targeting a location inside the loop. When the branch executes it will cause the loop count to be decremented even if it is taken (because it is the last instruction in the loop), so we need to nop after the branch to prevent the loop count from being decremented when the branch is taken. */voidxtensa_emit_loop_end (rtx insn, rtx *operands){ char done = 0; for (insn = PREV_INSN (insn); insn && !done; insn = PREV_INSN (insn)) { switch (GET_CODE (insn)) { case NOTE: case BARRIER: break; case CODE_LABEL: output_asm_insn (TARGET_DENSITY ? "nop.n" : "nop", operands); done = 1; break; default: { rtx body = PATTERN (insn); if (GET_CODE (body) == JUMP_INSN) { output_asm_insn (TARGET_DENSITY ? "nop.n" : "nop", operands); done = 1; } else if ((GET_CODE (body) != USE) && (GET_CODE (body) != CLOBBER)) done = 1; } break; } } output_asm_insn ("# loop end for %0", operands);}char *xtensa_emit_call (int callop, rtx *operands){ static char result[64]; rtx tgt = operands[callop]; if (GET_CODE (tgt) == CONST_INT) sprintf (result, "call8\t0x%lx", INTVAL (tgt)); else if (register_operand (tgt, VOIDmode)) sprintf (result, "callx8\t%%%d", callop); else sprintf (result, "call8\t%%%d", callop); return result;}/* Return the debugger register number to use for 'regno'. */intxtensa_dbx_register_number (int regno){ int first = -1; if (GP_REG_P (regno)) { regno -= GP_REG_FIRST; first = 0; } else if (BR_REG_P (regno)) { regno -= BR_REG_FIRST; first = 16; } else if (FP_REG_P (regno)) { regno -= FP_REG_FIRST; first = 48; } else if (ACC_REG_P (regno)) { first = 0x200; /* Start of Xtensa special registers. */ regno = 16; /* ACCLO is special register 16. */ } /* When optimizing, we sometimes get asked about pseudo-registers that don't represent hard registers. Return 0 for these. */ if (first == -1) return 0; return first + regno;}/* Argument support functions. *//* Initialize CUMULATIVE_ARGS for a function. */voidinit_cumulative_args (CUMULATIVE_ARGS *cum, int incoming){ cum->arg_words = 0; cum->incoming = incoming;}/* Advance the argument to the next argument position. */voidfunction_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type){ int words, max; int *arg_words; arg_words = &cum->arg_words; max = MAX_ARGS_IN_REGISTERS; words = (((mode != BLKmode) ? (int) GET_MODE_SIZE (mode) : int_size_in_bytes (type)) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; if (*arg_words < max && (targetm.calls.must_pass_in_stack (mode, type) || *arg_words + words > max)) *arg_words = max; *arg_words += words;}/* Return an RTL expression containing the register for the given mode, or 0 if the argument is to be passed on the stack. INCOMING_P is nonzero if this is an incoming argument to the current function. */rtxfunction_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, int incoming_p){ int regbase, words, max; int *arg_words; int regno; arg_words = &cum->arg_words; regbase = (incoming_p ? GP_ARG_FIRST : GP_OUTGOING_ARG_FIRST); max = MAX_ARGS_IN_REGISTERS; words = (((mode != BLKmode) ? (int) GET_MODE_SIZE (mode) : int_size_in_bytes (type)) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; if (type && (TYPE_ALIGN (type) > BITS_PER_WORD)) { int align = TYPE_ALIGN (type) / BITS_PER_WORD; *arg_words = (*arg_words + align - 1) & -align; } if (*arg_words + words > max) return (rtx)0; regno = regbase + *arg_words; if (cum->incoming && regno <= A7_REG && regno + words > A7_REG) cfun->machine->need_a7_copy = true; return gen_rtx_REG (mode, regno);}static boolxtensa_return_in_msb (tree valtype){ return (TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (valtype) && int_size_in_bytes (valtype) >= UNITS_PER_WORD);}voidoverride_options (void){ int regno; enum machine_mode mode; if (!TARGET_BOOLEANS && TARGET_HARD_FLOAT) error ("boolean registers required for the floating-point option"); xtensa_char_to_class['q'] = SP_REG; xtensa_char_to_class['a'] = GR_REGS; xtensa_char_to_class['b'] = ((TARGET_BOOLEANS) ? BR_REGS : NO_REGS); xtensa_char_to_class['f'] = ((TARGET_HARD_FLOAT) ? FP_REGS : NO_REGS); xtensa_char_to_class['A'] = ((TARGET_MAC16) ? ACC_REG : NO_REGS); xtensa_char_to_class['B'] = ((TARGET_SEXT) ? GR_REGS : NO_REGS); xtensa_char_to_class['C'] = ((TARGET_MUL16) ? GR_REGS: NO_REGS); xtensa_char_to_class['D'] = ((TARGET_DENSITY) ? GR_REGS: NO_REGS); xtensa_char_to_class['d'] = ((TARGET_DENSITY) ? AR_REGS: NO_REGS); xtensa_char_to_class['W'] = ((TARGET_CONST16) ? GR_REGS: NO_REGS); /* Set up array giving whether a given register can hold a given mode. */ for (mode = VOIDmode; mode != MAX_MACHINE_MODE; mode = (enum machine_mode) ((int) mode + 1)) { int size = GET_MODE_SIZE (mode); enum mode_class class = GET_MODE_CLASS (mode); for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) { int temp; if (ACC_REG_P (regno)) temp = (TARGET_MAC16 && (class == MODE_INT) && (size <= UNITS_PER_WORD)); else if (GP_REG_P (regno)) temp = ((regno & 1) == 0 || (size <= UNITS_PER_WORD)); else if (FP_REG_P (regno)) temp = (TARGET_HARD_FLOAT && (mode == SFmode)); else if (BR_REG_P (regno)) temp = (TARGET_BOOLEANS && (mode == CCmode)); else temp = FALSE; xtensa_hard_regno_mode_ok[(int) mode][regno] = temp; } } init_machine_status = xtensa_init_machine_status; /* Check PIC settings. PIC is only supported when using L32R instructions, and some targets need to always use PIC. */ if (flag_pic && TARGET_CONST16) error ("-f%s is not supported with CONST16 instructions", (flag_pic > 1 ? "PIC" : "pic")); else if (XTENSA_ALWAYS_PIC) { if (TARGET_CONST16) error ("PIC is required but not supported with CONST16 instructions"); flag_pic = 1; } /* There's no need for -fPIC (as opposed to -fpic) on Xtensa. */ if (flag_pic > 1) flag_pic = 1;}/* A C compound statement to output to stdio stream STREAM the assembler syntax for an instruction operand X. X is an RTL expression. CODE is a value that can be used to specify one of several ways of printing the operand. It is used when identical operands must be printed differently depending on the context. CODE comes from the '%' specification that was used to request printing of the operand. If the specification was just '%DIGIT' then CODE is 0; if the specification was '%LTR DIGIT' then CODE is the ASCII code for LTR. If X is a register, this macro should print the register's name. The names can be found in an array 'reg_names' whose type is 'char *[]'. 'reg_names' is initialized from 'REGISTER_NAMES'. When the machine description has a specification '%PUNCT' (a '%' followed by a punctuation character), this macro is called with a null pointer for X and the punctuation character for CODE. 'a', 'c', 'l', and 'n' are reserved. The Xtensa specific codes are: 'd' CONST_INT, print as signed decimal 'x' CONST_INT, print as signed hexadecimal 'K' CONST_INT, print number of bits in mask for EXTUI 'R' CONST_INT, print (X & 0x1f) 'L' CONST_INT, print ((32 - X) & 0x1f) 'D' REG, print second register of double-word register operand 'N' MEM, print address of next word following a memory operand 'v' MEM, if memory reference is volatile, output a MEMW before it 't' any constant, add "@h" suffix for top 16 bits 'b' any constant, add "@l" suffix for bottom 16 bits*/static voidprintx (FILE *file, signed int val){ /* Print a hexadecimal value in a nice way. */ if ((val > -0xa) && (val < 0xa)) fprintf (file, "%d", val); else if (val < 0) fprintf (file, "-0x%x", -val); else fprintf (file, "0x%x", val);}voidprint_operand (FILE *file, rtx x, int letter){ if (!x) error ("PRINT_OPERAND null pointer"); switch (letter) { case 'D': if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG) fprintf (file, "%s", reg_names[xt_true_regnum (x) + 1]); else output_operand_lossage ("invalid %%D value"); break; case 'v': if (GET_CODE (x) == MEM) { /* For a volatile memory reference, emit a MEMW before the load or store. */ if (MEM_VOLATILE_P (x)) fprintf (file, "memw\n\t"); } else output_operand_lossage ("invalid %%v value"); break; case 'N': if (GET_CODE (x) == MEM && (GET_MODE (x) == DFmode || GET_MODE (x) == DImode)) { x = adjust_address (x, GET_MODE (x) == DFmode ? SFmode : SImode, 4); output_address (XEXP (x, 0)); } else output_operand_lossage ("invalid %%N value"); break; case 'K': if (GET_CODE (x) == CONST_INT) { int num_bits = 0; unsigned val = INTVAL (x); while (val & 1) { num_bits += 1; val = val >> 1; } if ((val != 0) || (num_bits == 0) || (num_bits > 16)) fatal_insn ("invalid mask", x); fprintf (file, "%d", num_bits); } else output_operand_lossage ("invalid %%K value"); break; case 'L': if (GET_CODE (x) == CONST_INT) fprintf (file, "%ld", (32 - INTVAL (x)) & 0x1f); else output_operand_lossage ("invalid %%L value"); break; case 'R': if (GET_CODE (x) == CONST_INT) fprintf (file, "%ld", INTVAL (x) & 0x1f); else output_operand_lossage ("invalid %%R value"); break; case 'x': if (GET_CODE (x) == CONST_INT) printx (file, INTVAL (x)); else output_operand_lossage ("invalid %%x value"); break; case 'd': if (GET_CODE (x) == CONST_INT) fprintf (file, "%ld", INTVAL (x)); else output_operand_lossage ("invalid %%d value"); break; case 't': case 'b': if (GET_CODE (x) == CONST_INT) { printx (file, INTVAL (x)); fputs (letter == 't' ? "@h" : "@l", file); } else if (GET_CODE (x) == CONST_DOUBLE) { REAL_VALUE_TYPE r; REAL_VALUE_FROM_CONST_DOUBLE (r, x); if (GET_MODE (x) == SFmode) { long l; REAL_VALUE_TO_TARGET_SINGLE (r, l); fprintf (file, "0x%08lx@%c", l, letter == 't' ? 'h' : 'l'); } else output_operand_lossage ("invalid %%t/%%b value"); } else if (GET_CODE (x) == CONST) { /* X must be a symbolic constant on ELF. Write an expression suitable for 'const16' that sets the high or low 16 bits. */ if (GET_CODE (XEXP (x, 0)) != PLUS || (GET_CODE (XEXP (XEXP (x, 0), 0)) != SYMBOL_REF && GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF) || GET_CODE (XEXP (XEXP (x, 0), 1)) != CONST_INT) output_operand_lossage ("invalid %%t/%%b value"); print_operand (file, XEXP (XEXP (x, 0), 0), 0); fputs (letter == 't' ? "@h" : "@l", file); /* There must be a non-alphanumeric character between 'h' or 'l' and the number. The '-' is added by print_operand() already. */ if (INTVAL (XEXP (XEXP (x, 0), 1)) >= 0) fputs ("+", file); print_operand (file, XEXP (XEXP (x, 0), 1), 0); } else { output_addr_const (file, x); fputs (letter == 't' ? "@h" : "@l", file); } break; default: if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG) fprintf (file, "%s", reg_names[xt_true_regnum (x)]); else if (GET_CODE (x) == MEM) output_address (XEXP (x, 0)); else if (GET_CODE (x) == CONST_INT) fprintf (file, "%ld", INTVAL (x)); else output_addr_const (file, x); }}/* A C compound statement to output to stdio stream STREAM the assembler syntax for an instruction operand that is a memory reference whose address is ADDR. ADDR is an RTL expression. */voidprint_operand_address (FILE *file, rtx addr){ if (!addr)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -