📄 stormy16.c
字号:
voidxstormy16_initialize_trampoline (addr, fnaddr, static_chain) rtx addr; rtx fnaddr; rtx static_chain;{ rtx reg_addr = gen_reg_rtx (Pmode); rtx temp = gen_reg_rtx (HImode); rtx reg_fnaddr = gen_reg_rtx (HImode); rtx reg_addr_mem; reg_addr_mem = gen_rtx_MEM (HImode, reg_addr); emit_move_insn (reg_addr, addr); emit_move_insn (temp, GEN_INT (0x3130 | STATIC_CHAIN_REGNUM)); emit_move_insn (reg_addr_mem, temp); emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx)); emit_move_insn (temp, static_chain); emit_move_insn (reg_addr_mem, temp); emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx)); emit_move_insn (reg_fnaddr, fnaddr); emit_move_insn (temp, reg_fnaddr); emit_insn (gen_andhi3 (temp, temp, GEN_INT (0xFF))); emit_insn (gen_iorhi3 (temp, temp, GEN_INT (0x0200))); emit_move_insn (reg_addr_mem, temp); emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx)); emit_insn (gen_lshrhi3 (reg_fnaddr, reg_fnaddr, GEN_INT (8))); emit_move_insn (reg_addr_mem, reg_fnaddr);}/* Create an RTX representing the place where a function returns a value of data type VALTYPE. VALTYPE is a tree node representing a data type. Write `TYPE_MODE (VALTYPE)' to get the machine mode used to represent that type. On many machines, only the mode is relevant. (Actually, on most machines, scalar values are returned in the same place regardless of mode). If `PROMOTE_FUNCTION_RETURN' is defined, you must apply the same promotion rules specified in `PROMOTE_MODE' if VALTYPE is a scalar type. If the precise function being called is known, FUNC is a tree node (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer. This makes it possible to use a different value-returning convention for specific functions when all their calls are known. `FUNCTION_VALUE' is not used for return vales with aggregate data types, because these are returned in another way. See `STRUCT_VALUE_REGNUM' and related macros. */rtxxstormy16_function_value (valtype, func) tree valtype; tree func ATTRIBUTE_UNUSED;{ enum machine_mode mode; mode = TYPE_MODE (valtype); PROMOTE_MODE (mode, 0, valtype); return gen_rtx_REG (mode, RETURN_VALUE_REGNUM);}/* A C compound statement that outputs the assembler code for a thunk function, used to implement C++ virtual function calls with multiple inheritance. The thunk acts as a wrapper around a virtual function, adjusting the implicit object parameter before handing control off to the real function. First, emit code to add the integer DELTA to the location that contains the incoming first argument. Assume that this argument contains a pointer, and is the one used to pass the `this' pointer in C++. This is the incoming argument *before* the function prologue, e.g. `%o0' on a sparc. The addition must preserve the values of all other incoming arguments. After the addition, emit code to jump to FUNCTION, which is a `FUNCTION_DECL'. This is a direct pure jump, not a call, and does not touch the return address. Hence returning from FUNCTION will return to whoever called the current `thunk'. The effect must be as if @var{function} had been called directly with the adjusted first argument. This macro is responsible for emitting all of the code for a thunk function; TARGET_ASM_FUNCTION_PROLOGUE and TARGET_ASM_FUNCTION_EPILOGUE are not invoked. The THUNK_FNDECL is redundant. (DELTA and FUNCTION have already been extracted from it.) It might possibly be useful on some targets, but probably not. */static voidxstormy16_asm_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function) FILE *file; tree thunk_fndecl ATTRIBUTE_UNUSED; HOST_WIDE_INT delta; HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED; tree function;{ int regnum = FIRST_ARGUMENT_REGISTER; /* There might be a hidden first argument for a returned structure. */ if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)))) regnum += 1; fprintf (file, "\tadd %s,#0x%x\n", reg_names[regnum], (int) delta & 0xFFFF); fputs ("\tjmpf ", file); assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); putc ('\n', file);}/* Mark functions with SYMBOL_REF_FLAG. */static voidxstormy16_encode_section_info (decl, first) tree decl; int first ATTRIBUTE_UNUSED;{ if (TREE_CODE (decl) == FUNCTION_DECL) SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;}/* Output constructors and destructors. Just like default_named_section_asm_out_* but don't set the sections writable. */#undef TARGET_ASM_CONSTRUCTOR#define TARGET_ASM_CONSTRUCTOR xstormy16_asm_out_constructor#undef TARGET_ASM_DESTRUCTOR#define TARGET_ASM_DESTRUCTOR xstormy16_asm_out_destructorstatic voidxstormy16_asm_out_destructor (symbol, priority) rtx symbol; int priority;{ const char *section = ".dtors"; char buf[16]; /* ??? This only works reliably with the GNU linker. */ if (priority != DEFAULT_INIT_PRIORITY) { sprintf (buf, ".dtors.%.5u", /* Invert the numbering so the linker puts us in the proper order; constructors are run from right to left, and the linker sorts in increasing order. */ MAX_INIT_PRIORITY - priority); section = buf; } named_section_flags (section, 0); assemble_align (POINTER_SIZE); assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);}static voidxstormy16_asm_out_constructor (symbol, priority) rtx symbol; int priority;{ const char *section = ".ctors"; char buf[16]; /* ??? This only works reliably with the GNU linker. */ if (priority != DEFAULT_INIT_PRIORITY) { sprintf (buf, ".ctors.%.5u", /* Invert the numbering so the linker puts us in the proper order; constructors are run from right to left, and the linker sorts in increasing order. */ MAX_INIT_PRIORITY - priority); section = buf; } named_section_flags (section, 0); assemble_align (POINTER_SIZE); assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);}/* Print a memory address as an operand to reference that memory location. */voidxstormy16_print_operand_address (file, address) FILE * file; rtx address;{ HOST_WIDE_INT offset; int pre_dec, post_inc; /* There are a few easy cases. */ if (GET_CODE (address) == CONST_INT) { fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (address) & 0xFFFF); return; } if (CONSTANT_P (address) || GET_CODE (address) == CODE_LABEL) { output_addr_const (file, address); return; } /* Otherwise, it's hopefully something of the form (plus:HI (pre_dec:HI (reg:HI ...)) (const_int ...)) */ if (GET_CODE (address) == PLUS) { if (GET_CODE (XEXP (address, 1)) != CONST_INT) abort (); offset = INTVAL (XEXP (address, 1)); address = XEXP (address, 0); } else offset = 0; pre_dec = (GET_CODE (address) == PRE_DEC); post_inc = (GET_CODE (address) == POST_INC); if (pre_dec || post_inc) address = XEXP (address, 0); if (GET_CODE (address) != REG) abort (); fputc ('(', file); if (pre_dec) fputs ("--", file); fputs (reg_names [REGNO (address)], file); if (post_inc) fputs ("++", file); if (offset != 0) { fputc (',', file); fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset); } fputc (')', file);}/* Print an operand to an assembler instruction. */voidxstormy16_print_operand (file, x, code) FILE * file; rtx x; int code;{ switch (code) { case 'B': /* There is either one bit set, or one bit clear, in X. Print it preceded by '#'. */ { HOST_WIDE_INT xx = 1; HOST_WIDE_INT l; if (GET_CODE (x) == CONST_INT) xx = INTVAL (x); else output_operand_lossage ("`B' operand is not constant"); l = exact_log2 (xx); if (l == -1) l = exact_log2 (~xx); if (l == -1) output_operand_lossage ("`B' operand has multiple bits set"); fputs (IMMEDIATE_PREFIX, file); fprintf (file, HOST_WIDE_INT_PRINT_DEC, l); return; } case 'C': /* Print the symbol without a surrounding @fptr(). */ if (GET_CODE (x) == SYMBOL_REF) assemble_name (file, XSTR (x, 0)); else if (GET_CODE (x) == LABEL_REF) output_asm_label (x); else xstormy16_print_operand_address (file, x); return; case 'o': case 'O': /* Print the immediate operand less one, preceded by '#'. For 'O', negate it first. */ { HOST_WIDE_INT xx = 0; if (GET_CODE (x) == CONST_INT) xx = INTVAL (x); else output_operand_lossage ("`o' operand is not constant"); if (code == 'O') xx = -xx; fputs (IMMEDIATE_PREFIX, file); fprintf (file, HOST_WIDE_INT_PRINT_DEC, xx - 1); return; } case 0: /* Handled below. */ break; default: output_operand_lossage ("xstormy16_print_operand: unknown code"); return; } switch (GET_CODE (x)) { case REG: fputs (reg_names [REGNO (x)], file); break; case MEM: xstormy16_print_operand_address (file, XEXP (x, 0)); break; default: /* Some kind of constant or label; an immediate operand, so prefix it with '#' for the assembler. */ fputs (IMMEDIATE_PREFIX, file); output_addr_const (file, x); break; } return;}/* Expander for the `casesi' pattern. INDEX is the index of the switch statement. LOWER_BOUND is a CONST_INT that is the value of INDEX corresponding to the first table entry. RANGE is the number of table entries. TABLE is an ADDR_VEC that is the jump table. DEFAULT_LABEL is the address to branch to if INDEX is outside the range LOWER_BOUND to LOWER_BOUND+RANGE-1.*/void xstormy16_expand_casesi (index, lower_bound, range, table, default_label) rtx index; rtx lower_bound; rtx range; rtx table; rtx default_label;{ HOST_WIDE_INT range_i = INTVAL (range); rtx int_index; /* This code uses 'br', so it can deal only with tables of size up to 8192 entries. */ if (range_i >= 8192) sorry ("switch statement of size %lu entries too large", (unsigned long) range_i); index = expand_binop (SImode, sub_optab, index, lower_bound, NULL_RTX, 0, OPTAB_LIB_WIDEN); emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, SImode, 1, default_label); int_index = gen_lowpart_common (HImode, index); emit_insn (gen_ashlhi3 (int_index, int_index, GEN_INT (2))); emit_jump_insn (gen_tablejump_pcrel (int_index, table));}/* Output an ADDR_VEC. It is output as a sequence of 'jmpf' instructions, without label or alignment or any other special constructs. We know that the previous instruction will be the `tablejump_pcrel' output above. TODO: it might be nice to output 'br' instructions if they could all reach. */voidxstormy16_output_addr_vec (file, label, table) FILE *file; rtx label ATTRIBUTE_UNUSED; rtx table;{ int vlen, idx; function_section (current_function_decl); vlen = XVECLEN (table, 0); for (idx = 0; idx < vlen; idx++) { fputs ("\tjmpf ", file); output_asm_label (XEXP (XVECEXP (table, 0, idx), 0)); fputc ('\n', file); }}/* Expander for the `call' patterns. INDEX is the index of the switch statement. LOWER_BOUND is a CONST_INT that is the value of INDEX corresponding to the first table entry. RANGE is the number of table entries. TABLE is an ADDR_VEC that is the jump table. DEFAULT_LABEL is the address to branch to if INDEX is outside the range LOWER_BOUND to LOWER_BOUND+RANGE-1.*/void xstormy16_expand_call (retval, dest, counter) rtx retval; rtx dest; rtx counter;{ rtx call, temp; enum machine_mode mode; if (GET_CODE (dest) != MEM) abort (); dest = XEXP (dest, 0); if (! CONSTANT_P (dest) && GET_CODE (dest) != REG) dest = force_reg (Pmode, dest); if (retval == NULL) mode = VOIDmode; else mode = GET_MODE (retval); call = gen_rtx_CALL (mode, gen_rtx_MEM (FUNCTION_MODE, dest), counter); if (retval) call = gen_rtx_SET (VOIDmode, retval, call); if (! CONSTANT_P (dest)) { temp = gen_reg_rtx (HImode); emit_move_insn (temp, const0_rtx); } else temp = const0_rtx; call = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, call, gen_rtx_USE (VOIDmode, temp)));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -