ARM MOV 和 MVN 操作数 [英] ARM MOV and MVN operand

查看:27
本文介绍了ARM MOV 和 MVN 操作数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写代码来做两件事:如果我的值在 ARM 数据处理指令中可以作为常量表示,则将 1 返回到寄存器 r2.这段代码就是这样做的(如果效率低,请提供更好的方法).但是,我也想修改它以告诉我是否需要使用 MOV 或 MVN.

I'm trying to write code to do two things: return a 1 to register r2 if my value is presentable as a constant in the ARM data processing instruction. This code does that (offer better methods if it's inefficient please). However, I also want to modify it to tell me whether a MOV or MVN needs to be used.

    AREA    ArmExample18b, CODE

        ENTRY
            MOV r2, #0                          ;register return value. if =1, representable, otherwise, not representable      
            LDR r1, TABLE1                      ;input value we want to use
            LDR r3, TABLE1+4                    ;upper bound register
            LDR r4, TABLE1+8                    ;lower bound register
            MOV r5, #12

INVCHECK    CLZ r6, r1                          ;r6 contains number of leading zeros in r1
            RBIT r7, r1
            CLZ r8, r7                          ;r8 contains number of trailing zeros in r1
            CMP r6, r8
            SUBCS r9, r6, r8
            RSBCC r9, r6, r8
            CMP r9, #8
            MVNHI r1, r1
            BHI INVCHECK
            BLS LOOP
LOOP                                
            CMP r3, r1                          ;compare input value with upper bound
            BLO STOP                            ;if bigger than u.b, stop, r2 = 0 
            CMP r4, r1                          ;compare input value with lower bound
            MOVLS r2, #1                        ;if larger than lower bound, it falls within range, set r2 = 1
            BLS STOP                            ;then stop
            CMP r4, #0                          ;if r4 has reached 0, then we are at the end of comparisons and can stop
            BEQ STOP
            LDR r3, TABLE1 + r5                 ;change upper bound
            ADD r5, r5, #4          
            LDR r4, TABLE1 + r5                 ;change lower bound
            ADD r5, r5, #4          
            B LOOP
STOP        B STOP


TABLE1  DCD 0x500, 0x3fc0, 0x1000, 0xff0, 0x400, 0x3fc, 0x100, 0xff, 0

    END

推荐答案

但是,我也想修改它以告诉我是否需要使用 MOV 或 MVN.

However, I also want to modify it to tell me whether a MOV or MVN needs to be used.

测试 MOV 案例.如果不是,请测试 MVN 案例并设置一个标志(或任何您的 API 想要的).人们通常使用 +1 (MOV)、0(不能适应)、-1 (MVN),因为这可能很适合在调用方纯 ARM 中进行测试.

Test for the MOV case. If no, test for the MVN case and set a flag (or whatever your API wants). Often people use +1 (MOV), 0 (can not fit), -1 (MVN) as this might be nice to test in the caller pure ARM.

完全无知,我开始研究 gas(GNU 汇编程序所做的).我在 tc-arm.c 在名为 encode_arm_immediate() 的例程中.这是来源,

Being completely ignorant, I started by investigating what gas (GNU assembler does). I found the answer in tc-arm.c in a routine called encode_arm_immediate(). Here is the source,

/* If VAL can be encoded in the immediate field of an ARM instruction,
   return the encoded form.  Otherwise, return FAIL.  */

static unsigned int
encode_arm_immediate (unsigned int val)
{
  unsigned int a, i;

  for (i = 0; i < 32; i += 2)
    if ((a = rotate_left (val, i)) <= 0xff)
      return a | (i << 7); /* 12-bit pack: [shift-cnt,const].  */

  return FAIL;
}

一些有趣的点.它不像您的示例那样高效,但更正确.我不认为您正在处理像 0xf000000f 这样可以表示的常量.另外,同一个文件中move_or_literal_pool()中的代码有这个伪代码,

Some interesting points. It is not very efficient like your example, but it is more correct. I don't think you are handling constants like 0xf000000f which can be represented. Also, the code in move_or_literal_pool() in the same file has this pseudo code,

if((packed = encode_arm_immediate(val)) == FAIL)
    packed = encode_arm_immediate(~val);

很明显,如果您对 MOV 进行了测试,则可以对 MVN 进行补充和测试.事实上,我不认为通过尝试并行测试每个方法会更有效率,因为这会使逻辑过于复杂.当前步骤可以通过查找第一个设置位 (clz) 的指令最小化,因为您不需要遍历所有位 [参见 pop_count()].

It is pretty clear that if you have a test for MOV, you can complement and test for MVN. In fact, I don't think you will be more efficient by trying to test each in parallel as you complicate the logic too much. The current steps can be minimized with an instruction to find the first set bit (clz) as you don't need to iterate over all of the bits [see pop_count()].

 bits = pop_count(val);
 if(bits <= 8) {
    /* Search 'MOV' */ using clz to normalize */
    shift = clz(val);
    val =<< shift;
    if((val & 0xff<<24 == val) && !shift&1) goto it.
    if((val & 0xfe<<24 == val) &&  shift&1) goto it.
    /* test for rotation */
 }
 if(bits >= 32-8) {
    /* Set 'MVN' flag */
    /* as above */
 }

有多种方法可以实现人口计数和/或数字运行.真的,如果您的算法正确并处理旋转,那么简单的 encode_arm_immediate() 看起来它的简单性最终会与任何尝试使用高级指令的解决方案竞争检测位的运行.encode_arm_immediate() 将适合缓存,并且循环将在具有缓存和分支预测的 ARMv7 上快速运行.

There are various ways to implement a population count and/or run of numbers. Really, if your algorithm is correct and handles the rotation, the simple encode_arm_immediate() seems like it's simplicity will end up being very competitive to any solution that tries to use advanced instruction to detect runs of bits. The encode_arm_immediate() will fit in the cache and the loop will be running quickly on an ARMv7 with caches and branch prediction.

这篇关于ARM MOV 和 MVN 操作数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆