Mercurial > hg > CbC > CbC_gcc
comparison gcc/config/iq2000/iq2000.c @ 55:77e2b8dfacca gcc-4.4.5
update it from 4.4.3 to 4.5.0
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 12 Feb 2010 23:39:51 +0900 |
parents | a06113de4d67 |
children | b7f97abdc517 |
comparison
equal
deleted
inserted
replaced
52:c156f1bd5cd9 | 55:77e2b8dfacca |
---|---|
1 /* Subroutines used for code generation on Vitesse IQ2000 processors | 1 /* Subroutines used for code generation on Vitesse IQ2000 processors |
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 | 2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 |
3 Free Software Foundation, Inc. | 3 Free Software Foundation, Inc. |
4 | 4 |
5 This file is part of GCC. | 5 This file is part of GCC. |
6 | 6 |
7 GCC is free software; you can redistribute it and/or modify | 7 GCC is free software; you can redistribute it and/or modify |
87 long fp_sp_offset; /* Offset from new sp to store fp registers. */ | 87 long fp_sp_offset; /* Offset from new sp to store fp registers. */ |
88 int initialized; /* != 0 if frame size already calculated. */ | 88 int initialized; /* != 0 if frame size already calculated. */ |
89 int num_gp; /* Number of gp registers saved. */ | 89 int num_gp; /* Number of gp registers saved. */ |
90 } iq2000_frame_info; | 90 } iq2000_frame_info; |
91 | 91 |
92 struct machine_function GTY(()) | 92 struct GTY(()) machine_function |
93 { | 93 { |
94 /* Current frame information, calculated by compute_frame_size. */ | 94 /* Current frame information, calculated by compute_frame_size. */ |
95 long total_size; /* # bytes that the entire frame takes up. */ | 95 long total_size; /* # bytes that the entire frame takes up. */ |
96 long var_size; /* # bytes that variables take up. */ | 96 long var_size; /* # bytes that variables take up. */ |
97 long args_size; /* # bytes that outgoing arguments take up. */ | 97 long args_size; /* # bytes that outgoing arguments take up. */ |
116 enum processor_type iq2000_tune; | 116 enum processor_type iq2000_tune; |
117 | 117 |
118 /* Which instruction set architecture to use. */ | 118 /* Which instruction set architecture to use. */ |
119 int iq2000_isa; | 119 int iq2000_isa; |
120 | 120 |
121 /* Cached operands, and operator to compare for use in set/branch/trap | |
122 on condition codes. */ | |
123 rtx branch_cmp[2]; | |
124 | |
125 /* What type of branch to use. */ | |
126 enum cmp_type branch_type; | |
127 | |
128 /* Local variables. */ | 121 /* Local variables. */ |
129 | 122 |
130 /* The next branch instruction is a branch likely, not branch normal. */ | 123 /* The next branch instruction is a branch likely, not branch normal. */ |
131 static int iq2000_branch_likely; | 124 static int iq2000_branch_likely; |
132 | 125 |
163 enum machine_mode, tree, int *, | 156 enum machine_mode, tree, int *, |
164 int); | 157 int); |
165 static bool iq2000_rtx_costs (rtx, int, int, int *, bool); | 158 static bool iq2000_rtx_costs (rtx, int, int, int *, bool); |
166 static int iq2000_address_cost (rtx, bool); | 159 static int iq2000_address_cost (rtx, bool); |
167 static section *iq2000_select_section (tree, int, unsigned HOST_WIDE_INT); | 160 static section *iq2000_select_section (tree, int, unsigned HOST_WIDE_INT); |
161 static rtx iq2000_legitimize_address (rtx, rtx, enum machine_mode); | |
168 static bool iq2000_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, | 162 static bool iq2000_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, |
169 const_tree, bool); | 163 const_tree, bool); |
170 static int iq2000_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode, | 164 static int iq2000_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode, |
171 tree, bool); | 165 tree, bool); |
172 static void iq2000_va_start (tree, rtx); | 166 static void iq2000_va_start (tree, rtx); |
167 static bool iq2000_legitimate_address_p (enum machine_mode, rtx, bool); | |
168 static bool iq2000_can_eliminate (const int, const int); | |
169 static void iq2000_asm_trampoline_template (FILE *); | |
170 static void iq2000_trampoline_init (rtx, tree, rtx); | |
171 static rtx iq2000_function_value (const_tree, const_tree, bool); | |
172 static rtx iq2000_libcall_value (enum machine_mode, const_rtx); | |
173 | 173 |
174 #undef TARGET_INIT_BUILTINS | 174 #undef TARGET_INIT_BUILTINS |
175 #define TARGET_INIT_BUILTINS iq2000_init_builtins | 175 #define TARGET_INIT_BUILTINS iq2000_init_builtins |
176 #undef TARGET_EXPAND_BUILTIN | 176 #undef TARGET_EXPAND_BUILTIN |
177 #define TARGET_EXPAND_BUILTIN iq2000_expand_builtin | 177 #define TARGET_EXPAND_BUILTIN iq2000_expand_builtin |
184 #undef TARGET_ADDRESS_COST | 184 #undef TARGET_ADDRESS_COST |
185 #define TARGET_ADDRESS_COST iq2000_address_cost | 185 #define TARGET_ADDRESS_COST iq2000_address_cost |
186 #undef TARGET_ASM_SELECT_SECTION | 186 #undef TARGET_ASM_SELECT_SECTION |
187 #define TARGET_ASM_SELECT_SECTION iq2000_select_section | 187 #define TARGET_ASM_SELECT_SECTION iq2000_select_section |
188 | 188 |
189 #undef TARGET_LEGITIMIZE_ADDRESS | |
190 #define TARGET_LEGITIMIZE_ADDRESS iq2000_legitimize_address | |
191 | |
189 /* The assembler supports switchable .bss sections, but | 192 /* The assembler supports switchable .bss sections, but |
190 iq2000_select_section doesn't yet make use of them. */ | 193 iq2000_select_section doesn't yet make use of them. */ |
191 #undef TARGET_HAVE_SWITCHABLE_BSS_SECTIONS | 194 #undef TARGET_HAVE_SWITCHABLE_BSS_SECTIONS |
192 #define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false | 195 #define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false |
193 | 196 |
194 #undef TARGET_PROMOTE_FUNCTION_ARGS | 197 #undef TARGET_PROMOTE_FUNCTION_MODE |
195 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true | 198 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote |
196 #undef TARGET_PROMOTE_FUNCTION_RETURN | |
197 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true | |
198 #undef TARGET_PROMOTE_PROTOTYPES | 199 #undef TARGET_PROMOTE_PROTOTYPES |
199 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true | 200 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true |
200 | 201 |
202 #undef TARGET_FUNCTION_VALUE | |
203 #define TARGET_FUNCTION_VALUE iq2000_function_value | |
204 #undef TARGET_LIBCALL_VALUE | |
205 #define TARGET_LIBCALL_VALUE iq2000_libcall_value | |
201 #undef TARGET_RETURN_IN_MEMORY | 206 #undef TARGET_RETURN_IN_MEMORY |
202 #define TARGET_RETURN_IN_MEMORY iq2000_return_in_memory | 207 #define TARGET_RETURN_IN_MEMORY iq2000_return_in_memory |
203 #undef TARGET_PASS_BY_REFERENCE | 208 #undef TARGET_PASS_BY_REFERENCE |
204 #define TARGET_PASS_BY_REFERENCE iq2000_pass_by_reference | 209 #define TARGET_PASS_BY_REFERENCE iq2000_pass_by_reference |
205 #undef TARGET_CALLEE_COPIES | 210 #undef TARGET_CALLEE_COPIES |
213 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true | 218 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true |
214 | 219 |
215 #undef TARGET_EXPAND_BUILTIN_VA_START | 220 #undef TARGET_EXPAND_BUILTIN_VA_START |
216 #define TARGET_EXPAND_BUILTIN_VA_START iq2000_va_start | 221 #define TARGET_EXPAND_BUILTIN_VA_START iq2000_va_start |
217 | 222 |
223 #undef TARGET_LEGITIMATE_ADDRESS_P | |
224 #define TARGET_LEGITIMATE_ADDRESS_P iq2000_legitimate_address_p | |
225 | |
226 #undef TARGET_CAN_ELIMINATE | |
227 #define TARGET_CAN_ELIMINATE iq2000_can_eliminate | |
228 | |
229 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE | |
230 #define TARGET_ASM_TRAMPOLINE_TEMPLATE iq2000_asm_trampoline_template | |
231 #undef TARGET_TRAMPOLINE_INIT | |
232 #define TARGET_TRAMPOLINE_INIT iq2000_trampoline_init | |
233 | |
218 struct gcc_target targetm = TARGET_INITIALIZER; | 234 struct gcc_target targetm = TARGET_INITIALIZER; |
219 | 235 |
220 /* Return nonzero if we split the address into high and low parts. */ | 236 /* Return nonzero if we split the address into high and low parts. */ |
221 | 237 |
222 int | 238 int |
250 | 266 |
251 /* Return a nonzero value if XINSN is a legitimate address for a | 267 /* Return a nonzero value if XINSN is a legitimate address for a |
252 memory operand of the indicated MODE. STRICT is nonzero if this | 268 memory operand of the indicated MODE. STRICT is nonzero if this |
253 function is called during reload. */ | 269 function is called during reload. */ |
254 | 270 |
255 int | 271 bool |
256 iq2000_legitimate_address_p (enum machine_mode mode, rtx xinsn, int strict) | 272 iq2000_legitimate_address_p (enum machine_mode mode, rtx xinsn, bool strict) |
257 { | 273 { |
258 if (TARGET_DEBUG_A_MODE) | 274 if (TARGET_DEBUG_A_MODE) |
259 { | 275 { |
260 GO_PRINTF2 ("\n========== GO_IF_LEGITIMATE_ADDRESS, %sstrict\n", | 276 GO_PRINTF2 ("\n========== legitimate_address_p, %sstrict\n", |
261 strict ? "" : "not "); | 277 strict ? "" : "not "); |
262 GO_DEBUG_RTX (xinsn); | 278 GO_DEBUG_RTX (xinsn); |
263 } | 279 } |
264 | 280 |
265 /* Check for constant before stripping off SUBREG, so that we don't | 281 /* Check for constant before stripping off SUBREG, so that we don't |
312 return 1; | 328 return 1; |
313 } | 329 } |
314 } | 330 } |
315 | 331 |
316 if (TARGET_DEBUG_A_MODE) | 332 if (TARGET_DEBUG_A_MODE) |
317 GO_PRINTF ("Not a legitimate address\n"); | 333 GO_PRINTF ("Not a enum machine_mode mode, legitimate address\n"); |
318 | 334 |
319 /* The address was not legitimate. */ | 335 /* The address was not legitimate. */ |
320 return 0; | 336 return 0; |
321 } | 337 } |
322 | 338 |
1004 /* Emit the common code for doing conditional branches. | 1020 /* Emit the common code for doing conditional branches. |
1005 operand[0] is the label to jump to. | 1021 operand[0] is the label to jump to. |
1006 The comparison operands are saved away by cmp{si,di,sf,df}. */ | 1022 The comparison operands are saved away by cmp{si,di,sf,df}. */ |
1007 | 1023 |
1008 void | 1024 void |
1009 gen_conditional_branch (rtx operands[], enum rtx_code test_code) | 1025 gen_conditional_branch (rtx operands[], enum machine_mode mode) |
1010 { | 1026 { |
1011 enum cmp_type type = branch_type; | 1027 enum rtx_code test_code = GET_CODE (operands[0]); |
1012 rtx cmp0 = branch_cmp[0]; | 1028 rtx cmp0 = operands[1]; |
1013 rtx cmp1 = branch_cmp[1]; | 1029 rtx cmp1 = operands[2]; |
1014 enum machine_mode mode; | |
1015 rtx reg; | 1030 rtx reg; |
1016 int invert; | 1031 int invert; |
1017 rtx label1, label2; | 1032 rtx label1, label2; |
1018 | 1033 |
1019 switch (type) | 1034 invert = 0; |
1020 { | 1035 reg = gen_int_relational (test_code, NULL_RTX, cmp0, cmp1, &invert); |
1021 case CMP_SI: | 1036 |
1022 case CMP_DI: | 1037 if (reg) |
1023 mode = type == CMP_SI ? SImode : DImode; | 1038 { |
1024 invert = 0; | |
1025 reg = gen_int_relational (test_code, NULL_RTX, cmp0, cmp1, &invert); | |
1026 | |
1027 if (reg) | |
1028 { | |
1029 cmp0 = reg; | |
1030 cmp1 = const0_rtx; | |
1031 test_code = NE; | |
1032 } | |
1033 else if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0) | |
1034 /* We don't want to build a comparison against a nonzero | |
1035 constant. */ | |
1036 cmp1 = force_reg (mode, cmp1); | |
1037 | |
1038 break; | |
1039 | |
1040 case CMP_SF: | |
1041 case CMP_DF: | |
1042 reg = gen_reg_rtx (CCmode); | |
1043 | |
1044 /* For cmp0 != cmp1, build cmp0 == cmp1, and test for result == 0. */ | |
1045 emit_insn (gen_rtx_SET (VOIDmode, reg, | |
1046 gen_rtx_fmt_ee (test_code == NE ? EQ : test_code, | |
1047 CCmode, cmp0, cmp1))); | |
1048 | |
1049 test_code = test_code == NE ? EQ : NE; | |
1050 mode = CCmode; | |
1051 cmp0 = reg; | 1039 cmp0 = reg; |
1052 cmp1 = const0_rtx; | 1040 cmp1 = const0_rtx; |
1053 invert = 0; | 1041 test_code = NE; |
1054 break; | 1042 } |
1055 | 1043 else if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0) |
1056 default: | 1044 /* We don't want to build a comparison against a nonzero |
1057 abort_with_insn (gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1), | 1045 constant. */ |
1058 "bad test"); | 1046 cmp1 = force_reg (mode, cmp1); |
1059 } | |
1060 | 1047 |
1061 /* Generate the branch. */ | 1048 /* Generate the branch. */ |
1062 label1 = gen_rtx_LABEL_REF (VOIDmode, operands[0]); | 1049 label1 = gen_rtx_LABEL_REF (VOIDmode, operands[3]); |
1063 label2 = pc_rtx; | 1050 label2 = pc_rtx; |
1064 | 1051 |
1065 if (invert) | 1052 if (invert) |
1066 { | 1053 { |
1067 label2 = label1; | 1054 label2 = label1; |
1171 break; | 1158 break; |
1172 | 1159 |
1173 case DImode: | 1160 case DImode: |
1174 cum->gp_reg_found = 1; | 1161 cum->gp_reg_found = 1; |
1175 cum->arg_words += 2; | 1162 cum->arg_words += 2; |
1163 break; | |
1164 | |
1165 case TImode: | |
1166 cum->gp_reg_found = 1; | |
1167 cum->arg_words += 4; | |
1176 break; | 1168 break; |
1177 | 1169 |
1178 case QImode: | 1170 case QImode: |
1179 case HImode: | 1171 case HImode: |
1180 case SImode: | 1172 case SImode: |
1243 break; | 1235 break; |
1244 | 1236 |
1245 case DImode: | 1237 case DImode: |
1246 cum->arg_words += (cum->arg_words & 1); | 1238 cum->arg_words += (cum->arg_words & 1); |
1247 regbase = GP_ARG_FIRST; | 1239 regbase = GP_ARG_FIRST; |
1240 break; | |
1241 | |
1242 case TImode: | |
1243 cum->arg_words += (cum->arg_words & 3); | |
1244 regbase = GP_ARG_FIRST; | |
1245 break; | |
1248 } | 1246 } |
1249 | 1247 |
1250 if (*arg_words >= (unsigned) MAX_ARGS_IN_REGISTERS) | 1248 if (*arg_words >= (unsigned) MAX_ARGS_IN_REGISTERS) |
1251 { | 1249 { |
1252 if (TARGET_DEBUG_D_MODE) | 1250 if (TARGET_DEBUG_D_MODE) |
1695 | 1693 |
1696 /* Ok, we're done. */ | 1694 /* Ok, we're done. */ |
1697 return total_size; | 1695 return total_size; |
1698 } | 1696 } |
1699 | 1697 |
1698 | |
1699 /* We can always eliminate to the frame pointer. We can eliminate to the | |
1700 stack pointer unless a frame pointer is needed. */ | |
1701 | |
1702 bool | |
1703 iq2000_can_eliminate (const int from, const int to) | |
1704 { | |
1705 return (from == RETURN_ADDRESS_POINTER_REGNUM | |
1706 && (! leaf_function_p () | |
1707 || (to == GP_REG_FIRST + 31 && leaf_function_p))) | |
1708 || (from != RETURN_ADDRESS_POINTER_REGNUM | |
1709 && (to == HARD_FRAME_POINTER_REGNUM | |
1710 || (to == STACK_POINTER_REGNUM | |
1711 && ! frame_pointer_needed))); | |
1712 } | |
1713 | |
1700 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame | 1714 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame |
1701 pointer, argument pointer, or return address pointer. TO is either | 1715 pointer, argument pointer, or return address pointer. TO is either |
1702 the stack pointer or hard frame pointer. */ | 1716 the stack pointer or hard frame pointer. */ |
1703 | 1717 |
1704 int | 1718 int |
1875 if (aggregate_value_p (DECL_RESULT (fndecl), fndecl) | 1889 if (aggregate_value_p (DECL_RESULT (fndecl), fndecl) |
1876 && !cfun->returns_pcc_struct | 1890 && !cfun->returns_pcc_struct |
1877 && targetm.calls.struct_value_rtx (TREE_TYPE (fndecl), 1) == 0) | 1891 && targetm.calls.struct_value_rtx (TREE_TYPE (fndecl), 1) == 0) |
1878 { | 1892 { |
1879 tree type = build_pointer_type (fntype); | 1893 tree type = build_pointer_type (fntype); |
1880 tree function_result_decl = build_decl (PARM_DECL, NULL_TREE, type); | 1894 tree function_result_decl = build_decl (BUILTINS_LOCATION, |
1895 PARM_DECL, NULL_TREE, type); | |
1881 | 1896 |
1882 DECL_ARG_TYPE (function_result_decl) = type; | 1897 DECL_ARG_TYPE (function_result_decl) = type; |
1883 TREE_CHAIN (function_result_decl) = fnargs; | 1898 TREE_CHAIN (function_result_decl) = fnargs; |
1884 fnargs = function_result_decl; | 1899 fnargs = function_result_decl; |
1885 } | 1900 } |
2199 } | 2214 } |
2200 } | 2215 } |
2201 /* Return register to use for a function return value with VALTYPE for function | 2216 /* Return register to use for a function return value with VALTYPE for function |
2202 FUNC. */ | 2217 FUNC. */ |
2203 | 2218 |
2204 rtx | 2219 static rtx |
2205 iq2000_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED) | 2220 iq2000_function_value (const_tree valtype, |
2221 const_tree fn_decl_or_type, | |
2222 bool outgoing ATTRIBUTE_UNUSED) | |
2206 { | 2223 { |
2207 int reg = GP_RETURN; | 2224 int reg = GP_RETURN; |
2208 enum machine_mode mode = TYPE_MODE (valtype); | 2225 enum machine_mode mode = TYPE_MODE (valtype); |
2209 int unsignedp = TYPE_UNSIGNED (valtype); | 2226 int unsignedp = TYPE_UNSIGNED (valtype); |
2210 | 2227 tree func = fn_decl_or_type; |
2211 /* Since we define TARGET_PROMOTE_FUNCTION_RETURN that returns true, | 2228 |
2212 we must promote the mode just as PROMOTE_MODE does. */ | 2229 if (fn_decl_or_type |
2213 mode = promote_mode (valtype, mode, &unsignedp, 1); | 2230 && !DECL_P (fn_decl_or_type)) |
2231 fn_decl_or_type = NULL; | |
2232 | |
2233 /* Since we promote return types, we must promote the mode here too. */ | |
2234 mode = promote_function_mode (valtype, mode, &unsignedp, func, 1); | |
2214 | 2235 |
2215 return gen_rtx_REG (mode, reg); | 2236 return gen_rtx_REG (mode, reg); |
2216 } | 2237 } |
2238 | |
2239 /* Worker function for TARGET_LIBCALL_VALUE. */ | |
2240 | |
2241 static rtx | |
2242 iq2000_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) | |
2243 { | |
2244 return gen_rtx_REG (((GET_MODE_CLASS (mode) != MODE_INT | |
2245 || GET_MODE_SIZE (mode) >= 4) | |
2246 ? mode : SImode), | |
2247 GP_RETURN); | |
2248 } | |
2249 | |
2250 /* Worker function for FUNCTION_VALUE_REGNO_P. | |
2251 | |
2252 On the IQ2000, R2 and R3 are the only register thus used. */ | |
2253 | |
2254 bool | |
2255 iq2000_function_value_regno_p (const unsigned int regno) | |
2256 { | |
2257 return (regno == GP_RETURN); | |
2258 } | |
2259 | |
2217 | 2260 |
2218 /* Return true when an argument must be passed by reference. */ | 2261 /* Return true when an argument must be passed by reference. */ |
2219 | 2262 |
2220 static bool | 2263 static bool |
2221 iq2000_pass_by_reference (CUMULATIVE_ARGS *cum, enum machine_mode mode, | 2264 iq2000_pass_by_reference (CUMULATIVE_ARGS *cum, enum machine_mode mode, |
3201 | 3244 |
3202 else | 3245 else |
3203 output_addr_const (file, op); | 3246 output_addr_const (file, op); |
3204 } | 3247 } |
3205 | 3248 |
3249 | |
3250 /* For the IQ2000, transform: | |
3251 | |
3252 memory(X + <large int>) | |
3253 into: | |
3254 Y = <large int> & ~0x7fff; | |
3255 Z = X + Y | |
3256 memory (Z + (<large int> & 0x7fff)); | |
3257 */ | |
3258 | |
3259 rtx | |
3260 iq2000_legitimize_address (rtx xinsn, rtx old_x ATTRIBUTE_UNUSED, | |
3261 enum machine_mode mode) | |
3262 { | |
3263 if (TARGET_DEBUG_B_MODE) | |
3264 { | |
3265 GO_PRINTF ("\n========== LEGITIMIZE_ADDRESS\n"); | |
3266 GO_DEBUG_RTX (xinsn); | |
3267 } | |
3268 | |
3269 if (iq2000_check_split (xinsn, mode)) | |
3270 { | |
3271 return gen_rtx_LO_SUM (Pmode, | |
3272 copy_to_mode_reg (Pmode, | |
3273 gen_rtx_HIGH (Pmode, xinsn)), | |
3274 xinsn); | |
3275 } | |
3276 | |
3277 if (GET_CODE (xinsn) == PLUS) | |
3278 { | |
3279 rtx xplus0 = XEXP (xinsn, 0); | |
3280 rtx xplus1 = XEXP (xinsn, 1); | |
3281 enum rtx_code code0 = GET_CODE (xplus0); | |
3282 enum rtx_code code1 = GET_CODE (xplus1); | |
3283 | |
3284 if (code0 != REG && code1 == REG) | |
3285 { | |
3286 xplus0 = XEXP (xinsn, 1); | |
3287 xplus1 = XEXP (xinsn, 0); | |
3288 code0 = GET_CODE (xplus0); | |
3289 code1 = GET_CODE (xplus1); | |
3290 } | |
3291 | |
3292 if (code0 == REG && REG_MODE_OK_FOR_BASE_P (xplus0, mode) | |
3293 && code1 == CONST_INT && !SMALL_INT (xplus1)) | |
3294 { | |
3295 rtx int_reg = gen_reg_rtx (Pmode); | |
3296 rtx ptr_reg = gen_reg_rtx (Pmode); | |
3297 | |
3298 emit_move_insn (int_reg, | |
3299 GEN_INT (INTVAL (xplus1) & ~ 0x7fff)); | |
3300 | |
3301 emit_insn (gen_rtx_SET (VOIDmode, | |
3302 ptr_reg, | |
3303 gen_rtx_PLUS (Pmode, xplus0, int_reg))); | |
3304 | |
3305 return plus_constant (ptr_reg, INTVAL (xplus1) & 0x7fff); | |
3306 } | |
3307 } | |
3308 | |
3309 if (TARGET_DEBUG_B_MODE) | |
3310 GO_PRINTF ("LEGITIMIZE_ADDRESS could not fix.\n"); | |
3311 | |
3312 return xinsn; | |
3313 } | |
3314 | |
3315 | |
3206 static bool | 3316 static bool |
3207 iq2000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int * total, | 3317 iq2000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int * total, |
3208 bool speed ATTRIBUTE_UNUSED) | 3318 bool speed ATTRIBUTE_UNUSED) |
3209 { | 3319 { |
3210 enum machine_mode mode = GET_MODE (x); | 3320 enum machine_mode mode = GET_MODE (x); |
3340 return false; | 3450 return false; |
3341 } | 3451 } |
3342 return true; | 3452 return true; |
3343 } | 3453 } |
3344 | 3454 |
3455 /* Worker for TARGET_ASM_TRAMPOLINE_TEMPLATE. */ | |
3456 | |
3457 static void | |
3458 iq2000_asm_trampoline_template (FILE *f) | |
3459 { | |
3460 fprintf (f, "\t.word\t0x03e00821\t\t# move $1,$31\n"); | |
3461 fprintf (f, "\t.word\t0x04110001\t\t# bgezal $0,.+8\n"); | |
3462 fprintf (f, "\t.word\t0x00000000\t\t# nop\n"); | |
3463 if (Pmode == DImode) | |
3464 { | |
3465 fprintf (f, "\t.word\t0xdfe30014\t\t# ld $3,20($31)\n"); | |
3466 fprintf (f, "\t.word\t0xdfe2001c\t\t# ld $2,28($31)\n"); | |
3467 } | |
3468 else | |
3469 { | |
3470 fprintf (f, "\t.word\t0x8fe30014\t\t# lw $3,20($31)\n"); | |
3471 fprintf (f, "\t.word\t0x8fe20018\t\t# lw $2,24($31)\n"); | |
3472 } | |
3473 fprintf (f, "\t.word\t0x0060c821\t\t# move $25,$3 (abicalls)\n"); | |
3474 fprintf (f, "\t.word\t0x00600008\t\t# jr $3\n"); | |
3475 fprintf (f, "\t.word\t0x0020f821\t\t# move $31,$1\n"); | |
3476 fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); | |
3477 fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); | |
3478 } | |
3479 | |
3480 /* Worker for TARGET_TRAMPOLINE_INIT. */ | |
3481 | |
3482 static void | |
3483 iq2000_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) | |
3484 { | |
3485 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); | |
3486 rtx mem; | |
3487 | |
3488 emit_block_move (m_tramp, assemble_trampoline_template (), | |
3489 GEN_INT (TRAMPOLINE_CODE_SIZE), BLOCK_OP_NORMAL); | |
3490 | |
3491 mem = adjust_address (m_tramp, Pmode, TRAMPOLINE_CODE_SIZE); | |
3492 emit_move_insn (mem, fnaddr); | |
3493 mem = adjust_address (m_tramp, Pmode, | |
3494 TRAMPOLINE_CODE_SIZE + GET_MODE_SIZE (Pmode)); | |
3495 emit_move_insn (mem, chain_value); | |
3496 } | |
3497 | |
3345 #include "gt-iq2000.h" | 3498 #include "gt-iq2000.h" |