Mercurial > hg > CbC > CbC_gcc
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) |