2

2 つのことを行うコードを作成しようとしています。値が ARM データ処理命令で定数として提示できる場合、レジスタ r2 に 1 を返します。このコードはそれを行います (効率が悪い場合は、より良い方法を提供してください)。ただし、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 (収まらない)、-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 に答える