1 1.1 mrg /* Subroutines used for code generation on the Tilera TILE-Gx. 2 1.1 mrg Copyright (C) 2011-2022 Free Software Foundation, Inc. 3 1.1 mrg Contributed by Walter Lee (walt (at) tilera.com) 4 1.1 mrg 5 1.1 mrg This file is part of GCC. 6 1.1 mrg 7 1.1 mrg GCC is free software; you can redistribute it and/or modify it 8 1.1 mrg under the terms of the GNU General Public License as published 9 1.1 mrg by the Free Software Foundation; either version 3, or (at your 10 1.1 mrg option) any later version. 11 1.1 mrg 12 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT 13 1.1 mrg ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 1.1 mrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 1.1 mrg License for more details. 16 1.1 mrg 17 1.1 mrg You should have received a copy of the GNU General Public License 18 1.1 mrg along with GCC; see the file COPYING3. If not see 19 1.1 mrg <http://www.gnu.org/licenses/>. */ 20 1.1 mrg 21 1.1 mrg #define IN_TARGET_CODE 1 22 1.1 mrg 23 1.1 mrg #include "config.h" 24 1.1 mrg #include "system.h" 25 1.1 mrg #include "coretypes.h" 26 1.1 mrg #include "memmodel.h" 27 1.1 mrg #include "backend.h" 28 1.1 mrg #include "target.h" 29 1.1 mrg #include "rtl.h" 30 1.1 mrg #include "tree.h" 31 1.1 mrg #include "gimple.h" 32 1.1 mrg #include "df.h" 33 1.1 mrg #include "tm_p.h" 34 1.1 mrg #include "stringpool.h" 35 1.1 mrg #include "attribs.h" 36 1.1 mrg #include "expmed.h" 37 1.1 mrg #include "optabs.h" 38 1.1 mrg #include "regs.h" 39 1.1 mrg #include "emit-rtl.h" 40 1.1 mrg #include "recog.h" 41 1.1 mrg #include "diagnostic.h" 42 1.1 mrg #include "output.h" 43 1.1 mrg #include "insn-attr.h" 44 1.1 mrg #include "alias.h" 45 1.1 mrg #include "explow.h" 46 1.1 mrg #include "calls.h" 47 1.1 mrg #include "varasm.h" 48 1.1 mrg #include "expr.h" 49 1.1 mrg #include "langhooks.h" 50 1.1 mrg #include "cfgrtl.h" 51 1.1 mrg #include "tm-constrs.h" 52 1.1 mrg #include "dwarf2.h" 53 1.1 mrg #include "fold-const.h" 54 1.1 mrg #include "stor-layout.h" 55 1.1 mrg #include "gimplify.h" 56 1.1 mrg #include "tilegx-builtins.h" 57 1.1 mrg #include "tilegx-multiply.h" 58 1.1 mrg #include "builtins.h" 59 1.1 mrg #include "opts.h" 60 1.1 mrg 61 1.1 mrg /* This file should be included last. */ 62 1.1 mrg #include "target-def.h" 63 1.1 mrg 64 1.1 mrg /* SYMBOL_REF for GOT */ 65 1.1 mrg static GTY(()) rtx g_got_symbol = NULL; 66 1.1 mrg 67 1.1 mrg /* Report whether we're printing out the first address fragment of a 68 1.1 mrg POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to 69 1.1 mrg TARGET_PRINT_OPERAND_ADDRESS. */ 70 1.1 mrg static bool output_memory_autoinc_first; 71 1.1 mrg 72 1.1 mrg 73 1.1 mrg 75 1.1 mrg /* Option handling */ 76 1.1 mrg 77 1.1 mrg /* Implement TARGET_OPTION_OVERRIDE. */ 78 1.1 mrg static void 79 1.1 mrg tilegx_option_override (void) 80 1.1 mrg { 81 1.1 mrg if (OPTION_SET_P (tilegx_cmodel)) 82 1.1 mrg { 83 1.1 mrg switch (tilegx_cmodel) 84 1.1 mrg { 85 1.1 mrg case CM_SMALL: 86 1.1 mrg case CM_SMALL_PIC: 87 1.1 mrg if (flag_pic) 88 1.1 mrg tilegx_cmodel = CM_SMALL_PIC; 89 1.1 mrg break; 90 1.1 mrg 91 1.1 mrg case CM_LARGE: 92 1.1 mrg case CM_LARGE_PIC: 93 1.1 mrg if (flag_pic) 94 1.1 mrg tilegx_cmodel = CM_LARGE_PIC; 95 1.1 mrg break; 96 1.1 mrg 97 1.1 mrg default: 98 1.1 mrg gcc_unreachable (); 99 1.1 mrg } 100 1.1 mrg } 101 1.1 mrg else 102 1.1 mrg tilegx_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL; 103 1.1 mrg 104 1.1 mrg /* When modulo scheduling is enabled, we still rely on regular 105 1.1 mrg scheduler for bundling. */ 106 1.1 mrg if (flag_modulo_sched) 107 1.1 mrg flag_resched_modulo_sched = 1; 108 1.1 mrg } 109 1.1 mrg 110 1.1 mrg 112 1.1 mrg 113 1.1 mrg /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */ 114 1.1 mrg static bool 115 1.1 mrg tilegx_scalar_mode_supported_p (scalar_mode mode) 116 1.1 mrg { 117 1.1 mrg switch (mode) 118 1.1 mrg { 119 1.1 mrg case E_QImode: 120 1.1 mrg case E_HImode: 121 1.1 mrg case E_SImode: 122 1.1 mrg case E_DImode: 123 1.1 mrg case E_TImode: 124 1.1 mrg return true; 125 1.1 mrg 126 1.1 mrg case E_SFmode: 127 1.1 mrg case E_DFmode: 128 1.1 mrg return true; 129 1.1 mrg 130 1.1 mrg default: 131 1.1 mrg return false; 132 1.1 mrg } 133 1.1 mrg } 134 1.1 mrg 135 1.1 mrg 136 1.1 mrg /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */ 137 1.1 mrg static bool 138 1.1 mrg tilegx_vector_mode_supported_p (machine_mode mode) 139 1.1 mrg { 140 1.1 mrg return mode == V8QImode || mode == V4HImode || mode == V2SImode; 141 1.1 mrg } 142 1.1 mrg 143 1.1 mrg 144 1.1 mrg /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */ 145 1.1 mrg static bool 146 1.1 mrg tilegx_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, 147 1.1 mrg rtx x ATTRIBUTE_UNUSED) 148 1.1 mrg { 149 1.1 mrg return true; 150 1.1 mrg } 151 1.1 mrg 152 1.1 mrg 153 1.1 mrg /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */ 154 1.1 mrg static bool 155 1.1 mrg tilegx_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) 156 1.1 mrg { 157 1.1 mrg return (tilegx_cmodel != CM_LARGE && tilegx_cmodel != CM_LARGE_PIC 158 1.1 mrg && (decl != NULL)); 159 1.1 mrg } 160 1.1 mrg 161 1.1 mrg 162 1.1 mrg /* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are 163 1.1 mrg passed by reference. */ 164 1.1 mrg static bool 165 1.1 mrg tilegx_pass_by_reference (cumulative_args_t, const function_arg_info &arg) 166 1.1 mrg { 167 1.1 mrg return (arg.type 168 1.1 mrg && TYPE_SIZE (arg.type) 169 1.1 mrg && TREE_CODE (TYPE_SIZE (arg.type)) != INTEGER_CST); 170 1.1 mrg } 171 1.1 mrg 172 1.1 mrg 173 1.1 mrg /* Implement TARGET_RETURN_IN_MSB. We return a value in the most 174 1.1 mrg significant part of a register if: 175 1.1 mrg - the target is big-endian; and 176 1.1 mrg - the value has an aggregate type (e.g., structure or union). */ 177 1.1 mrg static bool 178 1.1 mrg tilegx_return_in_msb (const_tree valtype) 179 1.1 mrg { 180 1.1 mrg return (TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (valtype)); 181 1.1 mrg } 182 1.1 mrg 183 1.1 mrg 184 1.1 mrg /* Implement TARGET_RETURN_IN_MEMORY. */ 185 1.1 mrg static bool 186 1.1 mrg tilegx_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) 187 1.1 mrg { 188 1.1 mrg return !IN_RANGE (int_size_in_bytes (type), 189 1.1 mrg 0, TILEGX_NUM_RETURN_REGS * UNITS_PER_WORD); 190 1.1 mrg } 191 1.1 mrg 192 1.1 mrg 193 1.1 mrg /* Implement TARGET_MODE_REP_EXTENDED. */ 194 1.1 mrg static int 195 1.1 mrg tilegx_mode_rep_extended (scalar_int_mode mode, scalar_int_mode mode_rep) 196 1.1 mrg { 197 1.1 mrg /* SImode register values are sign-extended to DImode. */ 198 1.1 mrg if (mode == SImode && mode_rep == DImode) 199 1.1 mrg return SIGN_EXTEND; 200 1.1 mrg 201 1.1 mrg return UNKNOWN; 202 1.1 mrg } 203 1.1 mrg 204 1.1 mrg 205 1.1 mrg /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */ 206 1.1 mrg static unsigned int 207 1.1 mrg tilegx_function_arg_boundary (machine_mode mode, const_tree type) 208 1.1 mrg { 209 1.1 mrg unsigned int alignment; 210 1.1 mrg 211 1.1 mrg alignment = type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode); 212 1.1 mrg if (alignment < PARM_BOUNDARY) 213 1.1 mrg alignment = PARM_BOUNDARY; 214 1.1 mrg if (alignment > STACK_BOUNDARY) 215 1.1 mrg alignment = STACK_BOUNDARY; 216 1.1 mrg return alignment; 217 1.1 mrg } 218 1.1 mrg 219 1.1 mrg 220 1.1 mrg /* Implement TARGET_FUNCTION_ARG. */ 221 1.1 mrg static rtx 222 1.1 mrg tilegx_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) 223 1.1 mrg { 224 1.1 mrg CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v); 225 1.1 mrg int byte_size = arg.promoted_size_in_bytes (); 226 1.1 mrg bool doubleword_aligned_p; 227 1.1 mrg 228 1.1 mrg if (cum >= TILEGX_NUM_ARG_REGS) 229 1.1 mrg return NULL_RTX; 230 1.1 mrg 231 1.1 mrg /* See whether the argument has doubleword alignment. */ 232 1.1 mrg doubleword_aligned_p = 233 1.1 mrg tilegx_function_arg_boundary (arg.mode, arg.type) > BITS_PER_WORD; 234 1.1 mrg 235 1.1 mrg if (doubleword_aligned_p) 236 1.1 mrg cum += cum & 1; 237 1.1 mrg 238 1.1 mrg /* The ABI does not allow parameters to be passed partially in reg 239 1.1 mrg and partially in stack. */ 240 1.1 mrg if ((cum + (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) 241 1.1 mrg > TILEGX_NUM_ARG_REGS) 242 1.1 mrg return NULL_RTX; 243 1.1 mrg 244 1.1 mrg return gen_rtx_REG (arg.mode, cum); 245 1.1 mrg } 246 1.1 mrg 247 1.1 mrg 248 1.1 mrg /* Implement TARGET_FUNCTION_ARG_ADVANCE. */ 249 1.1 mrg static void 250 1.1 mrg tilegx_function_arg_advance (cumulative_args_t cum_v, 251 1.1 mrg const function_arg_info &arg) 252 1.1 mrg { 253 1.1 mrg CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); 254 1.1 mrg 255 1.1 mrg int byte_size = arg.promoted_size_in_bytes (); 256 1.1 mrg int word_size = (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; 257 1.1 mrg bool doubleword_aligned_p; 258 1.1 mrg 259 1.1 mrg /* See whether the argument has doubleword alignment. */ 260 1.1 mrg doubleword_aligned_p = 261 1.1 mrg tilegx_function_arg_boundary (arg.mode, arg.type) > BITS_PER_WORD; 262 1.1 mrg 263 1.1 mrg if (doubleword_aligned_p) 264 1.1 mrg *cum += *cum & 1; 265 1.1 mrg 266 1.1 mrg /* If the current argument does not fit in the pretend_args space, 267 1.1 mrg skip over it. */ 268 1.1 mrg if (*cum < TILEGX_NUM_ARG_REGS 269 1.1 mrg && *cum + word_size > TILEGX_NUM_ARG_REGS) 270 1.1 mrg *cum = TILEGX_NUM_ARG_REGS; 271 1.1 mrg 272 1.1 mrg *cum += word_size; 273 1.1 mrg } 274 1.1 mrg 275 1.1 mrg 276 1.1 mrg /* Implement TARGET_FUNCTION_VALUE. */ 277 1.1 mrg static rtx 278 1.1 mrg tilegx_function_value (const_tree valtype, const_tree fn_decl_or_type, 279 1.1 mrg bool outgoing ATTRIBUTE_UNUSED) 280 1.1 mrg { 281 1.1 mrg machine_mode mode; 282 1.1 mrg int unsigned_p; 283 1.1 mrg 284 1.1 mrg mode = TYPE_MODE (valtype); 285 1.1 mrg unsigned_p = TYPE_UNSIGNED (valtype); 286 1.1 mrg 287 1.1 mrg mode = promote_function_mode (valtype, mode, &unsigned_p, 288 1.1 mrg fn_decl_or_type, 1); 289 1.1 mrg 290 1.1 mrg return gen_rtx_REG (mode, 0); 291 1.1 mrg } 292 1.1 mrg 293 1.1 mrg 294 1.1 mrg /* Implement TARGET_LIBCALL_VALUE. */ 295 1.1 mrg static rtx 296 1.1 mrg tilegx_libcall_value (machine_mode mode, 297 1.1 mrg const_rtx fun ATTRIBUTE_UNUSED) 298 1.1 mrg { 299 1.1 mrg return gen_rtx_REG (mode, 0); 300 1.1 mrg } 301 1.1 mrg 302 1.1 mrg 303 1.1 mrg /* Implement FUNCTION_VALUE_REGNO_P. */ 304 1.1 mrg static bool 305 1.1 mrg tilegx_function_value_regno_p (const unsigned int regno) 306 1.1 mrg { 307 1.1 mrg return regno < TILEGX_NUM_RETURN_REGS; 308 1.1 mrg } 309 1.1 mrg 310 1.1 mrg 311 1.1 mrg /* Implement TARGET_BUILD_BUILTIN_VA_LIST. */ 312 1.1 mrg static tree 313 1.1 mrg tilegx_build_builtin_va_list (void) 314 1.1 mrg { 315 1.1 mrg tree f_args, f_skip, record, type_decl; 316 1.1 mrg bool owp; 317 1.1 mrg 318 1.1 mrg record = lang_hooks.types.make_type (RECORD_TYPE); 319 1.1 mrg 320 1.1 mrg type_decl = build_decl (BUILTINS_LOCATION, TYPE_DECL, 321 1.1 mrg get_identifier ("__va_list_tag"), record); 322 1.1 mrg 323 1.1 mrg f_args = build_decl (BUILTINS_LOCATION, FIELD_DECL, 324 1.1 mrg get_identifier ("__args"), ptr_type_node); 325 1.1 mrg f_skip = build_decl (BUILTINS_LOCATION, FIELD_DECL, 326 1.1 mrg get_identifier ("__skip"), ptr_type_node); 327 1.1 mrg 328 1.1 mrg DECL_FIELD_CONTEXT (f_args) = record; 329 1.1 mrg 330 1.1 mrg DECL_FIELD_CONTEXT (f_skip) = record; 331 1.1 mrg 332 1.1 mrg TREE_CHAIN (record) = type_decl; 333 1.1 mrg TYPE_NAME (record) = type_decl; 334 1.1 mrg TYPE_FIELDS (record) = f_args; 335 1.1 mrg TREE_CHAIN (f_args) = f_skip; 336 1.1 mrg 337 1.1 mrg /* We know this is being padded and we want it too. It is an 338 1.1 mrg internal type so hide the warnings from the user. */ 339 1.1 mrg owp = warn_padded; 340 1.1 mrg warn_padded = false; 341 1.1 mrg 342 1.1 mrg layout_type (record); 343 1.1 mrg 344 1.1 mrg warn_padded = owp; 345 1.1 mrg 346 1.1 mrg /* The correct type is an array type of one element. */ 347 1.1 mrg return record; 348 1.1 mrg } 349 1.1 mrg 350 1.1 mrg 351 1.1 mrg /* Implement TARGET_EXPAND_BUILTIN_VA_START. */ 352 1.1 mrg static void 353 1.1 mrg tilegx_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) 354 1.1 mrg { 355 1.1 mrg tree f_args, f_skip; 356 1.1 mrg tree args, skip, t; 357 1.1 mrg 358 1.1 mrg f_args = TYPE_FIELDS (TREE_TYPE (valist)); 359 1.1 mrg f_skip = TREE_CHAIN (f_args); 360 1.1 mrg 361 1.1 mrg args = 362 1.1 mrg build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE); 363 1.1 mrg skip = 364 1.1 mrg build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE); 365 1.1 mrg 366 1.1 mrg /* Find the __args area. */ 367 1.1 mrg t = make_tree (TREE_TYPE (args), virtual_incoming_args_rtx); 368 1.1 mrg t = fold_build_pointer_plus_hwi (t, 369 1.1 mrg UNITS_PER_WORD * 370 1.1 mrg (crtl->args.info - TILEGX_NUM_ARG_REGS)); 371 1.1 mrg 372 1.1 mrg if (crtl->args.pretend_args_size > 0) 373 1.1 mrg t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET); 374 1.1 mrg 375 1.1 mrg t = build2 (MODIFY_EXPR, TREE_TYPE (args), args, t); 376 1.1 mrg TREE_SIDE_EFFECTS (t) = 1; 377 1.1 mrg expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); 378 1.1 mrg 379 1.1 mrg /* Find the __skip area. */ 380 1.1 mrg t = make_tree (TREE_TYPE (skip), virtual_incoming_args_rtx); 381 1.1 mrg t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET); 382 1.1 mrg t = build2 (MODIFY_EXPR, TREE_TYPE (skip), skip, t); 383 1.1 mrg TREE_SIDE_EFFECTS (t) = 1; 384 1.1 mrg expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); 385 1.1 mrg } 386 1.1 mrg 387 1.1 mrg 388 1.1 mrg /* Implement TARGET_SETUP_INCOMING_VARARGS. */ 389 1.1 mrg static void 390 1.1 mrg tilegx_setup_incoming_varargs (cumulative_args_t cum, 391 1.1 mrg const function_arg_info &arg, 392 1.1 mrg int *pretend_args, int no_rtl) 393 1.1 mrg { 394 1.1 mrg CUMULATIVE_ARGS local_cum = *get_cumulative_args (cum); 395 1.1 mrg int first_reg; 396 1.1 mrg 397 1.1 mrg /* The caller has advanced CUM up to, but not beyond, the last named 398 1.1 mrg argument. Advance a local copy of CUM past the last "real" named 399 1.1 mrg argument, to find out how many registers are left over. */ 400 1.1 mrg targetm.calls.function_arg_advance (pack_cumulative_args (&local_cum), arg); 401 1.1 mrg first_reg = local_cum; 402 1.1 mrg 403 1.1 mrg if (local_cum < TILEGX_NUM_ARG_REGS) 404 1.1 mrg { 405 1.1 mrg *pretend_args = UNITS_PER_WORD * (TILEGX_NUM_ARG_REGS - first_reg); 406 1.1 mrg 407 1.1 mrg if (!no_rtl) 408 1.1 mrg { 409 1.1 mrg alias_set_type set = get_varargs_alias_set (); 410 1.1 mrg rtx tmp = 411 1.1 mrg gen_rtx_MEM (BLKmode, plus_constant (Pmode, 412 1.1 mrg virtual_incoming_args_rtx, 413 1.1 mrg -STACK_POINTER_OFFSET - 414 1.1 mrg UNITS_PER_WORD * 415 1.1 mrg (TILEGX_NUM_ARG_REGS - 416 1.1 mrg first_reg))); 417 1.1 mrg MEM_NOTRAP_P (tmp) = 1; 418 1.1 mrg set_mem_alias_set (tmp, set); 419 1.1 mrg move_block_from_reg (first_reg, tmp, 420 1.1 mrg TILEGX_NUM_ARG_REGS - first_reg); 421 1.1 mrg } 422 1.1 mrg } 423 1.1 mrg else 424 1.1 mrg *pretend_args = 0; 425 1.1 mrg } 426 1.1 mrg 427 1.1 mrg 428 1.1 mrg /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating 429 1.1 mrg the va_list structure VALIST as required to retrieve an argument of 430 1.1 mrg type TYPE, and returning that argument. 431 1.1 mrg 432 1.1 mrg ret = va_arg(VALIST, TYPE); 433 1.1 mrg 434 1.1 mrg generates code equivalent to: 435 1.1 mrg 436 1.1 mrg paddedsize = (sizeof(TYPE) + 7) & -8; 437 1.1 mrg if ( (VALIST.__args + paddedsize > VALIST.__skip) 438 1.1 mrg & (VALIST.__args <= VALIST.__skip)) 439 1.1 mrg addr = VALIST.__skip + STACK_POINTER_OFFSET; 440 1.1 mrg else 441 1.1 mrg addr = VALIST.__args; 442 1.1 mrg VALIST.__args = addr + paddedsize; 443 1.1 mrg if (BYTES_BIG_ENDIAN) 444 1.1 mrg ret = *(TYPE *)(addr + paddedsize - sizeof(TYPE)); 445 1.1 mrg else 446 1.1 mrg ret = *(TYPE *)addr; 447 1.1 mrg */ 448 1.1 mrg static tree 449 1.1 mrg tilegx_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, 450 1.1 mrg gimple_seq *post_p ATTRIBUTE_UNUSED) 451 1.1 mrg { 452 1.1 mrg tree f_args, f_skip; 453 1.1 mrg tree args, skip; 454 1.1 mrg HOST_WIDE_INT size, rsize; 455 1.1 mrg tree addr, tmp; 456 1.1 mrg bool pass_by_reference_p; 457 1.1 mrg 458 1.1 mrg f_args = TYPE_FIELDS (va_list_type_node); 459 1.1 mrg f_skip = TREE_CHAIN (f_args); 460 1.1 mrg 461 1.1 mrg args = 462 1.1 mrg build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE); 463 1.1 mrg skip = 464 1.1 mrg build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE); 465 1.1 mrg 466 1.1 mrg addr = create_tmp_var (ptr_type_node, "va_arg"); 467 1.1 mrg 468 1.1 mrg /* If an object is dynamically sized, a pointer to it is passed 469 1.1 mrg instead of the object itself. */ 470 1.1 mrg pass_by_reference_p = pass_va_arg_by_reference (type); 471 1.1 mrg 472 1.1 mrg if (pass_by_reference_p) 473 1.1 mrg type = build_pointer_type (type); 474 1.1 mrg 475 1.1 mrg size = int_size_in_bytes (type); 476 1.1 mrg rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD; 477 1.1 mrg 478 1.1 mrg /* If the alignment of the type is greater than the default for a 479 1.1 mrg parameter, align to the STACK_BOUNDARY. */ 480 1.1 mrg if (TYPE_ALIGN (type) > PARM_BOUNDARY) 481 1.1 mrg { 482 1.1 mrg /* Assert the only case we generate code for: when 483 1.1 mrg stack boundary = 2 * parm boundary. */ 484 1.1 mrg gcc_assert (STACK_BOUNDARY == PARM_BOUNDARY * 2); 485 1.1 mrg 486 1.1 mrg tmp = build2 (BIT_AND_EXPR, sizetype, 487 1.1 mrg fold_convert (sizetype, unshare_expr (args)), 488 1.1 mrg size_int (PARM_BOUNDARY / 8)); 489 1.1 mrg tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node, 490 1.1 mrg unshare_expr (args), tmp); 491 1.1 mrg 492 1.1 mrg gimplify_assign (unshare_expr (args), tmp, pre_p); 493 1.1 mrg } 494 1.1 mrg 495 1.1 mrg /* Build conditional expression to calculate addr. The expression 496 1.1 mrg will be gimplified later. */ 497 1.1 mrg tmp = fold_build_pointer_plus_hwi (unshare_expr (args), rsize); 498 1.1 mrg tmp = build2 (TRUTH_AND_EXPR, boolean_type_node, 499 1.1 mrg build2 (GT_EXPR, boolean_type_node, tmp, unshare_expr (skip)), 500 1.1 mrg build2 (LE_EXPR, boolean_type_node, unshare_expr (args), 501 1.1 mrg unshare_expr (skip))); 502 1.1 mrg 503 1.1 mrg tmp = build3 (COND_EXPR, ptr_type_node, tmp, 504 1.1 mrg build2 (POINTER_PLUS_EXPR, ptr_type_node, unshare_expr (skip), 505 1.1 mrg size_int (STACK_POINTER_OFFSET)), 506 1.1 mrg unshare_expr (args)); 507 1.1 mrg 508 1.1 mrg /* Adjust the address of va_arg if it is in big endian mode. */ 509 1.1 mrg if (BYTES_BIG_ENDIAN && rsize > size) 510 1.1 mrg tmp = fold_build_pointer_plus_hwi (tmp, rsize - size); 511 1.1 mrg gimplify_assign (addr, tmp, pre_p); 512 1.1 mrg 513 1.1 mrg /* Update VALIST.__args. */ 514 1.1 mrg 515 1.1 mrg if (BYTES_BIG_ENDIAN && rsize > size) 516 1.1 mrg tmp = fold_build_pointer_plus_hwi (addr, size); 517 1.1 mrg else 518 1.1 mrg tmp = fold_build_pointer_plus_hwi (addr, rsize); 519 1.1 mrg gimplify_assign (unshare_expr (args), tmp, pre_p); 520 1.1 mrg 521 1.1 mrg addr = fold_convert (build_pointer_type (type), addr); 522 1.1 mrg 523 1.1 mrg if (pass_by_reference_p) 524 1.1 mrg addr = build_va_arg_indirect_ref (addr); 525 1.1 mrg 526 1.1 mrg return build_va_arg_indirect_ref (addr); 527 1.1 mrg } 528 1.1 mrg 529 1.1 mrg 531 1.1 mrg 532 1.1 mrg /* Implement TARGET_RTX_COSTS. */ 533 1.1 mrg static bool 534 1.1 mrg tilegx_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno, 535 1.1 mrg int *total, bool speed) 536 1.1 mrg { 537 1.1 mrg int code = GET_CODE (x); 538 1.1 mrg 539 1.1 mrg switch (code) 540 1.1 mrg { 541 1.1 mrg case CONST_INT: 542 1.1 mrg /* If this is an 8-bit constant, return zero since it can be 543 1.1 mrg used nearly anywhere with no cost. If it is a valid operand 544 1.1 mrg for an ADD or AND, likewise return 0 if we know it will be 545 1.1 mrg used in that context. Otherwise, return 2 since it might be 546 1.1 mrg used there later. All other constants take at least two 547 1.1 mrg insns. */ 548 1.1 mrg if (satisfies_constraint_I (x)) 549 1.1 mrg { 550 1.1 mrg *total = 0; 551 1.1 mrg return true; 552 1.1 mrg } 553 1.1 mrg else if (outer_code == PLUS && add_operand (x, VOIDmode)) 554 1.1 mrg { 555 1.1 mrg /* Slightly penalize large constants even though we can add 556 1.1 mrg them in one instruction, because it forces the use of 557 1.1 mrg 2-wide bundling mode. */ 558 1.1 mrg *total = 1; 559 1.1 mrg return true; 560 1.1 mrg } 561 1.1 mrg else if (move_operand (x, SImode)) 562 1.1 mrg { 563 1.1 mrg /* We can materialize in one move. */ 564 1.1 mrg *total = COSTS_N_INSNS (1); 565 1.1 mrg return true; 566 1.1 mrg } 567 1.1 mrg else 568 1.1 mrg { 569 1.1 mrg /* We can materialize in two moves. */ 570 1.1 mrg *total = COSTS_N_INSNS (2); 571 1.1 mrg return true; 572 1.1 mrg } 573 1.1 mrg 574 1.1 mrg return false; 575 1.1 mrg 576 1.1 mrg case CONST: 577 1.1 mrg case LABEL_REF: 578 1.1 mrg case SYMBOL_REF: 579 1.1 mrg *total = COSTS_N_INSNS (2); 580 1.1 mrg return true; 581 1.1 mrg 582 1.1 mrg case CONST_DOUBLE: 583 1.1 mrg *total = COSTS_N_INSNS (4); 584 1.1 mrg return true; 585 1.1 mrg 586 1.1 mrg case HIGH: 587 1.1 mrg *total = 0; 588 1.1 mrg return true; 589 1.1 mrg 590 1.1 mrg case MEM: 591 1.1 mrg /* If outer-code was a sign or zero extension, a cost of 592 1.1 mrg COSTS_N_INSNS (1) was already added in, so account for 593 1.1 mrg that. */ 594 1.1 mrg if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND) 595 1.1 mrg *total = COSTS_N_INSNS (1); 596 1.1 mrg else 597 1.1 mrg *total = COSTS_N_INSNS (2); 598 1.1 mrg return true; 599 1.1 mrg 600 1.1 mrg case PLUS: 601 1.1 mrg /* Convey that shl[123]add are efficient. */ 602 1.1 mrg if (GET_CODE (XEXP (x, 0)) == MULT 603 1.1 mrg && cint_248_operand (XEXP (XEXP (x, 0), 1), VOIDmode)) 604 1.1 mrg { 605 1.1 mrg *total = (rtx_cost (XEXP (XEXP (x, 0), 0), mode, 606 1.1 mrg (enum rtx_code) outer_code, opno, speed) 607 1.1 mrg + rtx_cost (XEXP (x, 1), mode, 608 1.1 mrg (enum rtx_code) outer_code, opno, speed) 609 1.1 mrg + COSTS_N_INSNS (1)); 610 1.1 mrg return true; 611 1.1 mrg } 612 1.1 mrg return false; 613 1.1 mrg 614 1.1 mrg case MULT: 615 1.1 mrg *total = COSTS_N_INSNS (2); 616 1.1 mrg return false; 617 1.1 mrg 618 1.1 mrg case DIV: 619 1.1 mrg case UDIV: 620 1.1 mrg case MOD: 621 1.1 mrg case UMOD: 622 1.1 mrg /* These are handled by software and are very expensive. */ 623 1.1 mrg *total = COSTS_N_INSNS (100); 624 1.1 mrg return false; 625 1.1 mrg 626 1.1 mrg case UNSPEC: 627 1.1 mrg case UNSPEC_VOLATILE: 628 1.1 mrg { 629 1.1 mrg int num = XINT (x, 1); 630 1.1 mrg 631 1.1 mrg if (num <= TILEGX_LAST_LATENCY_1_INSN) 632 1.1 mrg *total = COSTS_N_INSNS (1); 633 1.1 mrg else if (num <= TILEGX_LAST_LATENCY_2_INSN) 634 1.1 mrg *total = COSTS_N_INSNS (2); 635 1.1 mrg else if (num > TILEGX_LAST_LATENCY_INSN) 636 1.1 mrg { 637 1.1 mrg if (num == UNSPEC_NON_TEMPORAL) 638 1.1 mrg { 639 1.1 mrg /* These are basically loads. */ 640 1.1 mrg if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND) 641 1.1 mrg *total = COSTS_N_INSNS (1); 642 1.1 mrg else 643 1.1 mrg *total = COSTS_N_INSNS (2); 644 1.1 mrg } 645 1.1 mrg else 646 1.1 mrg { 647 1.1 mrg if (outer_code == PLUS) 648 1.1 mrg *total = 0; 649 1.1 mrg else 650 1.1 mrg *total = COSTS_N_INSNS (1); 651 1.1 mrg } 652 1.1 mrg } 653 1.1 mrg else 654 1.1 mrg { 655 1.1 mrg switch (num) 656 1.1 mrg { 657 1.1 mrg case UNSPEC_BLOCKAGE: 658 1.1 mrg case UNSPEC_NETWORK_BARRIER: 659 1.1 mrg case UNSPEC_ATOMIC: 660 1.1 mrg *total = 0; 661 1.1 mrg break; 662 1.1 mrg 663 1.1 mrg case UNSPEC_LNK_AND_LABEL: 664 1.1 mrg case UNSPEC_MF: 665 1.1 mrg case UNSPEC_MOV_PCREL_STEP3: 666 1.1 mrg case UNSPEC_NETWORK_RECEIVE: 667 1.1 mrg case UNSPEC_NETWORK_SEND: 668 1.1 mrg case UNSPEC_SPR_MOVE: 669 1.1 mrg case UNSPEC_TLS_GD_ADD: 670 1.1 mrg *total = COSTS_N_INSNS (1); 671 1.1 mrg break; 672 1.1 mrg 673 1.1 mrg case UNSPEC_TLS_IE_LOAD: 674 1.1 mrg case UNSPEC_XCHG: 675 1.1 mrg *total = COSTS_N_INSNS (2); 676 1.1 mrg break; 677 1.1 mrg 678 1.1 mrg case UNSPEC_SP_SET: 679 1.1 mrg *total = COSTS_N_INSNS (3); 680 1.1 mrg break; 681 1.1 mrg 682 1.1 mrg case UNSPEC_SP_TEST: 683 1.1 mrg *total = COSTS_N_INSNS (4); 684 1.1 mrg break; 685 1.1 mrg 686 1.1 mrg case UNSPEC_CMPXCHG: 687 1.1 mrg case UNSPEC_INSN_CMPEXCH: 688 1.1 mrg case UNSPEC_LATENCY_L2: 689 1.1 mrg *total = COSTS_N_INSNS (11); 690 1.1 mrg break; 691 1.1 mrg 692 1.1 mrg case UNSPEC_TLS_GD_CALL: 693 1.1 mrg *total = COSTS_N_INSNS (30); 694 1.1 mrg break; 695 1.1 mrg 696 1.1 mrg case UNSPEC_LATENCY_MISS: 697 1.1 mrg *total = COSTS_N_INSNS (80); 698 1.1 mrg break; 699 1.1 mrg 700 1.1 mrg default: 701 1.1 mrg *total = COSTS_N_INSNS (1); 702 1.1 mrg } 703 1.1 mrg } 704 1.1 mrg return true; 705 1.1 mrg } 706 1.1 mrg 707 1.1 mrg default: 708 1.1 mrg return false; 709 1.1 mrg } 710 1.1 mrg } 711 1.1 mrg 712 1.1 mrg 714 1.1 mrg 715 1.1 mrg /* Rtl lowering. */ 716 1.1 mrg 717 1.1 mrg /* Create a temporary variable to hold a partial result, to enable 718 1.1 mrg CSE. */ 719 1.1 mrg static rtx 720 1.1 mrg create_temp_reg_if_possible (machine_mode mode, rtx default_reg) 721 1.1 mrg { 722 1.1 mrg return can_create_pseudo_p () ? gen_reg_rtx (mode) : default_reg; 723 1.1 mrg } 724 1.1 mrg 725 1.1 mrg 726 1.1 mrg /* Functions to save and restore machine-specific function data. */ 727 1.1 mrg static struct machine_function * 728 1.1 mrg tilegx_init_machine_status (void) 729 1.1 mrg { 730 1.1 mrg return ggc_cleared_alloc<machine_function> (); 731 1.1 mrg } 732 1.1 mrg 733 1.1 mrg 734 1.1 mrg /* Do anything needed before RTL is emitted for each function. */ 735 1.1 mrg void 736 1.1 mrg tilegx_init_expanders (void) 737 1.1 mrg { 738 1.1 mrg /* Arrange to initialize and mark the machine per-function 739 1.1 mrg status. */ 740 1.1 mrg init_machine_status = tilegx_init_machine_status; 741 1.1 mrg 742 1.1 mrg if (cfun && cfun->machine && flag_pic) 743 1.1 mrg { 744 1.1 mrg static int label_num = 0; 745 1.1 mrg 746 1.1 mrg char text_label_name[32]; 747 1.1 mrg 748 1.1 mrg struct machine_function *machine = cfun->machine; 749 1.1 mrg 750 1.1 mrg ASM_GENERATE_INTERNAL_LABEL (text_label_name, "L_PICLNK", label_num++); 751 1.1 mrg 752 1.1 mrg machine->text_label_symbol = 753 1.1 mrg gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (text_label_name)); 754 1.1 mrg 755 1.1 mrg machine->text_label_rtx = 756 1.1 mrg gen_rtx_REG (Pmode, TILEGX_PIC_TEXT_LABEL_REGNUM); 757 1.1 mrg 758 1.1 mrg machine->got_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM); 759 1.1 mrg 760 1.1 mrg machine->calls_tls_get_addr = false; 761 1.1 mrg } 762 1.1 mrg } 763 1.1 mrg 764 1.1 mrg 765 1.1 mrg /* Implement TARGET_EXPAND_TO_RTL_HOOK. */ 766 1.1 mrg static void 767 1.1 mrg tilegx_expand_to_rtl_hook (void) 768 1.1 mrg { 769 1.1 mrg /* Exclude earlier sets of crtl->uses_pic_offset_table, because we 770 1.1 mrg only care about uses actually emitted. */ 771 1.1 mrg crtl->uses_pic_offset_table = 0; 772 1.1 mrg } 773 1.1 mrg 774 1.1 mrg 775 1.1 mrg /* Implement TARGET_SHIFT_TRUNCATION_MASK. DImode shifts use the mode 776 1.1 mrg matching insns and therefore guarantee that the shift count is 777 1.1 mrg modulo 64. SImode shifts sometimes use the 64 bit version so do 778 1.1 mrg not hold such guarantee. */ 779 1.1 mrg static unsigned HOST_WIDE_INT 780 1.1 mrg tilegx_shift_truncation_mask (machine_mode mode) 781 1.1 mrg { 782 1.1 mrg return mode == DImode ? 63 : 0; 783 1.1 mrg } 784 1.1 mrg 785 1.1 mrg 786 1.1 mrg /* Implement TARGET_INIT_LIBFUNCS. */ 787 1.1 mrg static void 788 1.1 mrg tilegx_init_libfuncs (void) 789 1.1 mrg { 790 1.1 mrg /* We need to explicitly generate these libfunc's to support 791 1.1 mrg conversion of divide by constant to multiply (the divide stubs in 792 1.1 mrg tilegx.md exist also for this reason). Normally we'd expect gcc 793 1.1 mrg to lazily generate them when they are needed, but for some reason 794 1.1 mrg it's set up to only generate them if the mode is the word 795 1.1 mrg mode. */ 796 1.1 mrg set_optab_libfunc (sdiv_optab, SImode, "__divsi3"); 797 1.1 mrg set_optab_libfunc (udiv_optab, SImode, "__udivsi3"); 798 1.1 mrg set_optab_libfunc (smod_optab, SImode, "__modsi3"); 799 1.1 mrg set_optab_libfunc (umod_optab, SImode, "__umodsi3"); 800 1.1 mrg } 801 1.1 mrg 802 1.1 mrg 803 1.1 mrg /* Return true if X contains a thread-local symbol. */ 804 1.1 mrg static bool 805 1.1 mrg tilegx_tls_referenced_p (rtx x) 806 1.1 mrg { 807 1.1 mrg if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS) 808 1.1 mrg x = XEXP (XEXP (x, 0), 0); 809 1.1 mrg 810 1.1 mrg if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x)) 811 1.1 mrg return true; 812 1.1 mrg 813 1.1 mrg /* That's all we handle in tilegx_legitimize_tls_address for 814 1.1 mrg now. */ 815 1.1 mrg return false; 816 1.1 mrg } 817 1.1 mrg 818 1.1 mrg 819 1.1 mrg /* Return true if X requires a scratch register. It is given that 820 1.1 mrg flag_pic is on and that X satisfies CONSTANT_P. */ 821 1.1 mrg static int 822 1.1 mrg tilegx_pic_address_needs_scratch (rtx x) 823 1.1 mrg { 824 1.1 mrg if (GET_CODE (x) == CONST 825 1.1 mrg && GET_CODE (XEXP (x, 0)) == PLUS 826 1.1 mrg && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF 827 1.1 mrg || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF) 828 1.1 mrg && (CONST_INT_P (XEXP (XEXP (x, 0), 1)))) 829 1.1 mrg return true; 830 1.1 mrg 831 1.1 mrg return false; 832 1.1 mrg } 833 1.1 mrg 834 1.1 mrg 835 1.1 mrg /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for 836 1.1 mrg which we are willing to load the value into a register via a move 837 1.1 mrg pattern. TLS cannot be treated as a constant because it can 838 1.1 mrg include a function call. */ 839 1.1 mrg static bool 840 1.1 mrg tilegx_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x) 841 1.1 mrg { 842 1.1 mrg switch (GET_CODE (x)) 843 1.1 mrg { 844 1.1 mrg case CONST: 845 1.1 mrg case SYMBOL_REF: 846 1.1 mrg return !tilegx_tls_referenced_p (x); 847 1.1 mrg 848 1.1 mrg default: 849 1.1 mrg return true; 850 1.1 mrg } 851 1.1 mrg } 852 1.1 mrg 853 1.1 mrg 854 1.1 mrg /* Return true if the constant value X is a legitimate general operand 855 1.1 mrg when generating PIC code. It is given that flag_pic is on and that 856 1.1 mrg X satisfies CONSTANT_P. */ 857 1.1 mrg bool 858 1.1 mrg tilegx_legitimate_pic_operand_p (rtx x) 859 1.1 mrg { 860 1.1 mrg if (tilegx_pic_address_needs_scratch (x)) 861 1.1 mrg return false; 862 1.1 mrg 863 1.1 mrg if (tilegx_tls_referenced_p (x)) 864 1.1 mrg return false; 865 1.1 mrg 866 1.1 mrg return true; 867 1.1 mrg } 868 1.1 mrg 869 1.1 mrg 870 1.1 mrg /* Return true if the rtx X can be used as an address operand. */ 871 1.1 mrg static bool 872 1.1 mrg tilegx_legitimate_address_p (machine_mode ARG_UNUSED (mode), rtx x, 873 1.1 mrg bool strict) 874 1.1 mrg { 875 1.1 mrg if (GET_CODE (x) == SUBREG) 876 1.1 mrg x = SUBREG_REG (x); 877 1.1 mrg 878 1.1 mrg switch (GET_CODE (x)) 879 1.1 mrg { 880 1.1 mrg case POST_INC: 881 1.1 mrg case POST_DEC: 882 1.1 mrg if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) 883 1.1 mrg return false; 884 1.1 mrg 885 1.1 mrg x = XEXP (x, 0); 886 1.1 mrg break; 887 1.1 mrg 888 1.1 mrg case POST_MODIFY: 889 1.1 mrg if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) 890 1.1 mrg return false; 891 1.1 mrg 892 1.1 mrg if (GET_CODE (XEXP (x, 1)) != PLUS) 893 1.1 mrg return false; 894 1.1 mrg 895 1.1 mrg if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0))) 896 1.1 mrg return false; 897 1.1 mrg 898 1.1 mrg if (!satisfies_constraint_I (XEXP (XEXP (x, 1), 1))) 899 1.1 mrg return false; 900 1.1 mrg 901 1.1 mrg x = XEXP (x, 0); 902 1.1 mrg break; 903 1.1 mrg 904 1.1 mrg case REG: 905 1.1 mrg break; 906 1.1 mrg 907 1.1 mrg default: 908 1.1 mrg return false; 909 1.1 mrg } 910 1.1 mrg 911 1.1 mrg /* Check if x is a valid reg. */ 912 1.1 mrg if (!REG_P (x)) 913 1.1 mrg return false; 914 1.1 mrg 915 1.1 mrg if (strict) 916 1.1 mrg return REGNO_OK_FOR_BASE_P (REGNO (x)); 917 1.1 mrg else 918 1.1 mrg return true; 919 1.1 mrg } 920 1.1 mrg 921 1.1 mrg 922 1.1 mrg /* Return the rtx containing SYMBOL_REF to the text label. */ 923 1.1 mrg static rtx 924 1.1 mrg tilegx_text_label_symbol (void) 925 1.1 mrg { 926 1.1 mrg return cfun->machine->text_label_symbol; 927 1.1 mrg } 928 1.1 mrg 929 1.1 mrg 930 1.1 mrg /* Return the register storing the value of the text label. */ 931 1.1 mrg static rtx 932 1.1 mrg tilegx_text_label_rtx (void) 933 1.1 mrg { 934 1.1 mrg return cfun->machine->text_label_rtx; 935 1.1 mrg } 936 1.1 mrg 937 1.1 mrg 938 1.1 mrg /* Return the register storing the value of the global offset 939 1.1 mrg table. */ 940 1.1 mrg static rtx 941 1.1 mrg tilegx_got_rtx (void) 942 1.1 mrg { 943 1.1 mrg return cfun->machine->got_rtx; 944 1.1 mrg } 945 1.1 mrg 946 1.1 mrg 947 1.1 mrg /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */ 948 1.1 mrg static rtx 949 1.1 mrg tilegx_got_symbol (void) 950 1.1 mrg { 951 1.1 mrg if (g_got_symbol == NULL) 952 1.1 mrg g_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); 953 1.1 mrg 954 1.1 mrg return g_got_symbol; 955 1.1 mrg } 956 1.1 mrg 957 1.1 mrg 958 1.1 mrg /* Return a reference to the got to be used by tls references. */ 959 1.1 mrg static rtx 960 1.1 mrg tilegx_tls_got (void) 961 1.1 mrg { 962 1.1 mrg rtx temp; 963 1.1 mrg if (flag_pic) 964 1.1 mrg { 965 1.1 mrg crtl->uses_pic_offset_table = 1; 966 1.1 mrg return tilegx_got_rtx (); 967 1.1 mrg } 968 1.1 mrg 969 1.1 mrg temp = gen_reg_rtx (Pmode); 970 1.1 mrg emit_move_insn (temp, tilegx_got_symbol ()); 971 1.1 mrg 972 1.1 mrg return temp; 973 1.1 mrg } 974 1.1 mrg 975 1.1 mrg 976 1.1 mrg /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute 977 1.1 mrg this (thread-local) address. */ 978 1.1 mrg static rtx 979 1.1 mrg tilegx_legitimize_tls_address (rtx addr) 980 1.1 mrg { 981 1.1 mrg rtx ret; 982 1.1 mrg 983 1.1 mrg gcc_assert (can_create_pseudo_p ()); 984 1.1 mrg 985 1.1 mrg if (GET_CODE (addr) == SYMBOL_REF) 986 1.1 mrg switch (SYMBOL_REF_TLS_MODEL (addr)) 987 1.1 mrg { 988 1.1 mrg case TLS_MODEL_GLOBAL_DYNAMIC: 989 1.1 mrg case TLS_MODEL_LOCAL_DYNAMIC: 990 1.1 mrg { 991 1.1 mrg rtx r0, temp, temp2, temp3, got; 992 1.1 mrg 993 1.1 mrg ret = gen_reg_rtx (Pmode); 994 1.1 mrg r0 = gen_rtx_REG (Pmode, 0); 995 1.1 mrg temp = gen_reg_rtx (Pmode); 996 1.1 mrg temp2 = gen_reg_rtx (Pmode); 997 1.1 mrg temp3 = gen_reg_rtx (Pmode); 998 1.1 mrg 999 1.1 mrg got = tilegx_tls_got (); 1000 1.1 mrg if (TARGET_32BIT) 1001 1.1 mrg { 1002 1.1 mrg emit_insn (gen_mov_tls_gd_step1_32bit (temp, addr)); 1003 1.1 mrg emit_insn (gen_mov_tls_gd_step2_32bit (temp2, temp, addr)); 1004 1.1 mrg emit_insn (gen_tls_add_32bit (temp2, got, temp2, addr)); 1005 1.1 mrg } 1006 1.1 mrg else 1007 1.1 mrg { 1008 1.1 mrg emit_insn (gen_mov_tls_gd_step1 (temp, addr)); 1009 1.1 mrg emit_insn (gen_mov_tls_gd_step2 (temp2, temp, addr)); 1010 1.1 mrg emit_insn (gen_tls_add (temp2, got, temp2, addr)); 1011 1.1 mrg } 1012 1.1 mrg 1013 1.1 mrg emit_move_insn (r0, temp2); 1014 1.1 mrg 1015 1.1 mrg if (TARGET_32BIT) 1016 1.1 mrg { 1017 1.1 mrg emit_insn (gen_tls_gd_call_32bit (addr)); 1018 1.1 mrg } 1019 1.1 mrg else 1020 1.1 mrg { 1021 1.1 mrg emit_insn (gen_tls_gd_call (addr)); 1022 1.1 mrg } 1023 1.1 mrg 1024 1.1 mrg emit_move_insn (temp3, r0); 1025 1.1 mrg 1026 1.1 mrg rtx_insn *last; 1027 1.1 mrg if (TARGET_32BIT) 1028 1.1 mrg last = emit_insn (gen_tls_gd_add_32bit (ret, temp3, addr)); 1029 1.1 mrg else 1030 1.1 mrg last = emit_insn (gen_tls_gd_add (ret, temp3, addr)); 1031 1.1 mrg 1032 1.1 mrg set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr)); 1033 1.1 mrg break; 1034 1.1 mrg } 1035 1.1 mrg case TLS_MODEL_INITIAL_EXEC: 1036 1.1 mrg { 1037 1.1 mrg rtx temp, temp2, temp3, got; 1038 1.1 mrg rtx_insn *last; 1039 1.1 mrg 1040 1.1 mrg ret = gen_reg_rtx (Pmode); 1041 1.1 mrg temp = gen_reg_rtx (Pmode); 1042 1.1 mrg temp2 = gen_reg_rtx (Pmode); 1043 1.1 mrg temp3 = gen_reg_rtx (Pmode); 1044 1.1 mrg 1045 1.1 mrg got = tilegx_tls_got (); 1046 1.1 mrg if (TARGET_32BIT) 1047 1.1 mrg { 1048 1.1 mrg emit_insn (gen_mov_tls_ie_step1_32bit (temp, addr)); 1049 1.1 mrg emit_insn (gen_mov_tls_ie_step2_32bit (temp2, temp, addr)); 1050 1.1 mrg emit_insn (gen_tls_add_32bit (temp2, got, temp2, addr)); 1051 1.1 mrg emit_insn (gen_tls_ie_load_32bit (temp3, temp2, addr)); 1052 1.1 mrg } 1053 1.1 mrg else 1054 1.1 mrg { 1055 1.1 mrg emit_insn (gen_mov_tls_ie_step1 (temp, addr)); 1056 1.1 mrg emit_insn (gen_mov_tls_ie_step2 (temp2, temp, addr)); 1057 1.1 mrg emit_insn (gen_tls_add (temp2, got, temp2, addr)); 1058 1.1 mrg emit_insn (gen_tls_ie_load (temp3, temp2, addr)); 1059 1.1 mrg } 1060 1.1 mrg 1061 1.1 mrg last = 1062 1.1 mrg emit_move_insn(ret, 1063 1.1 mrg gen_rtx_PLUS (Pmode, 1064 1.1 mrg gen_rtx_REG (Pmode, 1065 1.1 mrg THREAD_POINTER_REGNUM), 1066 1.1 mrg temp3)); 1067 1.1 mrg set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr)); 1068 1.1 mrg break; 1069 1.1 mrg } 1070 1.1 mrg case TLS_MODEL_LOCAL_EXEC: 1071 1.1 mrg { 1072 1.1 mrg rtx temp, temp2; 1073 1.1 mrg rtx_insn *last; 1074 1.1 mrg 1075 1.1 mrg ret = gen_reg_rtx (Pmode); 1076 1.1 mrg temp = gen_reg_rtx (Pmode); 1077 1.1 mrg temp2 = gen_reg_rtx (Pmode); 1078 1.1 mrg 1079 1.1 mrg if (TARGET_32BIT) 1080 1.1 mrg { 1081 1.1 mrg emit_insn (gen_mov_tls_le_step1_32bit (temp, addr)); 1082 1.1 mrg emit_insn (gen_mov_tls_le_step2_32bit (temp2, temp, addr)); 1083 1.1 mrg } 1084 1.1 mrg else 1085 1.1 mrg { 1086 1.1 mrg emit_insn (gen_mov_tls_le_step1 (temp, addr)); 1087 1.1 mrg emit_insn (gen_mov_tls_le_step2 (temp2, temp, addr)); 1088 1.1 mrg } 1089 1.1 mrg 1090 1.1 mrg last = 1091 1.1 mrg emit_move_insn (ret, 1092 1.1 mrg gen_rtx_PLUS (Pmode, 1093 1.1 mrg gen_rtx_REG (Pmode, 1094 1.1 mrg THREAD_POINTER_REGNUM), 1095 1.1 mrg temp2)); 1096 1.1 mrg set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr)); 1097 1.1 mrg break; 1098 1.1 mrg } 1099 1.1 mrg default: 1100 1.1 mrg gcc_unreachable (); 1101 1.1 mrg } 1102 1.1 mrg else if (GET_CODE (addr) == CONST) 1103 1.1 mrg { 1104 1.1 mrg rtx base, offset; 1105 1.1 mrg 1106 1.1 mrg gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS); 1107 1.1 mrg 1108 1.1 mrg base = tilegx_legitimize_tls_address (XEXP (XEXP (addr, 0), 0)); 1109 1.1 mrg offset = XEXP (XEXP (addr, 0), 1); 1110 1.1 mrg 1111 1.1 mrg base = force_operand (base, NULL_RTX); 1112 1.1 mrg ret = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset)); 1113 1.1 mrg } 1114 1.1 mrg else 1115 1.1 mrg gcc_unreachable (); 1116 1.1 mrg 1117 1.1 mrg return ret; 1118 1.1 mrg } 1119 1.1 mrg 1120 1.1 mrg 1121 1.1 mrg /* Returns a register that points to ADDR, a symbolic address, by 1122 1.1 mrg computing its address relative to tilegx_text_label_symbol. */ 1123 1.1 mrg void 1124 1.1 mrg tilegx_compute_pcrel_address (rtx result, rtx addr) 1125 1.1 mrg { 1126 1.1 mrg rtx text_label_symbol = tilegx_text_label_symbol (); 1127 1.1 mrg rtx text_label_rtx = tilegx_text_label_rtx (); 1128 1.1 mrg rtx temp, temp2, temp3; 1129 1.1 mrg 1130 1.1 mrg temp = create_temp_reg_if_possible (Pmode, result); 1131 1.1 mrg temp2 = create_temp_reg_if_possible (Pmode, result); 1132 1.1 mrg 1133 1.1 mrg if (TARGET_32BIT) 1134 1.1 mrg { 1135 1.1 mrg emit_insn (gen_mov_pcrel_step1_32bit (temp, addr, text_label_symbol)); 1136 1.1 mrg emit_insn (gen_mov_pcrel_step2_32bit (temp2, temp, addr, 1137 1.1 mrg text_label_symbol)); 1138 1.1 mrg emit_insn (gen_mov_pcrel_step3_32bit (result, temp2, 1139 1.1 mrg text_label_rtx, 1140 1.1 mrg addr, text_label_symbol)); 1141 1.1 mrg } 1142 1.1 mrg else if (tilegx_cmodel == CM_LARGE_PIC) 1143 1.1 mrg { 1144 1.1 mrg temp3 = create_temp_reg_if_possible (Pmode, result); 1145 1.1 mrg emit_insn (gen_mov_large_pcrel_step1 (temp, addr, text_label_symbol)); 1146 1.1 mrg emit_insn (gen_mov_large_pcrel_step2 (temp2, temp, addr, 1147 1.1 mrg text_label_symbol)); 1148 1.1 mrg emit_insn (gen_mov_large_pcrel_step3 (temp3, temp2, addr, 1149 1.1 mrg text_label_symbol)); 1150 1.1 mrg emit_insn (gen_mov_large_pcrel_step4 (result, temp3, 1151 1.1 mrg text_label_rtx, 1152 1.1 mrg addr, text_label_symbol)); 1153 1.1 mrg } 1154 1.1 mrg else 1155 1.1 mrg { 1156 1.1 mrg emit_insn (gen_mov_pcrel_step1 (temp, addr, text_label_symbol)); 1157 1.1 mrg emit_insn (gen_mov_pcrel_step2 (temp2, temp, addr, text_label_symbol)); 1158 1.1 mrg emit_insn (gen_mov_pcrel_step3 (result, temp2, 1159 1.1 mrg text_label_rtx, 1160 1.1 mrg addr, text_label_symbol)); 1161 1.1 mrg } 1162 1.1 mrg } 1163 1.1 mrg 1164 1.1 mrg 1165 1.1 mrg /* Returns a register that points to the plt entry of ADDR, a symbolic 1166 1.1 mrg address, by computing its address relative to 1167 1.1 mrg tilegx_text_label_symbol. */ 1168 1.1 mrg void 1169 1.1 mrg tilegx_compute_pcrel_plt_address (rtx result, rtx addr) 1170 1.1 mrg { 1171 1.1 mrg rtx text_label_symbol = tilegx_text_label_symbol (); 1172 1.1 mrg rtx text_label_rtx = tilegx_text_label_rtx (); 1173 1.1 mrg rtx temp, temp2, temp3; 1174 1.1 mrg 1175 1.1 mrg temp = create_temp_reg_if_possible (Pmode, result); 1176 1.1 mrg temp2 = create_temp_reg_if_possible (Pmode, result); 1177 1.1 mrg 1178 1.1 mrg if (TARGET_32BIT) 1179 1.1 mrg { 1180 1.1 mrg emit_insn (gen_mov_plt_pcrel_step1_32bit (temp, addr, 1181 1.1 mrg text_label_symbol)); 1182 1.1 mrg emit_insn (gen_mov_plt_pcrel_step2_32bit (temp2, temp, addr, 1183 1.1 mrg text_label_symbol)); 1184 1.1 mrg emit_move_insn (result, gen_rtx_PLUS (Pmode, temp2, text_label_rtx)); 1185 1.1 mrg } 1186 1.1 mrg else 1187 1.1 mrg { 1188 1.1 mrg temp3 = create_temp_reg_if_possible (Pmode, result); 1189 1.1 mrg 1190 1.1 mrg emit_insn (gen_mov_plt_pcrel_step1 (temp, addr, text_label_symbol)); 1191 1.1 mrg emit_insn (gen_mov_plt_pcrel_step2 (temp2, temp, addr, 1192 1.1 mrg text_label_symbol)); 1193 1.1 mrg emit_insn (gen_mov_plt_pcrel_step3 (temp3, temp2, addr, 1194 1.1 mrg text_label_symbol)); 1195 1.1 mrg emit_move_insn (result, gen_rtx_PLUS (Pmode, temp3, text_label_rtx)); 1196 1.1 mrg } 1197 1.1 mrg } 1198 1.1 mrg 1199 1.1 mrg 1200 1.1 mrg /* Legitimize PIC addresses. If the address is already 1201 1.1 mrg position-independent, we return ORIG. Newly generated 1202 1.1 mrg position-independent addresses go into a reg. This is REG if 1203 1.1 mrg nonzero, otherwise we allocate register(s) as necessary. */ 1204 1.1 mrg static rtx 1205 1.1 mrg tilegx_legitimize_pic_address (rtx orig, 1206 1.1 mrg machine_mode mode ATTRIBUTE_UNUSED, 1207 1.1 mrg rtx reg) 1208 1.1 mrg { 1209 1.1 mrg if (GET_CODE (orig) == SYMBOL_REF) 1210 1.1 mrg { 1211 1.1 mrg rtx address, pic_ref; 1212 1.1 mrg 1213 1.1 mrg if (reg == 0) 1214 1.1 mrg { 1215 1.1 mrg gcc_assert (can_create_pseudo_p ()); 1216 1.1 mrg reg = gen_reg_rtx (Pmode); 1217 1.1 mrg } 1218 1.1 mrg 1219 1.1 mrg if (SYMBOL_REF_LOCAL_P (orig)) 1220 1.1 mrg { 1221 1.1 mrg /* If not during reload, allocate another temp reg here for 1222 1.1 mrg loading in the address, so that these instructions can be 1223 1.1 mrg optimized properly. */ 1224 1.1 mrg rtx temp_reg = create_temp_reg_if_possible (Pmode, reg); 1225 1.1 mrg tilegx_compute_pcrel_address (temp_reg, orig); 1226 1.1 mrg 1227 1.1 mrg /* Note: this is conservative. We use the text_label but we 1228 1.1 mrg don't use the pic_offset_table. However, in some cases 1229 1.1 mrg we may need the pic_offset_table (see 1230 1.1 mrg tilegx_fixup_pcrel_references). */ 1231 1.1 mrg crtl->uses_pic_offset_table = 1; 1232 1.1 mrg 1233 1.1 mrg address = temp_reg; 1234 1.1 mrg 1235 1.1 mrg emit_move_insn (reg, address); 1236 1.1 mrg return reg; 1237 1.1 mrg } 1238 1.1 mrg else 1239 1.1 mrg { 1240 1.1 mrg /* If not during reload, allocate another temp reg here for 1241 1.1 mrg loading in the address, so that these instructions can be 1242 1.1 mrg optimized properly. */ 1243 1.1 mrg rtx temp_reg = create_temp_reg_if_possible (Pmode, reg); 1244 1.1 mrg 1245 1.1 mrg gcc_assert (flag_pic); 1246 1.1 mrg if (flag_pic == 1) 1247 1.1 mrg { 1248 1.1 mrg if (TARGET_32BIT) 1249 1.1 mrg { 1250 1.1 mrg emit_insn (gen_add_got16_32bit (temp_reg, 1251 1.1 mrg tilegx_got_rtx (), 1252 1.1 mrg orig)); 1253 1.1 mrg } 1254 1.1 mrg else 1255 1.1 mrg { 1256 1.1 mrg emit_insn (gen_add_got16 (temp_reg, 1257 1.1 mrg tilegx_got_rtx (), orig)); 1258 1.1 mrg } 1259 1.1 mrg } 1260 1.1 mrg else 1261 1.1 mrg { 1262 1.1 mrg rtx temp_reg2 = create_temp_reg_if_possible (Pmode, reg); 1263 1.1 mrg rtx temp_reg3 = create_temp_reg_if_possible (Pmode, reg); 1264 1.1 mrg if (TARGET_32BIT) 1265 1.1 mrg { 1266 1.1 mrg emit_insn (gen_mov_got32_step1_32bit (temp_reg3, orig)); 1267 1.1 mrg emit_insn (gen_mov_got32_step2_32bit 1268 1.1 mrg (temp_reg2, temp_reg3, orig)); 1269 1.1 mrg } 1270 1.1 mrg else 1271 1.1 mrg { 1272 1.1 mrg emit_insn (gen_mov_got32_step1 (temp_reg3, orig)); 1273 1.1 mrg emit_insn (gen_mov_got32_step2 (temp_reg2, temp_reg3, 1274 1.1 mrg orig)); 1275 1.1 mrg } 1276 1.1 mrg emit_move_insn (temp_reg, 1277 1.1 mrg gen_rtx_PLUS (Pmode, 1278 1.1 mrg tilegx_got_rtx (), temp_reg2)); 1279 1.1 mrg } 1280 1.1 mrg 1281 1.1 mrg address = temp_reg; 1282 1.1 mrg 1283 1.1 mrg pic_ref = gen_const_mem (Pmode, address); 1284 1.1 mrg crtl->uses_pic_offset_table = 1; 1285 1.1 mrg emit_move_insn (reg, pic_ref); 1286 1.1 mrg /* The following put a REG_EQUAL note on this insn, so that 1287 1.1 mrg it can be optimized by loop. But it causes the label to 1288 1.1 mrg be optimized away. */ 1289 1.1 mrg /* set_unique_reg_note (insn, REG_EQUAL, orig); */ 1290 1.1 mrg return reg; 1291 1.1 mrg } 1292 1.1 mrg } 1293 1.1 mrg else if (GET_CODE (orig) == CONST) 1294 1.1 mrg { 1295 1.1 mrg rtx base, offset; 1296 1.1 mrg 1297 1.1 mrg if (GET_CODE (XEXP (orig, 0)) == PLUS 1298 1.1 mrg && XEXP (XEXP (orig, 0), 0) == tilegx_got_rtx ()) 1299 1.1 mrg return orig; 1300 1.1 mrg 1301 1.1 mrg if (reg == 0) 1302 1.1 mrg { 1303 1.1 mrg gcc_assert (can_create_pseudo_p ()); 1304 1.1 mrg reg = gen_reg_rtx (Pmode); 1305 1.1 mrg } 1306 1.1 mrg 1307 1.1 mrg gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS); 1308 1.1 mrg base = tilegx_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), 1309 1.1 mrg Pmode, reg); 1310 1.1 mrg offset = tilegx_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, 1311 1.1 mrg base == reg ? 0 : reg); 1312 1.1 mrg 1313 1.1 mrg if (CONST_INT_P (offset)) 1314 1.1 mrg { 1315 1.1 mrg if (can_create_pseudo_p ()) 1316 1.1 mrg offset = force_reg (Pmode, offset); 1317 1.1 mrg else 1318 1.1 mrg /* If we reach here, then something is seriously wrong. */ 1319 1.1 mrg gcc_unreachable (); 1320 1.1 mrg } 1321 1.1 mrg 1322 1.1 mrg if (can_create_pseudo_p ()) 1323 1.1 mrg return force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset)); 1324 1.1 mrg else 1325 1.1 mrg gcc_unreachable (); 1326 1.1 mrg } 1327 1.1 mrg else if (GET_CODE (orig) == LABEL_REF) 1328 1.1 mrg { 1329 1.1 mrg rtx address; 1330 1.1 mrg rtx temp_reg; 1331 1.1 mrg 1332 1.1 mrg if (reg == 0) 1333 1.1 mrg { 1334 1.1 mrg gcc_assert (can_create_pseudo_p ()); 1335 1.1 mrg reg = gen_reg_rtx (Pmode); 1336 1.1 mrg } 1337 1.1 mrg 1338 1.1 mrg /* If not during reload, allocate another temp reg here for 1339 1.1 mrg loading in the address, so that these instructions can be 1340 1.1 mrg optimized properly. */ 1341 1.1 mrg temp_reg = create_temp_reg_if_possible (Pmode, reg); 1342 1.1 mrg tilegx_compute_pcrel_address (temp_reg, orig); 1343 1.1 mrg 1344 1.1 mrg /* Note: this is conservative. We use the text_label but we 1345 1.1 mrg don't use the pic_offset_table. */ 1346 1.1 mrg crtl->uses_pic_offset_table = 1; 1347 1.1 mrg 1348 1.1 mrg address = temp_reg; 1349 1.1 mrg 1350 1.1 mrg emit_move_insn (reg, address); 1351 1.1 mrg 1352 1.1 mrg return reg; 1353 1.1 mrg } 1354 1.1 mrg 1355 1.1 mrg return orig; 1356 1.1 mrg } 1357 1.1 mrg 1358 1.1 mrg 1359 1.1 mrg /* Implement TARGET_LEGITIMIZE_ADDRESS. */ 1360 1.1 mrg static rtx 1361 1.1 mrg tilegx_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, 1362 1.1 mrg machine_mode mode) 1363 1.1 mrg { 1364 1.1 mrg if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD 1365 1.1 mrg && symbolic_operand (x, Pmode) && tilegx_tls_referenced_p (x)) 1366 1.1 mrg { 1367 1.1 mrg return tilegx_legitimize_tls_address (x); 1368 1.1 mrg } 1369 1.1 mrg else if (flag_pic) 1370 1.1 mrg { 1371 1.1 mrg return tilegx_legitimize_pic_address (x, mode, 0); 1372 1.1 mrg } 1373 1.1 mrg else 1374 1.1 mrg return x; 1375 1.1 mrg } 1376 1.1 mrg 1377 1.1 mrg 1378 1.1 mrg /* Implement TARGET_DELEGITIMIZE_ADDRESS. */ 1379 1.1 mrg static rtx 1380 1.1 mrg tilegx_delegitimize_address (rtx x) 1381 1.1 mrg { 1382 1.1 mrg x = delegitimize_mem_from_attrs (x); 1383 1.1 mrg 1384 1.1 mrg if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == UNSPEC) 1385 1.1 mrg { 1386 1.1 mrg switch (XINT (XEXP (x, 0), 1)) 1387 1.1 mrg { 1388 1.1 mrg case UNSPEC_HW0: 1389 1.1 mrg case UNSPEC_HW1: 1390 1.1 mrg case UNSPEC_HW2: 1391 1.1 mrg case UNSPEC_HW3: 1392 1.1 mrg case UNSPEC_HW0_LAST: 1393 1.1 mrg case UNSPEC_HW1_LAST: 1394 1.1 mrg case UNSPEC_HW2_LAST: 1395 1.1 mrg case UNSPEC_HW0_PCREL: 1396 1.1 mrg case UNSPEC_HW1_PCREL: 1397 1.1 mrg case UNSPEC_HW1_LAST_PCREL: 1398 1.1 mrg case UNSPEC_HW2_LAST_PCREL: 1399 1.1 mrg case UNSPEC_HW0_PLT_PCREL: 1400 1.1 mrg case UNSPEC_HW1_PLT_PCREL: 1401 1.1 mrg case UNSPEC_HW1_LAST_PLT_PCREL: 1402 1.1 mrg case UNSPEC_HW2_LAST_PLT_PCREL: 1403 1.1 mrg case UNSPEC_HW0_GOT: 1404 1.1 mrg case UNSPEC_HW0_LAST_GOT: 1405 1.1 mrg case UNSPEC_HW1_LAST_GOT: 1406 1.1 mrg case UNSPEC_HW0_TLS_GD: 1407 1.1 mrg case UNSPEC_HW1_LAST_TLS_GD: 1408 1.1 mrg case UNSPEC_HW0_TLS_IE: 1409 1.1 mrg case UNSPEC_HW1_LAST_TLS_IE: 1410 1.1 mrg case UNSPEC_HW0_TLS_LE: 1411 1.1 mrg case UNSPEC_HW1_LAST_TLS_LE: 1412 1.1 mrg x = XVECEXP (XEXP (x, 0), 0, 0); 1413 1.1 mrg break; 1414 1.1 mrg } 1415 1.1 mrg } 1416 1.1 mrg 1417 1.1 mrg return x; 1418 1.1 mrg } 1419 1.1 mrg 1420 1.1 mrg 1421 1.1 mrg /* Emit code to load the PIC register. */ 1422 1.1 mrg static void 1423 1.1 mrg load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED) 1424 1.1 mrg { 1425 1.1 mrg int orig_flag_pic = flag_pic; 1426 1.1 mrg 1427 1.1 mrg rtx got_symbol = tilegx_got_symbol (); 1428 1.1 mrg rtx text_label_symbol = tilegx_text_label_symbol (); 1429 1.1 mrg rtx text_label_rtx = tilegx_text_label_rtx (); 1430 1.1 mrg flag_pic = 0; 1431 1.1 mrg 1432 1.1 mrg if (TARGET_32BIT) 1433 1.1 mrg { 1434 1.1 mrg emit_insn (gen_insn_lnk_and_label_32bit (text_label_rtx, 1435 1.1 mrg text_label_symbol)); 1436 1.1 mrg } 1437 1.1 mrg else 1438 1.1 mrg { 1439 1.1 mrg emit_insn (gen_insn_lnk_and_label (text_label_rtx, text_label_symbol)); 1440 1.1 mrg } 1441 1.1 mrg 1442 1.1 mrg tilegx_compute_pcrel_address (tilegx_got_rtx (), got_symbol); 1443 1.1 mrg 1444 1.1 mrg flag_pic = orig_flag_pic; 1445 1.1 mrg 1446 1.1 mrg /* Need to emit this whether or not we obey regdecls, since 1447 1.1 mrg setjmp/longjmp can cause life info to screw up. ??? In the case 1448 1.1 mrg where we don't obey regdecls, this is not sufficient since we may 1449 1.1 mrg not fall out the bottom. */ 1450 1.1 mrg emit_use (tilegx_got_rtx ()); 1451 1.1 mrg } 1452 1.1 mrg 1453 1.1 mrg 1454 1.1 mrg /* Return the simd variant of the constant NUM of mode MODE, by 1455 1.1 mrg replicating it to fill an interger of mode DImode. NUM is first 1456 1.1 mrg truncated to fit in MODE. */ 1457 1.1 mrg rtx 1458 1.1 mrg tilegx_simd_int (rtx num, machine_mode mode) 1459 1.1 mrg { 1460 1.1 mrg HOST_WIDE_INT n = 0; 1461 1.1 mrg 1462 1.1 mrg gcc_assert (CONST_INT_P (num)); 1463 1.1 mrg 1464 1.1 mrg n = INTVAL (num); 1465 1.1 mrg 1466 1.1 mrg switch (mode) 1467 1.1 mrg { 1468 1.1 mrg case E_QImode: 1469 1.1 mrg n = 0x0101010101010101LL * (n & 0x000000FF); 1470 1.1 mrg break; 1471 1.1 mrg case E_HImode: 1472 1.1 mrg n = 0x0001000100010001LL * (n & 0x0000FFFF); 1473 1.1 mrg break; 1474 1.1 mrg case E_SImode: 1475 1.1 mrg n = 0x0000000100000001LL * (n & 0xFFFFFFFF); 1476 1.1 mrg break; 1477 1.1 mrg case E_DImode: 1478 1.1 mrg break; 1479 1.1 mrg default: 1480 1.1 mrg gcc_unreachable (); 1481 1.1 mrg } 1482 1.1 mrg 1483 1.1 mrg return GEN_INT (n); 1484 1.1 mrg } 1485 1.1 mrg 1486 1.1 mrg 1487 1.1 mrg /* Returns true iff VAL can be moved into a register in one 1488 1.1 mrg instruction. And if it can, it emits the code to move the constant 1489 1.1 mrg into DEST_REG. 1490 1.1 mrg 1491 1.1 mrg If THREE_WIDE_ONLY is true, this insists on an instruction that 1492 1.1 mrg works in a bundle containing three instructions. */ 1493 1.1 mrg static bool 1494 1.1 mrg expand_set_cint64_one_inst (rtx dest_reg, 1495 1.1 mrg HOST_WIDE_INT val, bool three_wide_only) 1496 1.1 mrg { 1497 1.1 mrg if (val == trunc_int_for_mode (val, QImode)) 1498 1.1 mrg { 1499 1.1 mrg /* Success! */ 1500 1.1 mrg emit_move_insn (dest_reg, GEN_INT (val)); 1501 1.1 mrg return true; 1502 1.1 mrg } 1503 1.1 mrg else if (!three_wide_only) 1504 1.1 mrg { 1505 1.1 mrg /* Test for the following constraints: J, K, N, P. We avoid 1506 1.1 mrg generating an rtx and using existing predicates because we 1507 1.1 mrg can be testing and rejecting a lot of constants, and GEN_INT 1508 1.1 mrg is O(N). */ 1509 1.1 mrg if ((val >= -32768 && val <= 65535) 1510 1.1 mrg || ((val == (val & 0xFF) * 0x0101010101010101LL)) 1511 1.1 mrg || (val == ((trunc_int_for_mode (val, QImode) & 0xFFFF) 1512 1.1 mrg * 0x0001000100010001LL))) 1513 1.1 mrg { 1514 1.1 mrg emit_move_insn (dest_reg, GEN_INT (val)); 1515 1.1 mrg return true; 1516 1.1 mrg } 1517 1.1 mrg } 1518 1.1 mrg 1519 1.1 mrg return false; 1520 1.1 mrg } 1521 1.1 mrg 1522 1.1 mrg 1523 1.1 mrg /* Implement DImode rotatert. */ 1524 1.1 mrg static HOST_WIDE_INT 1525 1.1 mrg rotate_right (HOST_WIDE_INT n, int count) 1526 1.1 mrg { 1527 1.1 mrg unsigned HOST_WIDE_INT x = n & 0xFFFFFFFFFFFFFFFFULL; 1528 1.1 mrg if (count == 0) 1529 1.1 mrg return x; 1530 1.1 mrg return ((x >> count) | (x << (64 - count))) & 0xFFFFFFFFFFFFFFFFULL; 1531 1.1 mrg } 1532 1.1 mrg 1533 1.1 mrg 1534 1.1 mrg /* Return true iff n contains exactly one contiguous sequence of 1 1535 1.1 mrg bits, possibly wrapping around from high bits to low bits. */ 1536 1.1 mrg bool 1537 1.1 mrg tilegx_bitfield_operand_p (HOST_WIDE_INT n, int *first_bit, int *last_bit) 1538 1.1 mrg { 1539 1.1 mrg int i; 1540 1.1 mrg 1541 1.1 mrg if (n == 0) 1542 1.1 mrg return false; 1543 1.1 mrg 1544 1.1 mrg for (i = 0; i < 64; i++) 1545 1.1 mrg { 1546 1.1 mrg unsigned HOST_WIDE_INT x = rotate_right (n, i); 1547 1.1 mrg if (!(x & 1)) 1548 1.1 mrg continue; 1549 1.1 mrg 1550 1.1 mrg /* See if x is a power of two minus one, i.e. only consecutive 1 1551 1.1 mrg bits starting from bit 0. */ 1552 1.1 mrg if ((x & (x + 1)) == 0) 1553 1.1 mrg { 1554 1.1 mrg if (first_bit != NULL) 1555 1.1 mrg *first_bit = i; 1556 1.1 mrg if (last_bit != NULL) 1557 1.1 mrg *last_bit = (i + exact_log2 (x ^ (x >> 1))) & 63; 1558 1.1 mrg 1559 1.1 mrg return true; 1560 1.1 mrg } 1561 1.1 mrg } 1562 1.1 mrg 1563 1.1 mrg return false; 1564 1.1 mrg } 1565 1.1 mrg 1566 1.1 mrg 1567 1.1 mrg /* Create code to move the CONST_INT value in src_val to dest_reg. */ 1568 1.1 mrg static void 1569 1.1 mrg expand_set_cint64 (rtx dest_reg, rtx src_val) 1570 1.1 mrg { 1571 1.1 mrg HOST_WIDE_INT val; 1572 1.1 mrg int leading_zeroes, trailing_zeroes; 1573 1.1 mrg int three_wide_only; 1574 1.1 mrg int shift, ins_shift, zero_cluster_shift; 1575 1.1 mrg rtx temp, subreg; 1576 1.1 mrg 1577 1.1 mrg gcc_assert (CONST_INT_P (src_val)); 1578 1.1 mrg val = trunc_int_for_mode (INTVAL (src_val), GET_MODE (dest_reg)); 1579 1.1 mrg 1580 1.1 mrg /* See if we can generate the constant in one instruction. */ 1581 1.1 mrg if (expand_set_cint64_one_inst (dest_reg, val, false)) 1582 1.1 mrg return; 1583 1.1 mrg 1584 1.1 mrg /* Force the destination to DImode so we can use DImode instructions 1585 1.1 mrg to create it. This both allows instructions like rotl, and 1586 1.1 mrg certain efficient 3-wide instructions. */ 1587 1.1 mrg subreg = simplify_gen_subreg (DImode, dest_reg, GET_MODE (dest_reg), 0); 1588 1.1 mrg gcc_assert (subreg != NULL); 1589 1.1 mrg dest_reg = subreg; 1590 1.1 mrg 1591 1.1 mrg temp = create_temp_reg_if_possible (DImode, dest_reg); 1592 1.1 mrg 1593 1.1 mrg leading_zeroes = 63 - floor_log2 (val & 0xFFFFFFFFFFFFFFFFULL); 1594 1.1 mrg trailing_zeroes = exact_log2 (val & -val); 1595 1.1 mrg 1596 1.1 mrg /* First try all three-wide instructions that generate a constant 1597 1.1 mrg (i.e. movei) followed by various shifts and rotates. If none of 1598 1.1 mrg those work, try various two-wide ways of generating a constant 1599 1.1 mrg followed by various shifts and rotates. */ 1600 1.1 mrg for (three_wide_only = 1; three_wide_only >= 0; three_wide_only--) 1601 1.1 mrg { 1602 1.1 mrg int count; 1603 1.1 mrg 1604 1.1 mrg if (expand_set_cint64_one_inst (temp, val >> trailing_zeroes, 1605 1.1 mrg three_wide_only)) 1606 1.1 mrg { 1607 1.1 mrg /* 0xFFFFFFFFFFFFA500 becomes: 1608 1.1 mrg movei temp, 0xFFFFFFFFFFFFFFA5 1609 1.1 mrg shli dest, temp, 8 */ 1610 1.1 mrg emit_move_insn (dest_reg, 1611 1.1 mrg gen_rtx_ASHIFT (DImode, temp, 1612 1.1 mrg GEN_INT (trailing_zeroes))); 1613 1.1 mrg return; 1614 1.1 mrg } 1615 1.1 mrg 1616 1.1 mrg if (expand_set_cint64_one_inst (temp, val << leading_zeroes, 1617 1.1 mrg three_wide_only)) 1618 1.1 mrg { 1619 1.1 mrg /* 0x7FFFFFFFFFFFFFFF becomes: 1620 1.1 mrg movei temp, -2 1621 1.1 mrg shrui dest, temp, 1 */ 1622 1.1 mrg emit_move_insn (dest_reg, 1623 1.1 mrg gen_rtx_LSHIFTRT (DImode, temp, 1624 1.1 mrg GEN_INT (leading_zeroes))); 1625 1.1 mrg return; 1626 1.1 mrg } 1627 1.1 mrg 1628 1.1 mrg /* Try rotating a one-instruction immediate. */ 1629 1.1 mrg for (count = 1; count < 64; count++) 1630 1.1 mrg { 1631 1.1 mrg HOST_WIDE_INT r = rotate_right (val, count); 1632 1.1 mrg if (expand_set_cint64_one_inst (temp, r, three_wide_only)) 1633 1.1 mrg { 1634 1.1 mrg /* 0xFFFFFFFFFFA5FFFF becomes: 1635 1.1 mrg movei temp, 0xFFFFFFFFFFFFFFA5 1636 1.1 mrg rotli dest, temp, 16 */ 1637 1.1 mrg emit_move_insn (dest_reg, 1638 1.1 mrg gen_rtx_ROTATE (DImode, temp, GEN_INT (count))); 1639 1.1 mrg return; 1640 1.1 mrg } 1641 1.1 mrg } 1642 1.1 mrg } 1643 1.1 mrg 1644 1.1 mrg /* There are two cases here to produce a large constant. 1645 1.1 mrg In the most general case, we do this: 1646 1.1 mrg 1647 1.1 mrg moveli x, hw3(NUM) 1648 1.1 mrg shl16insli x, x, hw2(NUM) 1649 1.1 mrg shl16insli x, x, hw1(NUM) 1650 1.1 mrg shl16insli x, x, hw0(NUM) 1651 1.1 mrg 1652 1.1 mrg However, we can sometimes do better. shl16insli is a poor way to 1653 1.1 mrg insert 16 zero bits, because simply shifting left by 16 has more 1654 1.1 mrg bundling freedom. So if we see any contiguous aligned sequence 1655 1.1 mrg of 16 or more zero bits (below the highest set bit), it is always 1656 1.1 mrg more efficient to materialize the bits above the zero bits, then 1657 1.1 mrg left shift to put in the zeroes, then insert whatever bits 1658 1.1 mrg remain. For example, we might end up with: 1659 1.1 mrg 1660 1.1 mrg movei x, NUM >> (37 + 16) 1661 1.1 mrg shli x, x, 37 1662 1.1 mrg shl16insli x, x, hw0(NUM) */ 1663 1.1 mrg 1664 1.1 mrg zero_cluster_shift = -1; 1665 1.1 mrg 1666 1.1 mrg for (shift = 0; shift < 48 - leading_zeroes; shift += 16) 1667 1.1 mrg { 1668 1.1 mrg HOST_WIDE_INT x = val >> shift; 1669 1.1 mrg 1670 1.1 mrg /* Find the least significant group of 16 aligned zero bits. */ 1671 1.1 mrg if ((x & 0xFFFF) == 0x0000) 1672 1.1 mrg { 1673 1.1 mrg /* Grab any following zero bits as well. */ 1674 1.1 mrg zero_cluster_shift = exact_log2 (x & -x); 1675 1.1 mrg shift += zero_cluster_shift; 1676 1.1 mrg break; 1677 1.1 mrg } 1678 1.1 mrg } 1679 1.1 mrg 1680 1.1 mrg if (zero_cluster_shift >= 0) 1681 1.1 mrg { 1682 1.1 mrg unsigned HOST_WIDE_INT leftover; 1683 1.1 mrg 1684 1.1 mrg /* Recursively create the constant above the lowest 16 zero 1685 1.1 mrg bits. */ 1686 1.1 mrg expand_set_cint64 (temp, GEN_INT (val >> shift)); 1687 1.1 mrg 1688 1.1 mrg /* See if we can easily insert the remaining bits, or if we need 1689 1.1 mrg to fall through to the more general case. */ 1690 1.1 mrg leftover = val - ((val >> shift) << shift); 1691 1.1 mrg if (leftover == 0) 1692 1.1 mrg { 1693 1.1 mrg /* A simple left shift is enough. */ 1694 1.1 mrg emit_move_insn (dest_reg, 1695 1.1 mrg gen_rtx_ASHIFT (DImode, temp, GEN_INT (shift))); 1696 1.1 mrg return; 1697 1.1 mrg } 1698 1.1 mrg else if (leftover <= 32767) 1699 1.1 mrg { 1700 1.1 mrg /* Left shift into position then add in the leftover. */ 1701 1.1 mrg rtx temp2 = create_temp_reg_if_possible (DImode, temp); 1702 1.1 mrg emit_move_insn (temp2, 1703 1.1 mrg gen_rtx_ASHIFT (DImode, temp, GEN_INT (shift))); 1704 1.1 mrg emit_move_insn (dest_reg, 1705 1.1 mrg gen_rtx_PLUS (DImode, temp2, GEN_INT (leftover))); 1706 1.1 mrg return; 1707 1.1 mrg } 1708 1.1 mrg else 1709 1.1 mrg { 1710 1.1 mrg /* Shift in the batch of >= 16 zeroes we detected earlier. 1711 1.1 mrg After this, shift will be aligned mod 16 so the final 1712 1.1 mrg loop can use shl16insli. */ 1713 1.1 mrg rtx temp2 = create_temp_reg_if_possible (DImode, temp); 1714 1.1 mrg rtx shift_count_rtx = GEN_INT (zero_cluster_shift); 1715 1.1 mrg 1716 1.1 mrg emit_move_insn (temp2, 1717 1.1 mrg gen_rtx_ASHIFT (DImode, temp, shift_count_rtx)); 1718 1.1 mrg 1719 1.1 mrg shift -= zero_cluster_shift; 1720 1.1 mrg temp = temp2; 1721 1.1 mrg } 1722 1.1 mrg } 1723 1.1 mrg else 1724 1.1 mrg { 1725 1.1 mrg /* Set as many high 16-bit blocks as we can with a single 1726 1.1 mrg instruction. We'll insert the remaining 16-bit blocks 1727 1.1 mrg below. */ 1728 1.1 mrg for (shift = 16;; shift += 16) 1729 1.1 mrg { 1730 1.1 mrg gcc_assert (shift < 64); 1731 1.1 mrg if (expand_set_cint64_one_inst (temp, val >> shift, false)) 1732 1.1 mrg break; 1733 1.1 mrg } 1734 1.1 mrg } 1735 1.1 mrg 1736 1.1 mrg /* At this point, temp == val >> shift, shift % 16 == 0, and we 1737 1.1 mrg still need to insert any bits of 'val' below 'shift'. Those bits 1738 1.1 mrg are guaranteed to not have 16 contiguous zeroes. */ 1739 1.1 mrg 1740 1.1 mrg gcc_assert ((shift & 15) == 0); 1741 1.1 mrg 1742 1.1 mrg for (ins_shift = shift - 16; ins_shift >= 0; ins_shift -= 16) 1743 1.1 mrg { 1744 1.1 mrg rtx result; 1745 1.1 mrg HOST_WIDE_INT bits = (val >> ins_shift) & 0xFFFF; 1746 1.1 mrg gcc_assert (bits != 0); 1747 1.1 mrg 1748 1.1 mrg /* On the last iteration we need to store into dest_reg. */ 1749 1.1 mrg if (ins_shift == 0) 1750 1.1 mrg result = dest_reg; 1751 1.1 mrg else 1752 1.1 mrg result = create_temp_reg_if_possible (DImode, dest_reg); 1753 1.1 mrg 1754 1.1 mrg emit_insn (gen_insn_shl16insli (result, temp, GEN_INT (bits))); 1755 1.1 mrg 1756 1.1 mrg temp = result; 1757 1.1 mrg } 1758 1.1 mrg } 1759 1.1 mrg 1760 1.1 mrg 1761 1.1 mrg /* Load OP1, a 64-bit constant, into OP0, a register. We know it 1762 1.1 mrg can't be done in one insn when we get here, the move expander 1763 1.1 mrg guarantees this. */ 1764 1.1 mrg void 1765 1.1 mrg tilegx_expand_set_const64 (rtx op0, rtx op1) 1766 1.1 mrg { 1767 1.1 mrg if (CONST_INT_P (op1)) 1768 1.1 mrg { 1769 1.1 mrg /* TODO: I don't know if we want to split large constants 1770 1.1 mrg now, or wait until later (with a define_split). 1771 1.1 mrg 1772 1.1 mrg Does splitting early help CSE? Does it harm other 1773 1.1 mrg optimizations that might fold loads? */ 1774 1.1 mrg expand_set_cint64 (op0, op1); 1775 1.1 mrg } 1776 1.1 mrg else 1777 1.1 mrg { 1778 1.1 mrg rtx temp = create_temp_reg_if_possible (Pmode, op0); 1779 1.1 mrg 1780 1.1 mrg if (TARGET_32BIT) 1781 1.1 mrg { 1782 1.1 mrg /* Generate the 2-insn sequence to materialize a symbolic 1783 1.1 mrg address. */ 1784 1.1 mrg emit_insn (gen_mov_address_32bit_step1 (temp, op1)); 1785 1.1 mrg emit_insn (gen_mov_address_32bit_step2 (op0, temp, op1)); 1786 1.1 mrg } 1787 1.1 mrg else 1788 1.1 mrg { 1789 1.1 mrg /* Generate the 3-insn sequence to materialize a symbolic 1790 1.1 mrg address. Note that this assumes that virtual addresses 1791 1.1 mrg fit in 48 signed bits, which is currently true. */ 1792 1.1 mrg rtx temp2 = create_temp_reg_if_possible (Pmode, op0); 1793 1.1 mrg emit_insn (gen_mov_address_step1 (temp, op1)); 1794 1.1 mrg emit_insn (gen_mov_address_step2 (temp2, temp, op1)); 1795 1.1 mrg emit_insn (gen_mov_address_step3 (op0, temp2, op1)); 1796 1.1 mrg } 1797 1.1 mrg } 1798 1.1 mrg } 1799 1.1 mrg 1800 1.1 mrg 1801 1.1 mrg /* Expand a move instruction. Return true if all work is done. */ 1802 1.1 mrg bool 1803 1.1 mrg tilegx_expand_mov (machine_mode mode, rtx *operands) 1804 1.1 mrg { 1805 1.1 mrg /* Handle sets of MEM first. */ 1806 1.1 mrg if (MEM_P (operands[0])) 1807 1.1 mrg { 1808 1.1 mrg if (can_create_pseudo_p ()) 1809 1.1 mrg operands[0] = validize_mem (operands[0]); 1810 1.1 mrg 1811 1.1 mrg if (reg_or_0_operand (operands[1], mode)) 1812 1.1 mrg return false; 1813 1.1 mrg 1814 1.1 mrg if (!reload_in_progress) 1815 1.1 mrg operands[1] = force_reg (mode, operands[1]); 1816 1.1 mrg } 1817 1.1 mrg 1818 1.1 mrg /* Fixup TLS cases. */ 1819 1.1 mrg if (CONSTANT_P (operands[1]) && tilegx_tls_referenced_p (operands[1])) 1820 1.1 mrg { 1821 1.1 mrg operands[1] = tilegx_legitimize_tls_address (operands[1]); 1822 1.1 mrg return false; 1823 1.1 mrg } 1824 1.1 mrg 1825 1.1 mrg /* Fixup PIC cases. */ 1826 1.1 mrg if (flag_pic && CONSTANT_P (operands[1])) 1827 1.1 mrg { 1828 1.1 mrg if (tilegx_pic_address_needs_scratch (operands[1])) 1829 1.1 mrg operands[1] = tilegx_legitimize_pic_address (operands[1], mode, 0); 1830 1.1 mrg 1831 1.1 mrg if (symbolic_operand (operands[1], mode)) 1832 1.1 mrg { 1833 1.1 mrg operands[1] = tilegx_legitimize_pic_address (operands[1], 1834 1.1 mrg mode, 1835 1.1 mrg (reload_in_progress ? 1836 1.1 mrg operands[0] : 1837 1.1 mrg NULL_RTX)); 1838 1.1 mrg return false; 1839 1.1 mrg } 1840 1.1 mrg } 1841 1.1 mrg 1842 1.1 mrg /* Accept non-constants and valid constants unmodified. */ 1843 1.1 mrg if (!CONSTANT_P (operands[1]) || move_operand (operands[1], mode)) 1844 1.1 mrg return false; 1845 1.1 mrg 1846 1.1 mrg /* Split large integers. */ 1847 1.1 mrg tilegx_expand_set_const64 (operands[0], operands[1]); 1848 1.1 mrg return true; 1849 1.1 mrg } 1850 1.1 mrg 1851 1.1 mrg 1852 1.1 mrg /* Expand unaligned loads. */ 1853 1.1 mrg void 1854 1.1 mrg tilegx_expand_unaligned_load (rtx dest_reg, rtx mem, HOST_WIDE_INT bitsize, 1855 1.1 mrg HOST_WIDE_INT bit_offset, bool sign) 1856 1.1 mrg { 1857 1.1 mrg machine_mode mode; 1858 1.1 mrg rtx addr_lo, addr_hi; 1859 1.1 mrg rtx mem_lo, mem_hi, hi; 1860 1.1 mrg rtx mema, wide_result; 1861 1.1 mrg int last_byte_offset; 1862 1.1 mrg HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT; 1863 1.1 mrg 1864 1.1 mrg mode = GET_MODE (dest_reg); 1865 1.1 mrg 1866 1.1 mrg if (bitsize == 2 * BITS_PER_UNIT && (bit_offset % BITS_PER_UNIT) == 0) 1867 1.1 mrg { 1868 1.1 mrg rtx mem_left, mem_right; 1869 1.1 mrg rtx left = gen_reg_rtx (mode); 1870 1.1 mrg 1871 1.1 mrg /* When just loading a two byte value, we can load the two bytes 1872 1.1 mrg individually and combine them efficiently. */ 1873 1.1 mrg 1874 1.1 mrg mem_lo = adjust_address (mem, QImode, byte_offset); 1875 1.1 mrg mem_hi = adjust_address (mem, QImode, byte_offset + 1); 1876 1.1 mrg 1877 1.1 mrg if (BYTES_BIG_ENDIAN) 1878 1.1 mrg { 1879 1.1 mrg mem_left = mem_lo; 1880 1.1 mrg mem_right = mem_hi; 1881 1.1 mrg } 1882 1.1 mrg else 1883 1.1 mrg { 1884 1.1 mrg mem_left = mem_hi; 1885 1.1 mrg mem_right = mem_lo; 1886 1.1 mrg } 1887 1.1 mrg 1888 1.1 mrg if (sign) 1889 1.1 mrg { 1890 1.1 mrg /* Do a signed load of the second byte and use bfins to set 1891 1.1 mrg the high bits of the result. */ 1892 1.1 mrg emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, dest_reg), 1893 1.1 mrg mem_right)); 1894 1.1 mrg emit_insn (gen_extendqidi2 (gen_lowpart (DImode, left), mem_left)); 1895 1.1 mrg emit_insn (gen_insv (gen_lowpart (DImode, dest_reg), 1896 1.1 mrg GEN_INT (64 - 8), GEN_INT (8), 1897 1.1 mrg gen_lowpart (DImode, left))); 1898 1.1 mrg } 1899 1.1 mrg else 1900 1.1 mrg { 1901 1.1 mrg /* Do two unsigned loads and use v1int_l to interleave 1902 1.1 mrg them. */ 1903 1.1 mrg rtx right = gen_reg_rtx (mode); 1904 1.1 mrg emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, right), 1905 1.1 mrg mem_right)); 1906 1.1 mrg emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, left), 1907 1.1 mrg mem_left)); 1908 1.1 mrg emit_insn (gen_insn_v1int_l (gen_lowpart (DImode, dest_reg), 1909 1.1 mrg gen_lowpart (DImode, left), 1910 1.1 mrg gen_lowpart (DImode, right))); 1911 1.1 mrg } 1912 1.1 mrg 1913 1.1 mrg return; 1914 1.1 mrg } 1915 1.1 mrg 1916 1.1 mrg mema = XEXP (mem, 0); 1917 1.1 mrg 1918 1.1 mrg /* AND addresses cannot be in any alias set, since they may 1919 1.1 mrg implicitly alias surrounding code. Ideally we'd have some alias 1920 1.1 mrg set that covered all types except those with alignment 8 or 1921 1.1 mrg higher. */ 1922 1.1 mrg addr_lo = force_reg (Pmode, plus_constant (Pmode, mema, byte_offset)); 1923 1.1 mrg mem_lo = change_address (mem, mode, 1924 1.1 mrg gen_rtx_AND (GET_MODE (mema), addr_lo, 1925 1.1 mrg GEN_INT (-8))); 1926 1.1 mrg set_mem_alias_set (mem_lo, 0); 1927 1.1 mrg 1928 1.1 mrg /* Load the high word at an address that will not fault if the low 1929 1.1 mrg address is aligned and at the very end of a page. */ 1930 1.1 mrg last_byte_offset = (bit_offset + bitsize - 1) / BITS_PER_UNIT; 1931 1.1 mrg addr_hi = force_reg (Pmode, plus_constant (Pmode, mema, last_byte_offset)); 1932 1.1 mrg mem_hi = change_address (mem, mode, 1933 1.1 mrg gen_rtx_AND (GET_MODE (mema), addr_hi, 1934 1.1 mrg GEN_INT (-8))); 1935 1.1 mrg set_mem_alias_set (mem_hi, 0); 1936 1.1 mrg 1937 1.1 mrg if (bitsize == 64) 1938 1.1 mrg { 1939 1.1 mrg addr_lo = make_safe_from (addr_lo, dest_reg); 1940 1.1 mrg wide_result = dest_reg; 1941 1.1 mrg } 1942 1.1 mrg else 1943 1.1 mrg { 1944 1.1 mrg wide_result = gen_reg_rtx (mode); 1945 1.1 mrg } 1946 1.1 mrg 1947 1.1 mrg /* Load hi first in case dest_reg is used in mema. */ 1948 1.1 mrg hi = gen_reg_rtx (mode); 1949 1.1 mrg emit_move_insn (hi, mem_hi); 1950 1.1 mrg emit_move_insn (wide_result, mem_lo); 1951 1.1 mrg 1952 1.1 mrg emit_insn (gen_insn_dblalign (gen_lowpart (DImode, wide_result), 1953 1.1 mrg gen_lowpart (DImode, wide_result), 1954 1.1 mrg gen_lowpart (DImode, hi), addr_lo)); 1955 1.1 mrg 1956 1.1 mrg if (bitsize != 64) 1957 1.1 mrg { 1958 1.1 mrg rtx extracted = 1959 1.1 mrg extract_bit_field (gen_lowpart (DImode, wide_result), 1960 1.1 mrg bitsize, bit_offset % BITS_PER_UNIT, 1961 1.1 mrg !sign, gen_lowpart (DImode, dest_reg), 1962 1.1 mrg DImode, DImode, false, NULL); 1963 1.1 mrg 1964 1.1 mrg if (extracted != dest_reg) 1965 1.1 mrg emit_move_insn (dest_reg, gen_lowpart (DImode, extracted)); 1966 1.1 mrg } 1967 1.1 mrg } 1968 1.1 mrg 1969 1.1 mrg 1970 1.1 mrg /* Expand unaligned stores. */ 1971 1.1 mrg static void 1972 1.1 mrg tilegx_expand_unaligned_store (rtx mem, rtx src, HOST_WIDE_INT bitsize, 1973 1.1 mrg HOST_WIDE_INT bit_offset) 1974 1.1 mrg { 1975 1.1 mrg HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT; 1976 1.1 mrg HOST_WIDE_INT bytesize = bitsize / BITS_PER_UNIT; 1977 1.1 mrg HOST_WIDE_INT shift_init, shift_increment, shift_amt; 1978 1.1 mrg HOST_WIDE_INT i; 1979 1.1 mrg rtx mem_addr; 1980 1.1 mrg rtx store_val; 1981 1.1 mrg 1982 1.1 mrg shift_init = BYTES_BIG_ENDIAN ? (bitsize - BITS_PER_UNIT) : 0; 1983 1.1 mrg shift_increment = BYTES_BIG_ENDIAN ? -BITS_PER_UNIT : BITS_PER_UNIT; 1984 1.1 mrg 1985 1.1 mrg for (i = 0, shift_amt = shift_init; 1986 1.1 mrg i < bytesize; 1987 1.1 mrg i++, shift_amt += shift_increment) 1988 1.1 mrg { 1989 1.1 mrg mem_addr = adjust_address (mem, QImode, byte_offset + i); 1990 1.1 mrg 1991 1.1 mrg if (shift_amt) 1992 1.1 mrg { 1993 1.1 mrg store_val = expand_simple_binop (DImode, LSHIFTRT, 1994 1.1 mrg gen_lowpart (DImode, src), 1995 1.1 mrg GEN_INT (shift_amt), NULL, 1, 1996 1.1 mrg OPTAB_LIB_WIDEN); 1997 1.1 mrg store_val = gen_lowpart (QImode, store_val); 1998 1.1 mrg } 1999 1.1 mrg else 2000 1.1 mrg { 2001 1.1 mrg store_val = gen_lowpart (QImode, src); 2002 1.1 mrg } 2003 1.1 mrg 2004 1.1 mrg emit_move_insn (mem_addr, store_val); 2005 1.1 mrg } 2006 1.1 mrg } 2007 1.1 mrg 2008 1.1 mrg 2009 1.1 mrg /* Implement the movmisalign patterns. One of the operands is a 2010 1.1 mrg memory that is not naturally aligned. Emit instructions to load 2011 1.1 mrg it. */ 2012 1.1 mrg void 2013 1.1 mrg tilegx_expand_movmisalign (machine_mode mode, rtx *operands) 2014 1.1 mrg { 2015 1.1 mrg if (MEM_P (operands[1])) 2016 1.1 mrg { 2017 1.1 mrg rtx tmp; 2018 1.1 mrg 2019 1.1 mrg if (register_operand (operands[0], mode)) 2020 1.1 mrg tmp = operands[0]; 2021 1.1 mrg else 2022 1.1 mrg tmp = gen_reg_rtx (mode); 2023 1.1 mrg 2024 1.1 mrg tilegx_expand_unaligned_load (tmp, operands[1], GET_MODE_BITSIZE (mode), 2025 1.1 mrg 0, true); 2026 1.1 mrg 2027 1.1 mrg if (tmp != operands[0]) 2028 1.1 mrg emit_move_insn (operands[0], tmp); 2029 1.1 mrg } 2030 1.1 mrg else if (MEM_P (operands[0])) 2031 1.1 mrg { 2032 1.1 mrg if (!reg_or_0_operand (operands[1], mode)) 2033 1.1 mrg operands[1] = force_reg (mode, operands[1]); 2034 1.1 mrg 2035 1.1 mrg tilegx_expand_unaligned_store (operands[0], operands[1], 2036 1.1 mrg GET_MODE_BITSIZE (mode), 0); 2037 1.1 mrg } 2038 1.1 mrg else 2039 1.1 mrg gcc_unreachable (); 2040 1.1 mrg 2041 1.1 mrg } 2042 1.1 mrg 2043 1.1 mrg 2044 1.1 mrg /* Implement the allocate_stack pattern (alloca). */ 2045 1.1 mrg void 2046 1.1 mrg tilegx_allocate_stack (rtx op0, rtx op1) 2047 1.1 mrg { 2048 1.1 mrg /* Technically the correct way to initialize chain_loc is with 2049 1.1 mrg * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem() 2050 1.1 mrg * sets the alias_set to that of a frame reference. Some of our 2051 1.1 mrg * tests rely on some unsafe assumption about when the chaining 2052 1.1 mrg * update is done, we need to be conservative about reordering the 2053 1.1 mrg * chaining instructions. 2054 1.1 mrg */ 2055 1.1 mrg rtx fp_addr = gen_reg_rtx (Pmode); 2056 1.1 mrg rtx fp_value = gen_reg_rtx (Pmode); 2057 1.1 mrg rtx fp_loc; 2058 1.1 mrg 2059 1.1 mrg emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx, 2060 1.1 mrg GEN_INT (UNITS_PER_WORD))); 2061 1.1 mrg 2062 1.1 mrg fp_loc = gen_frame_mem (Pmode, fp_addr); 2063 1.1 mrg 2064 1.1 mrg emit_move_insn (fp_value, fp_loc); 2065 1.1 mrg 2066 1.1 mrg op1 = force_reg (Pmode, op1); 2067 1.1 mrg 2068 1.1 mrg emit_move_insn (stack_pointer_rtx, 2069 1.1 mrg gen_rtx_MINUS (Pmode, stack_pointer_rtx, op1)); 2070 1.1 mrg 2071 1.1 mrg emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx, 2072 1.1 mrg GEN_INT (UNITS_PER_WORD))); 2073 1.1 mrg 2074 1.1 mrg fp_loc = gen_frame_mem (Pmode, fp_addr); 2075 1.1 mrg 2076 1.1 mrg emit_move_insn (fp_loc, fp_value); 2077 1.1 mrg 2078 1.1 mrg emit_move_insn (op0, virtual_stack_dynamic_rtx); 2079 1.1 mrg } 2080 1.1 mrg 2081 1.1 mrg 2083 1.1 mrg 2084 1.1 mrg /* Multiplies */ 2085 1.1 mrg 2086 1.1 mrg 2087 1.1 mrg /* Returns the insn_code in ENTRY. */ 2088 1.1 mrg static enum insn_code 2089 1.1 mrg tilegx_multiply_get_opcode (const struct tilegx_multiply_insn_seq_entry 2090 1.1 mrg *entry) 2091 1.1 mrg { 2092 1.1 mrg return tilegx_multiply_insn_seq_decode_opcode[entry->compressed_opcode]; 2093 1.1 mrg } 2094 1.1 mrg 2095 1.1 mrg 2096 1.1 mrg /* Returns the length of the 'op' array. */ 2097 1.1 mrg static int 2098 1.1 mrg tilegx_multiply_get_num_ops (const struct tilegx_multiply_insn_seq *seq) 2099 1.1 mrg { 2100 1.1 mrg /* The array either uses all of its allocated slots or is terminated 2101 1.1 mrg by a bogus opcode. Either way, the array size is the index of the 2102 1.1 mrg last valid opcode plus one. */ 2103 1.1 mrg int i; 2104 1.1 mrg for (i = tilegx_multiply_insn_seq_MAX_OPERATIONS - 1; i >= 0; i--) 2105 1.1 mrg if (tilegx_multiply_get_opcode (&seq->op[i]) != CODE_FOR_nothing) 2106 1.1 mrg return i + 1; 2107 1.1 mrg 2108 1.1 mrg /* An empty array is not allowed. */ 2109 1.1 mrg gcc_unreachable (); 2110 1.1 mrg } 2111 1.1 mrg 2112 1.1 mrg 2113 1.1 mrg /* We precompute a number of expression trees for multiplying by 2114 1.1 mrg constants. This generates code for such an expression tree by 2115 1.1 mrg walking through the nodes in the tree (which are conveniently 2116 1.1 mrg pre-linearized) and emitting an instruction for each one. */ 2117 1.1 mrg static void 2118 1.1 mrg tilegx_expand_constant_multiply_given_sequence (rtx result, rtx src, 2119 1.1 mrg const struct 2120 1.1 mrg tilegx_multiply_insn_seq *seq) 2121 1.1 mrg { 2122 1.1 mrg int i; 2123 1.1 mrg int num_ops; 2124 1.1 mrg 2125 1.1 mrg /* Keep track of the subexpressions computed so far, so later 2126 1.1 mrg instructions can refer to them. We seed the array with zero and 2127 1.1 mrg the value being multiplied. */ 2128 1.1 mrg int num_subexprs = 2; 2129 1.1 mrg rtx subexprs[tilegx_multiply_insn_seq_MAX_OPERATIONS + 2]; 2130 1.1 mrg subexprs[0] = const0_rtx; 2131 1.1 mrg subexprs[1] = src; 2132 1.1 mrg 2133 1.1 mrg /* Determine how many instructions we are going to generate. */ 2134 1.1 mrg num_ops = tilegx_multiply_get_num_ops (seq); 2135 1.1 mrg gcc_assert (num_ops > 0 2136 1.1 mrg && num_ops <= tilegx_multiply_insn_seq_MAX_OPERATIONS); 2137 1.1 mrg 2138 1.1 mrg for (i = 0; i < num_ops; i++) 2139 1.1 mrg { 2140 1.1 mrg const struct tilegx_multiply_insn_seq_entry *entry = &seq->op[i]; 2141 1.1 mrg 2142 1.1 mrg /* Figure out where to store the output of this instruction. */ 2143 1.1 mrg const bool is_last_op = (i + 1 == num_ops); 2144 1.1 mrg rtx out = is_last_op ? result : gen_reg_rtx (DImode); 2145 1.1 mrg 2146 1.1 mrg enum insn_code opcode = tilegx_multiply_get_opcode (entry); 2147 1.1 mrg if (opcode == CODE_FOR_ashldi3) 2148 1.1 mrg { 2149 1.1 mrg /* Handle shift by immediate. This is a special case because 2150 1.1 mrg the meaning of the second operand is a constant shift 2151 1.1 mrg count rather than an operand index. */ 2152 1.1 mrg 2153 1.1 mrg /* Make sure the shift count is in range. Zero should not 2154 1.1 mrg happen. */ 2155 1.1 mrg const int shift_count = entry->rhs; 2156 1.1 mrg gcc_assert (shift_count > 0 && shift_count < 64); 2157 1.1 mrg 2158 1.1 mrg /* Emit the actual instruction. */ 2159 1.1 mrg emit_insn (GEN_FCN (opcode) 2160 1.1 mrg (out, subexprs[entry->lhs], 2161 1.1 mrg gen_rtx_CONST_INT (DImode, shift_count))); 2162 1.1 mrg } 2163 1.1 mrg else 2164 1.1 mrg { 2165 1.1 mrg /* Handle a normal two-operand instruction, such as add or 2166 1.1 mrg shl1add. */ 2167 1.1 mrg 2168 1.1 mrg /* Make sure we are referring to a previously computed 2169 1.1 mrg subexpression. */ 2170 1.1 mrg gcc_assert (entry->rhs < num_subexprs); 2171 1.1 mrg 2172 1.1 mrg /* Emit the actual instruction. */ 2173 1.1 mrg emit_insn (GEN_FCN (opcode) 2174 1.1 mrg (out, subexprs[entry->lhs], subexprs[entry->rhs])); 2175 1.1 mrg } 2176 1.1 mrg 2177 1.1 mrg /* Record this subexpression for use by later expressions. */ 2178 1.1 mrg subexprs[num_subexprs++] = out; 2179 1.1 mrg } 2180 1.1 mrg } 2181 1.1 mrg 2182 1.1 mrg 2183 1.1 mrg /* bsearch helper function. */ 2184 1.1 mrg static int 2185 1.1 mrg tilegx_compare_multipliers (const void *key, const void *t) 2186 1.1 mrg { 2187 1.1 mrg long long delta = 2188 1.1 mrg (*(const long long *) key 2189 1.1 mrg - ((const struct tilegx_multiply_insn_seq *) t)->multiplier); 2190 1.1 mrg return (delta < 0) ? -1 : (delta > 0); 2191 1.1 mrg } 2192 1.1 mrg 2193 1.1 mrg 2194 1.1 mrg /* Returns the tilegx_multiply_insn_seq for multiplier, or NULL if none 2195 1.1 mrg exists. */ 2196 1.1 mrg static const struct tilegx_multiply_insn_seq * 2197 1.1 mrg tilegx_find_multiply_insn_seq_for_constant (long long multiplier) 2198 1.1 mrg { 2199 1.1 mrg return ((const struct tilegx_multiply_insn_seq *) 2200 1.1 mrg bsearch (&multiplier, tilegx_multiply_insn_seq_table, 2201 1.1 mrg tilegx_multiply_insn_seq_table_size, 2202 1.1 mrg sizeof tilegx_multiply_insn_seq_table[0], 2203 1.1 mrg tilegx_compare_multipliers)); 2204 1.1 mrg } 2205 1.1 mrg 2206 1.1 mrg 2207 1.1 mrg /* Try to a expand constant multiply in DImode by looking it up in a 2208 1.1 mrg precompiled table. OP0 is the result operand, OP1 is the source 2209 1.1 mrg operand, and MULTIPLIER is the value of the constant. Return true 2210 1.1 mrg if it succeeds. */ 2211 1.1 mrg static bool 2212 1.1 mrg tilegx_expand_const_muldi (rtx op0, rtx op1, long long multiplier) 2213 1.1 mrg { 2214 1.1 mrg /* See if we have precomputed an efficient way to multiply by this 2215 1.1 mrg constant. */ 2216 1.1 mrg const struct tilegx_multiply_insn_seq *seq = 2217 1.1 mrg tilegx_find_multiply_insn_seq_for_constant (multiplier); 2218 1.1 mrg if (seq != NULL) 2219 1.1 mrg { 2220 1.1 mrg tilegx_expand_constant_multiply_given_sequence (op0, op1, seq); 2221 1.1 mrg return true; 2222 1.1 mrg } 2223 1.1 mrg else 2224 1.1 mrg return false; 2225 1.1 mrg } 2226 1.1 mrg 2227 1.1 mrg 2228 1.1 mrg /* Expand the muldi pattern. */ 2229 1.1 mrg bool 2230 1.1 mrg tilegx_expand_muldi (rtx op0, rtx op1, rtx op2) 2231 1.1 mrg { 2232 1.1 mrg if (CONST_INT_P (op2)) 2233 1.1 mrg { 2234 1.1 mrg HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op2), DImode); 2235 1.1 mrg return tilegx_expand_const_muldi (op0, op1, n); 2236 1.1 mrg } 2237 1.1 mrg return false; 2238 1.1 mrg } 2239 1.1 mrg 2240 1.1 mrg 2241 1.1 mrg /* Expand a high multiply pattern in DImode. RESULT, OP1, OP2 are the 2242 1.1 mrg operands, and SIGN is true if it's a signed multiply, and false if 2243 1.1 mrg it's an unsigned multiply. */ 2244 1.1 mrg static void 2245 1.1 mrg tilegx_expand_high_multiply (rtx result, rtx op1, rtx op2, bool sign) 2246 1.1 mrg { 2247 1.1 mrg rtx tmp0 = gen_reg_rtx (DImode); 2248 1.1 mrg rtx tmp1 = gen_reg_rtx (DImode); 2249 1.1 mrg rtx tmp2 = gen_reg_rtx (DImode); 2250 1.1 mrg rtx tmp3 = gen_reg_rtx (DImode); 2251 1.1 mrg rtx tmp4 = gen_reg_rtx (DImode); 2252 1.1 mrg rtx tmp5 = gen_reg_rtx (DImode); 2253 1.1 mrg rtx tmp6 = gen_reg_rtx (DImode); 2254 1.1 mrg rtx tmp7 = gen_reg_rtx (DImode); 2255 1.1 mrg rtx tmp8 = gen_reg_rtx (DImode); 2256 1.1 mrg rtx tmp9 = gen_reg_rtx (DImode); 2257 1.1 mrg rtx tmp10 = gen_reg_rtx (DImode); 2258 1.1 mrg rtx tmp11 = gen_reg_rtx (DImode); 2259 1.1 mrg rtx tmp12 = gen_reg_rtx (DImode); 2260 1.1 mrg rtx tmp13 = gen_reg_rtx (DImode); 2261 1.1 mrg rtx result_lo = gen_reg_rtx (DImode); 2262 1.1 mrg 2263 1.1 mrg if (sign) 2264 1.1 mrg { 2265 1.1 mrg emit_insn (gen_insn_mul_hs_lu (tmp0, op1, op2)); 2266 1.1 mrg emit_insn (gen_insn_mul_hs_lu (tmp1, op2, op1)); 2267 1.1 mrg emit_insn (gen_insn_mul_lu_lu (tmp2, op1, op2)); 2268 1.1 mrg emit_insn (gen_insn_mul_hs_hs (tmp3, op1, op2)); 2269 1.1 mrg } 2270 1.1 mrg else 2271 1.1 mrg { 2272 1.1 mrg emit_insn (gen_insn_mul_hu_lu (tmp0, op1, op2)); 2273 1.1 mrg emit_insn (gen_insn_mul_hu_lu (tmp1, op2, op1)); 2274 1.1 mrg emit_insn (gen_insn_mul_lu_lu (tmp2, op1, op2)); 2275 1.1 mrg emit_insn (gen_insn_mul_hu_hu (tmp3, op1, op2)); 2276 1.1 mrg } 2277 1.1 mrg 2278 1.1 mrg emit_move_insn (tmp4, (gen_rtx_ASHIFT (DImode, tmp0, GEN_INT (32)))); 2279 1.1 mrg 2280 1.1 mrg emit_move_insn (tmp5, (gen_rtx_ASHIFT (DImode, tmp1, GEN_INT (32)))); 2281 1.1 mrg 2282 1.1 mrg emit_move_insn (tmp6, (gen_rtx_PLUS (DImode, tmp4, tmp5))); 2283 1.1 mrg emit_move_insn (result_lo, (gen_rtx_PLUS (DImode, tmp2, tmp6))); 2284 1.1 mrg 2285 1.1 mrg emit_move_insn (tmp7, gen_rtx_LTU (DImode, tmp6, tmp4)); 2286 1.1 mrg emit_move_insn (tmp8, gen_rtx_LTU (DImode, result_lo, tmp2)); 2287 1.1 mrg 2288 1.1 mrg if (sign) 2289 1.1 mrg { 2290 1.1 mrg emit_move_insn (tmp9, (gen_rtx_ASHIFTRT (DImode, tmp0, GEN_INT (32)))); 2291 1.1 mrg emit_move_insn (tmp10, (gen_rtx_ASHIFTRT (DImode, tmp1, GEN_INT (32)))); 2292 1.1 mrg } 2293 1.1 mrg else 2294 1.1 mrg { 2295 1.1 mrg emit_move_insn (tmp9, (gen_rtx_LSHIFTRT (DImode, tmp0, GEN_INT (32)))); 2296 1.1 mrg emit_move_insn (tmp10, (gen_rtx_LSHIFTRT (DImode, tmp1, GEN_INT (32)))); 2297 1.1 mrg } 2298 1.1 mrg 2299 1.1 mrg emit_move_insn (tmp11, (gen_rtx_PLUS (DImode, tmp3, tmp7))); 2300 1.1 mrg emit_move_insn (tmp12, (gen_rtx_PLUS (DImode, tmp8, tmp9))); 2301 1.1 mrg emit_move_insn (tmp13, (gen_rtx_PLUS (DImode, tmp11, tmp12))); 2302 1.1 mrg emit_move_insn (result, (gen_rtx_PLUS (DImode, tmp13, tmp10))); 2303 1.1 mrg } 2304 1.1 mrg 2305 1.1 mrg 2306 1.1 mrg /* Implement smuldi3_highpart. */ 2307 1.1 mrg void 2308 1.1 mrg tilegx_expand_smuldi3_highpart (rtx op0, rtx op1, rtx op2) 2309 1.1 mrg { 2310 1.1 mrg tilegx_expand_high_multiply (op0, op1, op2, true); 2311 1.1 mrg } 2312 1.1 mrg 2313 1.1 mrg 2314 1.1 mrg /* Implement umuldi3_highpart. */ 2315 1.1 mrg void 2316 1.1 mrg tilegx_expand_umuldi3_highpart (rtx op0, rtx op1, rtx op2) 2317 1.1 mrg { 2318 1.1 mrg tilegx_expand_high_multiply (op0, op1, op2, false); 2319 1.1 mrg } 2320 1.1 mrg 2321 1.1 mrg 2323 1.1 mrg 2324 1.1 mrg /* Compare and branches */ 2325 1.1 mrg 2326 1.1 mrg /* Produce the rtx yielding a bool for a floating point 2327 1.1 mrg comparison. */ 2328 1.1 mrg static bool 2329 1.1 mrg tilegx_emit_fp_setcc (rtx res, enum rtx_code code, machine_mode mode, 2330 1.1 mrg rtx op0, rtx op1) 2331 1.1 mrg { 2332 1.1 mrg /* TODO: Certain compares again constants can be done using entirely 2333 1.1 mrg integer operations. But you have to get the special cases right 2334 1.1 mrg e.g. NaN, +0 == -0, etc. */ 2335 1.1 mrg 2336 1.1 mrg rtx flags; 2337 1.1 mrg int flag_index; 2338 1.1 mrg rtx a = force_reg (DImode, gen_lowpart (DImode, op0)); 2339 1.1 mrg rtx b = force_reg (DImode, gen_lowpart (DImode, op1)); 2340 1.1 mrg 2341 1.1 mrg flags = gen_reg_rtx (DImode); 2342 1.1 mrg 2343 1.1 mrg if (mode == SFmode) 2344 1.1 mrg { 2345 1.1 mrg emit_insn (gen_insn_fsingle_add1 (flags, a, b)); 2346 1.1 mrg } 2347 1.1 mrg else 2348 1.1 mrg { 2349 1.1 mrg gcc_assert (mode == DFmode); 2350 1.1 mrg emit_insn (gen_insn_fdouble_add_flags (flags, a, b)); 2351 1.1 mrg } 2352 1.1 mrg 2353 1.1 mrg switch (code) 2354 1.1 mrg { 2355 1.1 mrg case EQ: flag_index = 30; break; 2356 1.1 mrg case NE: flag_index = 31; break; 2357 1.1 mrg case LE: flag_index = 27; break; 2358 1.1 mrg case LT: flag_index = 26; break; 2359 1.1 mrg case GE: flag_index = 29; break; 2360 1.1 mrg case GT: flag_index = 28; break; 2361 1.1 mrg default: gcc_unreachable (); 2362 1.1 mrg } 2363 1.1 mrg 2364 1.1 mrg gcc_assert (GET_MODE (res) == DImode); 2365 1.1 mrg emit_move_insn (res, gen_rtx_ZERO_EXTRACT (DImode, flags, GEN_INT (1), 2366 1.1 mrg GEN_INT (flag_index))); 2367 1.1 mrg return true; 2368 1.1 mrg } 2369 1.1 mrg 2370 1.1 mrg 2371 1.1 mrg /* Certain simplifications can be done to make invalid setcc 2372 1.1 mrg operations valid. Return the final comparison, or NULL if we can't 2373 1.1 mrg work. */ 2374 1.1 mrg static bool 2375 1.1 mrg tilegx_emit_setcc_internal (rtx res, enum rtx_code code, rtx op0, rtx op1, 2376 1.1 mrg machine_mode cmp_mode) 2377 1.1 mrg { 2378 1.1 mrg rtx tmp; 2379 1.1 mrg bool swap = false; 2380 1.1 mrg 2381 1.1 mrg if (cmp_mode == SFmode || cmp_mode == DFmode) 2382 1.1 mrg return tilegx_emit_fp_setcc (res, code, cmp_mode, op0, op1); 2383 1.1 mrg 2384 1.1 mrg /* The general case: fold the comparison code to the types of 2385 1.1 mrg compares that we have, choosing the branch as necessary. */ 2386 1.1 mrg 2387 1.1 mrg switch (code) 2388 1.1 mrg { 2389 1.1 mrg case EQ: 2390 1.1 mrg case NE: 2391 1.1 mrg case LE: 2392 1.1 mrg case LT: 2393 1.1 mrg case LEU: 2394 1.1 mrg case LTU: 2395 1.1 mrg /* We have these compares. */ 2396 1.1 mrg break; 2397 1.1 mrg 2398 1.1 mrg case GE: 2399 1.1 mrg case GT: 2400 1.1 mrg case GEU: 2401 1.1 mrg case GTU: 2402 1.1 mrg /* We do not have these compares, so we reverse the 2403 1.1 mrg operands. */ 2404 1.1 mrg swap = true; 2405 1.1 mrg break; 2406 1.1 mrg 2407 1.1 mrg default: 2408 1.1 mrg /* We should not have called this with any other code. */ 2409 1.1 mrg gcc_unreachable (); 2410 1.1 mrg } 2411 1.1 mrg 2412 1.1 mrg if (swap) 2413 1.1 mrg { 2414 1.1 mrg code = swap_condition (code); 2415 1.1 mrg tmp = op0, op0 = op1, op1 = tmp; 2416 1.1 mrg } 2417 1.1 mrg 2418 1.1 mrg if (!reg_or_0_operand (op0, cmp_mode)) 2419 1.1 mrg op0 = force_reg (cmp_mode, op0); 2420 1.1 mrg 2421 1.1 mrg if (!CONST_INT_P (op1) && !register_operand (op1, cmp_mode)) 2422 1.1 mrg op1 = force_reg (cmp_mode, op1); 2423 1.1 mrg 2424 1.1 mrg /* Return the setcc comparison. */ 2425 1.1 mrg emit_insn (gen_rtx_SET (res, gen_rtx_fmt_ee (code, DImode, op0, op1))); 2426 1.1 mrg 2427 1.1 mrg return true; 2428 1.1 mrg } 2429 1.1 mrg 2430 1.1 mrg 2431 1.1 mrg /* Implement cstore patterns. */ 2432 1.1 mrg bool 2433 1.1 mrg tilegx_emit_setcc (rtx operands[], machine_mode cmp_mode) 2434 1.1 mrg { 2435 1.1 mrg return 2436 1.1 mrg tilegx_emit_setcc_internal (operands[0], GET_CODE (operands[1]), 2437 1.1 mrg operands[2], operands[3], cmp_mode); 2438 1.1 mrg } 2439 1.1 mrg 2440 1.1 mrg 2441 1.1 mrg /* Return whether CODE is a signed comparison. */ 2442 1.1 mrg static bool 2443 1.1 mrg signed_compare_p (enum rtx_code code) 2444 1.1 mrg { 2445 1.1 mrg return (code == EQ || code == NE || code == LT || code == LE 2446 1.1 mrg || code == GT || code == GE); 2447 1.1 mrg } 2448 1.1 mrg 2449 1.1 mrg 2450 1.1 mrg /* Generate the comparison for a DImode conditional branch. */ 2451 1.1 mrg static rtx 2452 1.1 mrg tilegx_emit_cc_test (enum rtx_code code, rtx op0, rtx op1, 2453 1.1 mrg machine_mode cmp_mode, bool eq_ne_only) 2454 1.1 mrg { 2455 1.1 mrg enum rtx_code branch_code; 2456 1.1 mrg rtx temp; 2457 1.1 mrg 2458 1.1 mrg if (cmp_mode == SFmode || cmp_mode == DFmode) 2459 1.1 mrg { 2460 1.1 mrg /* Compute a boolean saying whether the comparison is true. */ 2461 1.1 mrg temp = gen_reg_rtx (DImode); 2462 1.1 mrg tilegx_emit_setcc_internal (temp, code, op0, op1, cmp_mode); 2463 1.1 mrg 2464 1.1 mrg /* Test that flag. */ 2465 1.1 mrg return gen_rtx_fmt_ee (NE, VOIDmode, temp, const0_rtx); 2466 1.1 mrg } 2467 1.1 mrg 2468 1.1 mrg /* Check for a compare against zero using a comparison we can do 2469 1.1 mrg directly. */ 2470 1.1 mrg if (op1 == const0_rtx 2471 1.1 mrg && (code == EQ || code == NE 2472 1.1 mrg || (!eq_ne_only && signed_compare_p (code)))) 2473 1.1 mrg { 2474 1.1 mrg op0 = force_reg (cmp_mode, op0); 2475 1.1 mrg return gen_rtx_fmt_ee (code, VOIDmode, op0, const0_rtx); 2476 1.1 mrg } 2477 1.1 mrg 2478 1.1 mrg /* The general case: fold the comparison code to the types of 2479 1.1 mrg compares that we have, choosing the branch as necessary. */ 2480 1.1 mrg switch (code) 2481 1.1 mrg { 2482 1.1 mrg case EQ: 2483 1.1 mrg case LE: 2484 1.1 mrg case LT: 2485 1.1 mrg case LEU: 2486 1.1 mrg case LTU: 2487 1.1 mrg /* We have these compares. */ 2488 1.1 mrg branch_code = NE; 2489 1.1 mrg break; 2490 1.1 mrg 2491 1.1 mrg case NE: 2492 1.1 mrg case GE: 2493 1.1 mrg case GT: 2494 1.1 mrg case GEU: 2495 1.1 mrg case GTU: 2496 1.1 mrg /* These must be reversed (except NE, but let's 2497 1.1 mrg canonicalize). */ 2498 1.1 mrg code = reverse_condition (code); 2499 1.1 mrg branch_code = EQ; 2500 1.1 mrg break; 2501 1.1 mrg 2502 1.1 mrg default: 2503 1.1 mrg gcc_unreachable (); 2504 1.1 mrg } 2505 1.1 mrg 2506 1.1 mrg if (CONST_INT_P (op1) && (!satisfies_constraint_I (op1) || code == LEU)) 2507 1.1 mrg { 2508 1.1 mrg HOST_WIDE_INT n = INTVAL (op1); 2509 1.1 mrg 2510 1.1 mrg switch (code) 2511 1.1 mrg { 2512 1.1 mrg case EQ: 2513 1.1 mrg /* Subtract off the value we want to compare against and see 2514 1.1 mrg if we get zero. This is cheaper than creating a constant 2515 1.1 mrg in a register. Except that subtracting -128 is more 2516 1.1 mrg expensive than seqi to -128, so we leave that alone. */ 2517 1.1 mrg /* ??? Don't do this when comparing against symbols, 2518 1.1 mrg otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 == 2519 1.1 mrg 0), which will be declared false out of hand (at least 2520 1.1 mrg for non-weak). */ 2521 1.1 mrg if (n != -128 2522 1.1 mrg && add_operand (GEN_INT (-n), DImode) 2523 1.1 mrg && !(symbolic_operand (op0, VOIDmode) 2524 1.1 mrg || (REG_P (op0) && REG_POINTER (op0)))) 2525 1.1 mrg { 2526 1.1 mrg /* TODO: Use a SIMD add immediate to hit zero for tiled 2527 1.1 mrg constants in a single instruction. */ 2528 1.1 mrg if (GET_MODE (op0) != DImode) 2529 1.1 mrg { 2530 1.1 mrg /* Convert to DImode so we can use addli. Note that 2531 1.1 mrg this will not actually generate any code because 2532 1.1 mrg sign extension from SI -> DI is a no-op. I don't 2533 1.1 mrg know if it's safe just to make a paradoxical 2534 1.1 mrg subreg here though. */ 2535 1.1 mrg rtx temp2 = gen_reg_rtx (DImode); 2536 1.1 mrg emit_insn (gen_extendsidi2 (temp2, op0)); 2537 1.1 mrg op0 = temp2; 2538 1.1 mrg } 2539 1.1 mrg else 2540 1.1 mrg { 2541 1.1 mrg op0 = force_reg (DImode, op0); 2542 1.1 mrg } 2543 1.1 mrg temp = gen_reg_rtx (DImode); 2544 1.1 mrg emit_move_insn (temp, gen_rtx_PLUS (DImode, op0, GEN_INT (-n))); 2545 1.1 mrg return gen_rtx_fmt_ee (reverse_condition (branch_code), 2546 1.1 mrg VOIDmode, temp, const0_rtx); 2547 1.1 mrg } 2548 1.1 mrg break; 2549 1.1 mrg 2550 1.1 mrg case LEU: 2551 1.1 mrg if (n == -1) 2552 1.1 mrg break; 2553 1.1 mrg /* FALLTHRU */ 2554 1.1 mrg 2555 1.1 mrg case LTU: 2556 1.1 mrg /* Change ((unsigned)x < 0x1000) into !((int)x >> 12), etc. 2557 1.1 mrg We use arithmetic shift right because it's a 3-wide op, 2558 1.1 mrg while logical shift right is not. */ 2559 1.1 mrg { 2560 1.1 mrg int first = exact_log2 (code == LTU ? n : n + 1); 2561 1.1 mrg if (first != -1) 2562 1.1 mrg { 2563 1.1 mrg op0 = force_reg (cmp_mode, op0); 2564 1.1 mrg temp = gen_reg_rtx (cmp_mode); 2565 1.1 mrg emit_move_insn (temp, 2566 1.1 mrg gen_rtx_ASHIFTRT (cmp_mode, op0, 2567 1.1 mrg GEN_INT (first))); 2568 1.1 mrg return gen_rtx_fmt_ee (reverse_condition (branch_code), 2569 1.1 mrg VOIDmode, temp, const0_rtx); 2570 1.1 mrg } 2571 1.1 mrg } 2572 1.1 mrg break; 2573 1.1 mrg 2574 1.1 mrg default: 2575 1.1 mrg break; 2576 1.1 mrg } 2577 1.1 mrg } 2578 1.1 mrg 2579 1.1 mrg /* Compute a flag saying whether we should branch. */ 2580 1.1 mrg temp = gen_reg_rtx (DImode); 2581 1.1 mrg tilegx_emit_setcc_internal (temp, code, op0, op1, cmp_mode); 2582 1.1 mrg 2583 1.1 mrg /* Return the branch comparison. */ 2584 1.1 mrg return gen_rtx_fmt_ee (branch_code, VOIDmode, temp, const0_rtx); 2585 1.1 mrg } 2586 1.1 mrg 2587 1.1 mrg 2588 1.1 mrg /* Generate the comparison for a conditional branch. */ 2589 1.1 mrg void 2590 1.1 mrg tilegx_emit_conditional_branch (rtx operands[], machine_mode cmp_mode) 2591 1.1 mrg { 2592 1.1 mrg rtx cmp_rtx = 2593 1.1 mrg tilegx_emit_cc_test (GET_CODE (operands[0]), operands[1], operands[2], 2594 1.1 mrg cmp_mode, false); 2595 1.1 mrg rtx branch_rtx = gen_rtx_SET (pc_rtx, 2596 1.1 mrg gen_rtx_IF_THEN_ELSE (VOIDmode, cmp_rtx, 2597 1.1 mrg gen_rtx_LABEL_REF 2598 1.1 mrg (VOIDmode, 2599 1.1 mrg operands[3]), 2600 1.1 mrg pc_rtx)); 2601 1.1 mrg emit_jump_insn (branch_rtx); 2602 1.1 mrg } 2603 1.1 mrg 2604 1.1 mrg 2605 1.1 mrg /* Implement the mov<mode>cc pattern. */ 2606 1.1 mrg rtx 2607 1.1 mrg tilegx_emit_conditional_move (rtx cmp) 2608 1.1 mrg { 2609 1.1 mrg return 2610 1.1 mrg tilegx_emit_cc_test (GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1), 2611 1.1 mrg GET_MODE (XEXP (cmp, 0)), true); 2612 1.1 mrg } 2613 1.1 mrg 2614 1.1 mrg 2615 1.1 mrg /* Return true if INSN is annotated with a REG_BR_PROB note that 2616 1.1 mrg indicates it's a branch that's predicted taken. */ 2617 1.1 mrg static bool 2618 1.1 mrg cbranch_predicted_p (rtx_insn *insn) 2619 1.1 mrg { 2620 1.1 mrg rtx x = find_reg_note (insn, REG_BR_PROB, 0); 2621 1.1 mrg 2622 1.1 mrg if (x) 2623 1.1 mrg { 2624 1.1 mrg return profile_probability::from_reg_br_prob_note (XINT (x, 0)) 2625 1.1 mrg >= profile_probability::even (); 2626 1.1 mrg } 2627 1.1 mrg 2628 1.1 mrg return false; 2629 1.1 mrg } 2630 1.1 mrg 2631 1.1 mrg 2632 1.1 mrg /* Output assembly code for a specific branch instruction, appending 2633 1.1 mrg the branch prediction flag to the opcode if appropriate. */ 2634 1.1 mrg static const char * 2635 1.1 mrg tilegx_output_simple_cbranch_with_opcode (rtx_insn *insn, const char *opcode, 2636 1.1 mrg int regop, bool reverse_predicted) 2637 1.1 mrg { 2638 1.1 mrg static char buf[64]; 2639 1.1 mrg sprintf (buf, "%s%s\t%%r%d, %%l0", opcode, 2640 1.1 mrg (cbranch_predicted_p (insn) ^ reverse_predicted) ? "t" : "", 2641 1.1 mrg regop); 2642 1.1 mrg return buf; 2643 1.1 mrg } 2644 1.1 mrg 2645 1.1 mrg 2646 1.1 mrg /* Output assembly code for a specific branch instruction, appending 2647 1.1 mrg the branch prediction flag to the opcode if appropriate. */ 2648 1.1 mrg const char * 2649 1.1 mrg tilegx_output_cbranch_with_opcode (rtx_insn *insn, rtx *operands, 2650 1.1 mrg const char *opcode, 2651 1.1 mrg const char *rev_opcode, int regop) 2652 1.1 mrg { 2653 1.1 mrg const char *branch_if_false; 2654 1.1 mrg rtx taken, not_taken; 2655 1.1 mrg bool is_simple_branch; 2656 1.1 mrg 2657 1.1 mrg gcc_assert (LABEL_P (operands[0])); 2658 1.1 mrg 2659 1.1 mrg is_simple_branch = true; 2660 1.1 mrg if (INSN_ADDRESSES_SET_P ()) 2661 1.1 mrg { 2662 1.1 mrg int from_addr = INSN_ADDRESSES (INSN_UID (insn)); 2663 1.1 mrg int to_addr = INSN_ADDRESSES (INSN_UID (operands[0])); 2664 1.1 mrg int delta = to_addr - from_addr; 2665 1.1 mrg is_simple_branch = IN_RANGE (delta, -524288, 524280); 2666 1.1 mrg } 2667 1.1 mrg 2668 1.1 mrg if (is_simple_branch) 2669 1.1 mrg { 2670 1.1 mrg /* Just a simple conditional branch. */ 2671 1.1 mrg return 2672 1.1 mrg tilegx_output_simple_cbranch_with_opcode (insn, opcode, regop, false); 2673 1.1 mrg } 2674 1.1 mrg 2675 1.1 mrg /* Generate a reversed branch around a direct jump. This fallback 2676 1.1 mrg does not use branch-likely instructions. */ 2677 1.1 mrg not_taken = gen_label_rtx (); 2678 1.1 mrg taken = operands[0]; 2679 1.1 mrg 2680 1.1 mrg /* Generate the reversed branch to NOT_TAKEN. */ 2681 1.1 mrg operands[0] = not_taken; 2682 1.1 mrg branch_if_false = 2683 1.1 mrg tilegx_output_simple_cbranch_with_opcode (insn, rev_opcode, regop, true); 2684 1.1 mrg output_asm_insn (branch_if_false, operands); 2685 1.1 mrg 2686 1.1 mrg output_asm_insn ("j\t%l0", &taken); 2687 1.1 mrg 2688 1.1 mrg /* Output NOT_TAKEN. */ 2689 1.1 mrg targetm.asm_out.internal_label (asm_out_file, "L", 2690 1.1 mrg CODE_LABEL_NUMBER (not_taken)); 2691 1.1 mrg return ""; 2692 1.1 mrg } 2693 1.1 mrg 2694 1.1 mrg 2695 1.1 mrg /* Output assembly code for a conditional branch instruction. */ 2696 1.1 mrg const char * 2697 1.1 mrg tilegx_output_cbranch (rtx_insn *insn, rtx *operands, bool reversed) 2698 1.1 mrg { 2699 1.1 mrg enum rtx_code code = GET_CODE (operands[1]); 2700 1.1 mrg const char *opcode; 2701 1.1 mrg const char *rev_opcode; 2702 1.1 mrg 2703 1.1 mrg if (reversed) 2704 1.1 mrg code = reverse_condition (code); 2705 1.1 mrg 2706 1.1 mrg switch (code) 2707 1.1 mrg { 2708 1.1 mrg case NE: 2709 1.1 mrg opcode = "bnez"; 2710 1.1 mrg rev_opcode = "beqz"; 2711 1.1 mrg break; 2712 1.1 mrg case EQ: 2713 1.1 mrg opcode = "beqz"; 2714 1.1 mrg rev_opcode = "bnez"; 2715 1.1 mrg break; 2716 1.1 mrg case GE: 2717 1.1 mrg opcode = "bgez"; 2718 1.1 mrg rev_opcode = "bltz"; 2719 1.1 mrg break; 2720 1.1 mrg case GT: 2721 1.1 mrg opcode = "bgtz"; 2722 1.1 mrg rev_opcode = "blez"; 2723 1.1 mrg break; 2724 1.1 mrg case LE: 2725 1.1 mrg opcode = "blez"; 2726 1.1 mrg rev_opcode = "bgtz"; 2727 1.1 mrg break; 2728 1.1 mrg case LT: 2729 1.1 mrg opcode = "bltz"; 2730 1.1 mrg rev_opcode = "bgez"; 2731 1.1 mrg break; 2732 1.1 mrg default: 2733 1.1 mrg gcc_unreachable (); 2734 1.1 mrg } 2735 1.1 mrg 2736 1.1 mrg return tilegx_output_cbranch_with_opcode (insn, operands, opcode, 2737 1.1 mrg rev_opcode, 2); 2738 1.1 mrg } 2739 1.1 mrg 2740 1.1 mrg 2741 1.1 mrg /* Implement the tablejump pattern. */ 2742 1.1 mrg void 2743 1.1 mrg tilegx_expand_tablejump (rtx op0, rtx op1) 2744 1.1 mrg { 2745 1.1 mrg if (flag_pic) 2746 1.1 mrg { 2747 1.1 mrg rtx temp = gen_reg_rtx (Pmode); 2748 1.1 mrg rtx temp2 = gen_reg_rtx (Pmode); 2749 1.1 mrg 2750 1.1 mrg tilegx_compute_pcrel_address (temp, gen_rtx_LABEL_REF (Pmode, op1)); 2751 1.1 mrg emit_move_insn (temp2, 2752 1.1 mrg gen_rtx_PLUS (Pmode, 2753 1.1 mrg convert_to_mode (Pmode, op0, false), 2754 1.1 mrg temp)); 2755 1.1 mrg op0 = temp2; 2756 1.1 mrg } 2757 1.1 mrg 2758 1.1 mrg emit_jump_insn (gen_tablejump_aux (op0, op1)); 2759 1.1 mrg } 2760 1.1 mrg 2761 1.1 mrg 2762 1.1 mrg /* Emit barrier before an atomic, as needed for the memory MODEL. */ 2763 1.1 mrg void 2764 1.1 mrg tilegx_pre_atomic_barrier (enum memmodel model) 2765 1.1 mrg { 2766 1.1 mrg if (need_atomic_barrier_p (model, true)) 2767 1.1 mrg emit_insn (gen_memory_barrier ()); 2768 1.1 mrg } 2769 1.1 mrg 2770 1.1 mrg 2771 1.1 mrg /* Emit barrier after an atomic, as needed for the memory MODEL. */ 2772 1.1 mrg void 2773 1.1 mrg tilegx_post_atomic_barrier (enum memmodel model) 2774 1.1 mrg { 2775 1.1 mrg if (need_atomic_barrier_p (model, false)) 2776 1.1 mrg emit_insn (gen_memory_barrier ()); 2777 1.1 mrg } 2778 1.1 mrg 2779 1.1 mrg 2780 1.1 mrg 2781 1.1 mrg /* Expand a builtin vector binary op, by calling gen function GEN with 2782 1.1 mrg operands in the proper modes. DEST is converted to DEST_MODE, and 2783 1.1 mrg src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */ 2784 1.1 mrg void 2785 1.1 mrg tilegx_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx), 2786 1.1 mrg machine_mode dest_mode, 2787 1.1 mrg rtx dest, 2788 1.1 mrg machine_mode src_mode, 2789 1.1 mrg rtx src0, rtx src1, bool do_src1) 2790 1.1 mrg { 2791 1.1 mrg dest = gen_lowpart (dest_mode, dest); 2792 1.1 mrg 2793 1.1 mrg if (src0 == const0_rtx) 2794 1.1 mrg src0 = CONST0_RTX (src_mode); 2795 1.1 mrg else 2796 1.1 mrg src0 = gen_lowpart (src_mode, src0); 2797 1.1 mrg 2798 1.1 mrg if (do_src1) 2799 1.1 mrg { 2800 1.1 mrg if (src1 == const0_rtx) 2801 1.1 mrg src1 = CONST0_RTX (src_mode); 2802 1.1 mrg else 2803 1.1 mrg src1 = gen_lowpart (src_mode, src1); 2804 1.1 mrg } 2805 1.1 mrg 2806 1.1 mrg emit_insn ((*gen) (dest, src0, src1)); 2807 1.1 mrg } 2808 1.1 mrg 2809 1.1 mrg 2811 1.1 mrg 2812 1.1 mrg /* Intrinsics */ 2813 1.1 mrg 2814 1.1 mrg 2815 1.1 mrg struct tile_builtin_info 2816 1.1 mrg { 2817 1.1 mrg enum insn_code icode; 2818 1.1 mrg tree fndecl; 2819 1.1 mrg }; 2820 1.1 mrg 2821 1.1 mrg static struct tile_builtin_info tilegx_builtin_info[TILEGX_BUILTIN_max] = { 2822 1.1 mrg { CODE_FOR_adddi3, NULL }, /* add */ 2823 1.1 mrg { CODE_FOR_addsi3, NULL }, /* addx */ 2824 1.1 mrg { CODE_FOR_ssaddsi3, NULL }, /* addxsc */ 2825 1.1 mrg { CODE_FOR_anddi3, NULL }, /* and */ 2826 1.1 mrg { CODE_FOR_insn_bfexts, NULL }, /* bfexts */ 2827 1.1 mrg { CODE_FOR_insn_bfextu, NULL }, /* bfextu */ 2828 1.1 mrg { CODE_FOR_insn_bfins, NULL }, /* bfins */ 2829 1.1 mrg { CODE_FOR_clzdi2, NULL }, /* clz */ 2830 1.1 mrg { CODE_FOR_insn_cmoveqz, NULL }, /* cmoveqz */ 2831 1.1 mrg { CODE_FOR_insn_cmovnez, NULL }, /* cmovnez */ 2832 1.1 mrg { CODE_FOR_insn_cmpeq_didi, NULL }, /* cmpeq */ 2833 1.1 mrg { CODE_FOR_insn_cmpexch, NULL }, /* cmpexch */ 2834 1.1 mrg { CODE_FOR_insn_cmpexch4, NULL }, /* cmpexch4 */ 2835 1.1 mrg { CODE_FOR_insn_cmples_didi, NULL }, /* cmples */ 2836 1.1 mrg { CODE_FOR_insn_cmpleu_didi, NULL }, /* cmpleu */ 2837 1.1 mrg { CODE_FOR_insn_cmplts_didi, NULL }, /* cmplts */ 2838 1.1 mrg { CODE_FOR_insn_cmpltu_didi, NULL }, /* cmpltu */ 2839 1.1 mrg { CODE_FOR_insn_cmpne_didi, NULL }, /* cmpne */ 2840 1.1 mrg { CODE_FOR_insn_cmul, NULL }, /* cmul */ 2841 1.1 mrg { CODE_FOR_insn_cmula, NULL }, /* cmula */ 2842 1.1 mrg { CODE_FOR_insn_cmulaf, NULL }, /* cmulaf */ 2843 1.1 mrg { CODE_FOR_insn_cmulf, NULL }, /* cmulf */ 2844 1.1 mrg { CODE_FOR_insn_cmulfr, NULL }, /* cmulfr */ 2845 1.1 mrg { CODE_FOR_insn_cmulh, NULL }, /* cmulh */ 2846 1.1 mrg { CODE_FOR_insn_cmulhr, NULL }, /* cmulhr */ 2847 1.1 mrg { CODE_FOR_insn_crc32_32, NULL }, /* crc32_32 */ 2848 1.1 mrg { CODE_FOR_insn_crc32_8, NULL }, /* crc32_8 */ 2849 1.1 mrg { CODE_FOR_ctzdi2, NULL }, /* ctz */ 2850 1.1 mrg { CODE_FOR_insn_dblalign, NULL }, /* dblalign */ 2851 1.1 mrg { CODE_FOR_insn_dblalign2, NULL }, /* dblalign2 */ 2852 1.1 mrg { CODE_FOR_insn_dblalign4, NULL }, /* dblalign4 */ 2853 1.1 mrg { CODE_FOR_insn_dblalign6, NULL }, /* dblalign6 */ 2854 1.1 mrg { CODE_FOR_insn_drain, NULL }, /* drain */ 2855 1.1 mrg { CODE_FOR_insn_dtlbpr, NULL }, /* dtlbpr */ 2856 1.1 mrg { CODE_FOR_insn_exch, NULL }, /* exch */ 2857 1.1 mrg { CODE_FOR_insn_exch4, NULL }, /* exch4 */ 2858 1.1 mrg { CODE_FOR_insn_fdouble_add_flags, NULL }, /* fdouble_add_flags */ 2859 1.1 mrg { CODE_FOR_insn_fdouble_addsub, NULL }, /* fdouble_addsub */ 2860 1.1 mrg { CODE_FOR_insn_fdouble_mul_flags, NULL }, /* fdouble_mul_flags */ 2861 1.1 mrg { CODE_FOR_insn_fdouble_pack1, NULL }, /* fdouble_pack1 */ 2862 1.1 mrg { CODE_FOR_insn_fdouble_pack2, NULL }, /* fdouble_pack2 */ 2863 1.1 mrg { CODE_FOR_insn_fdouble_sub_flags, NULL }, /* fdouble_sub_flags */ 2864 1.1 mrg { CODE_FOR_insn_fdouble_unpack_max, NULL }, /* fdouble_unpack_max */ 2865 1.1 mrg { CODE_FOR_insn_fdouble_unpack_min, NULL }, /* fdouble_unpack_min */ 2866 1.1 mrg { CODE_FOR_insn_fetchadd, NULL }, /* fetchadd */ 2867 1.1 mrg { CODE_FOR_insn_fetchadd4, NULL }, /* fetchadd4 */ 2868 1.1 mrg { CODE_FOR_insn_fetchaddgez, NULL }, /* fetchaddgez */ 2869 1.1 mrg { CODE_FOR_insn_fetchaddgez4, NULL }, /* fetchaddgez4 */ 2870 1.1 mrg { CODE_FOR_insn_fetchand, NULL }, /* fetchand */ 2871 1.1 mrg { CODE_FOR_insn_fetchand4, NULL }, /* fetchand4 */ 2872 1.1 mrg { CODE_FOR_insn_fetchor, NULL }, /* fetchor */ 2873 1.1 mrg { CODE_FOR_insn_fetchor4, NULL }, /* fetchor4 */ 2874 1.1 mrg { CODE_FOR_insn_finv, NULL }, /* finv */ 2875 1.1 mrg { CODE_FOR_insn_flush, NULL }, /* flush */ 2876 1.1 mrg { CODE_FOR_insn_flushwb, NULL }, /* flushwb */ 2877 1.1 mrg { CODE_FOR_insn_fnop, NULL }, /* fnop */ 2878 1.1 mrg { CODE_FOR_insn_fsingle_add1, NULL }, /* fsingle_add1 */ 2879 1.1 mrg { CODE_FOR_insn_fsingle_addsub2, NULL }, /* fsingle_addsub2 */ 2880 1.1 mrg { CODE_FOR_insn_fsingle_mul1, NULL }, /* fsingle_mul1 */ 2881 1.1 mrg { CODE_FOR_insn_fsingle_mul2, NULL }, /* fsingle_mul2 */ 2882 1.1 mrg { CODE_FOR_insn_fsingle_pack1, NULL }, /* fsingle_pack1 */ 2883 1.1 mrg { CODE_FOR_insn_fsingle_pack2, NULL }, /* fsingle_pack2 */ 2884 1.1 mrg { CODE_FOR_insn_fsingle_sub1, NULL }, /* fsingle_sub1 */ 2885 1.1 mrg { CODE_FOR_insn_icoh, NULL }, /* icoh */ 2886 1.1 mrg { CODE_FOR_insn_ill, NULL }, /* ill */ 2887 1.1 mrg { CODE_FOR_insn_info, NULL }, /* info */ 2888 1.1 mrg { CODE_FOR_insn_infol, NULL }, /* infol */ 2889 1.1 mrg { CODE_FOR_insn_inv, NULL }, /* inv */ 2890 1.1 mrg { CODE_FOR_insn_ld, NULL }, /* ld */ 2891 1.1 mrg { CODE_FOR_insn_ld1s, NULL }, /* ld1s */ 2892 1.1 mrg { CODE_FOR_insn_ld1u, NULL }, /* ld1u */ 2893 1.1 mrg { CODE_FOR_insn_ld2s, NULL }, /* ld2s */ 2894 1.1 mrg { CODE_FOR_insn_ld2u, NULL }, /* ld2u */ 2895 1.1 mrg { CODE_FOR_insn_ld4s, NULL }, /* ld4s */ 2896 1.1 mrg { CODE_FOR_insn_ld4u, NULL }, /* ld4u */ 2897 1.1 mrg { CODE_FOR_insn_ldna, NULL }, /* ldna */ 2898 1.1 mrg { CODE_FOR_insn_ldnt, NULL }, /* ldnt */ 2899 1.1 mrg { CODE_FOR_insn_ldnt1s, NULL }, /* ldnt1s */ 2900 1.1 mrg { CODE_FOR_insn_ldnt1u, NULL }, /* ldnt1u */ 2901 1.1 mrg { CODE_FOR_insn_ldnt2s, NULL }, /* ldnt2s */ 2902 1.1 mrg { CODE_FOR_insn_ldnt2u, NULL }, /* ldnt2u */ 2903 1.1 mrg { CODE_FOR_insn_ldnt4s, NULL }, /* ldnt4s */ 2904 1.1 mrg { CODE_FOR_insn_ldnt4u, NULL }, /* ldnt4u */ 2905 1.1 mrg { CODE_FOR_insn_ld_L2, NULL }, /* ld_L2 */ 2906 1.1 mrg { CODE_FOR_insn_ld1s_L2, NULL }, /* ld1s_L2 */ 2907 1.1 mrg { CODE_FOR_insn_ld1u_L2, NULL }, /* ld1u_L2 */ 2908 1.1 mrg { CODE_FOR_insn_ld2s_L2, NULL }, /* ld2s_L2 */ 2909 1.1 mrg { CODE_FOR_insn_ld2u_L2, NULL }, /* ld2u_L2 */ 2910 1.1 mrg { CODE_FOR_insn_ld4s_L2, NULL }, /* ld4s_L2 */ 2911 1.1 mrg { CODE_FOR_insn_ld4u_L2, NULL }, /* ld4u_L2 */ 2912 1.1 mrg { CODE_FOR_insn_ldna_L2, NULL }, /* ldna_L2 */ 2913 1.1 mrg { CODE_FOR_insn_ldnt_L2, NULL }, /* ldnt_L2 */ 2914 1.1 mrg { CODE_FOR_insn_ldnt1s_L2, NULL }, /* ldnt1s_L2 */ 2915 1.1 mrg { CODE_FOR_insn_ldnt1u_L2, NULL }, /* ldnt1u_L2 */ 2916 1.1 mrg { CODE_FOR_insn_ldnt2s_L2, NULL }, /* ldnt2s_L2 */ 2917 1.1 mrg { CODE_FOR_insn_ldnt2u_L2, NULL }, /* ldnt2u_L2 */ 2918 1.1 mrg { CODE_FOR_insn_ldnt4s_L2, NULL }, /* ldnt4s_L2 */ 2919 1.1 mrg { CODE_FOR_insn_ldnt4u_L2, NULL }, /* ldnt4u_L2 */ 2920 1.1 mrg { CODE_FOR_insn_ld_miss, NULL }, /* ld_miss */ 2921 1.1 mrg { CODE_FOR_insn_ld1s_miss, NULL }, /* ld1s_miss */ 2922 1.1 mrg { CODE_FOR_insn_ld1u_miss, NULL }, /* ld1u_miss */ 2923 1.1 mrg { CODE_FOR_insn_ld2s_miss, NULL }, /* ld2s_miss */ 2924 1.1 mrg { CODE_FOR_insn_ld2u_miss, NULL }, /* ld2u_miss */ 2925 1.1 mrg { CODE_FOR_insn_ld4s_miss, NULL }, /* ld4s_miss */ 2926 1.1 mrg { CODE_FOR_insn_ld4u_miss, NULL }, /* ld4u_miss */ 2927 1.1 mrg { CODE_FOR_insn_ldna_miss, NULL }, /* ldna_miss */ 2928 1.1 mrg { CODE_FOR_insn_ldnt_miss, NULL }, /* ldnt_miss */ 2929 1.1 mrg { CODE_FOR_insn_ldnt1s_miss, NULL }, /* ldnt1s_miss */ 2930 1.1 mrg { CODE_FOR_insn_ldnt1u_miss, NULL }, /* ldnt1u_miss */ 2931 1.1 mrg { CODE_FOR_insn_ldnt2s_miss, NULL }, /* ldnt2s_miss */ 2932 1.1 mrg { CODE_FOR_insn_ldnt2u_miss, NULL }, /* ldnt2u_miss */ 2933 1.1 mrg { CODE_FOR_insn_ldnt4s_miss, NULL }, /* ldnt4s_miss */ 2934 1.1 mrg { CODE_FOR_insn_ldnt4u_miss, NULL }, /* ldnt4u_miss */ 2935 1.1 mrg { CODE_FOR_insn_lnk, NULL }, /* lnk */ 2936 1.1 mrg { CODE_FOR_memory_barrier, NULL }, /* mf */ 2937 1.1 mrg { CODE_FOR_insn_mfspr, NULL }, /* mfspr */ 2938 1.1 mrg { CODE_FOR_insn_mm, NULL }, /* mm */ 2939 1.1 mrg { CODE_FOR_insn_mnz, NULL }, /* mnz */ 2940 1.1 mrg { CODE_FOR_movdi, NULL }, /* move */ 2941 1.1 mrg { CODE_FOR_insn_mtspr, NULL }, /* mtspr */ 2942 1.1 mrg { CODE_FOR_insn_mul_hs_hs, NULL }, /* mul_hs_hs */ 2943 1.1 mrg { CODE_FOR_insn_mul_hs_hu, NULL }, /* mul_hs_hu */ 2944 1.1 mrg { CODE_FOR_insn_mul_hs_ls, NULL }, /* mul_hs_ls */ 2945 1.1 mrg { CODE_FOR_insn_mul_hs_lu, NULL }, /* mul_hs_lu */ 2946 1.1 mrg { CODE_FOR_insn_mul_hu_hu, NULL }, /* mul_hu_hu */ 2947 1.1 mrg { CODE_FOR_insn_mul_hu_ls, NULL }, /* mul_hu_ls */ 2948 1.1 mrg { CODE_FOR_insn_mul_hu_lu, NULL }, /* mul_hu_lu */ 2949 1.1 mrg { CODE_FOR_insn_mul_ls_ls, NULL }, /* mul_ls_ls */ 2950 1.1 mrg { CODE_FOR_insn_mul_ls_lu, NULL }, /* mul_ls_lu */ 2951 1.1 mrg { CODE_FOR_insn_mul_lu_lu, NULL }, /* mul_lu_lu */ 2952 1.1 mrg { CODE_FOR_insn_mula_hs_hs, NULL }, /* mula_hs_hs */ 2953 1.1 mrg { CODE_FOR_insn_mula_hs_hu, NULL }, /* mula_hs_hu */ 2954 1.1 mrg { CODE_FOR_insn_mula_hs_ls, NULL }, /* mula_hs_ls */ 2955 1.1 mrg { CODE_FOR_insn_mula_hs_lu, NULL }, /* mula_hs_lu */ 2956 1.1 mrg { CODE_FOR_insn_mula_hu_hu, NULL }, /* mula_hu_hu */ 2957 1.1 mrg { CODE_FOR_insn_mula_hu_ls, NULL }, /* mula_hu_ls */ 2958 1.1 mrg { CODE_FOR_insn_mula_hu_lu, NULL }, /* mula_hu_lu */ 2959 1.1 mrg { CODE_FOR_insn_mula_ls_ls, NULL }, /* mula_ls_ls */ 2960 1.1 mrg { CODE_FOR_insn_mula_ls_lu, NULL }, /* mula_ls_lu */ 2961 1.1 mrg { CODE_FOR_insn_mula_lu_lu, NULL }, /* mula_lu_lu */ 2962 1.1 mrg { CODE_FOR_insn_mulax, NULL }, /* mulax */ 2963 1.1 mrg { CODE_FOR_mulsi3, NULL }, /* mulx */ 2964 1.1 mrg { CODE_FOR_insn_mz, NULL }, /* mz */ 2965 1.1 mrg { CODE_FOR_insn_nap, NULL }, /* nap */ 2966 1.1 mrg { CODE_FOR_nop, NULL }, /* nop */ 2967 1.1 mrg { CODE_FOR_insn_nor_di, NULL }, /* nor */ 2968 1.1 mrg { CODE_FOR_iordi3, NULL }, /* or */ 2969 1.1 mrg { CODE_FOR_popcountdi2, NULL }, /* pcnt */ 2970 1.1 mrg { CODE_FOR_insn_prefetch_l1, NULL }, /* prefetch_l1 */ 2971 1.1 mrg { CODE_FOR_insn_prefetch_l1_fault, NULL }, /* prefetch_l1_fault */ 2972 1.1 mrg { CODE_FOR_insn_prefetch_l2, NULL }, /* prefetch_l2 */ 2973 1.1 mrg { CODE_FOR_insn_prefetch_l2_fault, NULL }, /* prefetch_l2_fault */ 2974 1.1 mrg { CODE_FOR_insn_prefetch_l3, NULL }, /* prefetch_l3 */ 2975 1.1 mrg { CODE_FOR_insn_prefetch_l3_fault, NULL }, /* prefetch_l3_fault */ 2976 1.1 mrg { CODE_FOR_insn_revbits, NULL }, /* revbits */ 2977 1.1 mrg { CODE_FOR_bswapdi2, NULL }, /* revbytes */ 2978 1.1 mrg { CODE_FOR_rotldi3, NULL }, /* rotl */ 2979 1.1 mrg { CODE_FOR_ashldi3, NULL }, /* shl */ 2980 1.1 mrg { CODE_FOR_insn_shl16insli, NULL }, /* shl16insli */ 2981 1.1 mrg { CODE_FOR_insn_shl1add, NULL }, /* shl1add */ 2982 1.1 mrg { CODE_FOR_insn_shl1addx, NULL }, /* shl1addx */ 2983 1.1 mrg { CODE_FOR_insn_shl2add, NULL }, /* shl2add */ 2984 1.1 mrg { CODE_FOR_insn_shl2addx, NULL }, /* shl2addx */ 2985 1.1 mrg { CODE_FOR_insn_shl3add, NULL }, /* shl3add */ 2986 1.1 mrg { CODE_FOR_insn_shl3addx, NULL }, /* shl3addx */ 2987 1.1 mrg { CODE_FOR_ashlsi3, NULL }, /* shlx */ 2988 1.1 mrg { CODE_FOR_ashrdi3, NULL }, /* shrs */ 2989 1.1 mrg { CODE_FOR_lshrdi3, NULL }, /* shru */ 2990 1.1 mrg { CODE_FOR_lshrsi3, NULL }, /* shrux */ 2991 1.1 mrg { CODE_FOR_insn_shufflebytes, NULL }, /* shufflebytes */ 2992 1.1 mrg { CODE_FOR_insn_shufflebytes1, NULL }, /* shufflebytes1 */ 2993 1.1 mrg { CODE_FOR_insn_st, NULL }, /* st */ 2994 1.1 mrg { CODE_FOR_insn_st1, NULL }, /* st1 */ 2995 1.1 mrg { CODE_FOR_insn_st2, NULL }, /* st2 */ 2996 1.1 mrg { CODE_FOR_insn_st4, NULL }, /* st4 */ 2997 1.1 mrg { CODE_FOR_insn_stnt, NULL }, /* stnt */ 2998 1.1 mrg { CODE_FOR_insn_stnt1, NULL }, /* stnt1 */ 2999 1.1 mrg { CODE_FOR_insn_stnt2, NULL }, /* stnt2 */ 3000 1.1 mrg { CODE_FOR_insn_stnt4, NULL }, /* stnt4 */ 3001 1.1 mrg { CODE_FOR_subdi3, NULL }, /* sub */ 3002 1.1 mrg { CODE_FOR_subsi3, NULL }, /* subx */ 3003 1.1 mrg { CODE_FOR_sssubsi3, NULL }, /* subxsc */ 3004 1.1 mrg { CODE_FOR_insn_tblidxb0, NULL }, /* tblidxb0 */ 3005 1.1 mrg { CODE_FOR_insn_tblidxb1, NULL }, /* tblidxb1 */ 3006 1.1 mrg { CODE_FOR_insn_tblidxb2, NULL }, /* tblidxb2 */ 3007 1.1 mrg { CODE_FOR_insn_tblidxb3, NULL }, /* tblidxb3 */ 3008 1.1 mrg { CODE_FOR_insn_v1add, NULL }, /* v1add */ 3009 1.1 mrg { CODE_FOR_insn_v1addi, NULL }, /* v1addi */ 3010 1.1 mrg { CODE_FOR_insn_v1adduc, NULL }, /* v1adduc */ 3011 1.1 mrg { CODE_FOR_insn_v1adiffu, NULL }, /* v1adiffu */ 3012 1.1 mrg { CODE_FOR_insn_v1avgu, NULL }, /* v1avgu */ 3013 1.1 mrg { CODE_FOR_insn_v1cmpeq, NULL }, /* v1cmpeq */ 3014 1.1 mrg { CODE_FOR_insn_v1cmpeqi, NULL }, /* v1cmpeqi */ 3015 1.1 mrg { CODE_FOR_insn_v1cmples, NULL }, /* v1cmples */ 3016 1.1 mrg { CODE_FOR_insn_v1cmpleu, NULL }, /* v1cmpleu */ 3017 1.1 mrg { CODE_FOR_insn_v1cmplts, NULL }, /* v1cmplts */ 3018 1.1 mrg { CODE_FOR_insn_v1cmpltsi, NULL }, /* v1cmpltsi */ 3019 1.1 mrg { CODE_FOR_insn_v1cmpltu, NULL }, /* v1cmpltu */ 3020 1.1 mrg { CODE_FOR_insn_v1cmpltui, NULL }, /* v1cmpltui */ 3021 1.1 mrg { CODE_FOR_insn_v1cmpne, NULL }, /* v1cmpne */ 3022 1.1 mrg { CODE_FOR_insn_v1ddotpu, NULL }, /* v1ddotpu */ 3023 1.1 mrg { CODE_FOR_insn_v1ddotpua, NULL }, /* v1ddotpua */ 3024 1.1 mrg { CODE_FOR_insn_v1ddotpus, NULL }, /* v1ddotpus */ 3025 1.1 mrg { CODE_FOR_insn_v1ddotpusa, NULL }, /* v1ddotpusa */ 3026 1.1 mrg { CODE_FOR_insn_v1dotp, NULL }, /* v1dotp */ 3027 1.1 mrg { CODE_FOR_insn_v1dotpa, NULL }, /* v1dotpa */ 3028 1.1 mrg { CODE_FOR_insn_v1dotpu, NULL }, /* v1dotpu */ 3029 1.1 mrg { CODE_FOR_insn_v1dotpua, NULL }, /* v1dotpua */ 3030 1.1 mrg { CODE_FOR_insn_v1dotpus, NULL }, /* v1dotpus */ 3031 1.1 mrg { CODE_FOR_insn_v1dotpusa, NULL }, /* v1dotpusa */ 3032 1.1 mrg { CODE_FOR_insn_v1int_h, NULL }, /* v1int_h */ 3033 1.1 mrg { CODE_FOR_insn_v1int_l, NULL }, /* v1int_l */ 3034 1.1 mrg { CODE_FOR_insn_v1maxu, NULL }, /* v1maxu */ 3035 1.1 mrg { CODE_FOR_insn_v1maxui, NULL }, /* v1maxui */ 3036 1.1 mrg { CODE_FOR_insn_v1minu, NULL }, /* v1minu */ 3037 1.1 mrg { CODE_FOR_insn_v1minui, NULL }, /* v1minui */ 3038 1.1 mrg { CODE_FOR_insn_v1mnz, NULL }, /* v1mnz */ 3039 1.1 mrg { CODE_FOR_insn_v1multu, NULL }, /* v1multu */ 3040 1.1 mrg { CODE_FOR_insn_v1mulu, NULL }, /* v1mulu */ 3041 1.1 mrg { CODE_FOR_insn_v1mulus, NULL }, /* v1mulus */ 3042 1.1 mrg { CODE_FOR_insn_v1mz, NULL }, /* v1mz */ 3043 1.1 mrg { CODE_FOR_insn_v1sadau, NULL }, /* v1sadau */ 3044 1.1 mrg { CODE_FOR_insn_v1sadu, NULL }, /* v1sadu */ 3045 1.1 mrg { CODE_FOR_insn_v1shl, NULL }, /* v1shl */ 3046 1.1 mrg { CODE_FOR_insn_v1shl, NULL }, /* v1shli */ 3047 1.1 mrg { CODE_FOR_insn_v1shrs, NULL }, /* v1shrs */ 3048 1.1 mrg { CODE_FOR_insn_v1shrs, NULL }, /* v1shrsi */ 3049 1.1 mrg { CODE_FOR_insn_v1shru, NULL }, /* v1shru */ 3050 1.1 mrg { CODE_FOR_insn_v1shru, NULL }, /* v1shrui */ 3051 1.1 mrg { CODE_FOR_insn_v1sub, NULL }, /* v1sub */ 3052 1.1 mrg { CODE_FOR_insn_v1subuc, NULL }, /* v1subuc */ 3053 1.1 mrg { CODE_FOR_insn_v2add, NULL }, /* v2add */ 3054 1.1 mrg { CODE_FOR_insn_v2addi, NULL }, /* v2addi */ 3055 1.1 mrg { CODE_FOR_insn_v2addsc, NULL }, /* v2addsc */ 3056 1.1 mrg { CODE_FOR_insn_v2adiffs, NULL }, /* v2adiffs */ 3057 1.1 mrg { CODE_FOR_insn_v2avgs, NULL }, /* v2avgs */ 3058 1.1 mrg { CODE_FOR_insn_v2cmpeq, NULL }, /* v2cmpeq */ 3059 1.1 mrg { CODE_FOR_insn_v2cmpeqi, NULL }, /* v2cmpeqi */ 3060 1.1 mrg { CODE_FOR_insn_v2cmples, NULL }, /* v2cmples */ 3061 1.1 mrg { CODE_FOR_insn_v2cmpleu, NULL }, /* v2cmpleu */ 3062 1.1 mrg { CODE_FOR_insn_v2cmplts, NULL }, /* v2cmplts */ 3063 1.1 mrg { CODE_FOR_insn_v2cmpltsi, NULL }, /* v2cmpltsi */ 3064 1.1 mrg { CODE_FOR_insn_v2cmpltu, NULL }, /* v2cmpltu */ 3065 1.1 mrg { CODE_FOR_insn_v2cmpltui, NULL }, /* v2cmpltui */ 3066 1.1 mrg { CODE_FOR_insn_v2cmpne, NULL }, /* v2cmpne */ 3067 1.1 mrg { CODE_FOR_insn_v2dotp, NULL }, /* v2dotp */ 3068 1.1 mrg { CODE_FOR_insn_v2dotpa, NULL }, /* v2dotpa */ 3069 1.1 mrg { CODE_FOR_insn_v2int_h, NULL }, /* v2int_h */ 3070 1.1 mrg { CODE_FOR_insn_v2int_l, NULL }, /* v2int_l */ 3071 1.1 mrg { CODE_FOR_insn_v2maxs, NULL }, /* v2maxs */ 3072 1.1 mrg { CODE_FOR_insn_v2maxsi, NULL }, /* v2maxsi */ 3073 1.1 mrg { CODE_FOR_insn_v2mins, NULL }, /* v2mins */ 3074 1.1 mrg { CODE_FOR_insn_v2minsi, NULL }, /* v2minsi */ 3075 1.1 mrg { CODE_FOR_insn_v2mnz, NULL }, /* v2mnz */ 3076 1.1 mrg { CODE_FOR_insn_v2mulfsc, NULL }, /* v2mulfsc */ 3077 1.1 mrg { CODE_FOR_insn_v2muls, NULL }, /* v2muls */ 3078 1.1 mrg { CODE_FOR_insn_v2mults, NULL }, /* v2mults */ 3079 1.1 mrg { CODE_FOR_insn_v2mz, NULL }, /* v2mz */ 3080 1.1 mrg { CODE_FOR_insn_v2packh, NULL }, /* v2packh */ 3081 1.1 mrg { CODE_FOR_insn_v2packl, NULL }, /* v2packl */ 3082 1.1 mrg { CODE_FOR_insn_v2packuc, NULL }, /* v2packuc */ 3083 1.1 mrg { CODE_FOR_insn_v2sadas, NULL }, /* v2sadas */ 3084 1.1 mrg { CODE_FOR_insn_v2sadau, NULL }, /* v2sadau */ 3085 1.1 mrg { CODE_FOR_insn_v2sads, NULL }, /* v2sads */ 3086 1.1 mrg { CODE_FOR_insn_v2sadu, NULL }, /* v2sadu */ 3087 1.1 mrg { CODE_FOR_insn_v2shl, NULL }, /* v2shl */ 3088 1.1 mrg { CODE_FOR_insn_v2shl, NULL }, /* v2shli */ 3089 1.1 mrg { CODE_FOR_insn_v2shlsc, NULL }, /* v2shlsc */ 3090 1.1 mrg { CODE_FOR_insn_v2shrs, NULL }, /* v2shrs */ 3091 1.1 mrg { CODE_FOR_insn_v2shrs, NULL }, /* v2shrsi */ 3092 1.1 mrg { CODE_FOR_insn_v2shru, NULL }, /* v2shru */ 3093 1.1 mrg { CODE_FOR_insn_v2shru, NULL }, /* v2shrui */ 3094 1.1 mrg { CODE_FOR_insn_v2sub, NULL }, /* v2sub */ 3095 1.1 mrg { CODE_FOR_insn_v2subsc, NULL }, /* v2subsc */ 3096 1.1 mrg { CODE_FOR_insn_v4add, NULL }, /* v4add */ 3097 1.1 mrg { CODE_FOR_insn_v4addsc, NULL }, /* v4addsc */ 3098 1.1 mrg { CODE_FOR_insn_v4int_h, NULL }, /* v4int_h */ 3099 1.1 mrg { CODE_FOR_insn_v4int_l, NULL }, /* v4int_l */ 3100 1.1 mrg { CODE_FOR_insn_v4packsc, NULL }, /* v4packsc */ 3101 1.1 mrg { CODE_FOR_insn_v4shl, NULL }, /* v4shl */ 3102 1.1 mrg { CODE_FOR_insn_v4shlsc, NULL }, /* v4shlsc */ 3103 1.1 mrg { CODE_FOR_insn_v4shrs, NULL }, /* v4shrs */ 3104 1.1 mrg { CODE_FOR_insn_v4shru, NULL }, /* v4shru */ 3105 1.1 mrg { CODE_FOR_insn_v4sub, NULL }, /* v4sub */ 3106 1.1 mrg { CODE_FOR_insn_v4subsc, NULL }, /* v4subsc */ 3107 1.1 mrg { CODE_FOR_insn_wh64, NULL }, /* wh64 */ 3108 1.1 mrg { CODE_FOR_xordi3, NULL }, /* xor */ 3109 1.1 mrg { CODE_FOR_tilegx_network_barrier, NULL }, /* network_barrier */ 3110 1.1 mrg { CODE_FOR_tilegx_idn0_receive, NULL }, /* idn0_receive */ 3111 1.1 mrg { CODE_FOR_tilegx_idn1_receive, NULL }, /* idn1_receive */ 3112 1.1 mrg { CODE_FOR_tilegx_idn_send, NULL }, /* idn_send */ 3113 1.1 mrg { CODE_FOR_tilegx_udn0_receive, NULL }, /* udn0_receive */ 3114 1.1 mrg { CODE_FOR_tilegx_udn1_receive, NULL }, /* udn1_receive */ 3115 1.1 mrg { CODE_FOR_tilegx_udn2_receive, NULL }, /* udn2_receive */ 3116 1.1 mrg { CODE_FOR_tilegx_udn3_receive, NULL }, /* udn3_receive */ 3117 1.1 mrg { CODE_FOR_tilegx_udn_send, NULL }, /* udn_send */ 3118 1.1 mrg }; 3119 1.1 mrg 3120 1.1 mrg 3121 1.1 mrg struct tilegx_builtin_def 3122 1.1 mrg { 3123 1.1 mrg const char *name; 3124 1.1 mrg enum tilegx_builtin code; 3125 1.1 mrg bool is_const; 3126 1.1 mrg /* The first character is the return type. Subsequent characters 3127 1.1 mrg are the argument types. See char_to_type. */ 3128 1.1 mrg const char *type; 3129 1.1 mrg }; 3130 1.1 mrg 3131 1.1 mrg 3132 1.1 mrg static const struct tilegx_builtin_def tilegx_builtins[] = { 3133 1.1 mrg { "__insn_add", TILEGX_INSN_ADD, true, "lll" }, 3134 1.1 mrg { "__insn_addi", TILEGX_INSN_ADD, true, "lll" }, 3135 1.1 mrg { "__insn_addli", TILEGX_INSN_ADD, true, "lll" }, 3136 1.1 mrg { "__insn_addx", TILEGX_INSN_ADDX, true, "iii" }, 3137 1.1 mrg { "__insn_addxi", TILEGX_INSN_ADDX, true, "iii" }, 3138 1.1 mrg { "__insn_addxli", TILEGX_INSN_ADDX, true, "iii" }, 3139 1.1 mrg { "__insn_addxsc", TILEGX_INSN_ADDXSC, true, "iii" }, 3140 1.1 mrg { "__insn_and", TILEGX_INSN_AND, true, "lll" }, 3141 1.1 mrg { "__insn_andi", TILEGX_INSN_AND, true, "lll" }, 3142 1.1 mrg { "__insn_bfexts", TILEGX_INSN_BFEXTS, true, "llll" }, 3143 1.1 mrg { "__insn_bfextu", TILEGX_INSN_BFEXTU, true, "llll" }, 3144 1.1 mrg { "__insn_bfins", TILEGX_INSN_BFINS, true, "lllll"}, 3145 1.1 mrg { "__insn_clz", TILEGX_INSN_CLZ, true, "ll" }, 3146 1.1 mrg { "__insn_cmoveqz", TILEGX_INSN_CMOVEQZ, true, "llll" }, 3147 1.1 mrg { "__insn_cmovnez", TILEGX_INSN_CMOVNEZ, true, "llll" }, 3148 1.1 mrg { "__insn_cmpeq", TILEGX_INSN_CMPEQ, true, "lll" }, 3149 1.1 mrg { "__insn_cmpeqi", TILEGX_INSN_CMPEQ, true, "lll" }, 3150 1.1 mrg { "__insn_cmpexch", TILEGX_INSN_CMPEXCH, false, "lpl" }, 3151 1.1 mrg { "__insn_cmpexch4", TILEGX_INSN_CMPEXCH4, false, "ipi" }, 3152 1.1 mrg { "__insn_cmples", TILEGX_INSN_CMPLES, true, "lll" }, 3153 1.1 mrg { "__insn_cmpleu", TILEGX_INSN_CMPLEU, true, "lll" }, 3154 1.1 mrg { "__insn_cmplts", TILEGX_INSN_CMPLTS, true, "lll" }, 3155 1.1 mrg { "__insn_cmpltsi", TILEGX_INSN_CMPLTS, true, "lll" }, 3156 1.1 mrg { "__insn_cmpltu", TILEGX_INSN_CMPLTU, true, "lll" }, 3157 1.1 mrg { "__insn_cmpltui", TILEGX_INSN_CMPLTU, true, "lll" }, 3158 1.1 mrg { "__insn_cmpne", TILEGX_INSN_CMPNE, true, "lll" }, 3159 1.1 mrg { "__insn_cmul", TILEGX_INSN_CMUL, true, "lll" }, 3160 1.1 mrg { "__insn_cmula", TILEGX_INSN_CMULA, true, "llll" }, 3161 1.1 mrg { "__insn_cmulaf", TILEGX_INSN_CMULAF, true, "llll" }, 3162 1.1 mrg { "__insn_cmulf", TILEGX_INSN_CMULF, true, "lll" }, 3163 1.1 mrg { "__insn_cmulfr", TILEGX_INSN_CMULFR, true, "lll" }, 3164 1.1 mrg { "__insn_cmulh", TILEGX_INSN_CMULH, true, "lll" }, 3165 1.1 mrg { "__insn_cmulhr", TILEGX_INSN_CMULHR, true, "lll" }, 3166 1.1 mrg { "__insn_crc32_32", TILEGX_INSN_CRC32_32, true, "lll" }, 3167 1.1 mrg { "__insn_crc32_8", TILEGX_INSN_CRC32_8, true, "lll" }, 3168 1.1 mrg { "__insn_ctz", TILEGX_INSN_CTZ, true, "ll" }, 3169 1.1 mrg { "__insn_dblalign", TILEGX_INSN_DBLALIGN, true, "lllk" }, 3170 1.1 mrg { "__insn_dblalign2", TILEGX_INSN_DBLALIGN2, true, "lll" }, 3171 1.1 mrg { "__insn_dblalign4", TILEGX_INSN_DBLALIGN4, true, "lll" }, 3172 1.1 mrg { "__insn_dblalign6", TILEGX_INSN_DBLALIGN6, true, "lll" }, 3173 1.1 mrg { "__insn_drain", TILEGX_INSN_DRAIN, false, "v" }, 3174 1.1 mrg { "__insn_dtlbpr", TILEGX_INSN_DTLBPR, false, "vl" }, 3175 1.1 mrg { "__insn_exch", TILEGX_INSN_EXCH, false, "lpl" }, 3176 1.1 mrg { "__insn_exch4", TILEGX_INSN_EXCH4, false, "ipi" }, 3177 1.1 mrg { "__insn_fdouble_add_flags", TILEGX_INSN_FDOUBLE_ADD_FLAGS, true, "lll" }, 3178 1.1 mrg { "__insn_fdouble_addsub", TILEGX_INSN_FDOUBLE_ADDSUB, true, "llll" }, 3179 1.1 mrg { "__insn_fdouble_mul_flags", TILEGX_INSN_FDOUBLE_MUL_FLAGS, true, "lll" }, 3180 1.1 mrg { "__insn_fdouble_pack1", TILEGX_INSN_FDOUBLE_PACK1, true, "lll" }, 3181 1.1 mrg { "__insn_fdouble_pack2", TILEGX_INSN_FDOUBLE_PACK2, true, "llll" }, 3182 1.1 mrg { "__insn_fdouble_sub_flags", TILEGX_INSN_FDOUBLE_SUB_FLAGS, true, "lll" }, 3183 1.1 mrg { "__insn_fdouble_unpack_max", TILEGX_INSN_FDOUBLE_UNPACK_MAX, true, "lll" }, 3184 1.1 mrg { "__insn_fdouble_unpack_min", TILEGX_INSN_FDOUBLE_UNPACK_MIN, true, "lll" }, 3185 1.1 mrg { "__insn_fetchadd", TILEGX_INSN_FETCHADD, false, "lpl" }, 3186 1.1 mrg { "__insn_fetchadd4", TILEGX_INSN_FETCHADD4, false, "ipi" }, 3187 1.1 mrg { "__insn_fetchaddgez", TILEGX_INSN_FETCHADDGEZ, false, "lpl" }, 3188 1.1 mrg { "__insn_fetchaddgez4", TILEGX_INSN_FETCHADDGEZ4, false, "ipi" }, 3189 1.1 mrg { "__insn_fetchand", TILEGX_INSN_FETCHAND, false, "lpl" }, 3190 1.1 mrg { "__insn_fetchand4", TILEGX_INSN_FETCHAND4, false, "ipi" }, 3191 1.1 mrg { "__insn_fetchor", TILEGX_INSN_FETCHOR, false, "lpl" }, 3192 1.1 mrg { "__insn_fetchor4", TILEGX_INSN_FETCHOR4, false, "ipi" }, 3193 1.1 mrg { "__insn_finv", TILEGX_INSN_FINV, false, "vk" }, 3194 1.1 mrg { "__insn_flush", TILEGX_INSN_FLUSH, false, "vk" }, 3195 1.1 mrg { "__insn_flushwb", TILEGX_INSN_FLUSHWB, false, "v" }, 3196 1.1 mrg { "__insn_fnop", TILEGX_INSN_FNOP, false, "v" }, 3197 1.1 mrg { "__insn_fsingle_add1", TILEGX_INSN_FSINGLE_ADD1, true, "lll" }, 3198 1.1 mrg { "__insn_fsingle_addsub2", TILEGX_INSN_FSINGLE_ADDSUB2, true, "llll" }, 3199 1.1 mrg { "__insn_fsingle_mul1", TILEGX_INSN_FSINGLE_MUL1, true, "lll" }, 3200 1.1 mrg { "__insn_fsingle_mul2", TILEGX_INSN_FSINGLE_MUL2, true, "lll" }, 3201 1.1 mrg { "__insn_fsingle_pack1", TILEGX_INSN_FSINGLE_PACK1, true, "ll" }, 3202 1.1 mrg { "__insn_fsingle_pack2", TILEGX_INSN_FSINGLE_PACK2, true, "lll" }, 3203 1.1 mrg { "__insn_fsingle_sub1", TILEGX_INSN_FSINGLE_SUB1, true, "lll" }, 3204 1.1 mrg { "__insn_icoh", TILEGX_INSN_ICOH, false, "vk" }, 3205 1.1 mrg { "__insn_ill", TILEGX_INSN_ILL, false, "v" }, 3206 1.1 mrg { "__insn_info", TILEGX_INSN_INFO, false, "vl" }, 3207 1.1 mrg { "__insn_infol", TILEGX_INSN_INFOL, false, "vl" }, 3208 1.1 mrg { "__insn_inv", TILEGX_INSN_INV, false, "vp" }, 3209 1.1 mrg { "__insn_ld", TILEGX_INSN_LD, false, "lk" }, 3210 1.1 mrg { "__insn_ld1s", TILEGX_INSN_LD1S, false, "lk" }, 3211 1.1 mrg { "__insn_ld1u", TILEGX_INSN_LD1U, false, "lk" }, 3212 1.1 mrg { "__insn_ld2s", TILEGX_INSN_LD2S, false, "lk" }, 3213 1.1 mrg { "__insn_ld2u", TILEGX_INSN_LD2U, false, "lk" }, 3214 1.1 mrg { "__insn_ld4s", TILEGX_INSN_LD4S, false, "lk" }, 3215 1.1 mrg { "__insn_ld4u", TILEGX_INSN_LD4U, false, "lk" }, 3216 1.1 mrg { "__insn_ldna", TILEGX_INSN_LDNA, false, "lk" }, 3217 1.1 mrg { "__insn_ldnt", TILEGX_INSN_LDNT, false, "lk" }, 3218 1.1 mrg { "__insn_ldnt1s", TILEGX_INSN_LDNT1S, false, "lk" }, 3219 1.1 mrg { "__insn_ldnt1u", TILEGX_INSN_LDNT1U, false, "lk" }, 3220 1.1 mrg { "__insn_ldnt2s", TILEGX_INSN_LDNT2S, false, "lk" }, 3221 1.1 mrg { "__insn_ldnt2u", TILEGX_INSN_LDNT2U, false, "lk" }, 3222 1.1 mrg { "__insn_ldnt4s", TILEGX_INSN_LDNT4S, false, "lk" }, 3223 1.1 mrg { "__insn_ldnt4u", TILEGX_INSN_LDNT4U, false, "lk" }, 3224 1.1 mrg { "__insn_ld_L2", TILEGX_INSN_LD_L2, false, "lk" }, 3225 1.1 mrg { "__insn_ld1s_L2", TILEGX_INSN_LD1S_L2, false, "lk" }, 3226 1.1 mrg { "__insn_ld1u_L2", TILEGX_INSN_LD1U_L2, false, "lk" }, 3227 1.1 mrg { "__insn_ld2s_L2", TILEGX_INSN_LD2S_L2, false, "lk" }, 3228 1.1 mrg { "__insn_ld2u_L2", TILEGX_INSN_LD2U_L2, false, "lk" }, 3229 1.1 mrg { "__insn_ld4s_L2", TILEGX_INSN_LD4S_L2, false, "lk" }, 3230 1.1 mrg { "__insn_ld4u_L2", TILEGX_INSN_LD4U_L2, false, "lk" }, 3231 1.1 mrg { "__insn_ldna_L2", TILEGX_INSN_LDNA_L2, false, "lk" }, 3232 1.1 mrg { "__insn_ldnt_L2", TILEGX_INSN_LDNT_L2, false, "lk" }, 3233 1.1 mrg { "__insn_ldnt1s_L2", TILEGX_INSN_LDNT1S_L2, false, "lk" }, 3234 1.1 mrg { "__insn_ldnt1u_L2", TILEGX_INSN_LDNT1U_L2, false, "lk" }, 3235 1.1 mrg { "__insn_ldnt2s_L2", TILEGX_INSN_LDNT2S_L2, false, "lk" }, 3236 1.1 mrg { "__insn_ldnt2u_L2", TILEGX_INSN_LDNT2U_L2, false, "lk" }, 3237 1.1 mrg { "__insn_ldnt4s_L2", TILEGX_INSN_LDNT4S_L2, false, "lk" }, 3238 1.1 mrg { "__insn_ldnt4u_L2", TILEGX_INSN_LDNT4U_L2, false, "lk" }, 3239 1.1 mrg { "__insn_ld_miss", TILEGX_INSN_LD_MISS, false, "lk" }, 3240 1.1 mrg { "__insn_ld1s_miss", TILEGX_INSN_LD1S_MISS, false, "lk" }, 3241 1.1 mrg { "__insn_ld1u_miss", TILEGX_INSN_LD1U_MISS, false, "lk" }, 3242 1.1 mrg { "__insn_ld2s_miss", TILEGX_INSN_LD2S_MISS, false, "lk" }, 3243 1.1 mrg { "__insn_ld2u_miss", TILEGX_INSN_LD2U_MISS, false, "lk" }, 3244 1.1 mrg { "__insn_ld4s_miss", TILEGX_INSN_LD4S_MISS, false, "lk" }, 3245 1.1 mrg { "__insn_ld4u_miss", TILEGX_INSN_LD4U_MISS, false, "lk" }, 3246 1.1 mrg { "__insn_ldna_miss", TILEGX_INSN_LDNA_MISS, false, "lk" }, 3247 1.1 mrg { "__insn_ldnt_miss", TILEGX_INSN_LDNT_MISS, false, "lk" }, 3248 1.1 mrg { "__insn_ldnt1s_miss", TILEGX_INSN_LDNT1S_MISS, false, "lk" }, 3249 1.1 mrg { "__insn_ldnt1u_miss", TILEGX_INSN_LDNT1U_MISS, false, "lk" }, 3250 1.1 mrg { "__insn_ldnt2s_miss", TILEGX_INSN_LDNT2S_MISS, false, "lk" }, 3251 1.1 mrg { "__insn_ldnt2u_miss", TILEGX_INSN_LDNT2U_MISS, false, "lk" }, 3252 1.1 mrg { "__insn_ldnt4s_miss", TILEGX_INSN_LDNT4S_MISS, false, "lk" }, 3253 1.1 mrg { "__insn_ldnt4u_miss", TILEGX_INSN_LDNT4U_MISS, false, "lk" }, 3254 1.1 mrg { "__insn_lnk", TILEGX_INSN_LNK, true, "l" }, 3255 1.1 mrg { "__insn_mf", TILEGX_INSN_MF, false, "v" }, 3256 1.1 mrg { "__insn_mfspr", TILEGX_INSN_MFSPR, false, "ll" }, 3257 1.1 mrg { "__insn_mm", TILEGX_INSN_MM, true, "lllll"}, 3258 1.1 mrg { "__insn_mnz", TILEGX_INSN_MNZ, true, "lll" }, 3259 1.1 mrg { "__insn_move", TILEGX_INSN_MOVE, true, "ll" }, 3260 1.1 mrg { "__insn_movei", TILEGX_INSN_MOVE, true, "ll" }, 3261 1.1 mrg { "__insn_moveli", TILEGX_INSN_MOVE, true, "ll" }, 3262 1.1 mrg { "__insn_mtspr", TILEGX_INSN_MTSPR, false, "vll" }, 3263 1.1 mrg { "__insn_mul_hs_hs", TILEGX_INSN_MUL_HS_HS, true, "lll" }, 3264 1.1 mrg { "__insn_mul_hs_hu", TILEGX_INSN_MUL_HS_HU, true, "lll" }, 3265 1.1 mrg { "__insn_mul_hs_ls", TILEGX_INSN_MUL_HS_LS, true, "lll" }, 3266 1.1 mrg { "__insn_mul_hs_lu", TILEGX_INSN_MUL_HS_LU, true, "lll" }, 3267 1.1 mrg { "__insn_mul_hu_hu", TILEGX_INSN_MUL_HU_HU, true, "lll" }, 3268 1.1 mrg { "__insn_mul_hu_ls", TILEGX_INSN_MUL_HU_LS, true, "lll" }, 3269 1.1 mrg { "__insn_mul_hu_lu", TILEGX_INSN_MUL_HU_LU, true, "lll" }, 3270 1.1 mrg { "__insn_mul_ls_ls", TILEGX_INSN_MUL_LS_LS, true, "lll" }, 3271 1.1 mrg { "__insn_mul_ls_lu", TILEGX_INSN_MUL_LS_LU, true, "lll" }, 3272 1.1 mrg { "__insn_mul_lu_lu", TILEGX_INSN_MUL_LU_LU, true, "lll" }, 3273 1.1 mrg { "__insn_mula_hs_hs", TILEGX_INSN_MULA_HS_HS, true, "llll" }, 3274 1.1 mrg { "__insn_mula_hs_hu", TILEGX_INSN_MULA_HS_HU, true, "llll" }, 3275 1.1 mrg { "__insn_mula_hs_ls", TILEGX_INSN_MULA_HS_LS, true, "llll" }, 3276 1.1 mrg { "__insn_mula_hs_lu", TILEGX_INSN_MULA_HS_LU, true, "llll" }, 3277 1.1 mrg { "__insn_mula_hu_hu", TILEGX_INSN_MULA_HU_HU, true, "llll" }, 3278 1.1 mrg { "__insn_mula_hu_ls", TILEGX_INSN_MULA_HU_LS, true, "llll" }, 3279 1.1 mrg { "__insn_mula_hu_lu", TILEGX_INSN_MULA_HU_LU, true, "llll" }, 3280 1.1 mrg { "__insn_mula_ls_ls", TILEGX_INSN_MULA_LS_LS, true, "llll" }, 3281 1.1 mrg { "__insn_mula_ls_lu", TILEGX_INSN_MULA_LS_LU, true, "llll" }, 3282 1.1 mrg { "__insn_mula_lu_lu", TILEGX_INSN_MULA_LU_LU, true, "llll" }, 3283 1.1 mrg { "__insn_mulax", TILEGX_INSN_MULAX, true, "iiii" }, 3284 1.1 mrg { "__insn_mulx", TILEGX_INSN_MULX, true, "iii" }, 3285 1.1 mrg { "__insn_mz", TILEGX_INSN_MZ, true, "lll" }, 3286 1.1 mrg { "__insn_nap", TILEGX_INSN_NAP, false, "v" }, 3287 1.1 mrg { "__insn_nop", TILEGX_INSN_NOP, true, "v" }, 3288 1.1 mrg { "__insn_nor", TILEGX_INSN_NOR, true, "lll" }, 3289 1.1 mrg { "__insn_or", TILEGX_INSN_OR, true, "lll" }, 3290 1.1 mrg { "__insn_ori", TILEGX_INSN_OR, true, "lll" }, 3291 1.1 mrg { "__insn_pcnt", TILEGX_INSN_PCNT, true, "ll" }, 3292 1.1 mrg { "__insn_prefetch", TILEGX_INSN_PREFETCH_L1, false, "vk" }, 3293 1.1 mrg { "__insn_prefetch_l1", TILEGX_INSN_PREFETCH_L1, false, "vk" }, 3294 1.1 mrg { "__insn_prefetch_l1_fault", TILEGX_INSN_PREFETCH_L1_FAULT, false, "vk" }, 3295 1.1 mrg { "__insn_prefetch_l2", TILEGX_INSN_PREFETCH_L2, false, "vk" }, 3296 1.1 mrg { "__insn_prefetch_l2_fault", TILEGX_INSN_PREFETCH_L2_FAULT, false, "vk" }, 3297 1.1 mrg { "__insn_prefetch_l3", TILEGX_INSN_PREFETCH_L3, false, "vk" }, 3298 1.1 mrg { "__insn_prefetch_l3_fault", TILEGX_INSN_PREFETCH_L3_FAULT, false, "vk" }, 3299 1.1 mrg { "__insn_revbits", TILEGX_INSN_REVBITS, true, "ll" }, 3300 1.1 mrg { "__insn_revbytes", TILEGX_INSN_REVBYTES, true, "ll" }, 3301 1.1 mrg { "__insn_rotl", TILEGX_INSN_ROTL, true, "lli" }, 3302 1.1 mrg { "__insn_rotli", TILEGX_INSN_ROTL, true, "lli" }, 3303 1.1 mrg { "__insn_shl", TILEGX_INSN_SHL, true, "lli" }, 3304 1.1 mrg { "__insn_shl16insli", TILEGX_INSN_SHL16INSLI, true, "lll" }, 3305 1.1 mrg { "__insn_shl1add", TILEGX_INSN_SHL1ADD, true, "lll" }, 3306 1.1 mrg { "__insn_shl1addx", TILEGX_INSN_SHL1ADDX, true, "iii" }, 3307 1.1 mrg { "__insn_shl2add", TILEGX_INSN_SHL2ADD, true, "lll" }, 3308 1.1 mrg { "__insn_shl2addx", TILEGX_INSN_SHL2ADDX, true, "iii" }, 3309 1.1 mrg { "__insn_shl3add", TILEGX_INSN_SHL3ADD, true, "lll" }, 3310 1.1 mrg { "__insn_shl3addx", TILEGX_INSN_SHL3ADDX, true, "iii" }, 3311 1.1 mrg { "__insn_shli", TILEGX_INSN_SHL, true, "lli" }, 3312 1.1 mrg { "__insn_shlx", TILEGX_INSN_SHLX, true, "iii" }, 3313 1.1 mrg { "__insn_shlxi", TILEGX_INSN_SHLX, true, "iii" }, 3314 1.1 mrg { "__insn_shrs", TILEGX_INSN_SHRS, true, "lli" }, 3315 1.1 mrg { "__insn_shrsi", TILEGX_INSN_SHRS, true, "lli" }, 3316 1.1 mrg { "__insn_shru", TILEGX_INSN_SHRU, true, "lli" }, 3317 1.1 mrg { "__insn_shrui", TILEGX_INSN_SHRU, true, "lli" }, 3318 1.1 mrg { "__insn_shrux", TILEGX_INSN_SHRUX, true, "iii" }, 3319 1.1 mrg { "__insn_shruxi", TILEGX_INSN_SHRUX, true, "iii" }, 3320 1.1 mrg { "__insn_shufflebytes", TILEGX_INSN_SHUFFLEBYTES, true, "llll" }, 3321 1.1 mrg { "__insn_shufflebytes1", TILEGX_INSN_SHUFFLEBYTES1, true, "lll" }, 3322 1.1 mrg { "__insn_st", TILEGX_INSN_ST, false, "vpl" }, 3323 1.1 mrg { "__insn_st1", TILEGX_INSN_ST1, false, "vpl" }, 3324 1.1 mrg { "__insn_st2", TILEGX_INSN_ST2, false, "vpl" }, 3325 1.1 mrg { "__insn_st4", TILEGX_INSN_ST4, false, "vpl" }, 3326 1.1 mrg { "__insn_stnt", TILEGX_INSN_STNT, false, "vpl" }, 3327 1.1 mrg { "__insn_stnt1", TILEGX_INSN_STNT1, false, "vpl" }, 3328 1.1 mrg { "__insn_stnt2", TILEGX_INSN_STNT2, false, "vpl" }, 3329 1.1 mrg { "__insn_stnt4", TILEGX_INSN_STNT4, false, "vpl" }, 3330 1.1 mrg { "__insn_sub", TILEGX_INSN_SUB, true, "lll" }, 3331 1.1 mrg { "__insn_subx", TILEGX_INSN_SUBX, true, "iii" }, 3332 1.1 mrg { "__insn_subxsc", TILEGX_INSN_SUBXSC, true, "iii" }, 3333 1.1 mrg { "__insn_tblidxb0", TILEGX_INSN_TBLIDXB0, true, "lll" }, 3334 1.1 mrg { "__insn_tblidxb1", TILEGX_INSN_TBLIDXB1, true, "lll" }, 3335 1.1 mrg { "__insn_tblidxb2", TILEGX_INSN_TBLIDXB2, true, "lll" }, 3336 1.1 mrg { "__insn_tblidxb3", TILEGX_INSN_TBLIDXB3, true, "lll" }, 3337 1.1 mrg { "__insn_v1add", TILEGX_INSN_V1ADD, true, "lll" }, 3338 1.1 mrg { "__insn_v1addi", TILEGX_INSN_V1ADDI, true, "lll" }, 3339 1.1 mrg { "__insn_v1adduc", TILEGX_INSN_V1ADDUC, true, "lll" }, 3340 1.1 mrg { "__insn_v1adiffu", TILEGX_INSN_V1ADIFFU, true, "lll" }, 3341 1.1 mrg { "__insn_v1avgu", TILEGX_INSN_V1AVGU, true, "lll" }, 3342 1.1 mrg { "__insn_v1cmpeq", TILEGX_INSN_V1CMPEQ, true, "lll" }, 3343 1.1 mrg { "__insn_v1cmpeqi", TILEGX_INSN_V1CMPEQI, true, "lll" }, 3344 1.1 mrg { "__insn_v1cmples", TILEGX_INSN_V1CMPLES, true, "lll" }, 3345 1.1 mrg { "__insn_v1cmpleu", TILEGX_INSN_V1CMPLEU, true, "lll" }, 3346 1.1 mrg { "__insn_v1cmplts", TILEGX_INSN_V1CMPLTS, true, "lll" }, 3347 1.1 mrg { "__insn_v1cmpltsi", TILEGX_INSN_V1CMPLTSI, true, "lll" }, 3348 1.1 mrg { "__insn_v1cmpltu", TILEGX_INSN_V1CMPLTU, true, "lll" }, 3349 1.1 mrg { "__insn_v1cmpltui", TILEGX_INSN_V1CMPLTUI, true, "lll" }, 3350 1.1 mrg { "__insn_v1cmpne", TILEGX_INSN_V1CMPNE, true, "lll" }, 3351 1.1 mrg { "__insn_v1ddotpu", TILEGX_INSN_V1DDOTPU, true, "lll" }, 3352 1.1 mrg { "__insn_v1ddotpua", TILEGX_INSN_V1DDOTPUA, true, "llll" }, 3353 1.1 mrg { "__insn_v1ddotpus", TILEGX_INSN_V1DDOTPUS, true, "lll" }, 3354 1.1 mrg { "__insn_v1ddotpusa", TILEGX_INSN_V1DDOTPUSA, true, "llll" }, 3355 1.1 mrg { "__insn_v1dotp", TILEGX_INSN_V1DOTP, true, "lll" }, 3356 1.1 mrg { "__insn_v1dotpa", TILEGX_INSN_V1DOTPA, true, "llll" }, 3357 1.1 mrg { "__insn_v1dotpu", TILEGX_INSN_V1DOTPU, true, "lll" }, 3358 1.1 mrg { "__insn_v1dotpua", TILEGX_INSN_V1DOTPUA, true, "llll" }, 3359 1.1 mrg { "__insn_v1dotpus", TILEGX_INSN_V1DOTPUS, true, "lll" }, 3360 1.1 mrg { "__insn_v1dotpusa", TILEGX_INSN_V1DOTPUSA, true, "llll" }, 3361 1.1 mrg { "__insn_v1int_h", TILEGX_INSN_V1INT_H, true, "lll" }, 3362 1.1 mrg { "__insn_v1int_l", TILEGX_INSN_V1INT_L, true, "lll" }, 3363 1.1 mrg { "__insn_v1maxu", TILEGX_INSN_V1MAXU, true, "lll" }, 3364 1.1 mrg { "__insn_v1maxui", TILEGX_INSN_V1MAXUI, true, "lll" }, 3365 1.1 mrg { "__insn_v1minu", TILEGX_INSN_V1MINU, true, "lll" }, 3366 1.1 mrg { "__insn_v1minui", TILEGX_INSN_V1MINUI, true, "lll" }, 3367 1.1 mrg { "__insn_v1mnz", TILEGX_INSN_V1MNZ, true, "lll" }, 3368 1.1 mrg { "__insn_v1multu", TILEGX_INSN_V1MULTU, true, "lll" }, 3369 1.1 mrg { "__insn_v1mulu", TILEGX_INSN_V1MULU, true, "lll" }, 3370 1.1 mrg { "__insn_v1mulus", TILEGX_INSN_V1MULUS, true, "lll" }, 3371 1.1 mrg { "__insn_v1mz", TILEGX_INSN_V1MZ, true, "lll" }, 3372 1.1 mrg { "__insn_v1sadau", TILEGX_INSN_V1SADAU, true, "llll" }, 3373 1.1 mrg { "__insn_v1sadu", TILEGX_INSN_V1SADU, true, "lll" }, 3374 1.1 mrg { "__insn_v1shl", TILEGX_INSN_V1SHL, true, "lll" }, 3375 1.1 mrg { "__insn_v1shli", TILEGX_INSN_V1SHLI, true, "lll" }, 3376 1.1 mrg { "__insn_v1shrs", TILEGX_INSN_V1SHRS, true, "lll" }, 3377 1.1 mrg { "__insn_v1shrsi", TILEGX_INSN_V1SHRSI, true, "lll" }, 3378 1.1 mrg { "__insn_v1shru", TILEGX_INSN_V1SHRU, true, "lll" }, 3379 1.1 mrg { "__insn_v1shrui", TILEGX_INSN_V1SHRUI, true, "lll" }, 3380 1.1 mrg { "__insn_v1sub", TILEGX_INSN_V1SUB, true, "lll" }, 3381 1.1 mrg { "__insn_v1subuc", TILEGX_INSN_V1SUBUC, true, "lll" }, 3382 1.1 mrg { "__insn_v2add", TILEGX_INSN_V2ADD, true, "lll" }, 3383 1.1 mrg { "__insn_v2addi", TILEGX_INSN_V2ADDI, true, "lll" }, 3384 1.1 mrg { "__insn_v2addsc", TILEGX_INSN_V2ADDSC, true, "lll" }, 3385 1.1 mrg { "__insn_v2adiffs", TILEGX_INSN_V2ADIFFS, true, "lll" }, 3386 1.1 mrg { "__insn_v2avgs", TILEGX_INSN_V2AVGS, true, "lll" }, 3387 1.1 mrg { "__insn_v2cmpeq", TILEGX_INSN_V2CMPEQ, true, "lll" }, 3388 1.1 mrg { "__insn_v2cmpeqi", TILEGX_INSN_V2CMPEQI, true, "lll" }, 3389 1.1 mrg { "__insn_v2cmples", TILEGX_INSN_V2CMPLES, true, "lll" }, 3390 1.1 mrg { "__insn_v2cmpleu", TILEGX_INSN_V2CMPLEU, true, "lll" }, 3391 1.1 mrg { "__insn_v2cmplts", TILEGX_INSN_V2CMPLTS, true, "lll" }, 3392 1.1 mrg { "__insn_v2cmpltsi", TILEGX_INSN_V2CMPLTSI, true, "lll" }, 3393 1.1 mrg { "__insn_v2cmpltu", TILEGX_INSN_V2CMPLTU, true, "lll" }, 3394 1.1 mrg { "__insn_v2cmpltui", TILEGX_INSN_V2CMPLTUI, true, "lll" }, 3395 1.1 mrg { "__insn_v2cmpne", TILEGX_INSN_V2CMPNE, true, "lll" }, 3396 1.1 mrg { "__insn_v2dotp", TILEGX_INSN_V2DOTP, true, "lll" }, 3397 1.1 mrg { "__insn_v2dotpa", TILEGX_INSN_V2DOTPA, true, "llll" }, 3398 1.1 mrg { "__insn_v2int_h", TILEGX_INSN_V2INT_H, true, "lll" }, 3399 1.1 mrg { "__insn_v2int_l", TILEGX_INSN_V2INT_L, true, "lll" }, 3400 1.1 mrg { "__insn_v2maxs", TILEGX_INSN_V2MAXS, true, "lll" }, 3401 1.1 mrg { "__insn_v2maxsi", TILEGX_INSN_V2MAXSI, true, "lll" }, 3402 1.1 mrg { "__insn_v2mins", TILEGX_INSN_V2MINS, true, "lll" }, 3403 1.1 mrg { "__insn_v2minsi", TILEGX_INSN_V2MINSI, true, "lll" }, 3404 1.1 mrg { "__insn_v2mnz", TILEGX_INSN_V2MNZ, true, "lll" }, 3405 1.1 mrg { "__insn_v2mulfsc", TILEGX_INSN_V2MULFSC, true, "lll" }, 3406 1.1 mrg { "__insn_v2muls", TILEGX_INSN_V2MULS, true, "lll" }, 3407 1.1 mrg { "__insn_v2mults", TILEGX_INSN_V2MULTS, true, "lll" }, 3408 1.1 mrg { "__insn_v2mz", TILEGX_INSN_V2MZ, true, "lll" }, 3409 1.1 mrg { "__insn_v2packh", TILEGX_INSN_V2PACKH, true, "lll" }, 3410 1.1 mrg { "__insn_v2packl", TILEGX_INSN_V2PACKL, true, "lll" }, 3411 1.1 mrg { "__insn_v2packuc", TILEGX_INSN_V2PACKUC, true, "lll" }, 3412 1.1 mrg { "__insn_v2sadas", TILEGX_INSN_V2SADAS, true, "llll" }, 3413 1.1 mrg { "__insn_v2sadau", TILEGX_INSN_V2SADAU, true, "llll" }, 3414 1.1 mrg { "__insn_v2sads", TILEGX_INSN_V2SADS, true, "lll" }, 3415 1.1 mrg { "__insn_v2sadu", TILEGX_INSN_V2SADU, true, "lll" }, 3416 1.1 mrg { "__insn_v2shl", TILEGX_INSN_V2SHL, true, "lll" }, 3417 1.1 mrg { "__insn_v2shli", TILEGX_INSN_V2SHLI, true, "lll" }, 3418 1.1 mrg { "__insn_v2shlsc", TILEGX_INSN_V2SHLSC, true, "lll" }, 3419 1.1 mrg { "__insn_v2shrs", TILEGX_INSN_V2SHRS, true, "lll" }, 3420 1.1 mrg { "__insn_v2shrsi", TILEGX_INSN_V2SHRSI, true, "lll" }, 3421 1.1 mrg { "__insn_v2shru", TILEGX_INSN_V2SHRU, true, "lll" }, 3422 1.1 mrg { "__insn_v2shrui", TILEGX_INSN_V2SHRUI, true, "lll" }, 3423 1.1 mrg { "__insn_v2sub", TILEGX_INSN_V2SUB, true, "lll" }, 3424 1.1 mrg { "__insn_v2subsc", TILEGX_INSN_V2SUBSC, true, "lll" }, 3425 1.1 mrg { "__insn_v4add", TILEGX_INSN_V4ADD, true, "lll" }, 3426 1.1 mrg { "__insn_v4addsc", TILEGX_INSN_V4ADDSC, true, "lll" }, 3427 1.1 mrg { "__insn_v4int_h", TILEGX_INSN_V4INT_H, true, "lll" }, 3428 1.1 mrg { "__insn_v4int_l", TILEGX_INSN_V4INT_L, true, "lll" }, 3429 1.1 mrg { "__insn_v4packsc", TILEGX_INSN_V4PACKSC, true, "lll" }, 3430 1.1 mrg { "__insn_v4shl", TILEGX_INSN_V4SHL, true, "lll" }, 3431 1.1 mrg { "__insn_v4shlsc", TILEGX_INSN_V4SHLSC, true, "lll" }, 3432 1.1 mrg { "__insn_v4shrs", TILEGX_INSN_V4SHRS, true, "lll" }, 3433 1.1 mrg { "__insn_v4shru", TILEGX_INSN_V4SHRU, true, "lll" }, 3434 1.1 mrg { "__insn_v4sub", TILEGX_INSN_V4SUB, true, "lll" }, 3435 1.1 mrg { "__insn_v4subsc", TILEGX_INSN_V4SUBSC, true, "lll" }, 3436 1.1 mrg { "__insn_wh64", TILEGX_INSN_WH64, false, "vp" }, 3437 1.1 mrg { "__insn_xor", TILEGX_INSN_XOR, true, "lll" }, 3438 1.1 mrg { "__insn_xori", TILEGX_INSN_XOR, true, "lll" }, 3439 1.1 mrg { "__tile_network_barrier", TILEGX_NETWORK_BARRIER, false, "v" }, 3440 1.1 mrg { "__tile_idn0_receive", TILEGX_IDN0_RECEIVE, false, "l" }, 3441 1.1 mrg { "__tile_idn1_receive", TILEGX_IDN1_RECEIVE, false, "l" }, 3442 1.1 mrg { "__tile_idn_send", TILEGX_IDN_SEND, false, "vl" }, 3443 1.1 mrg { "__tile_udn0_receive", TILEGX_UDN0_RECEIVE, false, "l" }, 3444 1.1 mrg { "__tile_udn1_receive", TILEGX_UDN1_RECEIVE, false, "l" }, 3445 1.1 mrg { "__tile_udn2_receive", TILEGX_UDN2_RECEIVE, false, "l" }, 3446 1.1 mrg { "__tile_udn3_receive", TILEGX_UDN3_RECEIVE, false, "l" }, 3447 1.1 mrg { "__tile_udn_send", TILEGX_UDN_SEND, false, "vl" }, 3448 1.1 mrg }; 3449 1.1 mrg 3450 1.1 mrg 3451 1.1 mrg /* Convert a character in a builtin type string to a tree type. */ 3452 1.1 mrg static tree 3453 1.1 mrg char_to_type (char c) 3454 1.1 mrg { 3455 1.1 mrg static tree volatile_ptr_type_node = NULL; 3456 1.1 mrg static tree volatile_const_ptr_type_node = NULL; 3457 1.1 mrg 3458 1.1 mrg if (volatile_ptr_type_node == NULL) 3459 1.1 mrg { 3460 1.1 mrg volatile_ptr_type_node = 3461 1.1 mrg build_pointer_type (build_qualified_type (void_type_node, 3462 1.1 mrg TYPE_QUAL_VOLATILE)); 3463 1.1 mrg volatile_const_ptr_type_node = 3464 1.1 mrg build_pointer_type (build_qualified_type (void_type_node, 3465 1.1 mrg TYPE_QUAL_CONST 3466 1.1 mrg | TYPE_QUAL_VOLATILE)); 3467 1.1 mrg } 3468 1.1 mrg 3469 1.1 mrg switch (c) 3470 1.1 mrg { 3471 1.1 mrg case 'v': 3472 1.1 mrg return void_type_node; 3473 1.1 mrg case 'i': 3474 1.1 mrg return unsigned_type_node; 3475 1.1 mrg case 'l': 3476 1.1 mrg return long_long_unsigned_type_node; 3477 1.1 mrg case 'p': 3478 1.1 mrg return volatile_ptr_type_node; 3479 1.1 mrg case 'k': 3480 1.1 mrg return volatile_const_ptr_type_node; 3481 1.1 mrg default: 3482 1.1 mrg gcc_unreachable (); 3483 1.1 mrg } 3484 1.1 mrg } 3485 1.1 mrg 3486 1.1 mrg 3487 1.1 mrg /* Implement TARGET_INIT_BUILTINS. */ 3488 1.1 mrg static void 3489 1.1 mrg tilegx_init_builtins (void) 3490 1.1 mrg { 3491 1.1 mrg size_t i; 3492 1.1 mrg 3493 1.1 mrg for (i = 0; i < ARRAY_SIZE (tilegx_builtins); i++) 3494 1.1 mrg { 3495 1.1 mrg const struct tilegx_builtin_def *p = &tilegx_builtins[i]; 3496 1.1 mrg tree ftype, ret_type, arg_type_list = void_list_node; 3497 1.1 mrg tree decl; 3498 1.1 mrg int j; 3499 1.1 mrg 3500 1.1 mrg for (j = strlen (p->type) - 1; j > 0; j--) 3501 1.1 mrg { 3502 1.1 mrg arg_type_list = 3503 1.1 mrg tree_cons (NULL_TREE, char_to_type (p->type[j]), arg_type_list); 3504 1.1 mrg } 3505 1.1 mrg 3506 1.1 mrg ret_type = char_to_type (p->type[0]); 3507 1.1 mrg 3508 1.1 mrg ftype = build_function_type (ret_type, arg_type_list); 3509 1.1 mrg 3510 1.1 mrg decl = add_builtin_function (p->name, ftype, p->code, BUILT_IN_MD, 3511 1.1 mrg NULL, NULL); 3512 1.1 mrg 3513 1.1 mrg if (p->is_const) 3514 1.1 mrg TREE_READONLY (decl) = 1; 3515 1.1 mrg TREE_NOTHROW (decl) = 1; 3516 1.1 mrg 3517 1.1 mrg if (tilegx_builtin_info[p->code].fndecl == NULL) 3518 1.1 mrg tilegx_builtin_info[p->code].fndecl = decl; 3519 1.1 mrg } 3520 1.1 mrg } 3521 1.1 mrg 3522 1.1 mrg 3523 1.1 mrg /* Implement TARGET_EXPAND_BUILTIN. */ 3524 1.1 mrg static rtx 3525 1.1 mrg tilegx_expand_builtin (tree exp, 3526 1.1 mrg rtx target, 3527 1.1 mrg rtx subtarget ATTRIBUTE_UNUSED, 3528 1.1 mrg machine_mode mode ATTRIBUTE_UNUSED, 3529 1.1 mrg int ignore ATTRIBUTE_UNUSED) 3530 1.1 mrg { 3531 1.1 mrg #define MAX_BUILTIN_ARGS 4 3532 1.1 mrg 3533 1.1 mrg tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); 3534 1.1 mrg unsigned int fcode = DECL_MD_FUNCTION_CODE (fndecl); 3535 1.1 mrg tree arg; 3536 1.1 mrg call_expr_arg_iterator iter; 3537 1.1 mrg enum insn_code icode; 3538 1.1 mrg rtx op[MAX_BUILTIN_ARGS + 1], pat; 3539 1.1 mrg int opnum; 3540 1.1 mrg bool nonvoid; 3541 1.1 mrg insn_gen_fn fn; 3542 1.1 mrg 3543 1.1 mrg if (fcode >= TILEGX_BUILTIN_max) 3544 1.1 mrg internal_error ("bad builtin fcode"); 3545 1.1 mrg icode = tilegx_builtin_info[fcode].icode; 3546 1.1 mrg if (icode == 0) 3547 1.1 mrg internal_error ("bad builtin icode"); 3548 1.1 mrg 3549 1.1 mrg nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node; 3550 1.1 mrg 3551 1.1 mrg opnum = nonvoid; 3552 1.1 mrg FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) 3553 1.1 mrg { 3554 1.1 mrg const struct insn_operand_data *insn_op; 3555 1.1 mrg 3556 1.1 mrg if (arg == error_mark_node) 3557 1.1 mrg return NULL_RTX; 3558 1.1 mrg if (opnum > MAX_BUILTIN_ARGS) 3559 1.1 mrg return NULL_RTX; 3560 1.1 mrg 3561 1.1 mrg insn_op = &insn_data[icode].operand[opnum]; 3562 1.1 mrg 3563 1.1 mrg op[opnum] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL); 3564 1.1 mrg 3565 1.1 mrg if (!(*insn_op->predicate) (op[opnum], insn_op->mode)) 3566 1.1 mrg { 3567 1.1 mrg machine_mode opmode = insn_op->mode; 3568 1.1 mrg 3569 1.1 mrg /* pointer_operand and pmode_register_operand operands do 3570 1.1 mrg not specify a mode, so use the operand's mode instead 3571 1.1 mrg (which should always be right by the time we get here, 3572 1.1 mrg except for constants, which are VOIDmode). */ 3573 1.1 mrg if (opmode == VOIDmode) 3574 1.1 mrg { 3575 1.1 mrg machine_mode m = GET_MODE (op[opnum]); 3576 1.1 mrg gcc_assert (m == Pmode || m == VOIDmode); 3577 1.1 mrg opmode = Pmode; 3578 1.1 mrg } 3579 1.1 mrg 3580 1.1 mrg op[opnum] = copy_to_mode_reg (opmode, op[opnum]); 3581 1.1 mrg } 3582 1.1 mrg 3583 1.1 mrg if (!(*insn_op->predicate) (op[opnum], insn_op->mode)) 3584 1.1 mrg { 3585 1.1 mrg /* We still failed to meet the predicate even after moving 3586 1.1 mrg into a register. Assume we needed an immediate. */ 3587 1.1 mrg error_at (EXPR_LOCATION (exp), 3588 1.1 mrg "operand must be an immediate of the right size"); 3589 1.1 mrg return const0_rtx; 3590 1.1 mrg } 3591 1.1 mrg 3592 1.1 mrg opnum++; 3593 1.1 mrg } 3594 1.1 mrg 3595 1.1 mrg if (nonvoid) 3596 1.1 mrg { 3597 1.1 mrg machine_mode tmode = insn_data[icode].operand[0].mode; 3598 1.1 mrg if (!target 3599 1.1 mrg || GET_MODE (target) != tmode 3600 1.1 mrg || !(*insn_data[icode].operand[0].predicate) (target, tmode)) 3601 1.1 mrg { 3602 1.1 mrg if (tmode == VOIDmode) 3603 1.1 mrg { 3604 1.1 mrg /* get the mode from the return type. */ 3605 1.1 mrg tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))); 3606 1.1 mrg } 3607 1.1 mrg target = gen_reg_rtx (tmode); 3608 1.1 mrg } 3609 1.1 mrg op[0] = target; 3610 1.1 mrg } 3611 1.1 mrg 3612 1.1 mrg fn = GEN_FCN (icode); 3613 1.1 mrg switch (opnum) 3614 1.1 mrg { 3615 1.1 mrg case 0: 3616 1.1 mrg pat = fn (NULL_RTX); 3617 1.1 mrg break; 3618 1.1 mrg case 1: 3619 1.1 mrg pat = fn (op[0]); 3620 1.1 mrg break; 3621 1.1 mrg case 2: 3622 1.1 mrg pat = fn (op[0], op[1]); 3623 1.1 mrg break; 3624 1.1 mrg case 3: 3625 1.1 mrg pat = fn (op[0], op[1], op[2]); 3626 1.1 mrg break; 3627 1.1 mrg case 4: 3628 1.1 mrg pat = fn (op[0], op[1], op[2], op[3]); 3629 1.1 mrg break; 3630 1.1 mrg case 5: 3631 1.1 mrg pat = fn (op[0], op[1], op[2], op[3], op[4]); 3632 1.1 mrg break; 3633 1.1 mrg default: 3634 1.1 mrg gcc_unreachable (); 3635 1.1 mrg } 3636 1.1 mrg if (!pat) 3637 1.1 mrg return NULL_RTX; 3638 1.1 mrg 3639 1.1 mrg /* If we are generating a prefetch, tell the scheduler not to move 3640 1.1 mrg it around. */ 3641 1.1 mrg if (GET_CODE (pat) == PREFETCH) 3642 1.1 mrg PREFETCH_SCHEDULE_BARRIER_P (pat) = true; 3643 1.1 mrg 3644 1.1 mrg emit_insn (pat); 3645 1.1 mrg 3646 1.1 mrg if (nonvoid) 3647 1.1 mrg return target; 3648 1.1 mrg else 3649 1.1 mrg return const0_rtx; 3650 1.1 mrg } 3651 1.1 mrg 3652 1.1 mrg 3653 1.1 mrg /* Implement TARGET_BUILTIN_DECL. */ 3654 1.1 mrg static tree 3655 1.1 mrg tilegx_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) 3656 1.1 mrg { 3657 1.1 mrg if (code >= TILEGX_BUILTIN_max) 3658 1.1 mrg return error_mark_node; 3659 1.1 mrg 3660 1.1 mrg return tilegx_builtin_info[code].fndecl; 3661 1.1 mrg } 3662 1.1 mrg 3663 1.1 mrg 3665 1.1 mrg 3666 1.1 mrg /* Stack frames */ 3667 1.1 mrg 3668 1.1 mrg /* Return whether REGNO needs to be saved in the stack frame. */ 3669 1.1 mrg static bool 3670 1.1 mrg need_to_save_reg (unsigned int regno) 3671 1.1 mrg { 3672 1.1 mrg if (!call_used_or_fixed_reg_p (regno) 3673 1.1 mrg && df_regs_ever_live_p (regno)) 3674 1.1 mrg return true; 3675 1.1 mrg 3676 1.1 mrg if (flag_pic 3677 1.1 mrg && (regno == PIC_OFFSET_TABLE_REGNUM 3678 1.1 mrg || regno == TILEGX_PIC_TEXT_LABEL_REGNUM) 3679 1.1 mrg && (crtl->uses_pic_offset_table || crtl->saves_all_registers)) 3680 1.1 mrg return true; 3681 1.1 mrg 3682 1.1 mrg if (crtl->calls_eh_return) 3683 1.1 mrg { 3684 1.1 mrg unsigned i; 3685 1.1 mrg for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; i++) 3686 1.1 mrg { 3687 1.1 mrg if (regno == EH_RETURN_DATA_REGNO (i)) 3688 1.1 mrg return true; 3689 1.1 mrg } 3690 1.1 mrg } 3691 1.1 mrg 3692 1.1 mrg return false; 3693 1.1 mrg } 3694 1.1 mrg 3695 1.1 mrg 3696 1.1 mrg /* Return the size of the register savev area. This function is only 3697 1.1 mrg correct starting with local register allocation */ 3698 1.1 mrg static int 3699 1.1 mrg tilegx_saved_regs_size (void) 3700 1.1 mrg { 3701 1.1 mrg int reg_save_size = 0; 3702 1.1 mrg int regno; 3703 1.1 mrg int offset_to_frame; 3704 1.1 mrg int align_mask; 3705 1.1 mrg 3706 1.1 mrg for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) 3707 1.1 mrg if (need_to_save_reg (regno)) 3708 1.1 mrg reg_save_size += UNITS_PER_WORD; 3709 1.1 mrg 3710 1.1 mrg /* Pad out the register save area if necessary to make 3711 1.1 mrg frame_pointer_rtx be as aligned as the stack pointer. */ 3712 1.1 mrg offset_to_frame = crtl->args.pretend_args_size + reg_save_size; 3713 1.1 mrg align_mask = (STACK_BOUNDARY / BITS_PER_UNIT) - 1; 3714 1.1 mrg reg_save_size += (-offset_to_frame) & align_mask; 3715 1.1 mrg 3716 1.1 mrg return reg_save_size; 3717 1.1 mrg } 3718 1.1 mrg 3719 1.1 mrg 3720 1.1 mrg /* Round up frame size SIZE. */ 3721 1.1 mrg static int 3722 1.1 mrg round_frame_size (int size) 3723 1.1 mrg { 3724 1.1 mrg return ((size + STACK_BOUNDARY / BITS_PER_UNIT - 1) 3725 1.1 mrg & -STACK_BOUNDARY / BITS_PER_UNIT); 3726 1.1 mrg } 3727 1.1 mrg 3728 1.1 mrg 3729 1.1 mrg /* Emit a store in the stack frame to save REGNO at address ADDR, and 3730 1.1 mrg emit the corresponding REG_CFA_OFFSET note described by CFA and 3731 1.1 mrg CFA_OFFSET. Return the emitted insn. */ 3732 1.1 mrg static rtx 3733 1.1 mrg frame_emit_store (int regno, int regno_note, rtx addr, rtx cfa, 3734 1.1 mrg int cfa_offset) 3735 1.1 mrg { 3736 1.1 mrg rtx reg = gen_rtx_REG (DImode, regno); 3737 1.1 mrg rtx mem = gen_frame_mem (DImode, addr); 3738 1.1 mrg rtx mov = gen_movdi (mem, reg); 3739 1.1 mrg 3740 1.1 mrg /* Describe what just happened in a way that dwarf understands. We 3741 1.1 mrg use temporary registers to hold the address to make scheduling 3742 1.1 mrg easier, and use the REG_CFA_OFFSET to describe the address as an 3743 1.1 mrg offset from the CFA. */ 3744 1.1 mrg rtx reg_note = gen_rtx_REG (DImode, regno_note); 3745 1.1 mrg rtx cfa_relative_addr = gen_rtx_PLUS (Pmode, cfa, GEN_INT (cfa_offset)); 3746 1.1 mrg rtx cfa_relative_mem = gen_frame_mem (DImode, cfa_relative_addr); 3747 1.1 mrg rtx real = gen_rtx_SET (cfa_relative_mem, reg_note); 3748 1.1 mrg add_reg_note (mov, REG_CFA_OFFSET, real); 3749 1.1 mrg 3750 1.1 mrg return emit_insn (mov); 3751 1.1 mrg } 3752 1.1 mrg 3753 1.1 mrg 3754 1.1 mrg /* Emit a load in the stack frame to load REGNO from address ADDR. 3755 1.1 mrg Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is 3756 1.1 mrg non-null. Return the emitted insn. */ 3757 1.1 mrg static rtx_insn * 3758 1.1 mrg frame_emit_load (int regno, rtx addr, rtx *cfa_restores) 3759 1.1 mrg { 3760 1.1 mrg rtx reg = gen_rtx_REG (DImode, regno); 3761 1.1 mrg rtx mem = gen_frame_mem (DImode, addr); 3762 1.1 mrg if (cfa_restores) 3763 1.1 mrg *cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, *cfa_restores); 3764 1.1 mrg return emit_insn (gen_movdi (reg, mem)); 3765 1.1 mrg } 3766 1.1 mrg 3767 1.1 mrg 3768 1.1 mrg /* Helper function to set RTX_FRAME_RELATED_P on instructions, 3769 1.1 mrg including sequences. */ 3770 1.1 mrg static rtx 3771 1.1 mrg set_frame_related_p (void) 3772 1.1 mrg { 3773 1.1 mrg rtx_insn *seq = get_insns (); 3774 1.1 mrg rtx_insn *insn; 3775 1.1 mrg 3776 1.1 mrg end_sequence (); 3777 1.1 mrg 3778 1.1 mrg if (!seq) 3779 1.1 mrg return NULL_RTX; 3780 1.1 mrg 3781 1.1 mrg if (INSN_P (seq)) 3782 1.1 mrg { 3783 1.1 mrg insn = seq; 3784 1.1 mrg while (insn != NULL_RTX) 3785 1.1 mrg { 3786 1.1 mrg RTX_FRAME_RELATED_P (insn) = 1; 3787 1.1 mrg insn = NEXT_INSN (insn); 3788 1.1 mrg } 3789 1.1 mrg seq = emit_insn (seq); 3790 1.1 mrg } 3791 1.1 mrg else 3792 1.1 mrg { 3793 1.1 mrg seq = emit_insn (seq); 3794 1.1 mrg RTX_FRAME_RELATED_P (seq) = 1; 3795 1.1 mrg } 3796 1.1 mrg return seq; 3797 1.1 mrg } 3798 1.1 mrg 3799 1.1 mrg 3800 1.1 mrg #define FRP(exp) (start_sequence (), exp, set_frame_related_p ()) 3801 1.1 mrg 3802 1.1 mrg /* This emits code for 'sp += offset'. 3803 1.1 mrg 3804 1.1 mrg The ABI only allows us to modify 'sp' in a single 'addi' or 3805 1.1 mrg 'addli', so the backtracer understands it. Larger amounts cannot 3806 1.1 mrg use those instructions, so are added by placing the offset into a 3807 1.1 mrg large register and using 'add'. 3808 1.1 mrg 3809 1.1 mrg This happens after reload, so we need to expand it ourselves. */ 3810 1.1 mrg static rtx_insn * 3811 1.1 mrg emit_sp_adjust (int offset, int *next_scratch_regno, bool frame_related, 3812 1.1 mrg rtx reg_notes) 3813 1.1 mrg { 3814 1.1 mrg rtx to_add; 3815 1.1 mrg rtx imm_rtx = GEN_INT (offset); 3816 1.1 mrg rtx pat; 3817 1.1 mrg rtx_insn *insn; 3818 1.1 mrg 3819 1.1 mrg if (satisfies_constraint_J (imm_rtx)) 3820 1.1 mrg { 3821 1.1 mrg /* We can add this using a single immediate add. */ 3822 1.1 mrg to_add = imm_rtx; 3823 1.1 mrg } 3824 1.1 mrg else 3825 1.1 mrg { 3826 1.1 mrg rtx tmp = gen_rtx_REG (Pmode, (*next_scratch_regno)--); 3827 1.1 mrg tilegx_expand_set_const64 (tmp, imm_rtx); 3828 1.1 mrg to_add = tmp; 3829 1.1 mrg } 3830 1.1 mrg 3831 1.1 mrg /* Actually adjust the stack pointer. */ 3832 1.1 mrg if (TARGET_32BIT) 3833 1.1 mrg pat = gen_sp_adjust_32bit (stack_pointer_rtx, stack_pointer_rtx, to_add); 3834 1.1 mrg else 3835 1.1 mrg pat = gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx, to_add); 3836 1.1 mrg 3837 1.1 mrg insn = emit_insn (pat); 3838 1.1 mrg REG_NOTES (insn) = reg_notes; 3839 1.1 mrg 3840 1.1 mrg /* Describe what just happened in a way that dwarf understands. */ 3841 1.1 mrg if (frame_related) 3842 1.1 mrg { 3843 1.1 mrg rtx real = gen_rtx_SET (stack_pointer_rtx, 3844 1.1 mrg gen_rtx_PLUS (Pmode, stack_pointer_rtx, 3845 1.1 mrg imm_rtx)); 3846 1.1 mrg RTX_FRAME_RELATED_P (insn) = 1; 3847 1.1 mrg add_reg_note (insn, REG_CFA_ADJUST_CFA, real); 3848 1.1 mrg } 3849 1.1 mrg 3850 1.1 mrg return insn; 3851 1.1 mrg } 3852 1.1 mrg 3853 1.1 mrg 3854 1.1 mrg /* Return whether the current function is leaf. This takes into 3855 1.1 mrg account whether the function calls tls_get_addr. */ 3856 1.1 mrg static bool 3857 1.1 mrg tilegx_current_function_is_leaf (void) 3858 1.1 mrg { 3859 1.1 mrg return crtl->is_leaf && !cfun->machine->calls_tls_get_addr; 3860 1.1 mrg } 3861 1.1 mrg 3862 1.1 mrg 3863 1.1 mrg /* Return the frame size. */ 3864 1.1 mrg static int 3865 1.1 mrg compute_total_frame_size (void) 3866 1.1 mrg { 3867 1.1 mrg int total_size = (get_frame_size () + tilegx_saved_regs_size () 3868 1.1 mrg + crtl->outgoing_args_size 3869 1.1 mrg + crtl->args.pretend_args_size); 3870 1.1 mrg 3871 1.1 mrg if (!tilegx_current_function_is_leaf () || cfun->calls_alloca) 3872 1.1 mrg { 3873 1.1 mrg /* Make room for save area in callee. */ 3874 1.1 mrg total_size += STACK_POINTER_OFFSET; 3875 1.1 mrg } 3876 1.1 mrg 3877 1.1 mrg return round_frame_size (total_size); 3878 1.1 mrg } 3879 1.1 mrg 3880 1.1 mrg 3881 1.1 mrg /* Return nonzero if this function is known to have a null epilogue. 3882 1.1 mrg This allows the optimizer to omit jumps to jumps if no stack was 3883 1.1 mrg created. */ 3884 1.1 mrg bool 3885 1.1 mrg tilegx_can_use_return_insn_p (void) 3886 1.1 mrg { 3887 1.1 mrg return (reload_completed 3888 1.1 mrg && !cfun->static_chain_decl 3889 1.1 mrg && !compute_total_frame_size () 3890 1.1 mrg && tilegx_current_function_is_leaf () 3891 1.1 mrg && !crtl->profile && !df_regs_ever_live_p (TILEGX_LINK_REGNUM)); 3892 1.1 mrg } 3893 1.1 mrg 3894 1.1 mrg 3895 1.1 mrg /* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there 3896 1.1 mrg is a frame pointer, it computes the value relative to 3897 1.1 mrg that. Otherwise it uses the stack pointer. */ 3898 1.1 mrg static rtx 3899 1.1 mrg compute_frame_addr (int offset_from_fp, int *next_scratch_regno) 3900 1.1 mrg { 3901 1.1 mrg rtx base_reg_rtx, tmp_reg_rtx, offset_rtx; 3902 1.1 mrg int offset_from_base; 3903 1.1 mrg 3904 1.1 mrg if (frame_pointer_needed) 3905 1.1 mrg { 3906 1.1 mrg base_reg_rtx = hard_frame_pointer_rtx; 3907 1.1 mrg offset_from_base = offset_from_fp; 3908 1.1 mrg } 3909 1.1 mrg else 3910 1.1 mrg { 3911 1.1 mrg int offset_from_sp = compute_total_frame_size () + offset_from_fp; 3912 1.1 mrg offset_from_base = offset_from_sp; 3913 1.1 mrg base_reg_rtx = stack_pointer_rtx; 3914 1.1 mrg } 3915 1.1 mrg 3916 1.1 mrg if (offset_from_base == 0) 3917 1.1 mrg return base_reg_rtx; 3918 1.1 mrg 3919 1.1 mrg /* Compute the new value of the stack pointer. */ 3920 1.1 mrg tmp_reg_rtx = gen_rtx_REG (Pmode, (*next_scratch_regno)--); 3921 1.1 mrg offset_rtx = GEN_INT (offset_from_base); 3922 1.1 mrg 3923 1.1 mrg if (!add_operand (offset_rtx, Pmode)) 3924 1.1 mrg { 3925 1.1 mrg expand_set_cint64 (tmp_reg_rtx, offset_rtx); 3926 1.1 mrg offset_rtx = tmp_reg_rtx; 3927 1.1 mrg } 3928 1.1 mrg 3929 1.1 mrg emit_insn (gen_rtx_SET (tmp_reg_rtx, 3930 1.1 mrg gen_rtx_PLUS (Pmode, base_reg_rtx, offset_rtx))); 3931 1.1 mrg 3932 1.1 mrg return tmp_reg_rtx; 3933 1.1 mrg } 3934 1.1 mrg 3935 1.1 mrg 3936 1.1 mrg /* The stack frame looks like this: 3937 1.1 mrg +-------------+ 3938 1.1 mrg | ... | 3939 1.1 mrg | incoming | 3940 1.1 mrg | stack args | 3941 1.1 mrg AP -> +-------------+ 3942 1.1 mrg | caller's HFP| 3943 1.1 mrg +-------------+ 3944 1.1 mrg | lr save | 3945 1.1 mrg HFP -> +-------------+ 3946 1.1 mrg | var args | 3947 1.1 mrg | reg save | crtl->args.pretend_args_size bytes 3948 1.1 mrg +-------------+ 3949 1.1 mrg | ... | 3950 1.1 mrg | saved regs | tilegx_saved_regs_size() bytes 3951 1.1 mrg FP -> +-------------+ 3952 1.1 mrg | ... | 3953 1.1 mrg | vars | get_frame_size() bytes 3954 1.1 mrg +-------------+ 3955 1.1 mrg | ... | 3956 1.1 mrg | outgoing | 3957 1.1 mrg | stack args | crtl->outgoing_args_size bytes 3958 1.1 mrg +-------------+ 3959 1.1 mrg | HFP | ptr_size bytes (only here if nonleaf / alloca) 3960 1.1 mrg +-------------+ 3961 1.1 mrg | callee lr | ptr_size bytes (only here if nonleaf / alloca) 3962 1.1 mrg | save | 3963 1.1 mrg SP -> +-------------+ 3964 1.1 mrg 3965 1.1 mrg HFP == incoming SP. 3966 1.1 mrg 3967 1.1 mrg For functions with a frame larger than 32767 bytes, or which use 3968 1.1 mrg alloca (), r52 is used as a frame pointer. Otherwise there is no 3969 1.1 mrg frame pointer. 3970 1.1 mrg 3971 1.1 mrg FP is saved at SP+ptr_size before calling a subroutine so the callee 3972 1.1 mrg can chain. */ 3973 1.1 mrg void 3974 1.1 mrg tilegx_expand_prologue (void) 3975 1.1 mrg { 3976 1.1 mrg #define ROUND_ROBIN_SIZE 4 3977 1.1 mrg /* We round-robin through four scratch registers to hold temporary 3978 1.1 mrg addresses for saving registers, to make instruction scheduling 3979 1.1 mrg easier. */ 3980 1.1 mrg rtx reg_save_addr[ROUND_ROBIN_SIZE] = { 3981 1.1 mrg NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX 3982 1.1 mrg }; 3983 1.1 mrg rtx insn, cfa; 3984 1.1 mrg unsigned int which_scratch; 3985 1.1 mrg int offset, start_offset, regno; 3986 1.1 mrg 3987 1.1 mrg /* A register that holds a copy of the incoming fp. */ 3988 1.1 mrg int fp_copy_regno = -1; 3989 1.1 mrg 3990 1.1 mrg /* A register that holds a copy of the incoming sp. */ 3991 1.1 mrg int sp_copy_regno = -1; 3992 1.1 mrg 3993 1.1 mrg /* Next scratch register number to hand out (postdecrementing). */ 3994 1.1 mrg int next_scratch_regno = 29; 3995 1.1 mrg 3996 1.1 mrg int total_size = compute_total_frame_size (); 3997 1.1 mrg 3998 1.1 mrg if (flag_stack_usage_info) 3999 1.1 mrg current_function_static_stack_size = total_size; 4000 1.1 mrg 4001 1.1 mrg /* Save lr first in its special location because code after this 4002 1.1 mrg might use the link register as a scratch register. */ 4003 1.1 mrg if (df_regs_ever_live_p (TILEGX_LINK_REGNUM) || crtl->calls_eh_return) 4004 1.1 mrg { 4005 1.1 mrg FRP (frame_emit_store (TILEGX_LINK_REGNUM, TILEGX_LINK_REGNUM, 4006 1.1 mrg stack_pointer_rtx, stack_pointer_rtx, 0)); 4007 1.1 mrg emit_insn (gen_blockage ()); 4008 1.1 mrg } 4009 1.1 mrg 4010 1.1 mrg if (total_size == 0) 4011 1.1 mrg { 4012 1.1 mrg /* Load the PIC register if needed. */ 4013 1.1 mrg if (flag_pic && crtl->uses_pic_offset_table) 4014 1.1 mrg load_pic_register (false); 4015 1.1 mrg 4016 1.1 mrg return; 4017 1.1 mrg } 4018 1.1 mrg 4019 1.1 mrg cfa = stack_pointer_rtx; 4020 1.1 mrg 4021 1.1 mrg if (frame_pointer_needed) 4022 1.1 mrg { 4023 1.1 mrg fp_copy_regno = next_scratch_regno--; 4024 1.1 mrg 4025 1.1 mrg /* Copy the old frame pointer aside so we can save it later. */ 4026 1.1 mrg insn = 4027 1.1 mrg FRP (emit_move_insn (gen_rtx_REG (word_mode, fp_copy_regno), 4028 1.1 mrg gen_lowpart (word_mode, hard_frame_pointer_rtx))); 4029 1.1 mrg add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX); 4030 1.1 mrg 4031 1.1 mrg /* Set up the frame pointer. */ 4032 1.1 mrg insn = FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx)); 4033 1.1 mrg add_reg_note (insn, REG_CFA_DEF_CFA, hard_frame_pointer_rtx); 4034 1.1 mrg cfa = hard_frame_pointer_rtx; 4035 1.1 mrg REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY; 4036 1.1 mrg 4037 1.1 mrg /* fp holds a copy of the incoming sp, in case we need to store 4038 1.1 mrg it. */ 4039 1.1 mrg sp_copy_regno = HARD_FRAME_POINTER_REGNUM; 4040 1.1 mrg } 4041 1.1 mrg else if (!tilegx_current_function_is_leaf ()) 4042 1.1 mrg { 4043 1.1 mrg /* Copy the old stack pointer aside so we can save it later. */ 4044 1.1 mrg sp_copy_regno = next_scratch_regno--; 4045 1.1 mrg emit_move_insn (gen_rtx_REG (Pmode, sp_copy_regno), 4046 1.1 mrg stack_pointer_rtx); 4047 1.1 mrg } 4048 1.1 mrg 4049 1.1 mrg if (tilegx_current_function_is_leaf ()) 4050 1.1 mrg { 4051 1.1 mrg /* No need to store chain pointer to caller's frame. */ 4052 1.1 mrg emit_sp_adjust (-total_size, &next_scratch_regno, 4053 1.1 mrg !frame_pointer_needed, NULL_RTX); 4054 1.1 mrg } 4055 1.1 mrg else 4056 1.1 mrg { 4057 1.1 mrg /* Save the frame pointer (incoming sp value) to support 4058 1.1 mrg backtracing. First we need to create an rtx with the store 4059 1.1 mrg address. */ 4060 1.1 mrg rtx chain_addr = gen_rtx_REG (Pmode, next_scratch_regno--); 4061 1.1 mrg rtx size_rtx = GEN_INT (-(total_size - UNITS_PER_WORD)); 4062 1.1 mrg 4063 1.1 mrg if (add_operand (size_rtx, Pmode)) 4064 1.1 mrg { 4065 1.1 mrg /* Expose more parallelism by computing this value from the 4066 1.1 mrg original stack pointer, not the one after we have pushed 4067 1.1 mrg the frame. */ 4068 1.1 mrg rtx p = gen_rtx_PLUS (Pmode, stack_pointer_rtx, size_rtx); 4069 1.1 mrg emit_insn (gen_rtx_SET (chain_addr, p)); 4070 1.1 mrg emit_sp_adjust (-total_size, &next_scratch_regno, 4071 1.1 mrg !frame_pointer_needed, NULL_RTX); 4072 1.1 mrg } 4073 1.1 mrg else 4074 1.1 mrg { 4075 1.1 mrg /* The stack frame is large, so just store the incoming sp 4076 1.1 mrg value at *(new_sp + UNITS_PER_WORD). */ 4077 1.1 mrg rtx p; 4078 1.1 mrg emit_sp_adjust (-total_size, &next_scratch_regno, 4079 1.1 mrg !frame_pointer_needed, NULL_RTX); 4080 1.1 mrg p = gen_rtx_PLUS (Pmode, stack_pointer_rtx, 4081 1.1 mrg GEN_INT (UNITS_PER_WORD)); 4082 1.1 mrg emit_insn (gen_rtx_SET (chain_addr, p)); 4083 1.1 mrg } 4084 1.1 mrg 4085 1.1 mrg /* Save our frame pointer for backtrace chaining. */ 4086 1.1 mrg emit_insn (gen_movdi (gen_frame_mem (DImode, chain_addr), 4087 1.1 mrg gen_rtx_REG (DImode, sp_copy_regno))); 4088 1.1 mrg } 4089 1.1 mrg 4090 1.1 mrg /* Compute where to start storing registers we need to save. */ 4091 1.1 mrg start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD; 4092 1.1 mrg offset = start_offset; 4093 1.1 mrg 4094 1.1 mrg /* Store all registers that need saving. */ 4095 1.1 mrg which_scratch = 0; 4096 1.1 mrg for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) 4097 1.1 mrg if (need_to_save_reg (regno)) 4098 1.1 mrg { 4099 1.1 mrg rtx r = reg_save_addr[which_scratch]; 4100 1.1 mrg int from_regno; 4101 1.1 mrg int cfa_offset = frame_pointer_needed ? offset : total_size + offset; 4102 1.1 mrg 4103 1.1 mrg if (r == NULL_RTX) 4104 1.1 mrg { 4105 1.1 mrg int prev_scratch_regno = next_scratch_regno; 4106 1.1 mrg r = compute_frame_addr (offset, &next_scratch_regno); 4107 1.1 mrg if (prev_scratch_regno != next_scratch_regno) 4108 1.1 mrg reg_save_addr[which_scratch] = r; 4109 1.1 mrg } 4110 1.1 mrg else 4111 1.1 mrg { 4112 1.1 mrg /* Advance to the next stack slot to store this 4113 1.1 mrg register. */ 4114 1.1 mrg int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD; 4115 1.1 mrg rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride)); 4116 1.1 mrg emit_insn (gen_rtx_SET (r, p)); 4117 1.1 mrg } 4118 1.1 mrg 4119 1.1 mrg /* Save this register to the stack (but use the old fp value 4120 1.1 mrg we copied aside if appropriate). */ 4121 1.1 mrg from_regno = 4122 1.1 mrg (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM) 4123 1.1 mrg ? fp_copy_regno : regno; 4124 1.1 mrg FRP (frame_emit_store (from_regno, regno, r, cfa, cfa_offset)); 4125 1.1 mrg 4126 1.1 mrg offset -= UNITS_PER_WORD; 4127 1.1 mrg which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE; 4128 1.1 mrg } 4129 1.1 mrg 4130 1.1 mrg /* If profiling, force that to happen after the frame is set up. */ 4131 1.1 mrg if (crtl->profile) 4132 1.1 mrg emit_insn (gen_blockage ()); 4133 1.1 mrg 4134 1.1 mrg /* Load the PIC register if needed. */ 4135 1.1 mrg if (flag_pic && crtl->uses_pic_offset_table) 4136 1.1 mrg load_pic_register (false); 4137 1.1 mrg } 4138 1.1 mrg 4139 1.1 mrg 4140 1.1 mrg /* Implement the epilogue and sibcall_epilogue patterns. SIBCALL_P is 4141 1.1 mrg true for a sibcall_epilogue pattern, and false for an epilogue 4142 1.1 mrg pattern. */ 4143 1.1 mrg void 4144 1.1 mrg tilegx_expand_epilogue (bool sibcall_p) 4145 1.1 mrg { 4146 1.1 mrg /* We round-robin through four scratch registers to hold temporary 4147 1.1 mrg addresses for saving registers, to make instruction scheduling 4148 1.1 mrg easier. */ 4149 1.1 mrg rtx reg_save_addr[ROUND_ROBIN_SIZE] = { 4150 1.1 mrg NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX 4151 1.1 mrg }; 4152 1.1 mrg rtx_insn *last_insn, *insn; 4153 1.1 mrg unsigned int which_scratch; 4154 1.1 mrg int offset, start_offset, regno; 4155 1.1 mrg rtx cfa_restores = NULL_RTX; 4156 1.1 mrg 4157 1.1 mrg /* A register that holds a copy of the incoming fp. */ 4158 1.1 mrg int fp_copy_regno = -1; 4159 1.1 mrg 4160 1.1 mrg /* Next scratch register number to hand out (postdecrementing). */ 4161 1.1 mrg int next_scratch_regno = 29; 4162 1.1 mrg 4163 1.1 mrg int total_size = compute_total_frame_size (); 4164 1.1 mrg 4165 1.1 mrg last_insn = get_last_insn (); 4166 1.1 mrg 4167 1.1 mrg /* Load lr first since we are going to need it first. */ 4168 1.1 mrg insn = NULL; 4169 1.1 mrg if (df_regs_ever_live_p (TILEGX_LINK_REGNUM)) 4170 1.1 mrg { 4171 1.1 mrg insn = frame_emit_load (TILEGX_LINK_REGNUM, 4172 1.1 mrg compute_frame_addr (0, &next_scratch_regno), 4173 1.1 mrg &cfa_restores); 4174 1.1 mrg } 4175 1.1 mrg 4176 1.1 mrg if (total_size == 0) 4177 1.1 mrg { 4178 1.1 mrg if (insn) 4179 1.1 mrg { 4180 1.1 mrg RTX_FRAME_RELATED_P (insn) = 1; 4181 1.1 mrg REG_NOTES (insn) = cfa_restores; 4182 1.1 mrg } 4183 1.1 mrg goto done; 4184 1.1 mrg } 4185 1.1 mrg 4186 1.1 mrg /* Compute where to start restoring registers. */ 4187 1.1 mrg start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD; 4188 1.1 mrg offset = start_offset; 4189 1.1 mrg 4190 1.1 mrg if (frame_pointer_needed) 4191 1.1 mrg fp_copy_regno = next_scratch_regno--; 4192 1.1 mrg 4193 1.1 mrg /* Restore all callee-saved registers. */ 4194 1.1 mrg which_scratch = 0; 4195 1.1 mrg for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) 4196 1.1 mrg if (need_to_save_reg (regno)) 4197 1.1 mrg { 4198 1.1 mrg rtx r = reg_save_addr[which_scratch]; 4199 1.1 mrg if (r == NULL_RTX) 4200 1.1 mrg { 4201 1.1 mrg r = compute_frame_addr (offset, &next_scratch_regno); 4202 1.1 mrg reg_save_addr[which_scratch] = r; 4203 1.1 mrg } 4204 1.1 mrg else 4205 1.1 mrg { 4206 1.1 mrg /* Advance to the next stack slot to store this register. */ 4207 1.1 mrg int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD; 4208 1.1 mrg rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride)); 4209 1.1 mrg emit_insn (gen_rtx_SET (r, p)); 4210 1.1 mrg } 4211 1.1 mrg 4212 1.1 mrg if (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM) 4213 1.1 mrg frame_emit_load (fp_copy_regno, r, NULL); 4214 1.1 mrg else 4215 1.1 mrg frame_emit_load (regno, r, &cfa_restores); 4216 1.1 mrg 4217 1.1 mrg offset -= UNITS_PER_WORD; 4218 1.1 mrg which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE; 4219 1.1 mrg } 4220 1.1 mrg 4221 1.1 mrg if (!tilegx_current_function_is_leaf ()) 4222 1.1 mrg cfa_restores = 4223 1.1 mrg alloc_reg_note (REG_CFA_RESTORE, stack_pointer_rtx, cfa_restores); 4224 1.1 mrg 4225 1.1 mrg emit_insn (gen_blockage ()); 4226 1.1 mrg 4227 1.1 mrg if (frame_pointer_needed) 4228 1.1 mrg { 4229 1.1 mrg /* Restore the old stack pointer by copying from the frame 4230 1.1 mrg pointer. */ 4231 1.1 mrg if (TARGET_32BIT) 4232 1.1 mrg { 4233 1.1 mrg insn = emit_insn (gen_sp_restore_32bit (stack_pointer_rtx, 4234 1.1 mrg hard_frame_pointer_rtx)); 4235 1.1 mrg } 4236 1.1 mrg else 4237 1.1 mrg { 4238 1.1 mrg insn = emit_insn (gen_sp_restore (stack_pointer_rtx, 4239 1.1 mrg hard_frame_pointer_rtx)); 4240 1.1 mrg } 4241 1.1 mrg RTX_FRAME_RELATED_P (insn) = 1; 4242 1.1 mrg REG_NOTES (insn) = cfa_restores; 4243 1.1 mrg add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx); 4244 1.1 mrg } 4245 1.1 mrg else 4246 1.1 mrg { 4247 1.1 mrg insn = emit_sp_adjust (total_size, &next_scratch_regno, true, 4248 1.1 mrg cfa_restores); 4249 1.1 mrg } 4250 1.1 mrg 4251 1.1 mrg if (crtl->calls_eh_return) 4252 1.1 mrg { 4253 1.1 mrg if (TARGET_32BIT) 4254 1.1 mrg emit_insn (gen_sp_adjust_32bit (stack_pointer_rtx, stack_pointer_rtx, 4255 1.1 mrg EH_RETURN_STACKADJ_RTX)); 4256 1.1 mrg else 4257 1.1 mrg emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx, 4258 1.1 mrg EH_RETURN_STACKADJ_RTX)); 4259 1.1 mrg } 4260 1.1 mrg 4261 1.1 mrg /* Restore the old frame pointer. */ 4262 1.1 mrg if (frame_pointer_needed) 4263 1.1 mrg { 4264 1.1 mrg insn = emit_move_insn (gen_lowpart (DImode, hard_frame_pointer_rtx), 4265 1.1 mrg gen_rtx_REG (DImode, fp_copy_regno)); 4266 1.1 mrg add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx); 4267 1.1 mrg } 4268 1.1 mrg 4269 1.1 mrg /* Mark the pic registers as live outside of the function. */ 4270 1.1 mrg if (flag_pic) 4271 1.1 mrg { 4272 1.1 mrg emit_use (cfun->machine->text_label_rtx); 4273 1.1 mrg emit_use (cfun->machine->got_rtx); 4274 1.1 mrg } 4275 1.1 mrg 4276 1.1 mrg done: 4277 1.1 mrg if (!sibcall_p) 4278 1.1 mrg { 4279 1.1 mrg emit_jump_insn (gen__return ()); 4280 1.1 mrg } 4281 1.1 mrg else 4282 1.1 mrg { 4283 1.1 mrg emit_use (gen_rtx_REG (Pmode, TILEGX_LINK_REGNUM)); 4284 1.1 mrg } 4285 1.1 mrg 4286 1.1 mrg /* Mark all insns we just emitted as frame-related. */ 4287 1.1 mrg for (; last_insn != NULL_RTX; last_insn = next_insn (last_insn)) 4288 1.1 mrg RTX_FRAME_RELATED_P (last_insn) = 1; 4289 1.1 mrg } 4290 1.1 mrg 4291 1.1 mrg #undef ROUND_ROBIN_SIZE 4292 1.1 mrg 4293 1.1 mrg 4294 1.1 mrg /* Implement INITIAL_ELIMINATION_OFFSET. */ 4295 1.1 mrg int 4296 1.1 mrg tilegx_initial_elimination_offset (int from, int to) 4297 1.1 mrg { 4298 1.1 mrg int total_size = compute_total_frame_size (); 4299 1.1 mrg 4300 1.1 mrg if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) 4301 1.1 mrg { 4302 1.1 mrg return (total_size - crtl->args.pretend_args_size 4303 1.1 mrg - tilegx_saved_regs_size ()); 4304 1.1 mrg } 4305 1.1 mrg else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) 4306 1.1 mrg { 4307 1.1 mrg return -(crtl->args.pretend_args_size + tilegx_saved_regs_size ()); 4308 1.1 mrg } 4309 1.1 mrg else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) 4310 1.1 mrg { 4311 1.1 mrg return STACK_POINTER_OFFSET + total_size; 4312 1.1 mrg } 4313 1.1 mrg else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) 4314 1.1 mrg { 4315 1.1 mrg return STACK_POINTER_OFFSET; 4316 1.1 mrg } 4317 1.1 mrg else 4318 1.1 mrg gcc_unreachable (); 4319 1.1 mrg } 4320 1.1 mrg 4321 1.1 mrg 4322 1.1 mrg /* Return an RTX indicating where the return address to the calling 4323 1.1 mrg function can be found. */ 4324 1.1 mrg rtx 4325 1.1 mrg tilegx_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) 4326 1.1 mrg { 4327 1.1 mrg if (count != 0) 4328 1.1 mrg return const0_rtx; 4329 1.1 mrg 4330 1.1 mrg return get_hard_reg_initial_val (Pmode, TILEGX_LINK_REGNUM); 4331 1.1 mrg } 4332 1.1 mrg 4333 1.1 mrg 4334 1.1 mrg /* Implement EH_RETURN_HANDLER_RTX. The MEM needs to be volatile to 4335 1.1 mrg prevent it from being deleted. */ 4336 1.1 mrg rtx 4337 1.1 mrg tilegx_eh_return_handler_rtx (void) 4338 1.1 mrg { 4339 1.1 mrg rtx tmp = gen_frame_mem (Pmode, hard_frame_pointer_rtx); 4340 1.1 mrg MEM_VOLATILE_P (tmp) = true; 4341 1.1 mrg return tmp; 4342 1.1 mrg } 4343 1.1 mrg 4344 1.1 mrg 4346 1.1 mrg 4347 1.1 mrg /* Registers */ 4348 1.1 mrg 4349 1.1 mrg /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */ 4350 1.1 mrg static void 4351 1.1 mrg tilegx_conditional_register_usage (void) 4352 1.1 mrg { 4353 1.1 mrg global_regs[TILEGX_NETORDER_REGNUM] = 1; 4354 1.1 mrg /* TILEGX_PIC_TEXT_LABEL_REGNUM is conditionally used. */ 4355 1.1 mrg if (TILEGX_PIC_TEXT_LABEL_REGNUM != INVALID_REGNUM) 4356 1.1 mrg fixed_regs[TILEGX_PIC_TEXT_LABEL_REGNUM] = 1; 4357 1.1 mrg if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM) 4358 1.1 mrg fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; 4359 1.1 mrg } 4360 1.1 mrg 4361 1.1 mrg 4362 1.1 mrg /* Implement TARGET_FRAME_POINTER_REQUIRED. */ 4363 1.1 mrg static bool 4364 1.1 mrg tilegx_frame_pointer_required (void) 4365 1.1 mrg { 4366 1.1 mrg return crtl->calls_eh_return || cfun->calls_alloca; 4367 1.1 mrg } 4368 1.1 mrg 4369 1.1 mrg 4371 1.1 mrg 4372 1.1 mrg /* Scheduling and reorg */ 4373 1.1 mrg 4374 1.1 mrg /* Return the length of INSN. LENGTH is the initial length computed 4375 1.1 mrg by attributes in the machine-description file. This is where we 4376 1.1 mrg account for bundles. */ 4377 1.1 mrg int 4378 1.1 mrg tilegx_adjust_insn_length (rtx_insn *insn, int length) 4379 1.1 mrg { 4380 1.1 mrg machine_mode mode = GET_MODE (insn); 4381 1.1 mrg 4382 1.1 mrg /* A non-termininating instruction in a bundle has length 0. */ 4383 1.1 mrg if (mode == SImode) 4384 1.1 mrg return 0; 4385 1.1 mrg 4386 1.1 mrg /* By default, there is not length adjustment. */ 4387 1.1 mrg return length; 4388 1.1 mrg } 4389 1.1 mrg 4390 1.1 mrg 4391 1.1 mrg /* Implement TARGET_SCHED_ISSUE_RATE. */ 4392 1.1 mrg static int 4393 1.1 mrg tilegx_issue_rate (void) 4394 1.1 mrg { 4395 1.1 mrg return 3; 4396 1.1 mrg } 4397 1.1 mrg 4398 1.1 mrg 4399 1.1 mrg /* Return the rtx for the jump target. */ 4400 1.1 mrg static rtx 4401 1.1 mrg get_jump_target (rtx branch) 4402 1.1 mrg { 4403 1.1 mrg if (CALL_P (branch)) 4404 1.1 mrg { 4405 1.1 mrg rtx call; 4406 1.1 mrg call = PATTERN (branch); 4407 1.1 mrg 4408 1.1 mrg if (GET_CODE (call) == PARALLEL) 4409 1.1 mrg call = XVECEXP (call, 0, 0); 4410 1.1 mrg 4411 1.1 mrg if (GET_CODE (call) == SET) 4412 1.1 mrg call = SET_SRC (call); 4413 1.1 mrg 4414 1.1 mrg if (GET_CODE (call) == CALL) 4415 1.1 mrg return XEXP (XEXP (call, 0), 0); 4416 1.1 mrg } 4417 1.1 mrg return 0; 4418 1.1 mrg } 4419 1.1 mrg 4420 1.1 mrg 4421 1.1 mrg /* Implement TARGET_SCHED_ADJUST_COST. */ 4422 1.1 mrg static int 4423 1.1 mrg tilegx_sched_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, 4424 1.1 mrg int cost, unsigned int) 4425 1.1 mrg { 4426 1.1 mrg /* If we have a true dependence, INSN is a call, and DEP_INSN 4427 1.1 mrg defines a register that is needed by the call (argument or stack 4428 1.1 mrg pointer) , set its latency to 0 so that it can be bundled with 4429 1.1 mrg the call. Explicitly check for and exclude the case when 4430 1.1 mrg DEP_INSN defines the target of the jump. */ 4431 1.1 mrg if (CALL_P (insn) && dep_type == REG_DEP_TRUE) 4432 1.1 mrg { 4433 1.1 mrg rtx target = get_jump_target (insn); 4434 1.1 mrg if (!REG_P (target) || !set_of (target, dep_insn)) 4435 1.1 mrg return 0; 4436 1.1 mrg } 4437 1.1 mrg 4438 1.1 mrg return cost; 4439 1.1 mrg } 4440 1.1 mrg 4441 1.1 mrg 4442 1.1 mrg /* Skip over irrelevant NOTEs and such and look for the next insn we 4443 1.1 mrg would consider bundling. */ 4444 1.1 mrg static rtx_insn * 4445 1.1 mrg next_insn_to_bundle (rtx_insn *r, rtx_insn *end) 4446 1.1 mrg { 4447 1.1 mrg for (; r != end; r = NEXT_INSN (r)) 4448 1.1 mrg { 4449 1.1 mrg if (NONDEBUG_INSN_P (r) 4450 1.1 mrg && GET_CODE (PATTERN (r)) != USE 4451 1.1 mrg && GET_CODE (PATTERN (r)) != CLOBBER) 4452 1.1 mrg return r; 4453 1.1 mrg } 4454 1.1 mrg 4455 1.1 mrg return NULL; 4456 1.1 mrg } 4457 1.1 mrg 4458 1.1 mrg 4459 1.1 mrg /* Go through all insns, and use the information generated during 4460 1.1 mrg scheduling to generate SEQUENCEs to represent bundles of 4461 1.1 mrg instructions issued simultaneously. */ 4462 1.1 mrg static void 4463 1.1 mrg tilegx_gen_bundles (void) 4464 1.1 mrg { 4465 1.1 mrg basic_block bb; 4466 1.1 mrg FOR_EACH_BB_FN (bb, cfun) 4467 1.1 mrg { 4468 1.1 mrg rtx_insn *insn, *next, *prev; 4469 1.1 mrg rtx_insn *end = NEXT_INSN (BB_END (bb)); 4470 1.1 mrg 4471 1.1 mrg prev = NULL; 4472 1.1 mrg for (insn = next_insn_to_bundle (BB_HEAD (bb), end); insn; insn = next) 4473 1.1 mrg { 4474 1.1 mrg next = next_insn_to_bundle (NEXT_INSN (insn), end); 4475 1.1 mrg 4476 1.1 mrg /* Never wrap {} around inline asm. */ 4477 1.1 mrg if (GET_CODE (PATTERN (insn)) != ASM_INPUT) 4478 1.1 mrg { 4479 1.1 mrg if (next == NULL_RTX || GET_MODE (next) == TImode 4480 1.1 mrg /* NOTE: The scheduler incorrectly believes a call 4481 1.1 mrg insn can execute in the same cycle as the insn 4482 1.1 mrg after the call. This is of course impossible. 4483 1.1 mrg Really we need to fix the scheduler somehow, so 4484 1.1 mrg the code after the call gets scheduled 4485 1.1 mrg optimally. */ 4486 1.1 mrg || CALL_P (insn)) 4487 1.1 mrg { 4488 1.1 mrg /* Mark current insn as the end of a bundle. */ 4489 1.1 mrg PUT_MODE (insn, QImode); 4490 1.1 mrg } 4491 1.1 mrg else 4492 1.1 mrg { 4493 1.1 mrg /* Mark it as part of a bundle. */ 4494 1.1 mrg PUT_MODE (insn, SImode); 4495 1.1 mrg } 4496 1.1 mrg } 4497 1.1 mrg 4498 1.1 mrg /* Delete barrier insns, because they can mess up the 4499 1.1 mrg emitting of bundle braces. If it is end-of-bundle, then 4500 1.1 mrg the previous insn must be marked end-of-bundle. */ 4501 1.1 mrg if (get_attr_type (insn) == TYPE_NOTHING) { 4502 1.1 mrg if (GET_MODE (insn) == QImode && prev != NULL 4503 1.1 mrg && GET_MODE (prev) == SImode) 4504 1.1 mrg { 4505 1.1 mrg PUT_MODE (prev, QImode); 4506 1.1 mrg } 4507 1.1 mrg delete_insn (insn); 4508 1.1 mrg 4509 1.1 mrg // Note: prev remains the same for next iteration. 4510 1.1 mrg } 4511 1.1 mrg else 4512 1.1 mrg prev = insn; 4513 1.1 mrg } 4514 1.1 mrg } 4515 1.1 mrg } 4516 1.1 mrg 4517 1.1 mrg 4518 1.1 mrg /* Replace OLD_INSN with NEW_INSN. */ 4519 1.1 mrg static void 4520 1.1 mrg replace_insns (rtx_insn *old_insn, rtx_insn *new_insns) 4521 1.1 mrg { 4522 1.1 mrg if (new_insns) 4523 1.1 mrg emit_insn_before (new_insns, old_insn); 4524 1.1 mrg 4525 1.1 mrg delete_insn (old_insn); 4526 1.1 mrg } 4527 1.1 mrg 4528 1.1 mrg 4529 1.1 mrg /* Returns true if INSN is the first instruction of a pc-relative 4530 1.1 mrg address compuatation. */ 4531 1.1 mrg static bool 4532 1.1 mrg match_pcrel_step1 (rtx insn) 4533 1.1 mrg { 4534 1.1 mrg rtx pattern = PATTERN (insn); 4535 1.1 mrg rtx src; 4536 1.1 mrg 4537 1.1 mrg if (GET_CODE (pattern) != SET) 4538 1.1 mrg return false; 4539 1.1 mrg 4540 1.1 mrg src = SET_SRC (pattern); 4541 1.1 mrg 4542 1.1 mrg return (GET_CODE (src) == CONST 4543 1.1 mrg && GET_CODE (XEXP (src, 0)) == UNSPEC 4544 1.1 mrg && XINT (XEXP (src, 0), 1) == UNSPEC_HW1_LAST_PCREL); 4545 1.1 mrg } 4546 1.1 mrg 4547 1.1 mrg 4548 1.1 mrg /* Do the first replacement step in tilegx_fixup_pcrel_references. */ 4549 1.1 mrg static void 4550 1.1 mrg replace_mov_pcrel_step1 (rtx_insn *insn) 4551 1.1 mrg { 4552 1.1 mrg rtx pattern = PATTERN (insn); 4553 1.1 mrg rtx unspec; 4554 1.1 mrg rtx opnds[2]; 4555 1.1 mrg rtx_insn *new_insns; 4556 1.1 mrg 4557 1.1 mrg gcc_assert (GET_CODE (pattern) == SET); 4558 1.1 mrg opnds[0] = SET_DEST (pattern); 4559 1.1 mrg 4560 1.1 mrg gcc_assert (GET_CODE (SET_SRC (pattern)) == CONST); 4561 1.1 mrg 4562 1.1 mrg unspec = XEXP (SET_SRC (pattern), 0); 4563 1.1 mrg gcc_assert (GET_CODE (unspec) == UNSPEC); 4564 1.1 mrg gcc_assert (XINT (unspec, 1) == UNSPEC_HW1_LAST_PCREL); 4565 1.1 mrg opnds[1] = XVECEXP (unspec, 0, 0); 4566 1.1 mrg 4567 1.1 mrg /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */ 4568 1.1 mrg if (GET_CODE (opnds[1]) != SYMBOL_REF) 4569 1.1 mrg return; 4570 1.1 mrg 4571 1.1 mrg start_sequence (); 4572 1.1 mrg 4573 1.1 mrg if (flag_pic != 1) 4574 1.1 mrg { 4575 1.1 mrg if (TARGET_32BIT) 4576 1.1 mrg emit_insn (gen_mov_got32_step1_32bit (opnds[0], opnds[1])); 4577 1.1 mrg else 4578 1.1 mrg emit_insn (gen_mov_got32_step1 (opnds[0], opnds[1])); 4579 1.1 mrg } 4580 1.1 mrg 4581 1.1 mrg new_insns = get_insns (); 4582 1.1 mrg end_sequence (); 4583 1.1 mrg 4584 1.1 mrg replace_insns (insn, new_insns); 4585 1.1 mrg } 4586 1.1 mrg 4587 1.1 mrg 4588 1.1 mrg /* Returns true if INSN is the second instruction of a pc-relative 4589 1.1 mrg address compuatation. */ 4590 1.1 mrg static bool 4591 1.1 mrg match_pcrel_step2 (rtx_insn *insn) 4592 1.1 mrg { 4593 1.1 mrg rtx unspec; 4594 1.1 mrg rtx addr; 4595 1.1 mrg 4596 1.1 mrg if (TARGET_32BIT) 4597 1.1 mrg { 4598 1.1 mrg if (recog_memoized (insn) != CODE_FOR_insn_addr_shl16insli_32bit) 4599 1.1 mrg return false; 4600 1.1 mrg } 4601 1.1 mrg else 4602 1.1 mrg { 4603 1.1 mrg if (recog_memoized (insn) != CODE_FOR_insn_addr_shl16insli) 4604 1.1 mrg return false; 4605 1.1 mrg } 4606 1.1 mrg 4607 1.1 mrg unspec = SET_SRC (PATTERN (insn)); 4608 1.1 mrg addr = XVECEXP (unspec, 0, 1); 4609 1.1 mrg 4610 1.1 mrg return (GET_CODE (addr) == CONST 4611 1.1 mrg && GET_CODE (XEXP (addr, 0)) == UNSPEC 4612 1.1 mrg && XINT (XEXP (addr, 0), 1) == UNSPEC_HW0_PCREL); 4613 1.1 mrg } 4614 1.1 mrg 4615 1.1 mrg 4616 1.1 mrg /* Do the second replacement step in tilegx_fixup_pcrel_references. */ 4617 1.1 mrg static void 4618 1.1 mrg replace_mov_pcrel_step2 (rtx_insn *insn) 4619 1.1 mrg { 4620 1.1 mrg rtx pattern = PATTERN (insn); 4621 1.1 mrg rtx unspec; 4622 1.1 mrg rtx addr; 4623 1.1 mrg rtx opnds[3]; 4624 1.1 mrg rtx_insn *new_insns; 4625 1.1 mrg rtx got_rtx = tilegx_got_rtx (); 4626 1.1 mrg 4627 1.1 mrg gcc_assert (GET_CODE (pattern) == SET); 4628 1.1 mrg opnds[0] = SET_DEST (pattern); 4629 1.1 mrg 4630 1.1 mrg unspec = SET_SRC (pattern); 4631 1.1 mrg gcc_assert (GET_CODE (unspec) == UNSPEC); 4632 1.1 mrg gcc_assert (XINT (unspec, 1) == UNSPEC_INSN_ADDR_SHL16INSLI); 4633 1.1 mrg 4634 1.1 mrg opnds[1] = XVECEXP (unspec, 0, 0); 4635 1.1 mrg 4636 1.1 mrg addr = XVECEXP (unspec, 0, 1); 4637 1.1 mrg gcc_assert (GET_CODE (addr) == CONST); 4638 1.1 mrg 4639 1.1 mrg unspec = XEXP (addr, 0); 4640 1.1 mrg gcc_assert (GET_CODE (unspec) == UNSPEC); 4641 1.1 mrg gcc_assert (XINT (unspec, 1) == UNSPEC_HW0_PCREL); 4642 1.1 mrg opnds[2] = XVECEXP (unspec, 0, 0); 4643 1.1 mrg 4644 1.1 mrg /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */ 4645 1.1 mrg if (GET_CODE (opnds[2]) != SYMBOL_REF) 4646 1.1 mrg return; 4647 1.1 mrg 4648 1.1 mrg start_sequence (); 4649 1.1 mrg 4650 1.1 mrg if (flag_pic == 1) 4651 1.1 mrg { 4652 1.1 mrg if (TARGET_32BIT) 4653 1.1 mrg emit_insn (gen_add_got16_32bit (opnds[0], got_rtx, opnds[2])); 4654 1.1 mrg else 4655 1.1 mrg emit_insn (gen_add_got16 (opnds[0], got_rtx, opnds[2])); 4656 1.1 mrg } 4657 1.1 mrg else 4658 1.1 mrg { 4659 1.1 mrg if (TARGET_32BIT) 4660 1.1 mrg emit_insn (gen_mov_got32_step2_32bit 4661 1.1 mrg (opnds[0], opnds[1], opnds[2])); 4662 1.1 mrg else 4663 1.1 mrg emit_insn (gen_mov_got32_step2 (opnds[0], opnds[1], opnds[2])); 4664 1.1 mrg } 4665 1.1 mrg 4666 1.1 mrg new_insns = get_insns (); 4667 1.1 mrg end_sequence (); 4668 1.1 mrg 4669 1.1 mrg replace_insns (insn, new_insns); 4670 1.1 mrg } 4671 1.1 mrg 4672 1.1 mrg 4673 1.1 mrg /* Do the third replacement step in tilegx_fixup_pcrel_references. */ 4674 1.1 mrg static void 4675 1.1 mrg replace_mov_pcrel_step3 (rtx_insn *insn) 4676 1.1 mrg { 4677 1.1 mrg rtx pattern = PATTERN (insn); 4678 1.1 mrg rtx unspec; 4679 1.1 mrg rtx opnds[4]; 4680 1.1 mrg rtx_insn *new_insns; 4681 1.1 mrg rtx got_rtx = tilegx_got_rtx (); 4682 1.1 mrg rtx text_label_rtx = tilegx_text_label_rtx (); 4683 1.1 mrg 4684 1.1 mrg gcc_assert (GET_CODE (pattern) == SET); 4685 1.1 mrg opnds[0] = SET_DEST (pattern); 4686 1.1 mrg 4687 1.1 mrg unspec = SET_SRC (pattern); 4688 1.1 mrg gcc_assert (GET_CODE (unspec) == UNSPEC); 4689 1.1 mrg gcc_assert (XINT (unspec, 1) == UNSPEC_MOV_PCREL_STEP3); 4690 1.1 mrg 4691 1.1 mrg opnds[1] = got_rtx; 4692 1.1 mrg 4693 1.1 mrg if (XVECEXP (unspec, 0, 0) == text_label_rtx) 4694 1.1 mrg opnds[2] = XVECEXP (unspec, 0, 1); 4695 1.1 mrg else 4696 1.1 mrg { 4697 1.1 mrg gcc_assert (XVECEXP (unspec, 0, 1) == text_label_rtx); 4698 1.1 mrg opnds[2] = XVECEXP (unspec, 0, 0); 4699 1.1 mrg } 4700 1.1 mrg 4701 1.1 mrg opnds[3] = XVECEXP (unspec, 0, 2); 4702 1.1 mrg 4703 1.1 mrg /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */ 4704 1.1 mrg if (GET_CODE (opnds[3]) != SYMBOL_REF) 4705 1.1 mrg return; 4706 1.1 mrg 4707 1.1 mrg start_sequence (); 4708 1.1 mrg 4709 1.1 mrg if (flag_pic == 1) 4710 1.1 mrg { 4711 1.1 mrg emit_move_insn (opnds[0], gen_const_mem (Pmode, opnds[2])); 4712 1.1 mrg } 4713 1.1 mrg else 4714 1.1 mrg { 4715 1.1 mrg emit_move_insn (opnds[0], gen_rtx_PLUS (Pmode, opnds[1], opnds[2])); 4716 1.1 mrg emit_move_insn (opnds[0], gen_const_mem (Pmode, opnds[0])); 4717 1.1 mrg } 4718 1.1 mrg 4719 1.1 mrg new_insns = get_insns (); 4720 1.1 mrg end_sequence (); 4721 1.1 mrg 4722 1.1 mrg replace_insns (insn, new_insns); 4723 1.1 mrg } 4724 1.1 mrg 4725 1.1 mrg 4726 1.1 mrg /* We generate PC relative SYMBOL_REFs as an optimization, to avoid 4727 1.1 mrg going through the GOT when the symbol is local to the compilation 4728 1.1 mrg unit. But such a symbol requires that the common text_label that 4729 1.1 mrg we generate at the beginning of the function be in the same section 4730 1.1 mrg as the reference to the SYMBOL_REF. This may not be true if we 4731 1.1 mrg generate hot/cold sections. This function looks for such cases and 4732 1.1 mrg replaces such references with the longer sequence going through the 4733 1.1 mrg GOT. 4734 1.1 mrg 4735 1.1 mrg We expect following instruction sequence: 4736 1.1 mrg moveli tmp1, hw1_last(x-.L_PICLNK) [1] 4737 1.1 mrg shl16insli tmp2, tmp1, hw0(x-.L_PICLNK) [2] 4738 1.1 mrg add<x> tmp3, txt_label_reg, tmp2 [3] 4739 1.1 mrg 4740 1.1 mrg If we're compiling -fpic, we replace with the following sequence 4741 1.1 mrg (the numbers in brackets match the instructions they're replacing 4742 1.1 mrg above). 4743 1.1 mrg 4744 1.1 mrg add<x>li tmp2, got_reg, hw0_last_got(x) [2] 4745 1.1 mrg ld<4> tmp3, tmp2 [3] 4746 1.1 mrg 4747 1.1 mrg If we're compiling -fPIC, we replace the first instruction with: 4748 1.1 mrg 4749 1.1 mrg moveli tmp1, hw1_last_got(x) [1] 4750 1.1 mrg shl16insli tmp2, tmp1, hw0_got(x) [2] 4751 1.1 mrg add<x> tmp3, got_reg, tmp2 [3] 4752 1.1 mrg ld<4> tmp3, tmp3 [3] 4753 1.1 mrg 4754 1.1 mrg Note that we're careful to disturb the instruction sequence as 4755 1.1 mrg little as possible, since it's very late in the compilation 4756 1.1 mrg process. */ 4757 1.1 mrg static void 4758 1.1 mrg tilegx_fixup_pcrel_references (void) 4759 1.1 mrg { 4760 1.1 mrg rtx_insn *insn, *next_insn; 4761 1.1 mrg bool same_section_as_entry = true; 4762 1.1 mrg 4763 1.1 mrg for (insn = get_insns (); insn; insn = next_insn) 4764 1.1 mrg { 4765 1.1 mrg next_insn = NEXT_INSN (insn); 4766 1.1 mrg 4767 1.1 mrg if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS) 4768 1.1 mrg { 4769 1.1 mrg same_section_as_entry = !same_section_as_entry; 4770 1.1 mrg continue; 4771 1.1 mrg } 4772 1.1 mrg 4773 1.1 mrg if (same_section_as_entry) 4774 1.1 mrg continue; 4775 1.1 mrg 4776 1.1 mrg if (!(INSN_P (insn) 4777 1.1 mrg && GET_CODE (PATTERN (insn)) != USE 4778 1.1 mrg && GET_CODE (PATTERN (insn)) != CLOBBER)) 4779 1.1 mrg continue; 4780 1.1 mrg 4781 1.1 mrg if (TARGET_32BIT) 4782 1.1 mrg { 4783 1.1 mrg if (match_pcrel_step1 (insn)) 4784 1.1 mrg replace_mov_pcrel_step1 (insn); 4785 1.1 mrg else if (match_pcrel_step2 (insn)) 4786 1.1 mrg replace_mov_pcrel_step2 (insn); 4787 1.1 mrg else if (recog_memoized (insn) == CODE_FOR_mov_pcrel_step3_32bit) 4788 1.1 mrg replace_mov_pcrel_step3 (insn); 4789 1.1 mrg } 4790 1.1 mrg else 4791 1.1 mrg { 4792 1.1 mrg if (match_pcrel_step1 (insn)) 4793 1.1 mrg replace_mov_pcrel_step1 (insn); 4794 1.1 mrg else if (match_pcrel_step2 (insn)) 4795 1.1 mrg replace_mov_pcrel_step2 (insn); 4796 1.1 mrg else if (recog_memoized (insn) == CODE_FOR_mov_pcrel_step3) 4797 1.1 mrg replace_mov_pcrel_step3 (insn); 4798 1.1 mrg } 4799 1.1 mrg } 4800 1.1 mrg } 4801 1.1 mrg 4802 1.1 mrg 4803 1.1 mrg /* Ensure that no var tracking notes are emitted in the middle of a 4804 1.1 mrg three-instruction bundle. */ 4805 1.1 mrg static void 4806 1.1 mrg reorder_var_tracking_notes (void) 4807 1.1 mrg { 4808 1.1 mrg basic_block bb; 4809 1.1 mrg FOR_EACH_BB_FN (bb, cfun) 4810 1.1 mrg { 4811 1.1 mrg rtx_insn *insn, *next; 4812 1.1 mrg rtx_insn *queue = NULL; 4813 1.1 mrg bool in_bundle = false; 4814 1.1 mrg 4815 1.1 mrg for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next) 4816 1.1 mrg { 4817 1.1 mrg next = NEXT_INSN (insn); 4818 1.1 mrg 4819 1.1 mrg if (INSN_P (insn)) 4820 1.1 mrg { 4821 1.1 mrg /* Emit queued up notes at the last instruction of a 4822 1.1 mrg bundle. */ 4823 1.1 mrg if (GET_MODE (insn) == QImode) 4824 1.1 mrg { 4825 1.1 mrg while (queue) 4826 1.1 mrg { 4827 1.1 mrg rtx_insn *next_queue = PREV_INSN (queue); 4828 1.1 mrg SET_PREV_INSN (NEXT_INSN (insn)) = queue; 4829 1.1 mrg SET_NEXT_INSN (queue) = NEXT_INSN (insn); 4830 1.1 mrg SET_NEXT_INSN (insn) = queue; 4831 1.1 mrg SET_PREV_INSN (queue) = insn; 4832 1.1 mrg queue = next_queue; 4833 1.1 mrg } 4834 1.1 mrg in_bundle = false; 4835 1.1 mrg } 4836 1.1 mrg else if (GET_MODE (insn) == SImode) 4837 1.1 mrg in_bundle = true; 4838 1.1 mrg } 4839 1.1 mrg else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION) 4840 1.1 mrg { 4841 1.1 mrg if (in_bundle) 4842 1.1 mrg { 4843 1.1 mrg rtx_insn *prev = PREV_INSN (insn); 4844 1.1 mrg SET_PREV_INSN (next) = prev; 4845 1.1 mrg SET_NEXT_INSN (prev) = next; 4846 1.1 mrg 4847 1.1 mrg SET_PREV_INSN (insn) = queue; 4848 1.1 mrg queue = insn; 4849 1.1 mrg } 4850 1.1 mrg } 4851 1.1 mrg } 4852 1.1 mrg } 4853 1.1 mrg } 4854 1.1 mrg 4855 1.1 mrg 4856 1.1 mrg /* Perform machine dependent operations on the rtl chain INSNS. */ 4857 1.1 mrg static void 4858 1.1 mrg tilegx_reorg (void) 4859 1.1 mrg { 4860 1.1 mrg /* We are freeing block_for_insn in the toplev to keep compatibility 4861 1.1 mrg with old MDEP_REORGS that are not CFG based. Recompute it 4862 1.1 mrg now. */ 4863 1.1 mrg compute_bb_for_insn (); 4864 1.1 mrg 4865 1.1 mrg if (flag_reorder_blocks_and_partition) 4866 1.1 mrg { 4867 1.1 mrg tilegx_fixup_pcrel_references (); 4868 1.1 mrg } 4869 1.1 mrg 4870 1.1 mrg if (flag_schedule_insns_after_reload) 4871 1.1 mrg { 4872 1.1 mrg split_all_insns (); 4873 1.1 mrg 4874 1.1 mrg timevar_push (TV_SCHED2); 4875 1.1 mrg schedule_insns (); 4876 1.1 mrg timevar_pop (TV_SCHED2); 4877 1.1 mrg 4878 1.1 mrg /* Examine the schedule to group into bundles. */ 4879 1.1 mrg tilegx_gen_bundles (); 4880 1.1 mrg } 4881 1.1 mrg 4882 1.1 mrg df_analyze (); 4883 1.1 mrg 4884 1.1 mrg if (flag_var_tracking) 4885 1.1 mrg { 4886 1.1 mrg timevar_push (TV_VAR_TRACKING); 4887 1.1 mrg variable_tracking_main (); 4888 1.1 mrg reorder_var_tracking_notes (); 4889 1.1 mrg timevar_pop (TV_VAR_TRACKING); 4890 1.1 mrg } 4891 1.1 mrg 4892 1.1 mrg df_finish_pass (false); 4893 1.1 mrg } 4894 1.1 mrg 4895 1.1 mrg 4897 1.1 mrg 4898 1.1 mrg /* Assembly */ 4899 1.1 mrg 4900 1.1 mrg /* Select a format to encode pointers in exception handling data. 4901 1.1 mrg CODE is 0 for data, 1 for code labels, 2 for function pointers. 4902 1.1 mrg GLOBAL is true if the symbol may be affected by dynamic 4903 1.1 mrg relocations. */ 4904 1.1 mrg int 4905 1.1 mrg tilegx_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global) 4906 1.1 mrg { 4907 1.1 mrg int type = TARGET_32BIT ? DW_EH_PE_sdata4 : DW_EH_PE_sdata8; 4908 1.1 mrg return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | type; 4909 1.1 mrg } 4910 1.1 mrg 4911 1.1 mrg 4912 1.1 mrg /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */ 4913 1.1 mrg static void 4914 1.1 mrg tilegx_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, 4915 1.1 mrg HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, 4916 1.1 mrg tree function) 4917 1.1 mrg { 4918 1.1 mrg const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl)); 4919 1.1 mrg rtx this_rtx, funexp, addend; 4920 1.1 mrg rtx_insn *insn; 4921 1.1 mrg 4922 1.1 mrg /* Pretend to be a post-reload pass while generating rtl. */ 4923 1.1 mrg reload_completed = 1; 4924 1.1 mrg 4925 1.1 mrg /* Mark the end of the (empty) prologue. */ 4926 1.1 mrg emit_note (NOTE_INSN_PROLOGUE_END); 4927 1.1 mrg 4928 1.1 mrg /* Find the "this" pointer. If the function returns a structure, 4929 1.1 mrg the structure return pointer is in $1. */ 4930 1.1 mrg if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) 4931 1.1 mrg this_rtx = gen_rtx_REG (Pmode, 1); 4932 1.1 mrg else 4933 1.1 mrg this_rtx = gen_rtx_REG (Pmode, 0); 4934 1.1 mrg 4935 1.1 mrg /* Add DELTA to THIS_RTX. */ 4936 1.1 mrg if (!(delta >= -32868 && delta <= 32767)) 4937 1.1 mrg { 4938 1.1 mrg addend = gen_rtx_REG (Pmode, 29); 4939 1.1 mrg emit_move_insn (addend, GEN_INT (delta)); 4940 1.1 mrg } 4941 1.1 mrg else 4942 1.1 mrg addend = GEN_INT (delta); 4943 1.1 mrg 4944 1.1 mrg if (TARGET_32BIT) 4945 1.1 mrg emit_insn (gen_addsi3 (this_rtx, this_rtx, addend)); 4946 1.1 mrg else 4947 1.1 mrg emit_insn (gen_adddi3 (this_rtx, this_rtx, addend)); 4948 1.1 mrg 4949 1.1 mrg /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */ 4950 1.1 mrg if (vcall_offset) 4951 1.1 mrg { 4952 1.1 mrg rtx tmp; 4953 1.1 mrg 4954 1.1 mrg tmp = gen_rtx_REG (Pmode, 29); 4955 1.1 mrg emit_move_insn (tmp, gen_rtx_MEM (Pmode, this_rtx)); 4956 1.1 mrg 4957 1.1 mrg if (!(vcall_offset >= -32868 && vcall_offset <= 32767)) 4958 1.1 mrg { 4959 1.1 mrg addend = gen_rtx_REG (Pmode, 28); 4960 1.1 mrg emit_move_insn (addend, GEN_INT (vcall_offset)); 4961 1.1 mrg } 4962 1.1 mrg else 4963 1.1 mrg addend = GEN_INT (vcall_offset); 4964 1.1 mrg 4965 1.1 mrg if (TARGET_32BIT) 4966 1.1 mrg emit_insn (gen_addsi3 (tmp, tmp, addend)); 4967 1.1 mrg else 4968 1.1 mrg emit_insn (gen_adddi3 (tmp, tmp, addend)); 4969 1.1 mrg 4970 1.1 mrg emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp)); 4971 1.1 mrg 4972 1.1 mrg if (TARGET_32BIT) 4973 1.1 mrg emit_insn (gen_addsi3 (this_rtx, this_rtx, tmp)); 4974 1.1 mrg else 4975 1.1 mrg emit_insn (gen_adddi3 (this_rtx, this_rtx, tmp)); 4976 1.1 mrg } 4977 1.1 mrg 4978 1.1 mrg /* Generate a tail call to the target function. */ 4979 1.1 mrg if (!TREE_USED (function)) 4980 1.1 mrg { 4981 1.1 mrg assemble_external (function); 4982 1.1 mrg TREE_USED (function) = 1; 4983 1.1 mrg } 4984 1.1 mrg funexp = XEXP (DECL_RTL (function), 0); 4985 1.1 mrg funexp = gen_rtx_MEM (FUNCTION_MODE, funexp); 4986 1.1 mrg insn = emit_call_insn (gen_sibcall (funexp, const0_rtx)); 4987 1.1 mrg SIBLING_CALL_P (insn) = 1; 4988 1.1 mrg 4989 1.1 mrg /* Run just enough of rest_of_compilation to get the insns emitted. 4990 1.1 mrg There's not really enough bulk here to make other passes such as 4991 1.1 mrg instruction scheduling worth while. 4992 1.1 mrg 4993 1.1 mrg We don't currently bundle, but the instruciton sequence is all 4994 1.1 mrg serial except for the tail call, so we're only wasting one cycle. 4995 1.1 mrg */ 4996 1.1 mrg insn = get_insns (); 4997 1.1 mrg shorten_branches (insn); 4998 1.1 mrg assemble_start_function (thunk_fndecl, fnname); 4999 1.1 mrg final_start_function (insn, file, 1); 5000 1.1 mrg final (insn, file, 1); 5001 1.1 mrg final_end_function (); 5002 1.1 mrg assemble_end_function (thunk_fndecl, fnname); 5003 1.1 mrg 5004 1.1 mrg /* Stop pretending to be a post-reload pass. */ 5005 1.1 mrg reload_completed = 0; 5006 1.1 mrg } 5007 1.1 mrg 5008 1.1 mrg 5009 1.1 mrg /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */ 5010 1.1 mrg static void 5011 1.1 mrg tilegx_asm_trampoline_template (FILE *file) 5012 1.1 mrg { 5013 1.1 mrg int ptr_mode_size = GET_MODE_SIZE (ptr_mode); 5014 1.1 mrg if (TARGET_32BIT) 5015 1.1 mrg { 5016 1.1 mrg fprintf (file, "\tlnk r10\n"); 5017 1.1 mrg fprintf (file, "\taddxi r10, r10, 32\n"); 5018 1.1 mrg fprintf (file, "\tld4s_add r11, r10, %d\n", ptr_mode_size); 5019 1.1 mrg fprintf (file, "\tld4s r10, r10\n"); 5020 1.1 mrg fprintf (file, "\tjr r11\n"); 5021 1.1 mrg fprintf (file, "\t.word 0 # <function address>\n"); 5022 1.1 mrg fprintf (file, "\t.word 0 # <static chain value>\n"); 5023 1.1 mrg } 5024 1.1 mrg else 5025 1.1 mrg { 5026 1.1 mrg fprintf (file, "\tlnk r10\n"); 5027 1.1 mrg fprintf (file, "\taddi r10, r10, 32\n"); 5028 1.1 mrg fprintf (file, "\tld_add r11, r10, %d\n", ptr_mode_size); 5029 1.1 mrg fprintf (file, "\tld r10, r10\n"); 5030 1.1 mrg fprintf (file, "\tjr r11\n"); 5031 1.1 mrg fprintf (file, "\t.quad 0 # <function address>\n"); 5032 1.1 mrg fprintf (file, "\t.quad 0 # <static chain value>\n"); 5033 1.1 mrg } 5034 1.1 mrg } 5035 1.1 mrg 5036 1.1 mrg 5037 1.1 mrg /* Implement TARGET_TRAMPOLINE_INIT. */ 5038 1.1 mrg static void 5039 1.1 mrg tilegx_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain) 5040 1.1 mrg { 5041 1.1 mrg rtx fnaddr, chaddr; 5042 1.1 mrg rtx mem; 5043 1.1 mrg rtx begin_addr, end_addr; 5044 1.1 mrg int ptr_mode_size = GET_MODE_SIZE (ptr_mode); 5045 1.1 mrg 5046 1.1 mrg fnaddr = copy_to_reg (XEXP (DECL_RTL (fndecl), 0)); 5047 1.1 mrg chaddr = copy_to_reg (static_chain); 5048 1.1 mrg 5049 1.1 mrg emit_block_move (m_tramp, assemble_trampoline_template (), 5050 1.1 mrg GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); 5051 1.1 mrg 5052 1.1 mrg mem = adjust_address (m_tramp, ptr_mode, 5053 1.1 mrg TRAMPOLINE_SIZE - 2 * ptr_mode_size); 5054 1.1 mrg emit_move_insn (mem, fnaddr); 5055 1.1 mrg mem = adjust_address (m_tramp, ptr_mode, 5056 1.1 mrg TRAMPOLINE_SIZE - ptr_mode_size); 5057 1.1 mrg emit_move_insn (mem, chaddr); 5058 1.1 mrg 5059 1.1 mrg /* Get pointers to the beginning and end of the code block. */ 5060 1.1 mrg begin_addr = force_reg (Pmode, XEXP (m_tramp, 0)); 5061 1.1 mrg end_addr = force_reg (Pmode, plus_constant (Pmode, XEXP (m_tramp, 0), 5062 1.1 mrg TRAMPOLINE_SIZE)); 5063 1.1 mrg 5064 1.1 mrg maybe_emit_call_builtin___clear_cache (begin_addr, end_addr); 5065 1.1 mrg } 5066 1.1 mrg 5067 1.1 mrg 5068 1.1 mrg /* Implement TARGET_PRINT_OPERAND. */ 5069 1.1 mrg static void 5070 1.1 mrg tilegx_print_operand (FILE *file, rtx x, int code) 5071 1.1 mrg { 5072 1.1 mrg switch (code) 5073 1.1 mrg { 5074 1.1 mrg case 'c': 5075 1.1 mrg /* Print the compare operator opcode for conditional moves. */ 5076 1.1 mrg switch (GET_CODE (x)) 5077 1.1 mrg { 5078 1.1 mrg case EQ: 5079 1.1 mrg fputs ("z", file); 5080 1.1 mrg break; 5081 1.1 mrg case NE: 5082 1.1 mrg fputs ("nz", file); 5083 1.1 mrg break; 5084 1.1 mrg default: 5085 1.1 mrg output_operand_lossage ("invalid %%c operand"); 5086 1.1 mrg } 5087 1.1 mrg return; 5088 1.1 mrg 5089 1.1 mrg case 'C': 5090 1.1 mrg /* Print the compare operator opcode for conditional moves. */ 5091 1.1 mrg switch (GET_CODE (x)) 5092 1.1 mrg { 5093 1.1 mrg case EQ: 5094 1.1 mrg fputs ("nz", file); 5095 1.1 mrg break; 5096 1.1 mrg case NE: 5097 1.1 mrg fputs ("z", file); 5098 1.1 mrg break; 5099 1.1 mrg default: 5100 1.1 mrg output_operand_lossage ("invalid %%C operand"); 5101 1.1 mrg } 5102 1.1 mrg return; 5103 1.1 mrg 5104 1.1 mrg case 'd': 5105 1.1 mrg { 5106 1.1 mrg /* Print the compare operator opcode for conditional moves. */ 5107 1.1 mrg switch (GET_CODE (x)) 5108 1.1 mrg { 5109 1.1 mrg case EQ: 5110 1.1 mrg fputs ("eq", file); 5111 1.1 mrg break; 5112 1.1 mrg case NE: 5113 1.1 mrg fputs ("ne", file); 5114 1.1 mrg break; 5115 1.1 mrg default: 5116 1.1 mrg output_operand_lossage ("invalid %%d operand"); 5117 1.1 mrg } 5118 1.1 mrg return; 5119 1.1 mrg } 5120 1.1 mrg 5121 1.1 mrg case 'D': 5122 1.1 mrg { 5123 1.1 mrg /* Print the compare operator opcode for conditional moves. */ 5124 1.1 mrg switch (GET_CODE (x)) 5125 1.1 mrg { 5126 1.1 mrg case EQ: 5127 1.1 mrg fputs ("ne", file); 5128 1.1 mrg break; 5129 1.1 mrg case NE: 5130 1.1 mrg fputs ("eq", file); 5131 1.1 mrg break; 5132 1.1 mrg default: 5133 1.1 mrg output_operand_lossage ("invalid %%D operand"); 5134 1.1 mrg } 5135 1.1 mrg return; 5136 1.1 mrg } 5137 1.1 mrg 5138 1.1 mrg case 'H': 5139 1.1 mrg { 5140 1.1 mrg if (GET_CODE (x) == CONST 5141 1.1 mrg && GET_CODE (XEXP (x, 0)) == UNSPEC) 5142 1.1 mrg { 5143 1.1 mrg rtx addr = XVECEXP (XEXP (x, 0), 0, 0); 5144 1.1 mrg int unspec = XINT (XEXP (x, 0), 1); 5145 1.1 mrg const char *opstr = NULL; 5146 1.1 mrg switch (unspec) 5147 1.1 mrg { 5148 1.1 mrg case UNSPEC_HW0: 5149 1.1 mrg case UNSPEC_HW0_PCREL: 5150 1.1 mrg opstr = "hw0"; 5151 1.1 mrg break; 5152 1.1 mrg case UNSPEC_HW1: 5153 1.1 mrg case UNSPEC_HW1_PCREL: 5154 1.1 mrg opstr = "hw1"; 5155 1.1 mrg break; 5156 1.1 mrg case UNSPEC_HW2: 5157 1.1 mrg opstr = "hw2"; 5158 1.1 mrg break; 5159 1.1 mrg case UNSPEC_HW3: 5160 1.1 mrg opstr = "hw3"; 5161 1.1 mrg break; 5162 1.1 mrg case UNSPEC_HW0_LAST: 5163 1.1 mrg opstr = "hw0_last"; 5164 1.1 mrg break; 5165 1.1 mrg case UNSPEC_HW1_LAST: 5166 1.1 mrg case UNSPEC_HW1_LAST_PCREL: 5167 1.1 mrg opstr = "hw1_last"; 5168 1.1 mrg break; 5169 1.1 mrg case UNSPEC_HW2_LAST: 5170 1.1 mrg case UNSPEC_HW2_LAST_PCREL: 5171 1.1 mrg opstr = "hw2_last"; 5172 1.1 mrg break; 5173 1.1 mrg case UNSPEC_HW0_GOT: 5174 1.1 mrg opstr = "hw0_got"; 5175 1.1 mrg break; 5176 1.1 mrg case UNSPEC_HW0_LAST_GOT: 5177 1.1 mrg opstr = "hw0_last_got"; 5178 1.1 mrg break; 5179 1.1 mrg case UNSPEC_HW1_LAST_GOT: 5180 1.1 mrg opstr = "hw1_last_got"; 5181 1.1 mrg break; 5182 1.1 mrg case UNSPEC_HW0_TLS_GD: 5183 1.1 mrg opstr = "hw0_tls_gd"; 5184 1.1 mrg break; 5185 1.1 mrg case UNSPEC_HW1_LAST_TLS_GD: 5186 1.1 mrg opstr = "hw1_last_tls_gd"; 5187 1.1 mrg break; 5188 1.1 mrg case UNSPEC_HW0_TLS_IE: 5189 1.1 mrg opstr = "hw0_tls_ie"; 5190 1.1 mrg break; 5191 1.1 mrg case UNSPEC_HW1_LAST_TLS_IE: 5192 1.1 mrg opstr = "hw1_last_tls_ie"; 5193 1.1 mrg break; 5194 1.1 mrg case UNSPEC_HW0_TLS_LE: 5195 1.1 mrg opstr = "hw0_tls_le"; 5196 1.1 mrg break; 5197 1.1 mrg case UNSPEC_HW1_LAST_TLS_LE: 5198 1.1 mrg opstr = "hw1_last_tls_le"; 5199 1.1 mrg break; 5200 1.1 mrg case UNSPEC_HW0_PLT_PCREL: 5201 1.1 mrg opstr = "hw0_plt"; 5202 1.1 mrg break; 5203 1.1 mrg case UNSPEC_HW1_PLT_PCREL: 5204 1.1 mrg opstr = "hw1_plt"; 5205 1.1 mrg break; 5206 1.1 mrg case UNSPEC_HW1_LAST_PLT_PCREL: 5207 1.1 mrg opstr = "hw1_last_plt"; 5208 1.1 mrg break; 5209 1.1 mrg case UNSPEC_HW2_LAST_PLT_PCREL: 5210 1.1 mrg opstr = "hw2_last_plt"; 5211 1.1 mrg break; 5212 1.1 mrg default: 5213 1.1 mrg output_operand_lossage ("invalid %%H specifier"); 5214 1.1 mrg } 5215 1.1 mrg 5216 1.1 mrg fputs (opstr, file); 5217 1.1 mrg fputc ('(', file); 5218 1.1 mrg output_addr_const (file, addr); 5219 1.1 mrg 5220 1.1 mrg if (unspec == UNSPEC_HW0_PCREL 5221 1.1 mrg || unspec == UNSPEC_HW1_PCREL 5222 1.1 mrg || unspec == UNSPEC_HW1_LAST_PCREL 5223 1.1 mrg || unspec == UNSPEC_HW2_LAST_PCREL 5224 1.1 mrg || unspec == UNSPEC_HW0_PLT_PCREL 5225 1.1 mrg || unspec == UNSPEC_HW1_PLT_PCREL 5226 1.1 mrg || unspec == UNSPEC_HW1_LAST_PLT_PCREL 5227 1.1 mrg || unspec == UNSPEC_HW2_LAST_PLT_PCREL) 5228 1.1 mrg { 5229 1.1 mrg rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1); 5230 1.1 mrg fputs (" - " , file); 5231 1.1 mrg output_addr_const (file, addr2); 5232 1.1 mrg } 5233 1.1 mrg 5234 1.1 mrg fputc (')', file); 5235 1.1 mrg return; 5236 1.1 mrg } 5237 1.1 mrg else if (symbolic_operand (x, VOIDmode)) 5238 1.1 mrg { 5239 1.1 mrg output_addr_const (file, x); 5240 1.1 mrg return; 5241 1.1 mrg } 5242 1.1 mrg } 5243 1.1 mrg /* FALLTHRU */ 5244 1.1 mrg 5245 1.1 mrg case 'h': 5246 1.1 mrg { 5247 1.1 mrg /* Print the low 16 bits of a constant. */ 5248 1.1 mrg HOST_WIDE_INT i; 5249 1.1 mrg if (CONST_INT_P (x)) 5250 1.1 mrg i = INTVAL (x); 5251 1.1 mrg else if (GET_CODE (x) == CONST_DOUBLE) 5252 1.1 mrg i = CONST_DOUBLE_LOW (x); 5253 1.1 mrg else 5254 1.1 mrg { 5255 1.1 mrg output_operand_lossage ("invalid %%h operand"); 5256 1.1 mrg return; 5257 1.1 mrg } 5258 1.1 mrg i = trunc_int_for_mode (i, HImode); 5259 1.1 mrg fprintf (file, HOST_WIDE_INT_PRINT_DEC, i); 5260 1.1 mrg return; 5261 1.1 mrg } 5262 1.1 mrg 5263 1.1 mrg case 'I': 5264 1.1 mrg /* Print an auto-inc memory operand. */ 5265 1.1 mrg if (!MEM_P (x)) 5266 1.1 mrg { 5267 1.1 mrg output_operand_lossage ("invalid %%I operand"); 5268 1.1 mrg return; 5269 1.1 mrg } 5270 1.1 mrg 5271 1.1 mrg output_memory_autoinc_first = true; 5272 1.1 mrg output_address (GET_MODE (x), XEXP (x, 0)); 5273 1.1 mrg return; 5274 1.1 mrg 5275 1.1 mrg case 'i': 5276 1.1 mrg /* Print an auto-inc memory operand. */ 5277 1.1 mrg if (!MEM_P (x)) 5278 1.1 mrg { 5279 1.1 mrg output_operand_lossage ("invalid %%i operand"); 5280 1.1 mrg return; 5281 1.1 mrg } 5282 1.1 mrg 5283 1.1 mrg output_memory_autoinc_first = false; 5284 1.1 mrg output_address (GET_MODE (x), XEXP (x, 0)); 5285 1.1 mrg return; 5286 1.1 mrg 5287 1.1 mrg case 'j': 5288 1.1 mrg { 5289 1.1 mrg /* Print the low 8 bits of a constant. */ 5290 1.1 mrg HOST_WIDE_INT i; 5291 1.1 mrg if (CONST_INT_P (x)) 5292 1.1 mrg i = INTVAL (x); 5293 1.1 mrg else if (GET_CODE (x) == CONST_DOUBLE) 5294 1.1 mrg i = CONST_DOUBLE_LOW (x); 5295 1.1 mrg else if (GET_CODE (x) == CONST_VECTOR 5296 1.1 mrg && CONST_INT_P (CONST_VECTOR_ELT (x, 0))) 5297 1.1 mrg i = INTVAL (CONST_VECTOR_ELT (x, 0)); 5298 1.1 mrg else 5299 1.1 mrg { 5300 1.1 mrg output_operand_lossage ("invalid %%j operand"); 5301 1.1 mrg return; 5302 1.1 mrg } 5303 1.1 mrg i = trunc_int_for_mode (i, QImode); 5304 1.1 mrg fprintf (file, HOST_WIDE_INT_PRINT_DEC, i); 5305 1.1 mrg return; 5306 1.1 mrg } 5307 1.1 mrg 5308 1.1 mrg case 'P': 5309 1.1 mrg { 5310 1.1 mrg /* Print a constant plus one. */ 5311 1.1 mrg if (!CONST_INT_P (x)) 5312 1.1 mrg { 5313 1.1 mrg output_operand_lossage ("invalid %%P operand"); 5314 1.1 mrg return; 5315 1.1 mrg } 5316 1.1 mrg fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) + 1); 5317 1.1 mrg return; 5318 1.1 mrg } 5319 1.1 mrg 5320 1.1 mrg case 'm': 5321 1.1 mrg case 'M': 5322 1.1 mrg { 5323 1.1 mrg /* Print a bfextu-style bit range. */ 5324 1.1 mrg int first_bit, last_bit; 5325 1.1 mrg HOST_WIDE_INT flip = (code == 'm') ? ~0 : 0; 5326 1.1 mrg 5327 1.1 mrg if (!CONST_INT_P (x) 5328 1.1 mrg || !tilegx_bitfield_operand_p (INTVAL (x) ^ flip, 5329 1.1 mrg &first_bit, &last_bit)) 5330 1.1 mrg { 5331 1.1 mrg output_operand_lossage ("invalid %%%c operand", code); 5332 1.1 mrg return; 5333 1.1 mrg } 5334 1.1 mrg 5335 1.1 mrg fprintf (file, "%d, %d", first_bit, last_bit); 5336 1.1 mrg return; 5337 1.1 mrg } 5338 1.1 mrg 5339 1.1 mrg case 'N': 5340 1.1 mrg { 5341 1.1 mrg const char *reg = NULL; 5342 1.1 mrg 5343 1.1 mrg /* Print a network register. */ 5344 1.1 mrg if (!CONST_INT_P (x)) 5345 1.1 mrg { 5346 1.1 mrg output_operand_lossage ("invalid %%N operand"); 5347 1.1 mrg return; 5348 1.1 mrg } 5349 1.1 mrg 5350 1.1 mrg switch (INTVAL (x)) 5351 1.1 mrg { 5352 1.1 mrg case TILEGX_NETREG_IDN0: reg = "idn0"; break; 5353 1.1 mrg case TILEGX_NETREG_IDN1: reg = "idn1"; break; 5354 1.1 mrg case TILEGX_NETREG_UDN0: reg = "udn0"; break; 5355 1.1 mrg case TILEGX_NETREG_UDN1: reg = "udn1"; break; 5356 1.1 mrg case TILEGX_NETREG_UDN2: reg = "udn2"; break; 5357 1.1 mrg case TILEGX_NETREG_UDN3: reg = "udn3"; break; 5358 1.1 mrg default: 5359 1.1 mrg gcc_unreachable (); 5360 1.1 mrg } 5361 1.1 mrg 5362 1.1 mrg fprintf (file, reg); 5363 1.1 mrg return; 5364 1.1 mrg } 5365 1.1 mrg 5366 1.1 mrg case 'p': 5367 1.1 mrg if (GET_CODE (x) == SYMBOL_REF) 5368 1.1 mrg { 5369 1.1 mrg if (flag_pic && !SYMBOL_REF_LOCAL_P (x)) 5370 1.1 mrg fprintf (file, "plt("); 5371 1.1 mrg output_addr_const (file, x); 5372 1.1 mrg if (flag_pic && !SYMBOL_REF_LOCAL_P (x)) 5373 1.1 mrg fprintf (file, ")"); 5374 1.1 mrg } 5375 1.1 mrg else 5376 1.1 mrg output_addr_const (file, x); 5377 1.1 mrg return; 5378 1.1 mrg 5379 1.1 mrg case 'r': 5380 1.1 mrg /* In this case we need a register. Use 'zero' if the operand 5381 1.1 mrg is const0_rtx. */ 5382 1.1 mrg if (x == const0_rtx 5383 1.1 mrg || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x)))) 5384 1.1 mrg { 5385 1.1 mrg fputs ("zero", file); 5386 1.1 mrg return; 5387 1.1 mrg } 5388 1.1 mrg else if (!REG_P (x)) 5389 1.1 mrg { 5390 1.1 mrg output_operand_lossage ("invalid operand for 'r' specifier"); 5391 1.1 mrg return; 5392 1.1 mrg } 5393 1.1 mrg /* FALLTHRU */ 5394 1.1 mrg 5395 1.1 mrg case 0: 5396 1.1 mrg if (REG_P (x)) 5397 1.1 mrg { 5398 1.1 mrg fprintf (file, "%s", reg_names[REGNO (x)]); 5399 1.1 mrg return; 5400 1.1 mrg } 5401 1.1 mrg else if (MEM_P (x)) 5402 1.1 mrg { 5403 1.1 mrg output_address (VOIDmode, XEXP (x, 0)); 5404 1.1 mrg return; 5405 1.1 mrg } 5406 1.1 mrg else 5407 1.1 mrg { 5408 1.1 mrg output_addr_const (file, x); 5409 1.1 mrg return; 5410 1.1 mrg } 5411 1.1 mrg } 5412 1.1 mrg 5413 1.1 mrg debug_rtx (x); 5414 1.1 mrg output_operand_lossage ("unable to print out operand yet; code == %d (%c)", 5415 1.1 mrg code, code); 5416 1.1 mrg } 5417 1.1 mrg 5418 1.1 mrg 5419 1.1 mrg /* Implement TARGET_PRINT_OPERAND_ADDRESS. */ 5420 1.1 mrg static void 5421 1.1 mrg tilegx_print_operand_address (FILE *file, machine_mode mode, rtx addr) 5422 1.1 mrg { 5423 1.1 mrg if (GET_CODE (addr) == POST_DEC 5424 1.1 mrg || GET_CODE (addr) == POST_INC) 5425 1.1 mrg { 5426 1.1 mrg int offset = GET_MODE_SIZE (mode); 5427 1.1 mrg 5428 1.1 mrg gcc_assert (mode != VOIDmode); 5429 1.1 mrg 5430 1.1 mrg if (output_memory_autoinc_first) 5431 1.1 mrg fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]); 5432 1.1 mrg else 5433 1.1 mrg fprintf (file, "%d", 5434 1.1 mrg GET_CODE (addr) == POST_DEC ? -offset : offset); 5435 1.1 mrg } 5436 1.1 mrg else if (GET_CODE (addr) == POST_MODIFY) 5437 1.1 mrg { 5438 1.1 mrg gcc_assert (mode != VOIDmode); 5439 1.1 mrg 5440 1.1 mrg gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS); 5441 1.1 mrg 5442 1.1 mrg if (output_memory_autoinc_first) 5443 1.1 mrg fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]); 5444 1.1 mrg else 5445 1.1 mrg fprintf (file, HOST_WIDE_INT_PRINT_DEC, 5446 1.1 mrg INTVAL (XEXP (XEXP (addr, 1), 1))); 5447 1.1 mrg } 5448 1.1 mrg else 5449 1.1 mrg tilegx_print_operand (file, addr, 'r'); 5450 1.1 mrg } 5451 1.1 mrg 5452 1.1 mrg 5453 1.1 mrg /* Machine mode of current insn, for determining curly brace 5454 1.1 mrg placement. */ 5455 1.1 mrg static machine_mode insn_mode; 5456 1.1 mrg 5457 1.1 mrg 5458 1.1 mrg /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */ 5459 1.1 mrg void 5460 1.1 mrg tilegx_final_prescan_insn (rtx_insn *insn) 5461 1.1 mrg { 5462 1.1 mrg /* Record this for tilegx_asm_output_opcode to examine. */ 5463 1.1 mrg insn_mode = GET_MODE (insn); 5464 1.1 mrg } 5465 1.1 mrg 5466 1.1 mrg 5467 1.1 mrg /* While emitting asm, are we currently inside '{' for a bundle? */ 5468 1.1 mrg static bool tilegx_in_bundle = false; 5469 1.1 mrg 5470 1.1 mrg /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as 5471 1.1 mrg appropriate given the bundling information recorded by 5472 1.1 mrg tilegx_gen_bundles. */ 5473 1.1 mrg const char * 5474 1.1 mrg tilegx_asm_output_opcode (FILE *stream, const char *code) 5475 1.1 mrg { 5476 1.1 mrg bool pseudo = !strcmp (code, "pseudo"); 5477 1.1 mrg 5478 1.1 mrg if (!tilegx_in_bundle && insn_mode == SImode) 5479 1.1 mrg { 5480 1.1 mrg /* Start a new bundle. */ 5481 1.1 mrg fprintf (stream, "{\n\t"); 5482 1.1 mrg tilegx_in_bundle = true; 5483 1.1 mrg } 5484 1.1 mrg 5485 1.1 mrg if (tilegx_in_bundle && insn_mode == QImode) 5486 1.1 mrg { 5487 1.1 mrg /* Close an existing bundle. */ 5488 1.1 mrg static char buf[100]; 5489 1.1 mrg 5490 1.1 mrg gcc_assert (strlen (code) + 3 + 1 < sizeof (buf)); 5491 1.1 mrg 5492 1.1 mrg strcpy (buf, pseudo ? "" : code); 5493 1.1 mrg strcat (buf, "\n\t}"); 5494 1.1 mrg tilegx_in_bundle = false; 5495 1.1 mrg 5496 1.1 mrg return buf; 5497 1.1 mrg } 5498 1.1 mrg else 5499 1.1 mrg { 5500 1.1 mrg return pseudo ? "" : code; 5501 1.1 mrg } 5502 1.1 mrg } 5503 1.1 mrg 5504 1.1 mrg 5505 1.1 mrg /* Output assembler code to FILE to increment profiler label # LABELNO 5506 1.1 mrg for profiling a function entry. */ 5507 1.1 mrg void 5508 1.1 mrg tilegx_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED) 5509 1.1 mrg { 5510 1.1 mrg if (tilegx_in_bundle) 5511 1.1 mrg { 5512 1.1 mrg fprintf (file, "\t}\n"); 5513 1.1 mrg } 5514 1.1 mrg 5515 1.1 mrg if (cfun->static_chain_decl) 5516 1.1 mrg { 5517 1.1 mrg fprintf (file, 5518 1.1 mrg "\t{\n" 5519 1.1 mrg "\taddi\tsp, sp, -16\n" 5520 1.1 mrg "\tst\tsp, r10\n" 5521 1.1 mrg "\t}\n"); 5522 1.1 mrg } 5523 1.1 mrg 5524 1.1 mrg if (flag_pic) 5525 1.1 mrg { 5526 1.1 mrg fprintf (file, 5527 1.1 mrg "\t{\n" 5528 1.1 mrg "\tmove\tr10, lr\n" 5529 1.1 mrg "\tjal\tplt(%s)\n" 5530 1.1 mrg "\t}\n", MCOUNT_NAME); 5531 1.1 mrg } 5532 1.1 mrg else 5533 1.1 mrg { 5534 1.1 mrg fprintf (file, 5535 1.1 mrg "\t{\n" 5536 1.1 mrg "\tmove\tr10, lr\n" 5537 1.1 mrg "\tjal\t%s\n" 5538 1.1 mrg "\t}\n", MCOUNT_NAME); 5539 1.1 mrg } 5540 1.1 mrg 5541 1.1 mrg if (cfun->static_chain_decl) 5542 1.1 mrg { 5543 1.1 mrg fprintf (file, 5544 1.1 mrg "\taddi\tsp, sp, 16\n" 5545 1.1 mrg "\tld\tr10, sp\n"); 5546 1.1 mrg } 5547 1.1 mrg 5548 1.1 mrg tilegx_in_bundle = false; 5549 1.1 mrg } 5550 1.1 mrg 5551 1.1 mrg 5552 1.1 mrg /* Implement TARGET_ASM_FILE_END. */ 5553 1.1 mrg static void 5554 1.1 mrg tilegx_file_end (void) 5555 1.1 mrg { 5556 1.1 mrg if (NEED_INDICATE_EXEC_STACK) 5557 1.1 mrg file_end_indicate_exec_stack (); 5558 1.1 mrg } 5559 1.1 mrg 5560 1.1 mrg /* Implement TARGET_TRULY_NOOP_TRUNCATION. We represent all SI values 5561 1.1 mrg as sign-extended DI values in registers. */ 5562 1.1 mrg 5563 1.1 mrg static bool 5564 1.1 mrg tilegx_truly_noop_truncation (poly_uint64 outprec, poly_uint64 inprec) 5565 1.1 mrg { 5566 1.1 mrg return inprec <= 32 || outprec > 32; 5567 1.1 mrg } 5568 1.1 mrg 5569 1.1 mrg #undef TARGET_HAVE_TLS 5570 1.1 mrg #define TARGET_HAVE_TLS HAVE_AS_TLS 5571 1.1 mrg 5572 1.1 mrg #undef TARGET_OPTION_OVERRIDE 5573 1.1 mrg #define TARGET_OPTION_OVERRIDE tilegx_option_override 5574 1.1 mrg 5575 1.1 mrg #ifdef TARGET_THREAD_SSP_OFFSET 5576 1.1 mrg #undef TARGET_STACK_PROTECT_GUARD 5577 1.1 mrg #define TARGET_STACK_PROTECT_GUARD hook_tree_void_null 5578 1.1 mrg #endif 5579 1.1 mrg 5580 1.1 mrg #undef TARGET_SCALAR_MODE_SUPPORTED_P 5581 1.1 mrg #define TARGET_SCALAR_MODE_SUPPORTED_P tilegx_scalar_mode_supported_p 5582 1.1 mrg 5583 1.1 mrg #undef TARGET_VECTOR_MODE_SUPPORTED_P 5584 1.1 mrg #define TARGET_VECTOR_MODE_SUPPORTED_P tilegx_vector_mode_supported_p 5585 1.1 mrg 5586 1.1 mrg #undef TARGET_CANNOT_FORCE_CONST_MEM 5587 1.1 mrg #define TARGET_CANNOT_FORCE_CONST_MEM tilegx_cannot_force_const_mem 5588 1.1 mrg 5589 1.1 mrg #undef TARGET_FUNCTION_OK_FOR_SIBCALL 5590 1.1 mrg #define TARGET_FUNCTION_OK_FOR_SIBCALL tilegx_function_ok_for_sibcall 5591 1.1 mrg 5592 1.1 mrg #undef TARGET_PASS_BY_REFERENCE 5593 1.1 mrg #define TARGET_PASS_BY_REFERENCE tilegx_pass_by_reference 5594 1.1 mrg 5595 1.1 mrg #undef TARGET_RETURN_IN_MSB 5596 1.1 mrg #define TARGET_RETURN_IN_MSB tilegx_return_in_msb 5597 1.1 mrg 5598 1.1 mrg #undef TARGET_RETURN_IN_MEMORY 5599 1.1 mrg #define TARGET_RETURN_IN_MEMORY tilegx_return_in_memory 5600 1.1 mrg 5601 1.1 mrg #undef TARGET_MODE_REP_EXTENDED 5602 1.1 mrg #define TARGET_MODE_REP_EXTENDED tilegx_mode_rep_extended 5603 1.1 mrg 5604 1.1 mrg #undef TARGET_FUNCTION_ARG_BOUNDARY 5605 1.1 mrg #define TARGET_FUNCTION_ARG_BOUNDARY tilegx_function_arg_boundary 5606 1.1 mrg 5607 1.1 mrg #undef TARGET_FUNCTION_ARG 5608 1.1 mrg #define TARGET_FUNCTION_ARG tilegx_function_arg 5609 1.1 mrg 5610 1.1 mrg #undef TARGET_FUNCTION_ARG_ADVANCE 5611 1.1 mrg #define TARGET_FUNCTION_ARG_ADVANCE tilegx_function_arg_advance 5612 1.1 mrg 5613 1.1 mrg #undef TARGET_FUNCTION_VALUE 5614 1.1 mrg #define TARGET_FUNCTION_VALUE tilegx_function_value 5615 1.1 mrg 5616 1.1 mrg #undef TARGET_LIBCALL_VALUE 5617 1.1 mrg #define TARGET_LIBCALL_VALUE tilegx_libcall_value 5618 1.1 mrg 5619 1.1 mrg #undef TARGET_FUNCTION_VALUE_REGNO_P 5620 1.1 mrg #define TARGET_FUNCTION_VALUE_REGNO_P tilegx_function_value_regno_p 5621 1.1 mrg 5622 1.1 mrg #undef TARGET_PROMOTE_FUNCTION_MODE 5623 1.1 mrg #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote 5624 1.1 mrg 5625 1.1 mrg #undef TARGET_PROMOTE_PROTOTYPES 5626 1.1 mrg #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false 5627 1.1 mrg 5628 1.1 mrg #undef TARGET_BUILD_BUILTIN_VA_LIST 5629 1.1 mrg #define TARGET_BUILD_BUILTIN_VA_LIST tilegx_build_builtin_va_list 5630 1.1 mrg 5631 1.1 mrg #undef TARGET_EXPAND_BUILTIN_VA_START 5632 1.1 mrg #define TARGET_EXPAND_BUILTIN_VA_START tilegx_va_start 5633 1.1 mrg 5634 1.1 mrg #undef TARGET_SETUP_INCOMING_VARARGS 5635 1.1 mrg #define TARGET_SETUP_INCOMING_VARARGS tilegx_setup_incoming_varargs 5636 1.1 mrg 5637 1.1 mrg #undef TARGET_GIMPLIFY_VA_ARG_EXPR 5638 1.1 mrg #define TARGET_GIMPLIFY_VA_ARG_EXPR tilegx_gimplify_va_arg_expr 5639 1.1 mrg 5640 1.1 mrg #undef TARGET_RTX_COSTS 5641 1.1 mrg #define TARGET_RTX_COSTS tilegx_rtx_costs 5642 1.1 mrg 5643 1.1 mrg #undef TARGET_EXPAND_TO_RTL_HOOK 5644 1.1 mrg #define TARGET_EXPAND_TO_RTL_HOOK tilegx_expand_to_rtl_hook 5645 1.1 mrg 5646 1.1 mrg #undef TARGET_SHIFT_TRUNCATION_MASK 5647 1.1 mrg #define TARGET_SHIFT_TRUNCATION_MASK tilegx_shift_truncation_mask 5648 1.1 mrg 5649 1.1 mrg #undef TARGET_INIT_LIBFUNCS 5650 1.1 mrg #define TARGET_INIT_LIBFUNCS tilegx_init_libfuncs 5651 1.1 mrg 5652 1.1 mrg /* Limit to what we can reach in one addli. */ 5653 1.1 mrg #undef TARGET_MIN_ANCHOR_OFFSET 5654 1.1 mrg #define TARGET_MIN_ANCHOR_OFFSET -32768 5655 1.1 mrg #undef TARGET_MAX_ANCHOR_OFFSET 5656 1.1 mrg #define TARGET_MAX_ANCHOR_OFFSET 32767 5657 1.1 mrg 5658 1.1 mrg #undef TARGET_LEGITIMATE_CONSTANT_P 5659 1.1 mrg #define TARGET_LEGITIMATE_CONSTANT_P tilegx_legitimate_constant_p 5660 1.1 mrg 5661 1.1 mrg #undef TARGET_LRA_P 5662 1.1 mrg #define TARGET_LRA_P hook_bool_void_false 5663 1.1 mrg 5664 1.1 mrg #undef TARGET_LEGITIMATE_ADDRESS_P 5665 1.1 mrg #define TARGET_LEGITIMATE_ADDRESS_P tilegx_legitimate_address_p 5666 1.1 mrg 5667 1.1 mrg #undef TARGET_LEGITIMIZE_ADDRESS 5668 1.1 mrg #define TARGET_LEGITIMIZE_ADDRESS tilegx_legitimize_address 5669 1.1 mrg 5670 1.1 mrg #undef TARGET_DELEGITIMIZE_ADDRESS 5671 1.1 mrg #define TARGET_DELEGITIMIZE_ADDRESS tilegx_delegitimize_address 5672 1.1 mrg 5673 1.1 mrg #undef TARGET_INIT_BUILTINS 5674 1.1 mrg #define TARGET_INIT_BUILTINS tilegx_init_builtins 5675 1.1 mrg 5676 1.1 mrg #undef TARGET_BUILTIN_DECL 5677 1.1 mrg #define TARGET_BUILTIN_DECL tilegx_builtin_decl 5678 1.1 mrg 5679 1.1 mrg #undef TARGET_EXPAND_BUILTIN 5680 1.1 mrg #define TARGET_EXPAND_BUILTIN tilegx_expand_builtin 5681 1.1 mrg 5682 1.1 mrg #undef TARGET_CONDITIONAL_REGISTER_USAGE 5683 1.1 mrg #define TARGET_CONDITIONAL_REGISTER_USAGE tilegx_conditional_register_usage 5684 1.1 mrg 5685 1.1 mrg #undef TARGET_FRAME_POINTER_REQUIRED 5686 1.1 mrg #define TARGET_FRAME_POINTER_REQUIRED tilegx_frame_pointer_required 5687 1.1 mrg 5688 1.1 mrg #undef TARGET_DELAY_SCHED2 5689 1.1 mrg #define TARGET_DELAY_SCHED2 true 5690 1.1 mrg 5691 1.1 mrg #undef TARGET_DELAY_VARTRACK 5692 1.1 mrg #define TARGET_DELAY_VARTRACK true 5693 1.1 mrg 5694 1.1 mrg #undef TARGET_SCHED_ISSUE_RATE 5695 1.1 mrg #define TARGET_SCHED_ISSUE_RATE tilegx_issue_rate 5696 1.1 mrg 5697 1.1 mrg #undef TARGET_SCHED_ADJUST_COST 5698 1.1 mrg #define TARGET_SCHED_ADJUST_COST tilegx_sched_adjust_cost 5699 1.1 mrg 5700 1.1 mrg #undef TARGET_MACHINE_DEPENDENT_REORG 5701 1.1 mrg #define TARGET_MACHINE_DEPENDENT_REORG tilegx_reorg 5702 1.1 mrg 5703 1.1 mrg #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK 5704 1.1 mrg #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \ 5705 1.1 mrg hook_bool_const_tree_hwi_hwi_const_tree_true 5706 1.1 mrg 5707 1.1 mrg #undef TARGET_ASM_OUTPUT_MI_THUNK 5708 1.1 mrg #define TARGET_ASM_OUTPUT_MI_THUNK tilegx_output_mi_thunk 5709 1.1 mrg 5710 1.1 mrg #undef TARGET_ASM_TRAMPOLINE_TEMPLATE 5711 1.1 mrg #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilegx_asm_trampoline_template 5712 1.1 mrg 5713 1.1 mrg #undef TARGET_TRAMPOLINE_INIT 5714 1.1 mrg #define TARGET_TRAMPOLINE_INIT tilegx_trampoline_init 5715 1.1 mrg 5716 1.1 mrg #undef TARGET_PRINT_OPERAND 5717 1.1 mrg #define TARGET_PRINT_OPERAND tilegx_print_operand 5718 1.1 mrg 5719 1.1 mrg #undef TARGET_PRINT_OPERAND_ADDRESS 5720 1.1 mrg #define TARGET_PRINT_OPERAND_ADDRESS tilegx_print_operand_address 5721 1.1 mrg 5722 1.1 mrg #undef TARGET_ASM_FILE_END 5723 1.1 mrg #define TARGET_ASM_FILE_END tilegx_file_end 5724 1.1 mrg 5725 1.1 mrg #undef TARGET_ASM_ALIGNED_DI_OP 5726 1.1 mrg #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" 5727 1.1 mrg 5728 1.1 mrg #undef TARGET_CAN_USE_DOLOOP_P 5729 #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost 5730 5731 #undef TARGET_TRULY_NOOP_TRUNCATION 5732 #define TARGET_TRULY_NOOP_TRUNCATION tilegx_truly_noop_truncation 5733 5734 #undef TARGET_CONSTANT_ALIGNMENT 5735 #define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings 5736 5737 struct gcc_target targetm = TARGET_INITIALIZER; 5738 5739 #include "gt-tilegx.h" 5740