summaryrefslogtreecommitdiff
path: root/tcg/arm
diff options
context:
space:
mode:
authorAurelien Jarno <aurelien@aurel32.net>2011-01-06 22:43:13 +0100
committerAurelien Jarno <aurelien@aurel32.net>2011-01-10 07:30:30 +0100
commit0f11f25a001f6adca18689192182d415ff3dbb7c (patch)
treeb829ea7108e50558b65f1300725a84b76934918f /tcg/arm
parenta3e28aa5c748958e5719451aaff88a4d78e09a80 (diff)
downloadqemu-0f11f25a001f6adca18689192182d415ff3dbb7c.tar.gz
tcg/arm: improve constant loading
Improve constant loading in two ways: - On all ARM versions, it's possible to load 0xffffff00 = -0x100 using the mvn rd, #0. Fix the conditions. - On <= ARMv6 versions, where movw and movt are not available, load the constants using mov and orr with rotations depending on the constant to load. This is very useful for example to load constants where the low byte is 0. This reduce the generated code size by about 7%. Also fix the coding style at the same time. Cc: Andrzej Zaborowski <balrog@zabor.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Diffstat (limited to 'tcg/arm')
-rw-r--r--tcg/arm/tcg-target.c39
1 files changed, 21 insertions, 18 deletions
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 08c44c1123..1eb5605f8c 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -406,35 +406,38 @@ static inline void tcg_out_dat_imm(TCGContext *s,
}
static inline void tcg_out_movi32(TCGContext *s,
- int cond, int rd, int32_t arg)
+ int cond, int rd, uint32_t arg)
{
/* TODO: This is very suboptimal, we can easily have a constant
* pool somewhere after all the instructions. */
-
- if (arg < 0 && arg > -0x100)
- return tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff);
-
- if (use_armv7_instructions) {
+ if ((int)arg < 0 && (int)arg >= -0x100) {
+ tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff);
+ } else if (use_armv7_instructions) {
/* use movw/movt */
/* movw */
tcg_out32(s, (cond << 28) | 0x03000000 | (rd << 12)
| ((arg << 4) & 0x000f0000) | (arg & 0xfff));
- if (arg & 0xffff0000)
+ if (arg & 0xffff0000) {
/* movt */
tcg_out32(s, (cond << 28) | 0x03400000 | (rd << 12)
| ((arg >> 12) & 0x000f0000) | ((arg >> 16) & 0xfff));
- } else {
- tcg_out_dat_imm(s, cond, ARITH_MOV, rd, 0, arg & 0xff);
- if (arg & 0x0000ff00)
- tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd,
- ((arg >> 8) & 0xff) | 0xc00);
- if (arg & 0x00ff0000)
- tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd,
- ((arg >> 16) & 0xff) | 0x800);
- if (arg & 0xff000000)
- tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd,
- ((arg >> 24) & 0xff) | 0x400);
}
+ } else {
+ int opc = ARITH_MOV;
+ int rn = 0;
+
+ do {
+ int i, rot;
+
+ i = ctz32(arg) & ~1;
+ rot = ((32 - i) << 7) & 0xf00;
+ tcg_out_dat_imm(s, cond, opc, rd, rn, ((arg >> i) & 0xff) | rot);
+ arg &= ~(0xff << i);
+
+ opc = ARITH_ORR;
+ rn = rd;
+ } while (arg);
+ }
}
static inline void tcg_out_mul32(TCGContext *s,