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

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

问题描述

我想写code做两件事情:返回一个1到寄存器R2如果我的值是presentable作为ARM数据处理指令中的常数。这code这是否(提供更好的方法,如果它是低效率的,请)。不过,我也想修改它告诉我MOV或MVN是否需要使用。

 区域ArmExample18b,code        条目
            MOV R2,#0;注册返回值。如果= 1,再presentable,否则,不会再presentable
            LDR R1,TABLE1;输入值,我们要使用
            LDR R3,TABLE1 + 4;上限寄存器
            LDR R4,TABLE1 + 8;下界寄存器
            MOV R5,#12INVCHECK CLZ R6,R1,R6包含R1前导零的数
            RBIT R7,R1
            CLZ R8,R7,R8包含R1尾​​随零的数
            CMP R6,R8
            SUBCS R9,R6,R8
            RSBCC R9,R6,R8
            CMP R9,#8
            MVNHI R1,R1
            BHI INVCHECK
            BLS LOOP
循环
            CMP R3,R1;比较上限输入值
            BLO STOP;如果不是u.b更大,停止,R2 = 0
            CMP R4,R1;与下界比较输入值
            MOVLS R2,#1;如果大于下限,它落入在范围内,设定R2 = 1
            BLS STOP;然后停止
            CMP R4,#0;若R4已达到0,那么我们在比较的结束,并且可以停止
            BEQ STOP
            LDR R3,TABLE1 + R5;改变上限
            ADD R5,R5,#4
            LDR R4,TABLE1 + R5;改变下界
            ADD R5,R5,#4
            乙LOOP
STOP B STOP
TABLE1 DCD量0x500,0x3fc0,为0x1000,量0xFF0,0x400的,0x3FC中,为0x100,为0xFF,0    结束


解决方案

  

不过,我也想修改它告诉我MOV或MVN是否需要使用。


测试了 MOV 情况。如果没有,用于测试的 MVN 的情况下,并设置标志(或任何你想要的API)。人们常常用+1(MOV),0(不适合)-1(MVN),因为这可能是好的,在主叫方纯ARM测试。


被完全懵了,我开始调查的气体(GNU汇编器)是什么。我发现的 TC-arm.c在一个名为常规 连接code_arm_immediate()。这里是源,

  / *如果VAL可以连接codeD在ARM指令的立即字段,
   返回EN codeD形式。否则,返回FAIL。 * /静态无符号整型
EN code_arm_immediate(无符号整数VAL)
{
  unsigned int类型A,I;  对于(I = 0; I&下; 32; I + = 2)
    如果((α= rotate_left(VAL,我))≤= 0xff的)
      返回| (ⅰ&所述; 7;); / * 12位包:[SHIFT-CNT,常量。 * /  返回失败;
}

一些有趣的点。这是不喜欢你的例子非常有效的,但它是更正确。我不认为你正在处理像常量的 0xf000000f 的可重新presented。此外,在 move_or_literal_pool的code()在同一文件中有这样的伪code,

  IF((包装= EN code_arm_immediate(VAL))== FAIL)
    包装= EN code_arm_immediate(〜VAL);

这是pretty显然,如果你有 MOV A测试,可以补充和测试 MVN 。其实,我不认为你会试图通过测试每个并行因为你太复杂逻辑更有效。目前的步骤可以用一个指令来最小化找到的第一套位( CLZ ),因为你并不需要遍历所有的位[见<一href=\"http://stackoverflow.com/questions/15736602/fastest-way-to-count-number-of-1s-in-a-register-arm-assembly\">pop_count()].

 位= pop_count(VAL);
 如果(比特下; = 8){
    / *搜索'MOV'* /使用CLZ正常化* /
    移= CLZ(VAL);
    VAL =&LT;&LT;转移;
    如果((VAL&放大器; 0xff的&所述;&下; 24 == VAL)及&放大器;!移&放大器; 1)转到它。
    如果((VAL&放大器; 0xFE的&所述;&下; 24 == VAL)及&放大器;移&放大器; 1)转到它。
    / *测试旋转* /
 }
 如果(位&GT; = 32-8){
    / *设置MVN'标志* /
    /* 如上 */
 }

有实施的人口数的和/或数字的运行各种方式。真的,如果你的算法是的正确并处理旋转,简单的连接code_arm_immediate()好像它的简单性最终会被很有竞争力的到尝试使用高级指令检测位运行的任何解决方案。在连接code_arm_immediate()将适合在高速缓存和循环将迅速上的ARMv7与高速缓存和分支prediction运行。

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

解决方案

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

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.


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;
}

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);

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 */
 }

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天全站免登陆