From 54e9a19d9d7113828f585504d126e1a0c01fed77 Mon Sep 17 00:00:00 2001 From: DJ Delorie Date: Tue, 17 Aug 2004 18:51:28 -0400 Subject: [PATCH] extend.texi: Document new xstormy16 attribute. * doc/extend.texi: Document new xstormy16 attribute. * config/stormy16/stormy16.c (xstormy16_splittable_below100_operand): New. (xstormy16_splittable_below100_or_register): New. (combine_bnp): New. (xstormy16_reorg): New. (TARGET_MACHINE_DEPENDENT_REORG): Define. * config/stormy16/stormy16.md (movqi_internal): Make name public. (movhi_internal): Likewise. (cbhranchhi): Likewise. (cbhranchhi_neg): Likewise. (andhi3): Only allow splittable below100 operands. (iorhi3): Likewise. (peephole2): New and/zero_extend->and peephole. (peephole2): New load/ior/save->set1 peephole. (peephole2): New load/and/save->clr1 peephole. (bclrx, bclrx2, bclr7, bclr15): New. (bsetx, bsetx2, bset7, bset15): New. * config/stormy16/stormy16.c (xstormy16_print_operand): Be more liberal about acceptable 'B' masks. * config/stormy16/stormy16-protos.h (xstormy16_asm_output_aligned_common, xstormy16_below100_symbol, xstormy16_below100_operand, xstormy16_below100_or_register, xstormy16_onebit_set_operand, xstormy16_onebit_clr_operand): New. (PREDICATE_CODES): Add new predicates. * config/stormy16/stormy16.c (xstormy16_asm_output_aligned_common, xstormy16_below100_symbol, xstormy16_below100_operand, xstormy16_below100_or_register, xstormy16_onebit_set_operand, xstormy16_onebit_clr_operand): New. (xstormy16_expand_iorqi3, xstormy16_expand_andqi3): New. (xstormy16_legitimate_address_p): Allow below100 symbols. (xstormy16_extra_constraint_p): Add 'W' for below100 operands. (xstormy16_expand_move): Leave below100 operands as-is. (xstormy16_encode_section_info): Encode below100 symbols. (xstormy16_strip_name_encoding): New. (xstormy16_print_operand): Print 'b' as shift mask. (xstormy16_attribute_table): Add below100 attributes. (xstormy16_handle_below100_attribute): New. * config/stormy16/stormy16.h (EXTRA_SECTIONS): add in_bss100. (XSTORMY16_SECTION_FUNCTION): New. (EXTRA_SECTION_FUNCTIONS): Define using the above. (ASM_OUTPUT_ALIGNED_DECL_COMMON, ASM_OUTPUT_ALIGNED_DECL_LOCAL): New. (ASM_OUTPUT_SYMBOL_REF): Handle encoded symbols. (ASM_OUTPUT_LABELREF): Define. * config/stormy16/stormy16.md (movqi_internal): Add below100 support. (movhi_internal): Add below100 support. (andhi3): Add below100 support. (iorhi3): Add below100 support. (iorqi3, iorqi3_internal, andqi3, andqi3_internal): New. From-SVN: r86154 --- gcc/ChangeLog | 59 +++ gcc/config/stormy16/stormy16-protos.h | 16 + gcc/config/stormy16/stormy16.c | 561 +++++++++++++++++++++++++- gcc/config/stormy16/stormy16.h | 40 +- gcc/config/stormy16/stormy16.md | 289 ++++++++++++- gcc/doc/extend.texi | 17 + 6 files changed, 956 insertions(+), 26 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9e48dbb8514..81822a29c97 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,62 @@ +2004-08-17 DJ Delorie + + * doc/extend.texi: Document new xstormy16 attribute. + + * config/stormy16/stormy16.c (xstormy16_splittable_below100_operand): New. + (xstormy16_splittable_below100_or_register): New. + (combine_bnp): New. + (xstormy16_reorg): New. + (TARGET_MACHINE_DEPENDENT_REORG): Define. + + + * config/stormy16/stormy16.md (movqi_internal): Make name public. + (movhi_internal): Likewise. + (cbhranchhi): Likewise. + (cbhranchhi_neg): Likewise. + (andhi3): Only allow splittable below100 operands. + (iorhi3): Likewise. + (peephole2): New and/zero_extend->and peephole. + (peephole2): New load/ior/save->set1 peephole. + (peephole2): New load/and/save->clr1 peephole. + (bclrx, bclrx2, bclr7, bclr15): New. + (bsetx, bsetx2, bset7, bset15): New. + + * config/stormy16/stormy16.c (xstormy16_print_operand): Be more + liberal about acceptable 'B' masks. + + * config/stormy16/stormy16-protos.h + (xstormy16_asm_output_aligned_common, xstormy16_below100_symbol, + xstormy16_below100_operand, xstormy16_below100_or_register, + xstormy16_onebit_set_operand, xstormy16_onebit_clr_operand): New. + (PREDICATE_CODES): Add new predicates. + + * config/stormy16/stormy16.c + (xstormy16_asm_output_aligned_common, xstormy16_below100_symbol, + xstormy16_below100_operand, xstormy16_below100_or_register, + xstormy16_onebit_set_operand, xstormy16_onebit_clr_operand): New. + (xstormy16_expand_iorqi3, xstormy16_expand_andqi3): New. + (xstormy16_legitimate_address_p): Allow below100 symbols. + (xstormy16_extra_constraint_p): Add 'W' for below100 operands. + (xstormy16_expand_move): Leave below100 operands as-is. + (xstormy16_encode_section_info): Encode below100 symbols. + (xstormy16_strip_name_encoding): New. + (xstormy16_print_operand): Print 'b' as shift mask. + (xstormy16_attribute_table): Add below100 attributes. + (xstormy16_handle_below100_attribute): New. + + * config/stormy16/stormy16.h (EXTRA_SECTIONS): add in_bss100. + (XSTORMY16_SECTION_FUNCTION): New. + (EXTRA_SECTION_FUNCTIONS): Define using the above. + (ASM_OUTPUT_ALIGNED_DECL_COMMON, ASM_OUTPUT_ALIGNED_DECL_LOCAL): New. + (ASM_OUTPUT_SYMBOL_REF): Handle encoded symbols. + (ASM_OUTPUT_LABELREF): Define. + + * config/stormy16/stormy16.md (movqi_internal): Add below100 support. + (movhi_internal): Add below100 support. + (andhi3): Add below100 support. + (iorhi3): Add below100 support. + (iorqi3, iorqi3_internal, andqi3, andqi3_internal): New. + 2004-08-17 James E Wilson * config/mips/mips.c (gen_conditional_move): Use GET_MODE (op0) instead diff --git a/gcc/config/stormy16/stormy16-protos.h b/gcc/config/stormy16/stormy16-protos.h index 1d1d35c3591..a8b23565418 100644 --- a/gcc/config/stormy16/stormy16-protos.h +++ b/gcc/config/stormy16/stormy16-protos.h @@ -29,6 +29,13 @@ extern int direct_return (void); extern int xstormy16_interrupt_function_p (void); extern int xstormy16_epilogue_uses (int); extern void xstormy16_function_profiler (void); +extern const char *xstormy16_strip_name_encoding (const char *name); +extern void bss100_section (void); + +#if defined (TREE_CODE) +extern void xstormy16_asm_output_aligned_common (FILE *, tree, const char *, + int, int, int); +#endif #if defined (TREE_CODE) && defined (HAVE_MACHINE_MODES) extern CUMULATIVE_ARGS xstormy16_function_arg_advance @@ -56,6 +63,8 @@ extern void xstormy16_print_operand_address (FILE *, rtx); extern void xstormy16_expand_casesi (rtx, rtx, rtx, rtx, rtx); extern void xstormy16_output_addr_vec (FILE *, rtx, rtx); extern void xstormy16_expand_call (rtx, rtx, rtx); +extern void xstormy16_expand_iorqi3 (rtx *); +extern void xstormy16_expand_andqi3 (rtx *); #endif #if defined (HAVE_MACHINE_MODES) && defined (RTX_CODE) @@ -79,5 +88,12 @@ extern void xstormy16_expand_arith (enum machine_mode, enum rtx_code, extern int shift_operator (rtx, enum machine_mode); extern const char * xstormy16_output_shift (enum machine_mode, enum rtx_code, rtx, rtx, rtx); +extern int xstormy16_below100_symbol (rtx, enum machine_mode); +extern int xstormy16_below100_operand (rtx, enum machine_mode); +extern int xstormy16_splittable_below100_operand (rtx, enum machine_mode); +extern int xstormy16_below100_or_register (rtx, enum machine_mode); +extern int xstormy16_splittable_below100_or_register (rtx, enum machine_mode); +extern int xstormy16_onebit_set_operand (rtx, enum machine_mode); +extern int xstormy16_onebit_clr_operand (rtx, enum machine_mode); #endif diff --git a/gcc/config/stormy16/stormy16.c b/gcc/config/stormy16/stormy16.c index 7297fa6636c..cc044be4d6a 100644 --- a/gcc/config/stormy16/stormy16.c +++ b/gcc/config/stormy16/stormy16.c @@ -549,6 +549,194 @@ xstormy16_preferred_reload_class (rtx x, enum reg_class class) return class; } +/* Predicate for symbols and addresses that reflect special 8-bit + addressing. */ +int +xstormy16_below100_symbol (rtx x, + enum machine_mode mode ATTRIBUTE_UNUSED) +{ + if (GET_CODE (x) == CONST) + x = XEXP (x, 0); + if (GET_CODE (x) == PLUS + && GET_CODE (XEXP (x, 1)) == CONST_INT) + x = XEXP (x, 0); + if (GET_CODE (x) == SYMBOL_REF) + { + const char *n = XSTR (x, 0); + if (n[0] == '@' && n[1] == 'b' && n[2] == '.') + return 1; + } + if (GET_CODE (x) == CONST_INT) + { + HOST_WIDE_INT i = INTVAL (x); + if ((i >= 0x0000 && i <= 0x00ff) + || (i >= 0x7f00 && i <= 0x7fff)) + return 1; + } + return 0; +} + +/* Predicate for MEMs that can use special 8-bit addressing. */ +int +xstormy16_below100_operand (rtx x, enum machine_mode mode) +{ + if (GET_MODE (x) != mode) + return 0; + if (GET_CODE (x) == MEM) + x = XEXP (x, 0); + else if (GET_CODE (x) == SUBREG + && GET_CODE (XEXP (x, 0)) == MEM + && !MEM_VOLATILE_P (XEXP (x, 0))) + x = XEXP (XEXP (x, 0), 0); + else + return 0; + if (GET_CODE (x) == CONST_INT) + { + HOST_WIDE_INT i = INTVAL (x); + return (i >= 0x7f00 && i < 0x7fff); + } + return xstormy16_below100_symbol (x, HImode); +} + +/* Likewise, but only for non-volatile MEMs, for patterns where the + MEM will get split into smaller sized accesses. */ +int +xstormy16_splittable_below100_operand (rtx x, enum machine_mode mode) +{ + if (GET_CODE (x) == MEM && MEM_VOLATILE_P (x)) + return 0; + return xstormy16_below100_operand (x, mode); +} + +int +xstormy16_below100_or_register (rtx x, enum machine_mode mode) +{ + return (xstormy16_below100_operand (x, mode) + || register_operand (x, mode)); +} + +int +xstormy16_splittable_below100_or_register (rtx x, enum machine_mode mode) +{ + if (GET_CODE (x) == MEM && MEM_VOLATILE_P (x)) + return 0; + return (xstormy16_below100_operand (x, mode) + || register_operand (x, mode)); +} + +/* Predicate for constants with exactly one bit set. */ +int +xstormy16_onebit_set_operand (rtx x, enum machine_mode mode) +{ + HOST_WIDE_INT i; + if (GET_CODE (x) != CONST_INT) + return 0; + i = INTVAL (x); + if (mode == QImode) + i &= 0xff; + if (mode == HImode) + i &= 0xffff; + return exact_log2 (i) != -1; +} + +/* Predicate for constants with exactly one bit not set. */ +int +xstormy16_onebit_clr_operand (rtx x, enum machine_mode mode) +{ + HOST_WIDE_INT i; + if (GET_CODE (x) != CONST_INT) + return 0; + i = ~ INTVAL (x); + if (mode == QImode) + i &= 0xff; + if (mode == HImode) + i &= 0xffff; + return exact_log2 (i) != -1; +} + +/* Expand an 8-bit IOR. This either detects the one case we can + actually do, or uses a 16-bit IOR. */ +void +xstormy16_expand_iorqi3 (rtx *operands) +{ + rtx in, out, outsub, val; + + out = operands[0]; + in = operands[1]; + val = operands[2]; + + if (xstormy16_onebit_set_operand (val, QImode)) + { + if (!xstormy16_below100_or_register (in, QImode)) + in = copy_to_mode_reg (QImode, in); + if (!xstormy16_below100_or_register (out, QImode)) + out = gen_reg_rtx (QImode); + emit_insn (gen_iorqi3_internal (out, in, val)); + if (out != operands[0]) + emit_move_insn (operands[0], out); + return; + } + + if (GET_CODE (in) != REG) + in = copy_to_mode_reg (QImode, in); + if (GET_CODE (val) != REG + && GET_CODE (val) != CONST_INT) + val = copy_to_mode_reg (QImode, val); + if (GET_CODE (out) != REG) + out = gen_reg_rtx (QImode); + + in = simplify_gen_subreg (HImode, in, QImode, 0); + outsub = simplify_gen_subreg (HImode, out, QImode, 0); + if (GET_CODE (val) != CONST_INT) + val = simplify_gen_subreg (HImode, val, QImode, 0); + + emit_insn (gen_iorhi3 (outsub, in, val)); + + if (out != operands[0]) + emit_move_insn (operands[0], out); +} + +/* Likewise, for AND. */ +void +xstormy16_expand_andqi3 (rtx *operands) +{ + rtx in, out, outsub, val; + + out = operands[0]; + in = operands[1]; + val = operands[2]; + + if (xstormy16_onebit_clr_operand (val, QImode)) + { + if (!xstormy16_below100_or_register (in, QImode)) + in = copy_to_mode_reg (QImode, in); + if (!xstormy16_below100_or_register (out, QImode)) + out = gen_reg_rtx (QImode); + emit_insn (gen_andqi3_internal (out, in, val)); + if (out != operands[0]) + emit_move_insn (operands[0], out); + return; + } + + if (GET_CODE (in) != REG) + in = copy_to_mode_reg (QImode, in); + if (GET_CODE (val) != REG + && GET_CODE (val) != CONST_INT) + val = copy_to_mode_reg (QImode, val); + if (GET_CODE (out) != REG) + out = gen_reg_rtx (QImode); + + in = simplify_gen_subreg (HImode, in, QImode, 0); + outsub = simplify_gen_subreg (HImode, out, QImode, 0); + if (GET_CODE (val) != CONST_INT) + val = simplify_gen_subreg (HImode, val, QImode, 0); + + emit_insn (gen_andhi3 (outsub, in, val)); + + if (out != operands[0]) + emit_move_insn (operands[0], out); +} + #define LEGITIMATE_ADDRESS_INTEGER_P(X, OFFSET) \ (GET_CODE (X) == CONST_INT \ && (unsigned HOST_WIDE_INT) (INTVAL (X) + (OFFSET) + 2048) < 4096) @@ -579,6 +767,9 @@ xstormy16_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, if (GET_CODE (x) == REG && REGNO_OK_FOR_BASE_P (REGNO (x)) && (! strict || REGNO (x) < FIRST_PSEUDO_REGISTER)) return 1; + + if (xstormy16_below100_symbol(x, mode)) + return 1; return 0; } @@ -668,6 +859,9 @@ xstormy16_extra_constraint_p (rtx x, int c) return (GET_CODE (x) == CONST_INT && (INTVAL (x) == 0)); + case 'W': + return xstormy16_below100_operand(x, GET_MODE(x)); + default: return 0; } @@ -868,6 +1062,7 @@ xstormy16_expand_move (enum machine_mode mode, rtx dest, rtx src) && GET_CODE (dest) == MEM && (GET_CODE (XEXP (dest, 0)) != CONST_INT || ! xstormy16_legitimate_address_p (mode, XEXP (dest, 0), 0)) + && ! xstormy16_below100_operand (dest, mode) && GET_CODE (src) != REG && GET_CODE (src) != SUBREG) src = copy_to_mode_reg (mode, src); @@ -1489,6 +1684,119 @@ xstormy16_asm_output_mi_thunk (FILE *file, putc ('\n', file); } +/* The purpose of this function is to override the default behavior of + BSS objects. Normally, they go into .bss or .sbss via ".common" + directives, but we need to override that and put them in + .bss_below100. We can't just use a section override (like we do + for .data_below100), because that makes them initialized rather + than uninitialized. */ +void +xstormy16_asm_output_aligned_common (FILE *stream, + tree decl ATTRIBUTE_UNUSED, + const char *name, + int size, + int align, + int global) +{ + if (name[0] == '@' && name[2] == '.') + { + const char *op = 0; + switch (name[1]) + { + case 'b': + bss100_section(); + op = "space"; + break; + } + if (op) + { + const char *name2; + int p2align = 0; + + while (align > 8) + { + align /= 2; + p2align ++; + } + name2 = xstormy16_strip_name_encoding (name); + if (global) + fprintf (stream, "\t.globl\t%s\n", name2); + if (p2align) + fprintf (stream, "\t.p2align %d\n", p2align); + fprintf (stream, "\t.type\t%s, @object\n", name2); + fprintf (stream, "\t.size\t%s, %d\n", name2, size); + fprintf (stream, "%s:\n\t.%s\t%d\n", name2, op, size); + return; + } + } + + if (!global) + { + fprintf (stream, "\t.local\t"); + assemble_name (stream, name); + fprintf (stream, "\n"); + } + fprintf (stream, "\t.comm\t"); + assemble_name (stream, name); + fprintf (stream, ",%u,%u\n", size, align); +} + +/* Mark symbols with the "below100" attribute so that we can use the + special addressing modes for them. */ + +static void +xstormy16_encode_section_info (tree decl, + rtx r, + int first ATTRIBUTE_UNUSED) +{ + if (TREE_CODE (decl) == VAR_DECL + && (lookup_attribute ("below100", DECL_ATTRIBUTES (decl)) + || lookup_attribute ("BELOW100", DECL_ATTRIBUTES (decl)))) + { + const char *newsection = 0; + char *newname; + tree idp; + rtx rtlname, rtl; + const char *oldname; + + rtl = r; + rtlname = XEXP (rtl, 0); + if (GET_CODE (rtlname) == SYMBOL_REF) + oldname = XSTR (rtlname, 0); + else if (GET_CODE (rtlname) == MEM + && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF) + oldname = XSTR (XEXP (rtlname, 0), 0); + else + abort (); + + if (DECL_INITIAL (decl)) + { + newsection = ".data_below100"; + DECL_SECTION_NAME (decl) = build_string (strlen (newsection), newsection); + } + + newname = alloca (strlen (oldname) + 4); + sprintf (newname, "@b.%s", oldname); + idp = get_identifier (newname); + XEXP (rtl, 0) = + gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); + } +} + +const char * +xstormy16_strip_name_encoding (const char *name) +{ + while (1) + { + if (name[0] == '@' && name[2] == '.') + name += 3; + else if (name[0] == '*') + name ++; + else + return name; + } +} + /* Output constructors and destructors. Just like default_named_section_asm_out_* but don't set the sections writable. */ #undef TARGET_ASM_CONSTRUCTOR @@ -1603,6 +1911,7 @@ xstormy16_print_operand (FILE *file, rtx x, int code) /* There is either one bit set, or one bit clear, in X. Print it preceded by '#'. */ { + static int bits_set[8] = { 0, 1, 1, 2, 1, 2, 2, 3 }; HOST_WIDE_INT xx = 1; HOST_WIDE_INT l; @@ -1611,9 +1920,30 @@ xstormy16_print_operand (FILE *file, rtx x, int code) else output_operand_lossage ("`B' operand is not constant"); - l = exact_log2 (xx); - if (l == -1) - l = exact_log2 (~xx); + /* GCC sign-extends masks with the MSB set, so we have to + detect all the cases that differ only in sign extension + beyond the bits we care about. Normally, the predicates + and constraints ensure that we have the right values. This + works correctly for valid masks. */ + if (bits_set[xx & 7] <= 1) + { + /* Remove sign extension bits. */ + if ((~xx & ~(HOST_WIDE_INT)0xff) == 0) + xx &= 0xff; + else if ((~xx & ~(HOST_WIDE_INT)0xffff) == 0) + xx &= 0xffff; + l = exact_log2 (xx); + } + else + { + /* Add sign extension bits. */ + if ((xx & ~(HOST_WIDE_INT)0xff) == 0) + xx |= ~(HOST_WIDE_INT)0xff; + else if ((xx & ~(HOST_WIDE_INT)0xffff) == 0) + xx |= ~(HOST_WIDE_INT)0xffff; + l = exact_log2 (~xx); + } + if (l == -1) output_operand_lossage ("`B' operand has multiple bits set"); @@ -1650,6 +1980,24 @@ xstormy16_print_operand (FILE *file, rtx x, int code) return; } + case 'b': + /* Print the shift mask for bp/bn. */ + { + 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 = 7 - xx; + + fputs (IMMEDIATE_PREFIX, file); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, l); + return; + } + case 0: /* Handled below. */ break; @@ -2040,11 +2388,15 @@ xstormy16_interrupt_function_p (void) #define TARGET_ATTRIBUTE_TABLE xstormy16_attribute_table static tree xstormy16_handle_interrupt_attribute (tree *, tree, tree, int, bool *); +static tree xstormy16_handle_below100_attribute + (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 }, + { "BELOW100", 0, 0, false, false, false, xstormy16_handle_below100_attribute }, + { "below100", 0, 0, false, false, false, xstormy16_handle_below100_attribute }, { NULL, 0, 0, false, false, false, NULL } }; @@ -2065,6 +2417,34 @@ xstormy16_handle_interrupt_attribute (tree *node, tree name, return NULL_TREE; } + +/* Handle an "below" attribute; + arguments as in struct attribute_spec.handler. */ +static tree +xstormy16_handle_below100_attribute (tree *node, + tree name ATTRIBUTE_UNUSED, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + bool *no_add_attrs) +{ + if (TREE_CODE (*node) != VAR_DECL + && TREE_CODE (*node) != POINTER_TYPE + && TREE_CODE (*node) != TYPE_DECL) + { + warning ("`__BELOW100__' attribute only applies to variables"); + *no_add_attrs = true; + } + else if (args == NULL_TREE && TREE_CODE (*node) == VAR_DECL) + { + if (! (TREE_PUBLIC (*node) || TREE_STATIC (*node))) + { + warning ("__BELOW100__ attribute not allowed with auto storage class."); + *no_add_attrs = true; + } + } + + return NULL_TREE; +} #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS xstormy16_init_builtins @@ -2182,6 +2562,174 @@ xstormy16_expand_builtin(tree exp, rtx target, return retval; } + + +/* Look for combinations of insns that can be converted to BN or BP + opcodes. This is, unfortunately, too complex to do with MD + patterns. */ +static void +combine_bnp (rtx insn) +{ + int insn_code, regno, need_extend, mask; + rtx cond, reg, and, load, qireg, mem; + enum machine_mode load_mode = QImode; + + insn_code = recog_memoized (insn); + if (insn_code != CODE_FOR_cbranchhi + && insn_code != CODE_FOR_cbranchhi_neg) + return; + + cond = XVECEXP (PATTERN (insn), 0, 0); /* set */ + cond = XEXP (cond, 1); /* if */ + cond = XEXP (cond, 0); /* cond */ + switch (GET_CODE (cond)) + { + case NE: + case EQ: + need_extend = 0; + break; + case LT: + case GE: + need_extend = 1; + break; + default: + return; + } + + reg = XEXP (cond, 0); + if (GET_CODE (reg) != REG) + return; + regno = REGNO (reg); + if (XEXP (cond, 1) != const0_rtx) + return; + if (! find_regno_note (insn, REG_DEAD, regno)) + return; + qireg = gen_rtx_REG (QImode, regno); + + if (need_extend) + { + /* LT and GE conditionals should have an sign extend before + them. */ + for (and = prev_real_insn (insn); and; and = prev_real_insn (and)) + { + int and_code = recog_memoized (and); + if (and_code == CODE_FOR_extendqihi2 + && rtx_equal_p (XEXP (PATTERN (and), 0), reg) + && rtx_equal_p (XEXP (XEXP (PATTERN (and), 1), 0), qireg)) + { + break; + } + + if (and_code == CODE_FOR_movhi_internal + && rtx_equal_p (XEXP (PATTERN (and), 0), reg)) + { + /* This is for testing bit 15. */ + and = insn; + break; + } + + if (reg_mentioned_p (reg, and)) + return; + if (GET_CODE (and) != NOTE + && GET_CODE (and) != INSN) + return; + } + } + else + { + /* EQ and NE conditionals have an AND before them. */ + for (and = prev_real_insn (insn); and; and = prev_real_insn (and)) + { + if (recog_memoized (and) == CODE_FOR_andhi3 + && rtx_equal_p (XEXP (PATTERN (and), 0), reg) + && rtx_equal_p (XEXP (XEXP (PATTERN (and), 1), 0), reg)) + { + break; + } + + if (reg_mentioned_p (reg, and)) + return; + if (GET_CODE (and) != NOTE + && GET_CODE (and) != INSN) + return; + } + } + if (!and) + return; + + for (load = prev_real_insn (and); load; load = prev_real_insn (load)) + { + int load_code = recog_memoized (load); + if (load_code == CODE_FOR_movhi_internal + && rtx_equal_p (XEXP (PATTERN (load), 0), reg) + && xstormy16_below100_operand (XEXP (PATTERN (load), 1), HImode) + && ! MEM_VOLATILE_P (XEXP (PATTERN (load), 1))) + { + load_mode = HImode; + break; + } + + if (load_code == CODE_FOR_movqi_internal + && rtx_equal_p (XEXP (PATTERN (load), 0), qireg) + && xstormy16_below100_operand (XEXP (PATTERN (load), 1), QImode)) + { + load_mode = QImode; + break; + } + + if (reg_mentioned_p (reg, load)) + return; + if (GET_CODE (load) != NOTE + && GET_CODE (load) != INSN) + return; + } + if (!load) + return; + + if (!need_extend) + { + if (!xstormy16_onebit_set_operand (XEXP (XEXP (PATTERN (and), 1), 1), load_mode)) + return; + mask = (int) INTVAL (XEXP (XEXP (PATTERN (and), 1), 1)); + } + else + mask = (load_mode == HImode) ? 0x8000 : 0x80; + + mem = XEXP (PATTERN (load), 1); + if (load_mode == HImode) + { + rtx addr = XEXP (mem, 0); + if (! (mask & 0xff)) + { + addr = plus_constant (addr, 1); + mask >>= 8; + } + mem = gen_rtx_MEM (QImode, addr); + } + + if (need_extend) + XEXP (cond, 0) = gen_rtx_SIGN_EXTEND (HImode, mem); + else + XEXP (cond, 0) = gen_rtx_AND (QImode, mem, GEN_INT (mask)); + INSN_CODE (insn) = -1; + delete_insn (load); + if (and != insn) + delete_insn (and); +} + +static void +xstormy16_reorg (void) +{ + rtx insn; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (! JUMP_P (insn)) + continue; + combine_bnp (insn); + } +} + /* Worker function for TARGET_RETURN_IN_MEMORY. */ @@ -2196,6 +2744,10 @@ xstormy16_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED) #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_STRIP_NAME_ENCODING +#define TARGET_STRIP_NAME_ENCODING xstormy16_strip_name_encoding #undef TARGET_ASM_OUTPUT_MI_THUNK #define TARGET_ASM_OUTPUT_MI_THUNK xstormy16_asm_output_mi_thunk @@ -2222,4 +2774,7 @@ xstormy16_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED) #undef TARGET_RETURN_IN_MEMORY #define TARGET_RETURN_IN_MEMORY xstormy16_return_in_memory +#undef TARGET_MACHINE_DEPENDENT_REORG +#define TARGET_MACHINE_DEPENDENT_REORG xstormy16_reorg + struct gcc_target targetm = TARGET_INITIALIZER; diff --git a/gcc/config/stormy16/stormy16.h b/gcc/config/stormy16/stormy16.h index 31eb43e2b29..1cb40f6f0e0 100644 --- a/gcc/config/stormy16/stormy16.h +++ b/gcc/config/stormy16/stormy16.h @@ -626,6 +626,26 @@ do { \ #undef DTORS_SECTION_ASM_OP #define CTORS_SECTION_ASM_OP "\t.section\t.ctors,\"a\"" #define DTORS_SECTION_ASM_OP "\t.section\t.dtors,\"a\"" +#define EXTRA_SECTIONS in_bss100 + +/* We define the function body in a separate macro so that if we ever + add another section, we can just add an entry to + EXTRA_SECTION_FUNCTIONS without making it difficult to read. It is + not used anywhere else. */ +#define XSTORMY16_SECTION_FUNCTION(name, in, string, bits) \ + void \ + name () \ + { \ + if (in_section != in) \ + { \ + fprintf (asm_out_file, "\t.section %s,\"aw\",@%sbits\n", string, bits); \ + in_section = in; \ + } \ + } + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + XSTORMY16_SECTION_FUNCTION (bss100_section, in_bss100, ".bss_below100", "no") #define JUMP_TABLES_IN_TEXT_SECTION 1 @@ -642,15 +662,23 @@ do { \ #define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == '|') +#define ASM_OUTPUT_ALIGNED_DECL_COMMON(STREAM, DECL, NAME, SIZE, ALIGNMENT) \ + xstormy16_asm_output_aligned_common(STREAM, DECL, NAME, SIZE, ALIGNMENT, 1) +#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(STREAM, DECL, NAME, SIZE, ALIGNMENT) \ + xstormy16_asm_output_aligned_common(STREAM, DECL, NAME, SIZE, ALIGNMENT, 0) + /* Output and Generation of Labels. */ #define ASM_OUTPUT_SYMBOL_REF(STREAM, SYMBOL) \ do { \ + const char *rn = XSTR (SYMBOL, 0); \ + if (rn[0] == '@' && rn[2] == '.') \ + rn += 3; \ if (SYMBOL_REF_FUNCTION_P (SYMBOL)) \ - ASM_OUTPUT_LABEL_REF ((STREAM), XSTR (SYMBOL, 0)); \ + ASM_OUTPUT_LABEL_REF ((STREAM), rn); \ else \ - assemble_name (STREAM, XSTR (SYMBOL, 0)); \ + assemble_name (STREAM, rn); \ } while (0) #define ASM_OUTPUT_LABEL_REF(STREAM, NAME) \ @@ -660,6 +688,9 @@ do { \ fputc (')', STREAM); \ } while (0) +#define ASM_OUTPUT_LABELREF(STREAM, NAME) \ + asm_fprintf ((STREAM), "%U%s", xstormy16_strip_name_encoding (NAME)); + /* Globalizing directive for a label. */ #define GLOBAL_ASM_OP "\t.globl " @@ -785,6 +816,11 @@ do { \ {"equality_operator", {EQ, NE }}, \ {"inequality_operator", {GE, GT, LE, LT, GEU, GTU, LEU, LTU }}, \ {"xstormy16_ineqsi_operator", {LT, GE, LTU, GEU }}, \ + {"xstormy16_below100_operand", {MEM }}, \ + {"xstormy16_below100_or_register", {MEM, REG }}, \ + {"xstormy16_splittable_below100_or_register", {MEM, REG }}, \ + {"xstormy16_onebit_clr_operand", {CONST_INT }}, \ + {"xstormy16_onebit_set_operand", {CONST_INT }}, \ {"nonimmediate_nonstack_operand", {REG, MEM}}, #define CASE_VECTOR_MODE SImode diff --git a/gcc/config/stormy16/stormy16.md b/gcc/config/stormy16/stormy16.md index 7625246f0bd..372ca2f1210 100644 --- a/gcc/config/stormy16/stormy16.md +++ b/gcc/config/stormy16/stormy16.md @@ -130,9 +130,9 @@ "" "{ xstormy16_expand_move (QImode, operands[0], operands[1]); DONE; }") -(define_insn "*movqi_internal" - [(set (match_operand:QI 0 "nonimmediate_nonstack_operand" "=r,m,e,e,T,r,S") - (match_operand:QI 1 "general_operand" "r,e,m,i,i,i,i"))] +(define_insn "movqi_internal" + [(set (match_operand:QI 0 "nonimmediate_nonstack_operand" "=r,m,e,e,T,r,S,W,r") + (match_operand:QI 1 "general_operand" "r,e,m,i,i,i,i,ir,W"))] "" "@ mov %0,%1 @@ -141,6 +141,8 @@ mov %0,%1 mov Rx,%1 mov %0,%1 + mov.b %0,%1 + mov.b %0,%1 mov.b %0,%1" [(set_attr_alternative "length" [(const_int 2) @@ -153,8 +155,10 @@ (const_int 2) (const_int 2) (const_int 4) - (const_int 4)]) - (set_attr "psw_operand" "0,0,0,0,nop,0,nop")]) + (const_int 4) + (const_int 2) + (const_int 2)]) + (set_attr "psw_operand" "0,0,0,0,nop,0,nop,0,0")]) (define_insn "pushhi" [(set (mem:HI (post_inc (reg:HI 15))) @@ -178,9 +182,9 @@ "" "{ xstormy16_expand_move (HImode, operands[0], operands[1]); DONE; }") -(define_insn "*movhi_internal" - [(set (match_operand:HI 0 "nonimmediate_nonstack_operand" "=r,m,e,e,T,r,S") - (match_operand:HI 1 "xs_hi_general_operand" "r,e,m,L,L,i,i"))] +(define_insn "movhi_internal" + [(set (match_operand:HI 0 "nonimmediate_nonstack_operand" "=r,m,e,e,T,r,S,W,r") + (match_operand:HI 1 "xs_hi_general_operand" "r,e,m,L,L,i,i,ir,W"))] "" "@ mov %0,%1 @@ -189,6 +193,8 @@ mov.w %0,%1 mov.w Rx,%1 mov.w %0,%1 + mov.w %0,%1 + mov.w %0,%1 mov.w %0,%1" [(set_attr_alternative "length" [(const_int 2) @@ -201,8 +207,10 @@ (const_int 2) (const_int 2) (const_int 4) + (const_int 4) + (const_int 4) (const_int 4)]) - (set_attr "psw_operand" "0,0,0,0,nop,0,nop")]) + (set_attr "psw_operand" "0,0,0,0,nop,0,nop,0,0")]) (define_expand "movsi" [(set (match_operand:SI 0 "nonimmediate_operand" "") @@ -552,29 +560,63 @@ ;; Logical AND, 16 bit integers (define_insn "andhi3" - [(set (match_operand:HI 0 "register_operand" "=T,r,r,r") - (and:HI (match_operand:HI 1 "register_operand" "%0,0,0,0") - (match_operand:HI 2 "nonmemory_operand" "L,r,K,i")))] + [(set (match_operand:HI 0 "xstormy16_splittable_below100_or_register" "=T,r,r,r,W") + (and:HI (match_operand:HI 1 "xstormy16_below100_or_register" "%0,0,0,0,0") + (match_operand:HI 2 "nonmemory_operand" "L,r,K,i,K")))] "" "@ and Rx,%2 and %0,%2 clr1 %0,%B2 - and %0,%2" - [(set_attr "length" "2,2,2,4")]) + and %0,%2 + #" + [(set_attr "length" "2,2,2,4,2")]) + +(define_split + [(set (match_operand:HI 0 "xstormy16_below100_operand" "") + (and:HI (match_operand:HI 1 "xstormy16_below100_operand" "") + (match_operand:HI 2 "xstormy16_onebit_clr_operand" "")))] + "" + [(set (match_dup 3) + (and:QI (match_dup 4) + (match_dup 5)))] + "{ int s = ((INTVAL (operands[2]) & 0xff) == 0xff) ? 1 : 0; + operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, s); + operands[4] = simplify_gen_subreg (QImode, operands[1], HImode, s); + operands[5] = simplify_gen_subreg (QImode, operands[2], HImode, s); + operands[5] = GEN_INT (INTVAL (operands[5]) | ~(HOST_WIDE_INT)0xff); + } +") ;; Inclusive OR, 16 bit integers (define_insn "iorhi3" - [(set (match_operand:HI 0 "register_operand" "=T,r,r,r") - (ior:HI (match_operand:HI 1 "register_operand" "%0,0,0,0") - (match_operand:HI 2 "nonmemory_operand" "L,r,J,i")))] + [(set (match_operand:HI 0 "xstormy16_splittable_below100_or_register" "=T,r,r,r,W") + (ior:HI (match_operand:HI 1 "xstormy16_below100_or_register" "%0,0,0,0,0") + (match_operand:HI 2 "nonmemory_operand" "L,r,J,i,J")))] "" "@ or Rx,%2 or %0,%2 set1 %0,%B2 - or %0,%2" - [(set_attr "length" "2,2,2,4")]) + or %0,%2 + #" + [(set_attr "length" "2,2,2,4,2")]) + +(define_split + [(set (match_operand:HI 0 "xstormy16_below100_operand" "") + (ior:HI (match_operand:HI 1 "xstormy16_below100_operand" "") + (match_operand:HI 2 "xstormy16_onebit_set_operand" "")))] + "" + [(set (match_dup 3) + (ior:QI (match_dup 4) + (match_dup 5)))] + "{ int s = ((INTVAL (operands[2]) & 0xff) == 0x00) ? 1 : 0; + operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, s); + operands[4] = simplify_gen_subreg (QImode, operands[1], HImode, s); + operands[5] = simplify_gen_subreg (QImode, operands[2], HImode, s); + operands[5] = GEN_INT (INTVAL (operands[5]) & 0xff); + } +") ;; Exclusive OR, 16 bit integers (define_insn "xorhi3" @@ -796,7 +838,7 @@ "{ xstormy16_emit_cbranch (LTU, operands[0]); DONE; }") -(define_insn "*cbranchhi" +(define_insn "cbranchhi" [(set (pc) (if_then_else (match_operator:HI 1 "comparison_operator" [(match_operand:HI 2 "nonmemory_operand" @@ -814,7 +856,7 @@ [(set_attr "branch_class" "bcc12") (set_attr "psw_operand" "0,0,1")]) -(define_insn "*cbranchhi_neg" +(define_insn "cbranchhi_neg" [(set (pc) (if_then_else (match_operator:HI 1 "comparison_operator" [(match_operand:HI 2 "nonmemory_operand" @@ -1095,3 +1137,208 @@ "" [(set_attr "length" "0") (set_attr "psw_operand" "nop")]) + +;;--------------------------------------------------------------------------- + +(define_expand "iorqi3" + [(match_operand:QI 0 "xstormy16_below100_or_register" "") + (match_operand:QI 1 "xstormy16_below100_or_register" "") + (match_operand:QI 2 "nonmemory_operand" "")] + "" + " +{ + xstormy16_expand_iorqi3 (operands); + DONE; +}") + +(define_insn "iorqi3_internal" + [(set (match_operand:QI 0 "xstormy16_below100_or_register" "=Wr") + (ior:QI (match_operand:QI 1 "xstormy16_below100_or_register" "0") + (match_operand:QI 2 "xstormy16_onebit_set_operand" "i")))] + "" + "set1 %0,%B2" + [(set_attr "length" "2") + (set_attr "psw_operand" "0")]) + +(define_peephole2 + [(set (match_operand:QI 0 "register_operand" "") + (match_operand:QI 1 "xstormy16_below100_operand" "")) + (set (match_operand:HI 2 "register_operand" "") + (ior:HI (match_operand:HI 3 "register_operand" "") + (match_operand:QI 4 "xstormy16_onebit_set_operand" ""))) + (set (match_operand:QI 5 "xstormy16_below100_operand" "") + (match_operand:QI 6 "register_operand" "")) + ] + "REGNO (operands[0]) == REGNO (operands[2]) + && REGNO (operands[0]) == REGNO (operands[3]) + && REGNO (operands[0]) == REGNO (operands[6]) + && rtx_equal_p (operands[1], operands[5])" + [(set (match_dup 1) + (ior:QI (match_dup 1) + (match_dup 4))) + ] + "") + + +(define_expand "andqi3" + [(match_operand:QI 0 "xstormy16_below100_or_register" "") + (match_operand:QI 1 "xstormy16_below100_or_register" "") + (match_operand:QI 2 "nonmemory_operand" "")] + "" + " +{ + xstormy16_expand_andqi3 (operands); + DONE; +}") + +(define_insn "andqi3_internal" + [(set (match_operand:QI 0 "xstormy16_below100_or_register" "=Wr") + (and:QI (match_operand:QI 1 "xstormy16_below100_or_register" "0") + (match_operand:QI 2 "xstormy16_onebit_clr_operand" "i")))] + "" + "clr1 %0,%B2" + [(set_attr "length" "2") + (set_attr "psw_operand" "0")]) + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (and:HI (match_operand:HI 1 "register_operand" "") + (match_operand 2 "immediate_operand" ""))) + (set (match_operand:HI 3 "register_operand" "") + (zero_extend:HI (match_operand:QI 4 "register_operand" ""))); + ] + "REGNO (operands[0]) == REGNO (operands[1]) + && REGNO (operands[0]) == REGNO (operands[3]) + && REGNO (operands[0]) == REGNO (operands[4])" + [(set (match_dup 0) + (and:HI (match_dup 1) + (match_dup 5))) + ] + "operands[5] = GEN_INT (INTVAL (operands[2]) & 0xff);") + +(define_peephole2 + [(set (match_operand:QI 0 "register_operand" "") + (match_operand:QI 1 "xstormy16_below100_operand" "")) + (set (match_operand:HI 2 "register_operand" "") + (and:HI (match_operand:HI 3 "register_operand" "") + (match_operand:QI 4 "xstormy16_onebit_clr_operand" ""))) + (set (match_operand:QI 5 "xstormy16_below100_operand" "") + (match_operand:QI 6 "register_operand" "")) + ] + "REGNO (operands[0]) == REGNO (operands[2]) + && REGNO (operands[0]) == REGNO (operands[3]) + && REGNO (operands[0]) == REGNO (operands[6]) + && rtx_equal_p (operands[1], operands[5])" + [(set (match_dup 1) + (and:QI (match_dup 1) + (match_dup 4))) + ] + "") + +;; GCC uses different techniques to optimize MSB and LSB accesses, so +;; we have to code those separately. + +(define_insn "*bclrx" + [(set (pc) + (if_then_else (eq:HI (and:QI (match_operand:QI 1 "xstormy16_below100_operand" "W") + (match_operand:HI 2 "immediate_operand" "i")) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc))) + (clobber (match_operand:BI 3 "" "=y"))] + "" + "bn %1,%B2,%l0" + [(set_attr "length" "4") + (set_attr "psw_operand" "nop")]) + +(define_insn "*bclrx2" + [(set (pc) + (if_then_else (zero_extract:HI + (xor:HI (subreg:HI + (match_operand:QI 1 "xstormy16_below100_operand" "W") 0) + (match_operand:HI 2 "xstormy16_onebit_set_operand" "J")) + (const_int 1) + (match_operand:HI 3 "immediate_operand" "i")) + (label_ref (match_operand 0 "" "")) + (pc))) + (clobber (match_operand:BI 4 "" "=y"))] + "" + "bn %1,%B2,%l0" + [(set_attr "length" "4") + (set_attr "psw_operand" "nop")]) + +(define_insn "*bclr7" + [(set (pc) + (if_then_else (xor:HI (lshiftrt:HI (subreg:HI + (match_operand:QI 1 "xstormy16_below100_operand" "W") 0) + (const_int 7)) + (const_int 1)) + (label_ref (match_operand 0 "" "")) + (pc))) + (clobber (match_operand:BI 2 "" "=y"))] + "" + "bn %1,#7,%l0" + [(set_attr "length" "4") + (set_attr "psw_operand" "nop")]) + +(define_insn "*bclr15" + [(set (pc) + (if_then_else (ge:HI (sign_extend:HI (match_operand:QI 1 "xstormy16_below100_operand" "W")) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc))) + (clobber (match_operand:BI 2 "" "=y"))] + "" + "bn %1,#7,%l0" + [(set_attr "length" "4") + (set_attr "psw_operand" "nop")]) + +(define_insn "*bsetx" + [(set (pc) + (if_then_else (ne:HI (and:QI (match_operand:QI 1 "xstormy16_below100_operand" "W") + (match_operand:HI 2 "immediate_operand" "i")) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc))) + (clobber (match_operand:BI 3 "" "=y"))] + "" + "bp %1,%B2,%l0" + [(set_attr "length" "4") + (set_attr "psw_operand" "nop")]) + +(define_insn "*bsetx2" + [(set (pc) + (if_then_else (zero_extract:HI (match_operand:QI 1 "xstormy16_below100_operand" "W") + (const_int 1) + (match_operand:HI 2 "immediate_operand" "i")) + (label_ref (match_operand 0 "" "")) + (pc))) + (clobber (match_operand:BI 3 "" "=y"))] + "" + "bp %1,%b2,%l0" + [(set_attr "length" "4") + (set_attr "psw_operand" "nop")]) + +(define_insn "*bset7" + [(set (pc) + (if_then_else (lshiftrt:HI (subreg:HI (match_operand:QI 1 "xstormy16_below100_operand" "W") 0) + (const_int 7)) + (label_ref (match_operand 0 "" "")) + (pc))) + (clobber (match_operand:BI 2 "" "=y"))] + "" + "bp %1,#7,%l0" + [(set_attr "length" "4") + (set_attr "psw_operand" "nop")]) + +(define_insn "*bset15" + [(set (pc) + (if_then_else (lt:HI (sign_extend:HI (match_operand:QI 1 "xstormy16_below100_operand" "W")) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc))) + (clobber (match_operand:BI 2 "" "=y"))] + "" + "bp %1,#7,%l0" + [(set_attr "length" "4") + (set_attr "psw_operand" "nop")]) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index b7229d0a8fd..5023f2776d6 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2977,6 +2977,23 @@ Currently @option{-m[no-]ms-bitfields} is provided for the Microsoft Windows X86 compilers to match the native Microsoft compiler. @end table +@subsection Xstormy16 Variable Attributes + +One attribute is currently defined for xstormy16 configurations: +@code{below100} + +@table @code +@item below100 +@cindex @code{below100} attribute + +If a variable has the @code{below100} attribute (@code{BELOW100} is +allowed also), GCC will place the variable in the first 0x100 bytes of +memory and use special opcodes to access it. Such variables will be +placed in either the @code{.bss_below100} section or the +@code{.data_below100} section. + +@end table + @node Type Attributes @section Specifying Attributes of Types @cindex attribute of types -- 2.30.2