2

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

    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
4

2 回答 2

3

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

测试MOV案例。如果不是,请测试MVN案例并设置一个标志(或您的 API 想要的任何内容)。人们经常使用 +1 (MOV)、0 (can not fit)、-1 (MVN),因为这在调用者纯 ARM 中测试可能很好。


由于完全无知,我开始研究什么气体(GNU 汇编程序)。我在tc-arm.c的一个名为encode_arm_immediate(). 这里是来源,

/* 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()同一文件中的代码具有此伪代码,

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

很明显,如果你有一个测试MOV,你可以补充和测试MVN。事实上,我不认为你会因为你的逻辑过于复杂而尝试并行测试每一个来提高效率。当前步骤可以通过查找第一个设置位 ( clz) 的指令最小化,因为您不需要遍历所有位 [参见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 上快速运行。

于 2015-01-15T16:42:15.873 回答
2

@artlessnoise 对解决方法提供了详尽的解释(这是 IMO 的“真正”答案),但由于这激起了我的兴趣,我想从头开始解决它。在 ARM7 上,你没有后来架构的所有花哨的位操作指令,但事实证明它们在这里有点红鲱鱼。直截了当的“尝试每个有效的旋转,直到找到一个适合 8 位(即 <=255)”的方法出现了一些精美紧凑的惯用程序集(GNU 风格,因为我无法说服 armcc 工具链很好地发挥作用):

.syntax unified
.cpu   arm7tdmi
.globl    testconst
testconst:
    mov   r2, #32
1:  mov   r1, r0, ror r2
    cmp   r1, #255
    movls r0, #1          @ using EABI registers for the sake of this example
    movls pc, lr
    cmn   r1, #256        @ no good? how about the inverted version then?
    movhs r0, #-1         @ note that we'll still have the separated 
    movhs pc, lr          @  value and shift parts in r1 and r2 when we
    subs  r2, #2          @  return - those might come in handy later
    bne   1b
    mov   r0, #0
    mov   pc, lr

有了这个小测试程序:

#include <stdio.h>

int testconst(int);

void test(int c) {
    int r = testconst(c);
    printf("%i (%08x) %s\n", c, c,
           r > 0 ? "fits MOV" :
           r < 0 ? "fits MVN" :
           "doesn't work");
}

int main(void) {
    test(0);
    test(42);
    test(-42);
    test(0xff);
    test(0x1ff);
    test(0x81);
    test(0x10001);
    test(0xff << 12);
    test(0xff << 11);
    test(~(0xff << 12));
    test(~(0x101 << 12));
    test(0xf000000f);
    test(0xf000001f);
    test(~0xf000000f);
    test(~0xf800000f);
}

给出预期的结果:

/ # ./bittest
0 (00000000) fits MOV
42 (0000002a) fits MOV
-42 (ffffffd6) fits MVN
255 (000000ff) fits MOV
511 (000001ff) doesn't work
129 (00000081) fits MOV
65537 (00010001) doesn't work
1044480 (000ff000) fits MOV
522240 (0007f800) doesn't work
-1044481 (fff00fff) fits MVN
-1052673 (ffefefff) doesn't work
-268435441 (f000000f) fits MOV
-268435425 (f000001f) doesn't work
268435440 (0ffffff0) fits MVN
134217712 (07fffff0) doesn't work

欢呼!

于 2015-01-15T21:19:11.633 回答