views:

674

answers:

6

In ARM assembly immediates are encoded by an 8-bit rotated value which means we can only encode

(0-256)^2n.

Now my problem is that I want to clear the upper 16-bits of r0 and replace it with the half-word stored r1. But because of the limited range of the immediates I have to do: -

bic r0, r0, #0xff000000
bic r0, r0, #0x00ff0000
add r0, r0, r1, LSL #16

Is it possible to do replace the 2 bic instructions with a single instruction? 0xffff0000 is unencodable. Perhaps I should be using another logical operation to clear the upper 16-bits?

Thanks

EDIT: Sorry I forgot to say that the top 16-bits of r1 is empty, and I'm using an ARM7TDMI

A: 

If you can clear the whole thing, you could xor it with itself.

If you need to retain the bottom half, might you be able to left-shift the register 8 bits and back? That may be same number of instructions, though.

warren
A: 

For the C code

 (a<<16)|((short)b)

gcc generates

    mov     r1, r1, asl #16
    mov     r1, r1, asr #16
    orr     r0, r1, r0, asl #16

which doesn't use any immediates - it's still two instructions, though.

Martin v. Löwis
Yeh i think that is equivalent (with r0 and r1 the other way around). But as warren said, i have to do a shift left and right which is still the same number of instructions.
Tarski
Thing you forgot is let the compiler know the high 16bit of `b` are clean. If you try `int merge(int a, short b) { return (a << 16) | b; }` GCC outputs what bobince suggested :). It's good practice to supply the compiler everything you know.
LiraNuna
+1  A: 

On ARMv6 (e.g. MPCore), you can say

    uxth    r1, r1
    orr     r0, r1, r0, asl #16
Martin v. Löwis
+1  A: 

"replace it with the half-word stored r1" - does this mean you can assume the top 16 bits of r1 are zero? If so,

add r0, r1, r0 lsl #16
mov r0, r0 ror #16

Think of the mov as a placeholder, since you can hopefully move the ror to whatever would take r0 as input next and actually do useful work in the same cycle.

moonshadow
+3  A: 

How about:

orr r0,r1,r0,lsl #16
mov r0,r0,ror #16

(This assumes that the top halfword of r1 is empty, like your reference code did.) Depending on the circumstances, you might be able to omit the final mov here by merging it with some later code.

+4  A: 

If you have a new enough ARM core the asked question is simple:

movt    r0, #0
orr     r0, r0, r1,lsl#16

See http://www.keil.com/support/man/docs/armasm/armasm_cjagdjbf.htm

However if you do have ARMv6+ you can actually do the whole quoted example in one go:

pkhbt   r0, r0, r1,lsl#16

See http://www.keil.com/support/man/docs/armasm/armasm_cihjedjg.htm

bobince
These are both thumb instructions, right?
Martin v. Löwis
Keil claims they are available as ARM instructions as well as Thumb. I've personally never had cause to use anything beyond ARMv4 in anger, but I believe they should work.
bobince
Edit: “I'm using an ARM7TDMI” — ARM7TDMI is ARMv4, or possibly ARMv5... either way sadly not new enough to feature either ‘movt’ or ‘pkh’.
bobince