comparison gcc/config/avr/avr.c @ 63:b7f97abdc517 gcc-4.6-20100522

update gcc from gcc-4.5.0 to gcc-4.6
author ryoma <e075725@ie.u-ryukyu.ac.jp>
date Mon, 24 May 2010 12:47:05 +0900
parents 77e2b8dfacca
children f6334be47118
comparison
equal deleted inserted replaced
56:3c8a44c06a95 63:b7f97abdc517
1 /* Subroutines for insn-output.c for ATMEL AVR micro controllers 1 /* Subroutines for insn-output.c for ATMEL AVR micro controllers
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008,
3 2009 Free Software Foundation, Inc. 3 2009, 2010 Free Software Foundation, Inc.
4 Contributed by Denis Chertykov (chertykov@gmail.com) 4 Contributed by Denis Chertykov (chertykov@gmail.com)
5 5
6 This file is part of GCC. 6 This file is part of GCC.
7 7
8 GCC is free software; you can redistribute it and/or modify 8 GCC is free software; you can redistribute it and/or modify
24 #include "coretypes.h" 24 #include "coretypes.h"
25 #include "tm.h" 25 #include "tm.h"
26 #include "rtl.h" 26 #include "rtl.h"
27 #include "regs.h" 27 #include "regs.h"
28 #include "hard-reg-set.h" 28 #include "hard-reg-set.h"
29 #include "real.h"
30 #include "insn-config.h" 29 #include "insn-config.h"
31 #include "conditions.h" 30 #include "conditions.h"
32 #include "insn-attr.h" 31 #include "insn-attr.h"
33 #include "flags.h" 32 #include "flags.h"
34 #include "reload.h" 33 #include "reload.h"
4216 AS1 (ror,%A0)), 4215 AS1 (ror,%A0)),
4217 insn, operands, len, 4); 4216 insn, operands, len, 4);
4218 return ""; 4217 return "";
4219 } 4218 }
4220 4219
4220 /* Create RTL split patterns for byte sized rotate expressions. This
4221 produces a series of move instructions and considers overlap situations.
4222 Overlapping non-HImode operands need a scratch register. */
4223
4224 bool
4225 avr_rotate_bytes (rtx operands[])
4226 {
4227 int i, j;
4228 enum machine_mode mode = GET_MODE (operands[0]);
4229 bool overlapped = reg_overlap_mentioned_p (operands[0], operands[1]);
4230 bool same_reg = rtx_equal_p (operands[0], operands[1]);
4231 int num = INTVAL (operands[2]);
4232 rtx scratch = operands[3];
4233 /* Work out if byte or word move is needed. Odd byte rotates need QImode.
4234 Word move if no scratch is needed, otherwise use size of scratch. */
4235 enum machine_mode move_mode = QImode;
4236 if (num & 0xf)
4237 move_mode = QImode;
4238 else if ((mode == SImode && !same_reg) || !overlapped)
4239 move_mode = HImode;
4240 else
4241 move_mode = GET_MODE (scratch);
4242
4243 /* Force DI rotate to use QI moves since other DI moves are currently split
4244 into QI moves so forward propagation works better. */
4245 if (mode == DImode)
4246 move_mode = QImode;
4247 /* Make scratch smaller if needed. */
4248 if (GET_MODE (scratch) == HImode && move_mode == QImode)
4249 scratch = simplify_gen_subreg (move_mode, scratch, HImode, 0);
4250
4251 int move_size = GET_MODE_SIZE (move_mode);
4252 /* Number of bytes/words to rotate. */
4253 int offset = (num >> 3) / move_size;
4254 /* Number of moves needed. */
4255 int size = GET_MODE_SIZE (mode) / move_size;
4256 /* Himode byte swap is special case to avoid a scratch register. */
4257 if (mode == HImode && same_reg)
4258 {
4259 /* HImode byte swap, using xor. This is as quick as using scratch. */
4260 rtx src, dst;
4261 src = simplify_gen_subreg (move_mode, operands[1], mode, 0);
4262 dst = simplify_gen_subreg (move_mode, operands[0], mode, 1);
4263 if (!rtx_equal_p (dst, src))
4264 {
4265 emit_move_insn (dst, gen_rtx_XOR (QImode, dst, src));
4266 emit_move_insn (src, gen_rtx_XOR (QImode, src, dst));
4267 emit_move_insn (dst, gen_rtx_XOR (QImode, dst, src));
4268 }
4269 }
4270 else
4271 {
4272 /* Create linked list of moves to determine move order. */
4273 struct {
4274 rtx src, dst;
4275 int links;
4276 } move[size + 8];
4277
4278 /* Generate list of subreg moves. */
4279 for (i = 0; i < size; i++)
4280 {
4281 int from = i;
4282 int to = (from + offset) % size;
4283 move[i].src = simplify_gen_subreg (move_mode, operands[1],
4284 mode, from * move_size);
4285 move[i].dst = simplify_gen_subreg (move_mode, operands[0],
4286 mode, to * move_size);
4287 move[i].links = -1;
4288 }
4289 /* Mark dependence where a dst of one move is the src of another move.
4290 The first move is a conflict as it must wait until second is
4291 performed. We ignore moves to self - we catch this later. */
4292 if (overlapped)
4293 for (i = 0; i < size; i++)
4294 if (reg_overlap_mentioned_p (move[i].dst, operands[1]))
4295 for (j = 0; j < size; j++)
4296 if (j != i && rtx_equal_p (move[j].src, move[i].dst))
4297 {
4298 /* The dst of move i is the src of move j. */
4299 move[i].links = j;
4300 break;
4301 }
4302
4303 int blocked = -1;
4304 int moves = 0;
4305 /* Go through move list and perform non-conflicting moves. As each
4306 non-overlapping move is made, it may remove other conflicts
4307 so the process is repeated until no conflicts remain. */
4308 do
4309 {
4310 blocked = -1;
4311 moves = 0;
4312 /* Emit move where dst is not also a src or we have used that
4313 src already. */
4314 for (i = 0; i < size; i++)
4315 if (move[i].src != NULL_RTX)
4316 if (move[i].links == -1 || move[move[i].links].src == NULL_RTX)
4317 {
4318 moves++;
4319 /* Ignore NOP moves to self. */
4320 if (!rtx_equal_p (move[i].dst, move[i].src))
4321 emit_move_insn (move[i].dst, move[i].src);
4322
4323 /* Remove conflict from list. */
4324 move[i].src = NULL_RTX;
4325 }
4326 else
4327 blocked = i;
4328
4329 /* Check for deadlock. This is when no moves occurred and we have
4330 at least one blocked move. */
4331 if (moves == 0 && blocked != -1)
4332 {
4333 /* Need to use scratch register to break deadlock.
4334 Add move to put dst of blocked move into scratch.
4335 When this move occurs, it will break chain deadlock.
4336 The scratch register is substituted for real move. */
4337
4338 move[size].src = move[blocked].dst;
4339 move[size].dst = scratch;
4340 /* Scratch move is never blocked. */
4341 move[size].links = -1;
4342 /* Make sure we have valid link. */
4343 gcc_assert (move[blocked].links != -1);
4344 /* Replace src of blocking move with scratch reg. */
4345 move[move[blocked].links].src = scratch;
4346 /* Make dependent on scratch move occuring. */
4347 move[blocked].links = size;
4348 size=size+1;
4349 }
4350 }
4351 while (blocked != -1);
4352 }
4353 return true;
4354 }
4355
4221 /* Modifies the length assigned to instruction INSN 4356 /* Modifies the length assigned to instruction INSN
4222 LEN is the initially computed length of the insn. */ 4357 LEN is the initially computed length of the insn. */
4223 4358
4224 int 4359 int
4225 adjust_insn_length (rtx insn, int len) 4360 adjust_insn_length (rtx insn, int len)