--- /gcc/config/m32c/addsub.md 2008-01-15 11:37:31.000000000 +0530 +++ /gcc/config/m32c/addsub.md 2008-01-15 12:02:42.000000000 +0530 @@ -35,25 +35,44 @@ (define_insn "addhi3" [(set (match_operand:HI 0 "m32c_nonimmediate_operand" - "=SdRhi,SdRhi,??Rmm,??Rmm, SdRhi,??Rmm, Rhi, Raw, Raw, !Rsp") - (plus:HI (match_operand:HI 1 "m32c_any_operand" - "%0,0,0,0, 0,0, Raw, Rfb, Rfb, 0") - (match_operand:HI 2 "m32c_any_operand" - "IU2sSdRhi,?Rmm,IU2sSdRhi,?Rmm, IM2,IM2, IS2IU2, I00, IS1, i")))] + "=SdRhi,SdRhi,??Rmm,??Rmm, SdRhi,??Rmm, Rhi, Raw, Raw, !Rsp") + (plus:HI (match_operand:HI 1 "m32c_any_operand" + "%0,0,0,0, 0,0, Raw, Rfb, Rfb, 0") + (match_operand:HI 2 "m32c_any_operand" + "IU2sSdRhi,?Rmm,IU2sSdRhi,?Rmm, IM2,IM2, IS2IU2, I00, IS1, i")))] "" - "@ - add.w\t%2,%0 - add.w\t%2,%0 - add.w\t%2,%0 - add.w\t%2,%0 - sub.w\t%m2,%0 - sub.w\t%m2,%0 - mova\t%d2[%1],%0 - stc\t%1,%0 - mova\t%D2[%1],%0 - add.w\t%2,%0" - [(set_attr "flags" "oszc,oszc,oszc,oszc,oszc,oszc,n,n,n,oszc")] - ) + "* + switch (which_alternative) + { + case 0: + if (TARGET_A16 + && GET_CODE (operands[2]) == SYMBOL_REF + && far_data_p (operands[2])== 1 + && near_data_p (operands[2])== 0) + return m32c_disp_pattern (insn, operands); + else + return \"add.w\t%2,%0\"; + case 1: + return \"add.w\t%2,%0\"; + case 2: + return \"add.w\t%2,%0\"; + case 3: + return \"add.w\t%2,%0\"; + case 4: + return \"sub.w\t%m2,%0\"; + case 5: + return \"sub.w\t%m2,%0\"; + case 6: + return \"mova\t%d2[%1],%0\"; + case 7: + return \"stc\t%1,%0\"; + case 8: + return \"mova\t%D2[%1],%0\"; + case 9: + return \"add.w\t%2,%0\"; +}" + [(set_attr "flags" "oszc,oszc,oszc,oszc,oszc,oszc,n,n,n,oszc")] + ) (define_insn "addpsi3" [(set (match_operand:PSI 0 "m32c_nonimmediate_operand" "=Rpi,Raa,SdRpi,SdRpi,Rsp*Rmm, Rpi,Rpi") --- /gcc/config/m32c/m32c.c 2008-01-15 12:05:59.000000000 +0530 +++ /gcc/config/m32c/m32c.c 2008-01-15 12:02:05.000000000 +0530 @@ -61,6 +61,8 @@ typedef enum static tree interrupt_handler (tree *, tree, tree, int, bool *); static tree function_vector_handler (tree *, tree, tree, int, bool *); static int interrupt_p (tree node); +static tree far_data_handler (tree *, tree, tree, int, bool *); +static tree near_data_handler (tree *, tree, tree, int, bool *); static bool m32c_asm_integer (rtx, unsigned int, int); static int m32c_comp_type_attributes (tree, tree); static bool m32c_fixed_condition_code_regs (unsigned int *, unsigned int *); @@ -74,6 +76,7 @@ static bool m32c_strict_argument_naming static rtx m32c_struct_value_rtx (tree, int); static rtx m32c_subreg (enum machine_mode, rtx, enum machine_mode, int); static int need_to_save (int); +static section * m32c_select_section (tree, int, unsigned HOST_WIDE_INT); int current_function_special_page_vector (rtx); #define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0) @@ -980,6 +983,18 @@ m32c_extra_constraint_p2 (rtx value, cha return 0; return m32c_legitimate_address_p (GET_MODE (value), XEXP (value, 0), 1); } + else if (memcmp (str, "Sc", 2) == 0) + { + rtx r; + if (RTX_IS ("m+rs")) + { + if (REGNO (patternr[2]) == A0_REGNO) + return 1; + else + return 0; + } + return 0; + } else if (memcmp (str, "Sa", 2) == 0) { rtx r; @@ -995,6 +1010,10 @@ m32c_extra_constraint_p2 (rtx value, cha { return (RTX_IS ("mi") || RTX_IS ("ms") || RTX_IS ("m+si")); } + else if (memcmp (str, "Sn", 2) == 0) + { + return (RTX_IS ("ms") || RTX_IS ("m+si")); + } else if (memcmp (str, "Ss", 2) == 0) { return ((RTX_IS ("mr") @@ -2318,6 +2337,29 @@ m32c_print_operand (FILE * file, rtx x, unsigned_const = 1; code = 0; } + if (code == 'z') + { + assemble_name (file, XSTR (x, 0)); + return; + } + if (code == 'Z') + { + assemble_name (file, XSTR (x, 0)); + fprintf (file,"+2"); + return; + } + if (code == 'y') + { + assemble_name (file, XSTR (x, 0)); + fprintf (file,"+4"); + return; + } + if (code == 'Y') + { + assemble_name (file, XSTR (x, 0)); + fprintf (file,"+6"); + return; + } /* This one is only for debugging; you can put it in a pattern to force this error. */ if (code == '!') @@ -2714,6 +2756,514 @@ interrupt_p (tree node ATTRIBUTE_UNUSED) return 0; } +/* Returns TRUE if given tree has the "far" attribute. */ +int +far_data_p (rtx x) +{ + tree t = SYMBOL_REF_DECL (x); + if (t == NULL) + return 0; + if (GET_CODE (x) == SYMBOL_REF) + { + if (TREE_CODE (t) != VAR_DECL) + return 0; + if (TARGET_M16C && TREE_READONLY (t) && (!TYPE_VOLATILE (t))) + { + return 1; + } + tree list = M32C_ATTRIBUTES (t); + while (list) + { + if (is_attribute_p ("far", TREE_PURPOSE (list))) + return 1; + + list = TREE_CHAIN (list); + } + } + return 0; +} + +/* Returns TRUE if given tree has the "far" attribute. */ +int +far_data_a1a0 (rtx x) +{ + tree t = MEM_EXPR (x); + if (t == NULL) + return 0; + if (GET_CODE (XEXP (x, 0)) == REG) + { + if (TREE_CODE (t) != VAR_DECL) + return 0; + + if (TARGET_M16C && TREE_READONLY (t) && (!TYPE_VOLATILE (t))) + { + return 1; + } + + tree list = M32C_ATTRIBUTES (t); + while (list) + { + if (is_attribute_p ("far", TREE_PURPOSE (list))) + return 1; + list = TREE_CHAIN (list); + } + } + return 0; +} + +static tree +far_data_handler (tree * node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool * no_add_attrs) +{ + if (!TARGET_R8C && !TARGET_M16C) + { + warning (OPT_Wattributes, + "%qs attribute is supported only for R8C and M16C targets, attribute ignored", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + return NULL_TREE; + } + if (TREE_CODE (*node) != VAR_DECL) + { + warning (OPT_Wattributes, "%qs attribute only applies to variables", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + return NULL_TREE; + } + if (TARGET_R8C) + { + if (TREE_STATIC (*node) || DECL_EXTERNAL (*node)) + { + if (!TREE_READONLY (*node) || (TYPE_VOLATILE (*node))) + { + warning (OPT_Wattributes, + "for R8C targets %qs attribute applies only for constants, attribute ignored", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + return NULL_TREE; + } + } + } + if (TREE_STATIC (*node) || DECL_EXTERNAL (*node)) + { + if (TREE_READONLY (*node) && (!TYPE_VOLATILE (*node))) + DECL_SECTION_NAME (*node) = build_string (9, ".frodata"); + else if (DECL_INITIAL (*node)) + DECL_SECTION_NAME (*node) = build_string (7, ".fdata"); + else if (*node && TREE_CODE (*node) == VAR_DECL + && DECL_INITIAL (*node) == NULL_TREE) + DECL_SECTION_NAME (*node) = build_string (6, ".fbss"); + } + return NULL_TREE; +} + +/* Returns TRUE if given tree has the "near" attribute. */ +int +near_data_p (rtx x) +{ + tree t = SYMBOL_REF_DECL (x); + if (t == NULL) + return 0; + if (GET_CODE (x) == SYMBOL_REF) + { + if (TREE_CODE (t) != VAR_DECL) + return 0; + tree list = M32C_ATTRIBUTES (t); + + while (list) + { + if (is_attribute_p ("near", TREE_PURPOSE (list))) + return 1; + list = TREE_CHAIN (list); + } + } + return 0; +} + +/* Returns TRUE if given tree has the "near" attribute. */ +near_data_a1a0 (rtx x) +{ + tree t = MEM_EXPR (x); + if (t == NULL) + return 0; + + if (GET_CODE (XEXP (x, 0)) == REG) + { + + if (TREE_CODE (t) != VAR_DECL) + return 0; + tree list = M32C_ATTRIBUTES (t); + while (list) + { + if (is_attribute_p ("near", TREE_PURPOSE (list))) + return 1; + + list = TREE_CHAIN (list); + } + } + return 0; +} + +static tree +near_data_handler (tree * node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool * no_add_attrs) +{ + if (!TARGET_M16C) + { + warning (OPT_Wattributes, + "%qs attribute is supported only for M16C targets, attribute ignored", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + return NULL_TREE; + } + if (TREE_CODE (*node) != VAR_DECL) + { + warning (OPT_Wattributes, "%qs attribute only applies to variables", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + return NULL_TREE; + } + if (TREE_STATIC (*node) || DECL_EXTERNAL (*node)) + { + if (TREE_READONLY (*node) && (!TYPE_VOLATILE (*node))) + DECL_SECTION_NAME (*node) = build_string (9, ".nrodata"); + else if (DECL_INITIAL (*node)) + DECL_SECTION_NAME (*node) = build_string (7, ".ndata"); + else if (*node && TREE_CODE (*node) == VAR_DECL + && DECL_INITIAL (*node) == NULL_TREE) + DECL_SECTION_NAME (*node) = build_string (6, ".nbss"); + } + return NULL_TREE; +} + +/* Copy the constant string from '.rodata' section in far memory to + 'data' section in near memory */ +section * +m32c_select_section (tree decl, int reloc, + unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED) +{ + if (DECL_P (decl)) + { + if (decl_readonly_section (decl, reloc)) + return readonly_data_section; + } + else if (TREE_CODE (decl) == CONSTRUCTOR) + { + if (!((flag_pic && reloc) + || !TREE_READONLY (decl) + || TREE_SIDE_EFFECTS (decl) || !TREE_CONSTANT (decl))) + return readonly_data_section; + } + else if (TREE_CODE (decl) == STRING_CST) + { + if (TARGET_M16C) + { + return data_section; + } + else + { + return readonly_data_section; + } + } + else if (!(flag_pic && reloc)) + return readonly_data_section; + + return data_section; +} + +/* Returns the instructions to access array elements using the + displacement. */ +char * +m32c_disp_pattern (rtx insn, rtx * operands) +{ + rtx x, y, z, start, end, start1, start2, start3; + start = NEXT_INSN (insn); + start1 = NEXT_INSN (start); + start2 = NEXT_INSN (start1); + start3 = NEXT_INSN (start2); + x = (operands[2]); + end = PATTERN (start); + if (TARGET_A16 && INSN_CODE (insn) == CODE_FOR_addhi3 + && (INSN_CODE (start) == CODE_FOR_movhi_op + || INSN_CODE (start) == CODE_FOR_movsi_splittable) + && GET_CODE (x) == SYMBOL_REF && far_data_p (x) == 1 + && near_data_p (x) == 0 && GET_CODE (operands[0]) == REG + && REGNO (operands[0]) == A0_REGNO) + { + if ((INSN_CODE (start1) == CODE_FOR_movhi_op) + && (INSN_CODE (start2) == CODE_FOR_movhi_op) + && (INSN_CODE (start3) == CODE_FOR_movhi_op) + && REGNO (XEXP (PATTERN (start), 0)) == R0_REGNO + && GET_CODE (XEXP (PATTERN (start), 1)) == MEM + && REGNO (XEXP (XEXP (PATTERN (start), 1), 0)) == A0_REGNO + && REGNO (XEXP (PATTERN (start1), 0)) == R2_REGNO + && GET_CODE (XEXP (PATTERN (start1), 1)) == MEM + && GET_CODE (XEXP (XEXP (PATTERN (start1), 1), 0)) == PLUS + && REGNO (XEXP (XEXP (XEXP (PATTERN (start1), 1), 0), 0)) == + A0_REGNO) + { + output_asm_insn ("lde.w %z2[a0],r0", operands); + output_asm_insn ("lde.w %Z2[a0],r2", operands); + output_asm_insn ("lde.w %y2[a0],r1", operands); + output_asm_insn ("lde.w %Y2[a0],r3", operands); + delete_insn (insn); + delete_insn (start); + delete_insn (start1); + delete_insn (start2); + delete_insn (start3); + return ""; + } + else if ((INSN_CODE (start1) == CODE_FOR_movhi_op) + && (INSN_CODE (start2) == CODE_FOR_movhi_op) + && (INSN_CODE (start3) == CODE_FOR_movhi_op) + && REGNO (XEXP (PATTERN (start3), 0)) == R0_REGNO + && REGNO (XEXP (PATTERN (start2), 0)) == R2_REGNO + && GET_CODE (XEXP (PATTERN (start2), 1)) == MEM + && GET_CODE (XEXP (XEXP (PATTERN (start2), 1), 0)) == PLUS + && REGNO (XEXP (XEXP (XEXP (PATTERN (start2), 1), 0), 0)) == + A0_REGNO) + { + output_asm_insn ("lde.w %Y2[a0],r0", operands); + output_asm_insn ("lde.w %y2[a0],r2", operands); + output_asm_insn ("lde.w %Z2[a0],r1", operands); + output_asm_insn ("lde.w %z2[a0],r3", operands); + delete_insn (insn); + delete_insn (start); + delete_insn (start1); + delete_insn (start2); + delete_insn (start3); + return ""; + } + else if ((INSN_CODE (start1) == CODE_FOR_movhi_op) + && (REGNO (XEXP (PATTERN (start), 0)) == R0_REGNO + || REGNO (XEXP (PATTERN (start), 0)) == R1_REGNO) + && GET_CODE (XEXP (PATTERN (start), 1)) == MEM + && REGNO (XEXP (XEXP (PATTERN (start), 1), 0)) == A0_REGNO + && (REGNO (XEXP (PATTERN (start1), 0)) == R2_REGNO + || REGNO (XEXP (PATTERN (start1), 0)) == R3_REGNO)) + { + if (REGNO (XEXP (PATTERN (start), 0)) == R0_REGNO) + { + output_asm_insn ("lde.w %z2[a0],r0", operands); + output_asm_insn ("lde.w %Z2[a0],r2", operands); + } + else + { + output_asm_insn ("lde.w %z2[a0],r1", operands); + output_asm_insn ("lde.w %Z2[a0],r3", operands); + } + delete_insn (insn); + delete_insn (start); + delete_insn (start1); + return ""; + } + else if ((INSN_CODE (start1) == CODE_FOR_movhi_op) + && (REGNO (XEXP (PATTERN (start1), 0)) == R0_REGNO + || REGNO (XEXP (PATTERN (start1), 0)) == R1_REGNO) + && (REGNO (XEXP (PATTERN (start), 0)) == R2_REGNO + || REGNO (XEXP (PATTERN (start), 0)) == R3_REGNO) + && GET_CODE (XEXP (XEXP (PATTERN (start), 1), 0)) == PLUS + && REGNO (XEXP (XEXP (XEXP (PATTERN (start), 1), 0), 0)) == + A0_REGNO) + { + if (REGNO (XEXP (PATTERN (start1), 0)) == R0_REGNO) + { + output_asm_insn ("lde.w %Z2[a0],r0", operands); + output_asm_insn ("lde.w %z2[a0],r2", operands); + } + else + { + output_asm_insn ("lde.w %Z2[a0],r1", operands); + output_asm_insn ("lde.w %z2[a0],r3", operands); + } + delete_insn (insn); + delete_insn (start); + delete_insn (start1); + return ""; + } + else if (INSN_CODE (start) == CODE_FOR_movsi_splittable + && GET_MODE (XEXP (PATTERN (start), 0)) == SImode + && GET_CODE (XEXP (PATTERN (start), 0)) == REG + && (REGNO (XEXP (PATTERN (start), 0)) == R0_REGNO + || REGNO (XEXP (PATTERN (start), 0)) == R1_REGNO) + && GET_CODE (XEXP (PATTERN (start), 1)) == MEM + && GET_CODE (XEXP (XEXP (PATTERN (start), 1), 0)) == REG + && REGNO (XEXP (XEXP (PATTERN (start), 1), 0)) == A0_REGNO) + { + if (REGNO (XEXP (PATTERN (start), 0)) == R0_REGNO) + { + output_asm_insn ("lde.w %Z2[a0],r2", operands); + output_asm_insn ("lde.w %z2[a0],r0", operands); + } + else + { + output_asm_insn ("lde.w %Z2[a0],r3", operands); + output_asm_insn ("lde.w %z2[a0],r1", operands); + } + delete_insn (insn); + delete_insn (start); + return ""; + } + else if ((INSN_CODE (start) == CODE_FOR_movhi_op) + && GET_CODE (XEXP (PATTERN (start), 1)) == MEM + && GET_CODE (XEXP (XEXP (PATTERN (start), 1), 0)) == REG + && REGNO (XEXP (XEXP (PATTERN (start), 1), 0)) == A0_REGNO + && GET_CODE (XEXP (PATTERN (start), 0)) == REG) + { + operands[0] = XEXP (PATTERN (start), 0); + output_asm_insn ("lde.w %z2[a0],%0", operands); + delete_insn (insn); + delete_insn (start); + return ""; + } + else if ((INSN_CODE (start1) == CODE_FOR_movhi_op) + && (INSN_CODE (start2) == CODE_FOR_movhi_op) + && (INSN_CODE (start3) == CODE_FOR_movhi_op) + && REGNO (XEXP (PATTERN (start), 1)) == R0_REGNO + && GET_CODE (XEXP (PATTERN (start), 0)) == MEM + && REGNO (XEXP (XEXP (PATTERN (start), 0), 0)) == A0_REGNO + && REGNO (XEXP (PATTERN (start1), 1)) == R2_REGNO + && GET_CODE (XEXP (PATTERN (start1), 0)) == MEM + && GET_CODE (XEXP (XEXP (PATTERN (start1), 0), 0)) == PLUS + && REGNO (XEXP (XEXP (XEXP (PATTERN (start1), 0), 0), 0)) == + A0_REGNO) + { + output_asm_insn ("ste.w r0,%z2[a0]", operands); + output_asm_insn ("ste.w r2,%Z2[a0]", operands); + output_asm_insn ("ste.w r1,%y2[a0]", operands); + output_asm_insn ("ste.w r3,%Y2[a0]", operands); + delete_insn (insn); + delete_insn (start); + delete_insn (start1); + delete_insn (start2); + delete_insn (start3); + return ""; + } + else if ((INSN_CODE (start1) == CODE_FOR_movhi_op) + && (INSN_CODE (start2) == CODE_FOR_movhi_op) + && (INSN_CODE (start3) == CODE_FOR_movhi_op) + && REGNO (XEXP (PATTERN (start3), 1)) == R0_REGNO + && REGNO (XEXP (PATTERN (start2), 1)) == R2_REGNO + && GET_CODE (XEXP (PATTERN (start2), 0)) == MEM + && GET_CODE (XEXP (XEXP (PATTERN (start2), 0), 0)) == PLUS + && REGNO (XEXP (XEXP (XEXP (PATTERN (start2), 0), 0), 0)) == + A0_REGNO) + { + output_asm_insn ("ste.w r0,%Y2[a0]", operands); + output_asm_insn ("ste.w r2,%y2[a0]", operands); + output_asm_insn ("ste.w r1,%Z2[a0]", operands); + output_asm_insn ("ste.w r3,%z2[a0]", operands); + delete_insn (insn); + delete_insn (start); + delete_insn (start1); + delete_insn (start2); + delete_insn (start3); + return ""; + } + else if ((INSN_CODE (start1) == CODE_FOR_movhi_op) + && (REGNO (XEXP (PATTERN (start), 1)) == R0_REGNO + || REGNO (XEXP (PATTERN (start), 1)) == R1_REGNO) + && GET_CODE (XEXP (PATTERN (start), 0)) == MEM + && REGNO (XEXP (XEXP (PATTERN (start), 0), 0)) == A0_REGNO + && (REGNO (XEXP (PATTERN (start1), 1)) == R2_REGNO + || REGNO (XEXP (PATTERN (start1), 1)) == R3_REGNO) + && GET_CODE (XEXP (PATTERN (start1), 0)) == MEM + && GET_CODE (XEXP (XEXP (PATTERN (start1), 0), 0)) == PLUS + && REGNO (XEXP (XEXP (XEXP (PATTERN (start1), 0), 0), 0)) == + A0_REGNO) + { + if (REGNO (XEXP (PATTERN (start), 1)) == R0_REGNO) + { + output_asm_insn ("ste.w r0,%z2[a0]", operands); + output_asm_insn ("ste.w r2,%Z2[a0]", operands); + } + else + { + output_asm_insn ("ste.w r1,%z2[a0]", operands); + output_asm_insn ("ste.w r3,%Z2[a0]", operands); + } + delete_insn (insn); + delete_insn (start); + delete_insn (start1); + return ""; + } + else if ((INSN_CODE (start1) == CODE_FOR_movhi_op) + && (REGNO (XEXP (PATTERN (start1), 1)) == R0_REGNO + || REGNO (XEXP (PATTERN (start1), 1)) == R1_REGNO) + && (REGNO (XEXP (PATTERN (start), 1)) == R2_REGNO + || REGNO (XEXP (PATTERN (start), 1)) == R3_REGNO) + && GET_CODE (XEXP (PATTERN (start), 0)) == MEM + && GET_CODE (XEXP (XEXP (PATTERN (start), 0), 0)) == PLUS + && REGNO (XEXP (XEXP (XEXP (PATTERN (start), 0), 0), 0)) == + A0_REGNO) + { + if (REGNO (XEXP (PATTERN (start1), 1)) == R0_REGNO) + { + output_asm_insn ("ste.w r0,%Z2[a0]", operands); + output_asm_insn ("ste.w r2,%z2[a0]", operands); + } + else + { + output_asm_insn ("ste.w r1,%Z2[a0]", operands); + output_asm_insn ("ste.w r3,%z2[a0]", operands); + } + delete_insn (insn); + delete_insn (start); + delete_insn (start1); + return ""; + } + else if (INSN_CODE (start) == CODE_FOR_movsi_splittable + && GET_MODE (XEXP (PATTERN (start), 1)) == SImode + && GET_CODE (XEXP (PATTERN (start), 1)) == REG + && (REGNO (XEXP (PATTERN (start), 1)) == R0_REGNO + || REGNO (XEXP (PATTERN (start), 1)) == R1_REGNO) + && GET_CODE (XEXP (PATTERN (start), 0)) == MEM + && GET_CODE (XEXP (XEXP (PATTERN (start), 0), 0)) == REG + && REGNO (XEXP (XEXP (PATTERN (start), 0), 0)) == A0_REGNO) + { + if (REGNO (XEXP (PATTERN (start), 1)) == R0_REGNO) + { + output_asm_insn ("ste.w r2,%Z2[a0]", operands); + output_asm_insn ("ste.w r0,%z2[a0]", operands); + } + else + { + output_asm_insn ("ste.w r3,%Z2[a0]", operands); + output_asm_insn ("ste.w r1,%z2[a0]", operands); + } + delete_insn (insn); + delete_insn (start); + return ""; + } + else if ((INSN_CODE (start) == CODE_FOR_movhi_op) + && GET_CODE (XEXP (PATTERN (start), 0)) == MEM + && GET_CODE (XEXP (XEXP (PATTERN (start), 0), 0)) == REG + && REGNO (XEXP (XEXP (PATTERN (start), 0), 0)) == A0_REGNO + && GET_CODE (XEXP (PATTERN (start), 1)) == REG) + { + operands[1] = XEXP (PATTERN (start), 1); + output_asm_insn ("ste.w %1,%z2[a0]", operands); + delete_insn (insn); + delete_insn (start); + return ""; + } + else + { + output_asm_insn ("add.w %2,%0", operands); + delete_insn (insn); + return ""; + } + } + else + { + output_asm_insn ("add.w %2,%0", operands); + delete_insn (insn); + return ""; + } +} + static tree interrupt_handler (tree * node ATTRIBUTE_UNUSED, tree name ATTRIBUTE_UNUSED, @@ -2821,6 +3371,8 @@ current_function_special_page_vector (rt #define TARGET_ATTRIBUTE_TABLE m32c_attribute_table static const struct attribute_spec m32c_attribute_table[] = { {"interrupt", 0, 0, false, false, false, interrupt_handler}, + {"far", 0, 0, false, false, false, far_data_handler}, + {"near", 0, 0, false, false, false, near_data_handler}, {"function_vector", 1, 1, true, false, false, function_vector_handler}, {0, 0, 0, 0, 0, 0, 0} }; @@ -4206,6 +4758,11 @@ m32c_output_compare (rtx insn, rtx *oper #undef TARGET_ENCODE_SECTION_INFO #define TARGET_ENCODE_SECTION_INFO m32c_encode_section_info +#if 1 +#undef TARGET_ASM_SELECT_SECTION +#define TARGET_ASM_SELECT_SECTION m32c_select_section +#endif + /* The Global `targetm' Variable. */ struct gcc_target targetm = TARGET_INITIALIZER; --- /gcc/config/m32c/m32c-protos.h 2008-01-15 12:06:45.000000000 +0530 +++ /gcc/config/m32c/m32c-protos.h 2008-01-08 17:37:34.000000000 +0530 @@ -87,6 +87,7 @@ int m32c_mode_dependent_address (rtx); int m32c_modes_tieable_p (MM, MM); bool m32c_mov_ok (rtx *, MM); char * m32c_output_compare (rtx, rtx *); +char * m32c_disp_pattern (rtx, rtx *); void m32c_pend_compare (rtx *); int m32c_preferred_output_reload_class (rtx, int); int m32c_preferred_reload_class (rtx, int); @@ -111,6 +112,10 @@ void m32c_function_arg_advance (CUMULATI tree m32c_gimplify_va_arg_expr (tree, tree, tree *, tree *); void m32c_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int); bool m32c_promote_function_return (tree); +int far_data_p (rtx); +int near_data_p (rtx); +int far_data_a1a0 (rtx); +int near_data_a1a0 (rtx); int m32c_special_page_vector_p (tree); #endif --- /gcc/config/m32c/mov.md 2008-01-15 11:37:37.000000000 +0530 +++ /gcc/config/m32c/mov.md 2008-01-15 17:41:04.000000000 +0530 @@ -30,6 +30,159 @@ ;; Match push/pop before mov.b for passing char as arg, ;; e.g. stdlib/efgcvt.c. + +;; M16C-20bit Access +(define_insn "movqildabs_op" + [(set (match_operand:QI 0 "mra_nopp_operand" "=Rqi*Rmm") + (match_operand:QI 1 "m32c_20babsqi_operand" "Sn"))] + "TARGET_A16 && m32c_mov_ok (operands, QImode)" + "* +{ + HOST_WIDE_INT a = 0, b = 0; + if (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF) + { + a = far_data_p (XEXP (operands[1], 0)); + b = near_data_p (XEXP (operands[1], 0)); + } + else if (GET_CODE (XEXP (operands[1], 0)) == CONST) + { + a = far_data_p (XEXP (XEXP (XEXP (operands[1], 0), 0), 0)); + b = near_data_p (XEXP (XEXP (XEXP (operands[1], 0), 0), 0)); + } + + if ((a == 1) && (b == 0)) + return \"lde.b\\t%1,%0\"; + else + return \"mov.b\\t%1,%0\"; +}" + [(set_attr "flags" "n")] +) + +(define_insn "movqistabs_op" + [(set (match_operand:QI 0 "m32c_20babsqi_operand" "=Sn") + (match_operand:QI 1 "mrai_nopp_operand" "Rqi*Rmm"))] + "TARGET_M16C && m32c_mov_ok (operands, QImode)" + "* +{ + HOST_WIDE_INT a = 0, b = 0; + if (GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF) + { + a = far_data_p (XEXP (operands[0], 0)); + b = near_data_p (XEXP (operands[0], 0)); + } + else if (GET_CODE (XEXP (operands[0], 0)) == CONST) + { + a = far_data_p (XEXP (XEXP (XEXP (operands[0], 0), 0), 0)); + b = near_data_p (XEXP (XEXP (XEXP (operands[0], 0), 0), 0)); + } + + if ((a == 1) && (b == 0)) + return \"ste.b\\t%1,%0\"; + else + return \"mov.b\\t%1,%0\"; +}" + [(set_attr "flags" "n")] +) + +(define_insn "movqilddisp_op" + [(set (match_operand:QI 0 "mra_nopp_operand" "=Rqi*Rmm") + (match_operand:QI 1 "m32c_20bdisp_operand" "Sd"))] + "TARGET_A16 && m32c_mov_ok (operands, QImode) + && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == SYMBOL_REF" + "* +{ + HOST_WIDE_INT a = 0, b = 0; + if (GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == SYMBOL_REF) + { + a = far_data_p (XEXP (XEXP (operands[1], 0),1)); + b = near_data_p (XEXP (XEXP (operands[1], 0),1)); + } + if ((a == 1) && (b == 0) && REGNO (XEXP (XEXP (operands[1], 0), 0)) == A0_REGNO) + return \"lde.b\\t%1,%0\"; + else if (REGNO (XEXP (XEXP (operands[1], 0), 0)) == A0_REGNO) + return \"mov.b\\t%1,%0\"; + else + { + operands[1] = XEXP (XEXP (operands[1], 0), 0); + output_asm_insn (\"mov.b\\t%1,a0\",operands); + operands[1] = XEXP (XEXP (operands[1], 0), 1); + return \"mov.b\\t%z1[a0],%0\"; + } +}" + [(set_attr "flags" "n")] +) + +(define_insn "movqistdisp_op" + [(set (match_operand:QI 0 "m32c_20bdisp_operand" "=Sd") + (match_operand:QI 1 "mra_nopp_operand" "Rqi*Rmm"))] + "TARGET_M16C && m32c_mov_ok (operands, QImode) + && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == SYMBOL_REF" + "* +{ + HOST_WIDE_INT a = 0, b = 0; + if (GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == SYMBOL_REF) + { + a = far_data_p (XEXP (XEXP (operands[0], 0),1)); + b = near_data_p (XEXP (XEXP (operands[0], 0),1)); + } + if ((a == 1) && (b == 0) && REGNO (XEXP (XEXP (operands[0], 0), 0)) == A0_REGNO) + return \"ste.b\\t%1,%0\"; + else if (REGNO (XEXP (XEXP (operands[0], 0), 0)) == A0_REGNO) + return \"mov.b\\t%1,%0\"; + else + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); + output_asm_insn (\"mov.b\\t%0,a0\",operands); + operands[0] = XEXP (XEXP (operands[0], 0), 1); + return \"mov.b\\t%1,%z0[a0]\"; + } +}" + [(set_attr "flags" "n")] +) + +(define_insn "movqildA1A0_op" +[(set (match_operand:QI 0 "mra_nopp_operand" "=Rqi*Rmm") + (match_operand:QI 1 "m32c_20bA1A0_operand" ""))] + "TARGET_A16 && m32c_mov_ok (operands, QImode) + && REGNO (XEXP (operands[1], 0)) == A0_REGNO" + "* +{ + HOST_WIDE_INT a = 0, b = 0; + if (GET_CODE (XEXP (operands[1], 0)) == REG) + { + a = far_data_a1a0 (operands[1]); + b = near_data_a1a0 (operands[1]); + } + if ((a == 1) && (b == 0)) + return \"lde.b\\t%1,%0\"; + else + return \"mov.b\\t%1,%0\"; +}" + [(set_attr "flags" "n")] +) + +(define_insn "movqistA1A0_op" + [(set (match_operand:QI 0 "m32c_20bA1A0_operand" "") + (match_operand:QI 1 "mra_nopp_operand" "Rqi*Rmm"))] + "TARGET_M16C && m32c_mov_ok (operands, QImode)" + "* +{ + HOST_WIDE_INT a = 0, b = 0; + if (GET_CODE (XEXP (operands[0], 0)) == REG) + { + a = far_data_a1a0 (operands[0]); + b = near_data_a1a0 (operands[0]); + } + if ((a == 1) && (b == 0)) + return \"ste.b\\t%1,%0\"; + else + return \"mov.b\\t%1,%0\"; +}" + [(set_attr "flags" "n")] +) + +; M16C-20bit Access + (define_insn "movqi_op" [(set (match_operand:QI 0 "m32c_nonimmediate_operand" "=Rqi*Rmm, <, RqiSd*Rmm, SdSs, Rqi*Rmm, Sd") @@ -53,12 +206,168 @@ "if (m32c_prepare_move (operands, QImode)) DONE;" ) +;; M16C-20bit Access +(define_insn "movhildabs_op" + [(set (match_operand:HI 0 "mra_nopp_operand" "=Rhi*Rmm") + (match_operand:HI 1 "m32c_20babshi_operand" ""))] + "TARGET_A16 && m32c_mov_ok (operands, HImode)" + "* +{ + HOST_WIDE_INT a = 0, b = 0; + if (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF) + { + a = far_data_p (XEXP (operands[1], 0)); + b = near_data_p (XEXP (operands[1], 0)); + } + else if (GET_CODE (XEXP (operands[1], 0)) == CONST) + { + a = far_data_p (XEXP (XEXP (XEXP (operands[1], 0), 0), 0)); + b = near_data_p (XEXP (XEXP (XEXP (operands[1], 0), 0), 0)); + } + + if ((a == 1) && (b == 0)) + return \"lde.w\\t%1,%0\"; + else + return \"mov.w\\t%1,%0\"; +}" + [(set_attr "flags" "n")] +) + +(define_insn "movhistabs_op" + [(set (match_operand:HI 0 "m32c_20babshi_operand" "") + (match_operand:HI 1 "mrai_nopp_operand" "iRhi*Rmm"))] + "TARGET_M16C && m32c_mov_ok (operands, HImode)" + "* +{ + HOST_WIDE_INT a = 0, b = 0; + if (GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF) + { + a = far_data_p (XEXP (operands[0], 0)); + b = near_data_p (XEXP (operands[0], 0)); + } + else if (GET_CODE (XEXP (operands[0], 0)) == CONST) + { + a = far_data_p (XEXP (XEXP (XEXP (operands[0], 0), 0), 0)); + b = near_data_p (XEXP (XEXP (XEXP (operands[0], 0), 0), 0)); + } + if ((a == 1) && (b == 0) && GET_CODE (operands[1]) == CONST_INT) + return \"mov.w\\t%1,mem14\;ste.w\\tmem14,%0\"; + else if ((a == 1) && (b == 0)) + return \"ste.w\\t%1,%0\"; + else + return \"mov.w\\t%1,%0\"; +}" + [(set_attr "flags" "n")] +) + +(define_insn "movhilddisp_op" +[(set (match_operand:HI 0 "mra_nopp_operand" "=Rhi*Rmm") + (match_operand:HI 1 "m32c_20bdisphi_operand" ""))] + "TARGET_A16 && m32c_mov_ok (operands, HImode) + && REGNO (XEXP (XEXP (operands[1], 0), 0)) == A0_REGNO" + "* +{ + HOST_WIDE_INT a = 0, b = 0; + if (GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == SYMBOL_REF) + { + a = far_data_p (XEXP (XEXP (operands[1], 0), 1)); + b = near_data_p (XEXP (XEXP (operands[1], 0), 1)); + } + else if (GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST) + { + a = far_data_p (XEXP (XEXP (XEXP (XEXP (operands[1], 0), 1), 0), 0)); + b = near_data_p (XEXP (XEXP (XEXP (XEXP (operands[1], 0), 1), 0), 0)); + } + if ((a == 1) && (b == 0)) + return \"lde.w\\t%1,%0\"; + else + return \"mov.w\\t%1,%0\"; +}" + [(set_attr "flags" "n")] +) + +(define_insn "movhistdisp_op" + [(set (match_operand:HI 0 "m32c_20bdisphi_operand" "") + (match_operand:HI 1 "mra_nopp_operand" "Rhi*Rmm"))] + "TARGET_M16C && m32c_mov_ok (operands, HImode) + && (REGNO (XEXP (XEXP (operands[0], 0), 0)) == A0_REGNO + || REGNO (XEXP (XEXP (operands[0], 0), 0)) == A1_REGNO)" + "* +{ + HOST_WIDE_INT a = 0, b = 0; + if (GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == SYMBOL_REF) + { + a = far_data_p (XEXP (XEXP (operands[0], 0), 1)); + b = near_data_p (XEXP (XEXP (operands[0], 0), 1)); + } + else if (GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST) + { + a = far_data_p (XEXP (XEXP (XEXP (XEXP (operands[0], 0), 1), 0), 0)); + b = near_data_p (XEXP (XEXP (XEXP (XEXP (operands[0], 0), 1), 0), 0)); + } + if ((a == 1) && (b == 0) && REGNO (XEXP (XEXP (operands[0], 0), 0)) == A0_REGNO) + return \"ste.w\\t%1,%0\"; + else if ((a == 1) && (b == 0) && REGNO (XEXP (XEXP (operands[0], 0), 0)) == A1_REGNO) + { + output_asm_insn (\"mov.w\\ta1,a0\",operands); + operands[0] = XEXP (XEXP (operands[0], 0), 1); + return \"ste.w\\t%1,%z0[a0]\"; + } + else + return \"mov.w\\t%1,%0\"; +}" + [(set_attr "flags" "n")] +) + +(define_insn "movhildA1A0_op" + [(set (match_operand:HI 0 "mra_nopp_operand" "=Rhi*Rmm") + (match_operand:HI 1 "m32c_20bA1A0_operand" ""))] + "TARGET_A16 && m32c_mov_ok (operands, HImode) + && REGNO (XEXP (operands[1], 0)) == A0_REGNO" + "* +{ + HOST_WIDE_INT a = 0, b = 0; + if (GET_CODE (XEXP (operands[1], 0)) == REG) + { + a = far_data_a1a0 (operands[1]); + b = near_data_a1a0 (operands[1]); + } + if ((a == 1) && (b == 0)) + return \"lde.w\\t%1,%0\"; + else + return \"mov.w\\t%1,%0\"; +}" + [(set_attr "flags" "n")] +) + +(define_insn "movhistA1A0_op" + [(set (match_operand:HI 0 "m32c_20bA1A0_operand" "") + (match_operand:HI 1 "mra_nopp_operand" "Rhi*Rmm"))] + "TARGET_M16C && m32c_mov_ok (operands, HImode)" + "* +{ + HOST_WIDE_INT a = 0, b = 0; + if (GET_CODE (XEXP (operands[0], 0)) == REG + && REGNO (XEXP (operands[0], 0)) == A0_REGNO) + { + a = far_data_a1a0 (operands[0]); + b = near_data_a1a0 (operands[0]); + } + if ((a == 1) && (b == 0)) + return \"ste.w\\t%1,%0\"; + else + return \"mov.w\\t%1,%0\"; +}" + [(set_attr "flags" "n")] +) + +;; M16C-20bit Access (define_insn "movhi_op" [(set (match_operand:HI 0 "m32c_nonimmediate_operand" - "=Rhi*Rmm, Sd, SdSs, *Rcr, RhiSd*Rmm, <, RhiSd*Rmm, <, *Rcr") - (match_operand:HI 1 "m32c_any_operand" - "iRhi*RmmSdSs, i, Rhi*Rmm, RhiSd*Rmm, *Rcr, iRhiSd*Rmm, >, *Rcr, >"))] + "=Rhi*Rmm, Sd, SdSs, *Rcr, RhiSd*Rmm, <, RhiSd*Rmm, <, *Rcr") + (match_operand:HI 1 "m32c_any_operand" + "iRhi*RmmSdSs, i, Rhi*Rmm, RhiSd*Rmm, *Rcr, iRhiSd*Rmm, >, *Rcr, >"))] "m32c_mov_ok (operands, HImode)" "@ mov.w\t%1,%0 --- /gcc/config/m32c/predicates.md 2008-01-15 11:37:38.000000000 +0530 +++ /gcc/config/m32c/predicates.md 2008-01-15 17:22:32.000000000 +0530 @@ -157,6 +157,17 @@ (not (match_operand 1 "cr_operand" ""))) (not (match_operand 2 "m32c_wide_subreg" "")))) +; As above, but no push/pop operations +(define_predicate "mrai_nopp_operand" + (match_operand 0 "mrai_operand" "") +{ + if (GET_CODE (op) == MEM + && (GET_CODE (XEXP (op, 0)) == PRE_DEC + || (GET_CODE (XEXP (op, 0)) == POST_INC))) + return 0; + return 1; +}) + ; Likewise, plus true for subregs. (define_predicate "mrasi_operand" (and (match_operand 0 "general_operand" "") @@ -285,3 +296,83 @@ (define_predicate "m32c_1mask16_operand" (and (match_operand 0 "const_int_operand") (match_test "m32c_const_ok_for_constraint_p(INTVAL(op), 'I', \"Imw\")"))) + +; TRUE for memory values that satisfy ABS in HImode for 20 bit memory +(define_predicate "m32c_20babshi_operand" + (match_operand 0 "memory_operand" "") +{ + HOST_WIDE_INT a = 0, b = 0; + if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF + && far_data_p (XEXP (op, 0)) == 0 + && near_data_p (XEXP (op, 0)) == 0) + return 0; + + if (GET_CODE (op) == MEM + && (GET_CODE (XEXP (op, 0)) == PRE_DEC + || (GET_CODE (XEXP (op, 0)) == POST_INC) + || (GET_CODE (XEXP (op, 0)) == PLUS) + || (GET_CODE (XEXP (op, 0)) == REG))) + return 0; + return 1; +}) + +; TRUE for memory values that satisfy ABS in QImode for 20 bit memory +(define_predicate "m32c_20babsqi_operand" + (and (match_operand 0 "memory_operand" "") + (match_test "m32c_extra_constraint_p (op, 'S', \"Sn\")"))) +; M16C-20bit Access + +; TRUE for memory values that satisfy [A1A0] for 20 bit memory +(define_predicate "m32c_20bA1A0_operand" + (match_operand 0 "memory_operand" "") +{ + if (GET_CODE (op) == MEM + && GET_CODE (XEXP (op, 0)) == REG + && far_data_a1a0 (op) == 1 + && REGNO (XEXP (op, 0)) == A0_REGNO + && (GET_MODE_SIZE (GET_MODE (XEXP (op, 0))) == 3 + || GET_MODE_SIZE (GET_MODE (XEXP (op, 0))) == 4)) + return 1; + return 0; +}) + +; TRUE for memory values that satisfy disp:20[A0] in QImode for 20 bit +; memory +(define_predicate "m32c_20bdisp_operand" + (match_operand 0 "memory_operand" "") +{ + if (GET_CODE (XEXP (op, 0)) == PLUS + && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG + && far_data_p (XEXP (XEXP (op, 0), 1)) == 1 + && GET_CODE (XEXP (XEXP (op, 0), 1)) == SYMBOL_REF + && (INTVAL (XEXP (XEXP (op, 0), 1)) > 0)) + return 1; + return 0; +}) + +; TRUE for memory values that satisfy disp:20[A0] in HImode for 20 bit +; memory +(define_predicate "m32c_20bdisphi_operand" + (match_operand 0 "memory_operand" "") +{ + if (GET_CODE (XEXP (op, 0)) == PLUS + && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG + && (REGNO (XEXP (XEXP (op, 0), 0)) == A0_REGNO + || REGNO (XEXP (XEXP (op, 0), 0)) == A1_REGNO) + && ((GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST + && far_data_p (XEXP (XEXP (XEXP (XEXP (op, 0), 1), 0), 0)) == 1) + || (GET_CODE (XEXP (XEXP (op, 0), 1)) == SYMBOL_REF + && far_data_p (XEXP (XEXP (op, 0), 1)) == 1))) + return 1; + return 0; +}) + +; TRUE for memory values which contains base address in SYMBOL-REF +(define_predicate "sym_operand" + (match_operand 0 "immediate_operand" "") +{ + if (GET_CODE (op) == SYMBOL_REF + && far_data_p (op) == 1) + return 1; + return 0; +}) --- /gcc/config/m32c/t-m32c 2008-01-15 11:37:39.000000000 +0530 +++ /gcc/config/m32c/t-m32c 2008-01-08 17:37:34.000000000 +0530 @@ -65,8 +65,8 @@ m32c-pragma.o: $(srcdir)/config/m32c/m32 # We support four CPU series, but R8C and M16C share one multilib, and # M32C and M32CM share another. -MULTILIB_OPTIONS = mcpu=m32cm -MULTILIB_DIRNAMES = m32cm -MULTILIB_MATCHES = mcpu?m32cm=mcpu?m32c mcpu?r8c=mcpu?m16c +MULTILIB_OPTIONS = mcpu=m16c/mcpu=m32cm +MULTILIB_DIRNAMES = m16c m32cm +MULTILIB_MATCHES = mcpu?m32cm=mcpu?m32c EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o --- /gcc/doc/extend.texi 2008-01-15 11:37:40.000000000 +0530 +++ /gcc/doc/extend.texi 2007-12-24 17:40:44.000000000 +0530 @@ -1854,6 +1854,16 @@ At the end of a function, it will jump t instead of using @code{rts}. The board-specific return routine simulates the @code{rtc}. +On M16C target the @code{far} attribute causes the compiler to +place the variables in different sections as:- +1. non-initialized non-constant data varaibles in ".fbss" section. +2. initialized non-constant data varaibles in ".fdata" section. +On R8C target the @code{far} attribute causes the compiler to +place the constant variables in ".frodata" section. + +The compiler will use the @code{lde} and @code{ste} instructions +to access the data from 20 bit (far)memory address. + @item fastcall @cindex functions that pop the argument stack on the 386 On the Intel 386, the @code{fastcall} attribute causes the compiler to @@ -2151,6 +2161,13 @@ use the normal calling convention based This attribute can be used to cancel the effect of the @option{-mlong-calls} option. +On M16C target the @code{near} attribute causes the compiler to +place the constant variables in ".nrodata" section. By default +".rodata" section will be placed in far memory for m16C target. + +The compiler will use the @code{mov} instructions to access the +data from near memory. + @item nesting @cindex Allow nesting in an interrupt handler on the Blackfin processor. Use this attribute together with @code{interrupt_handler},