📄 stormy16.c
字号:
emit_call_insn (call);}/* Expanders for multiword computational operations. *//* Expander for arithmetic operations; emit insns to compute (set DEST (CODE:MODE SRC0 SRC1)) using CARRY as a temporary. When CODE is COMPARE, a branch template is generated (this saves duplicating code in xstormy16_split_cbranch). */void xstormy16_expand_arith (mode, code, dest, src0, src1, carry) enum machine_mode mode; enum rtx_code code; rtx dest; rtx src0; rtx src1; rtx carry;{ int num_words = GET_MODE_BITSIZE (mode) / BITS_PER_WORD; int i; int firstloop = 1; if (code == NEG) { rtx zero_reg = gen_reg_rtx (word_mode); emit_move_insn (zero_reg, src0); src0 = zero_reg; } for (i = 0; i < num_words; i++) { rtx w_src0, w_src1, w_dest; rtx insn; if (code == NEG) w_src0 = src0; else w_src0 = simplify_gen_subreg (word_mode, src0, mode, i * UNITS_PER_WORD); w_src1 = simplify_gen_subreg (word_mode, src1, mode, i * UNITS_PER_WORD); w_dest = simplify_gen_subreg (word_mode, dest, mode, i * UNITS_PER_WORD); switch (code) { case PLUS: if (firstloop && GET_CODE (w_src1) == CONST_INT && INTVAL (w_src1) == 0) continue; if (firstloop) insn = gen_addchi4 (w_dest, w_src0, w_src1, carry); else insn = gen_addchi5 (w_dest, w_src0, w_src1, carry, carry); break; case NEG: case MINUS: case COMPARE: if (code == COMPARE && i == num_words - 1) { rtx branch, sub, clobber, sub_1; sub_1 = gen_rtx_MINUS (HImode, w_src0, gen_rtx_ZERO_EXTEND (HImode, carry)); sub = gen_rtx_SET (VOIDmode, w_dest, gen_rtx_MINUS (HImode, sub_1, w_src1)); clobber = gen_rtx_CLOBBER (VOIDmode, carry); branch = gen_rtx_SET (VOIDmode, pc_rtx, gen_rtx_IF_THEN_ELSE (VOIDmode, gen_rtx_EQ (HImode, sub_1, w_src1), pc_rtx, pc_rtx)); insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (3, branch, sub, clobber)); } else if (firstloop && code != COMPARE && GET_CODE (w_src1) == CONST_INT && INTVAL (w_src1) == 0) continue; else if (firstloop) insn = gen_subchi4 (w_dest, w_src0, w_src1, carry); else insn = gen_subchi5 (w_dest, w_src0, w_src1, carry, carry); break; case IOR: case XOR: case AND: if (GET_CODE (w_src1) == CONST_INT && INTVAL (w_src1) == -(code == AND)) continue; insn = gen_rtx_SET (VOIDmode, w_dest, gen_rtx (code, mode, w_src0, w_src1)); break; case NOT: insn = gen_rtx_SET (VOIDmode, w_dest, gen_rtx_NOT (mode, w_src0)); break; default: abort (); } firstloop = 0; emit (insn); }}/* Return 1 if OP is a shift operator. */intshift_operator (op, mode) register rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ enum rtx_code code = GET_CODE (op); return (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT);}/* The shift operations are split at output time for constant values; variable-width shifts get handed off to a library routine. Generate an output string to do (set X (CODE:MODE X SIZE_R)) SIZE_R will be a CONST_INT, X will be a hard register. */const char * xstormy16_output_shift (mode, code, x, size_r, temp) enum machine_mode mode; enum rtx_code code; rtx x; rtx size_r; rtx temp;{ HOST_WIDE_INT size; const char *r0, *r1, *rt; static char r[64]; if (GET_CODE (size_r) != CONST_INT || GET_CODE (x) != REG || mode != SImode) abort (); size = INTVAL (size_r) & (GET_MODE_BITSIZE (mode) - 1); if (size == 0) return ""; r0 = reg_names [REGNO (x)]; r1 = reg_names [REGNO (x) + 1]; /* For shifts of size 1, we can use the rotate instructions. */ if (size == 1) { switch (code) { case ASHIFT: sprintf (r, "shl %s,#1 | rlc %s,#1", r0, r1); break; case ASHIFTRT: sprintf (r, "asr %s,#1 | rrc %s,#1", r1, r0); break; case LSHIFTRT: sprintf (r, "shr %s,#1 | rrc %s,#1", r1, r0); break; default: abort (); } return r; } /* For large shifts, there are easy special cases. */ if (size == 16) { switch (code) { case ASHIFT: sprintf (r, "mov %s,%s | mov %s,#0", r1, r0, r0); break; case ASHIFTRT: sprintf (r, "mov %s,%s | asr %s,#15", r0, r1, r1); break; case LSHIFTRT: sprintf (r, "mov %s,%s | mov %s,#0", r0, r1, r1); break; default: abort (); } return r; } if (size > 16) { switch (code) { case ASHIFT: sprintf (r, "mov %s,%s | mov %s,#0 | shl %s,#%d", r1, r0, r0, r1, (int) size - 16); break; case ASHIFTRT: sprintf (r, "mov %s,%s | asr %s,#15 | asr %s,#%d", r0, r1, r1, r0, (int) size - 16); break; case LSHIFTRT: sprintf (r, "mov %s,%s | mov %s,#0 | shr %s,#%d", r0, r1, r1, r0, (int) size - 16); break; default: abort (); } return r; } /* For the rest, we have to do more work. In particular, we need a temporary. */ rt = reg_names [REGNO (temp)]; switch (code) { case ASHIFT: sprintf (r, "mov %s,%s | shl %s,#%d | shl %s,#%d | shr %s,#%d | or %s,%s", rt, r0, r0, (int) size, r1, (int) size, rt, (int) 16-size, r1, rt); break; case ASHIFTRT: sprintf (r, "mov %s,%s | asr %s,#%d | shr %s,#%d | shl %s,#%d | or %s,%s", rt, r1, r1, (int) size, r0, (int) size, rt, (int) 16-size, r0, rt); break; case LSHIFTRT: sprintf (r, "mov %s,%s | shr %s,#%d | shr %s,#%d | shl %s,#%d | or %s,%s", rt, r1, r1, (int) size, r0, (int) size, rt, (int) 16-size, r0, rt); break; default: abort (); } return r;}/* Attribute handling. *//* Return nonzero if the function is an interrupt function. */intxstormy16_interrupt_function_p (){ tree attributes; /* The dwarf2 mechanism asks for INCOMING_FRAME_SP_OFFSET before any functions are declared, which is demonstrably wrong, but it is worked around here. FIXME. */ if (!cfun) return 0; attributes = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); return lookup_attribute ("interrupt", attributes) != NULL_TREE;}#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE xstormy16_attribute_tablestatic tree xstormy16_handle_interrupt_attribute PARAMS ((tree *, tree, tree, int, bool *));static const struct attribute_spec xstormy16_attribute_table[] ={ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ { "interrupt", 0, 0, false, true, true, xstormy16_handle_interrupt_attribute }, { NULL, 0, 0, false, false, false, NULL }};/* Handle an "interrupt" attribute; arguments as in struct attribute_spec.handler. */static treexstormy16_handle_interrupt_attribute (node, name, args, flags, no_add_attrs) tree *node; tree name; tree args ATTRIBUTE_UNUSED; int flags ATTRIBUTE_UNUSED; bool *no_add_attrs;{ if (TREE_CODE (*node) != FUNCTION_TYPE) { warning ("`%s' attribute only applies to functions", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } return NULL_TREE;}#undef TARGET_INIT_BUILTINS#define TARGET_INIT_BUILTINS xstormy16_init_builtins#undef TARGET_EXPAND_BUILTIN#define TARGET_EXPAND_BUILTIN xstormy16_expand_builtinstatic struct { const char *name; int md_code; const char *arg_ops; /* 0..9, t for temp register, r for return value */ const char *arg_types; /* s=short,l=long, upper case for unsigned */} s16builtins[] = { { "__sdivlh", CODE_FOR_sdivlh, "rt01", "sls" }, { "__smodlh", CODE_FOR_sdivlh, "tr01", "sls" }, { "__udivlh", CODE_FOR_udivlh, "rt01", "SLS" }, { "__umodlh", CODE_FOR_udivlh, "tr01", "SLS" }, { 0, 0, 0, 0 }};static voidxstormy16_init_builtins (){ tree args, ret_type, arg; int i, a; ret_type = void_type_node; for (i=0; s16builtins[i].name; i++) { args = void_list_node; for (a=strlen (s16builtins[i].arg_types)-1; a>=0; a--) { switch (s16builtins[i].arg_types[a]) { case 's': arg = short_integer_type_node; break; case 'S': arg = short_unsigned_type_node; break; case 'l': arg = long_integer_type_node; break; case 'L': arg = long_unsigned_type_node; break; default: abort(); } if (a == 0) ret_type = arg; else args = tree_cons (NULL_TREE, arg, args); } builtin_function (s16builtins[i].name, build_function_type (ret_type, args), i, BUILT_IN_MD, NULL, NULL); }}static rtxxstormy16_expand_builtin(exp, target, subtarget, mode, ignore) tree exp; rtx target; rtx subtarget ATTRIBUTE_UNUSED; enum machine_mode mode ATTRIBUTE_UNUSED; int ignore ATTRIBUTE_UNUSED;{ rtx op[10], args[10], pat, copyto[10], retval = 0; tree fndecl, argtree; int i, a, o, code; fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); argtree = TREE_OPERAND (exp, 1); i = DECL_FUNCTION_CODE (fndecl); code = s16builtins[i].md_code; for (a = 0; a < 10 && argtree; a++) { args[a] = expand_expr (TREE_VALUE (argtree), NULL_RTX, VOIDmode, 0); argtree = TREE_CHAIN (argtree); } for (o = 0; s16builtins[i].arg_ops[o]; o++) { char ao = s16builtins[i].arg_ops[o]; char c = insn_data[code].operand[o].constraint[0]; int omode; copyto[o] = 0; omode = insn_data[code].operand[o].mode; if (ao == 'r') op[o] = target ? target : gen_reg_rtx (omode); else if (ao == 't') op[o] = gen_reg_rtx (omode); else op[o] = args[(int) hex_value (ao)]; if (! (*insn_data[code].operand[o].predicate) (op[o], GET_MODE (op[o]))) { if (c == '+' || c == '=') { copyto[o] = op[o]; op[o] = gen_reg_rtx (omode); } else op[o] = copy_to_mode_reg (omode, op[o]); } if (ao == 'r') retval = op[o]; } pat = GEN_FCN (code) (op[0], op[1], op[2], op[3], op[4], op[5], op[6], op[7], op[8], op[9]); emit_insn (pat); for (o = 0; s16builtins[i].arg_ops[o]; o++) if (copyto[o]) { emit_move_insn (copyto[o], op[o]); if (op[o] == retval) retval = copyto[o]; } return retval;}#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"#undef TARGET_ASM_ALIGNED_SI_OP#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO xstormy16_encode_section_info#undef TARGET_ASM_OUTPUT_MI_THUNK#define TARGET_ASM_OUTPUT_MI_THUNK xstormy16_asm_output_mi_thunk#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcallstruct gcc_target targetm = TARGET_INITIALIZER;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -