0

I'm working on a project where I'm trying not to use the MOVS command but a combination of MOV and other commands.

        mov     r3, #-2147483648
        str     r3, [r7, #36]
        mvn     r3, #-2147483648
        str     r3, [r7, #32]
        movs    r3, #0
        str     r3, [r7, #28]
        movs    r3, #0
        str     r3, [r7, #24]

As you can see movs is used twice here, what could be its equivalent? Possibly using ldr and mov? Thanks!

  • 1
    Have you tried just using `mov` instead of `movs`? Also, what variant of the ARM instruction set are you programming for? – fuz Mar 07 '22 at 00:58
  • @fuz, this is a good suggestion, but the OP hasn't shown what happens after the last `str` Are there conditions between the last `str` and and the next condition code setting instruction? It is often the case that `movs` is the only form available for thumb and there is no choice but to use it. It would be helpful to know the architectures (port from -> to) or if there is some coding standard involved. – artless noise Mar 07 '22 at 16:03

1 Answers1

3

tst reg,reg sets flags according to the value, so mov dst,src + tst dst,dst would be the naive drop-in replacement for any case.

Or in your case, your str instructions don't depend on flags so you could just use mov r3, #0. (Once; reading it with str doesn't destroy the value so there's no need to set it again).

But if you really want to also set flags according to the 0 value, you could zero a register inefficiently with ands r3, #0. (Setting to all-ones inefficiently with orrs r3, #-1 isn't possible in ARM mode; the immediate isn't encodeable. But it is in Thumb mode with Thumb-2 available.)

(Or eors r3,r3 or subs r3,r3 to borrow the x86 zeroing idiom, but note that ARM CPUs won't special case that and run it efficiently. In fact they're not allowed to do so: the memory-ordering model has data-dependency ordering like C++11 std::memory_order_consume was supposed to expose, but is otherwise weakly ordered. eors and subs, like all ALU instructions, are guaranteed to carry a data dependency on their inputs, regardless of any special cases.)


For copying a register, adds reg, reg, #0 should do the trick. This is apparently a separate instruction with a separate opcode even in Thumb mode.

.syntax unified
.thumb_func
adds r1, r2, #0
movs r1, r2

arm-none-eabi-gcc -mcpu=cortex-a53 -c arm.s && arm-none-eabi-objdump -d arm.o

   0:   1c11            adds    r1, r2, #0
   2:   0011            movs    r1, r2

Arm dedicated comparisons

Comparison Arithmetic
cmp subs
cmn adds
tst ands
teq eors

Ie, these four instructions perform the arithmetic equivalent, but do not write the results to a destination. The only effect is to set condition codes, as if the arithmetic instruction was used.

In order to properly port this, it would be good to resolve what the intent of the original movs is. It is quite possible that the condition codes are not needed and this was a limitation of the architecture the code was originally targeting.

artless noise
  • 21,212
  • 6
  • 68
  • 105
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Unfortunately I can't use tst in my project, do you know of any other combination that might work? – Charlieglider Mar 07 '22 at 05:07
  • @Charlieglider: I assume `cmp reg, #0` also sets flags the same as `tst`, or even `adds reg, #0`. I don't know ARM well enough to be 100% certain there isn't some obscure difference in a seldom-used flag, but you could check with a debugger. – Peter Cordes Mar 07 '22 at 08:19
  • 1
    I think the `tst` versus `cmp` goes to the intent here. Ie, what exactly are the condition codes being used for. From the given assembler sequence it is not clear. If they are used, I think only the 'Z' bit would be tested. But really I think it is a vestige of a thumb encoding the OP has to port. Ie, there was no plain `mov` in the thumb1 ISA. If this is the case, a simple `mov` will suffice. – artless noise Mar 07 '22 at 16:28