From 94953e6d748741693298ea6e5e4b86ea706ef026 Mon Sep 17 00:00:00 2001 From: Laurent Desnogues Date: Sat, 22 Aug 2009 14:29:09 +0200 Subject: [PATCH] ARM back-end: Handle all possible immediates for ALU ops this patch handles all possible constants for immediate operand of ALU ops. I'm not very satisfied by the implementation. Laurent Signed-off-by: Laurent Desnogues Signed-off-by: Andrzej Zaborowski --- tcg/arm/tcg-target.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 6b55762b65..525994c9c1 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -179,11 +179,36 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) return 0; } +static inline uint32_t rotl(uint32_t val, int n) +{ + return (val << n) | (val >> (32 - n)); +} + +/* ARM immediates for ALU instructions are made of an unsigned 8-bit + right-rotated by an even amount between 0 and 30. */ +static inline int encode_imm(uint32_t imm) +{ + /* simple case, only lower bits */ + if ((imm & ~0xff) == 0) + return 0; + /* then try a simple even shift */ + shift = ctz32(imm) & ~1; + if (((imm >> shift) & ~0xff) == 0) + return 32 - shift; + /* now try harder with rotations */ + if ((rotl(imm, 2) & ~0xff) == 0) + return 2; + if ((rotl(imm, 4) & ~0xff) == 0) + return 4; + if ((rotl(imm, 6) & ~0xff) == 0) + return 6; + /* imm can't be encoded */ + return -1; +} static inline int check_fit_imm(uint32_t imm) { - /* XXX: use rotation */ - return (imm & ~0xff) == 0; + return encode_imm(imm) >= 0; } /* Test if a constant matches the constraint. @@ -1407,10 +1432,12 @@ static inline void tcg_out_op(TCGContext *s, int opc, c = ARITH_EOR; /* Fall through. */ gen_arith: - if (const_args[2]) + if (const_args[2]) { + int rot; + rot = encode_imm(args[2]); tcg_out_dat_imm(s, COND_AL, c, - args[0], args[1], args[2]); - else + args[0], args[1], rotl(args[2], rot) | (rot << 7)); + } else tcg_out_dat_reg(s, COND_AL, c, args[0], args[1], args[2], SHIFT_IMM_LSL(0)); break;