Arm 어셈블리 학습 노트(9) - 효율적인 분기 코드 및 비정합 데이터 접근

4867 단어 ARM 어셈블리
분기 코드 switch(x)는 우리가 평상시 코드에서 매우 흔히 볼 수 있고 비교적 시간이 걸리는 조작이기도 하기 때문에 최적화되면 코드의 효율을 크게 향상시킬 수 있다.

1. 0 <=x < N 유형의 분기 코드


이 경우 N은 다음 C 코드의 경우 크게 사용할 수 없습니다.
4
int ref_switch(int x)
{
     switch (x) {
                 case 0: return method_0();
                 case 1: return method_1();
                 case 2: return method_2();
                 case 3: return method_3();
                 case 4: return method_4();
                 case 5: return method_5();
                 case 6: return method_6();
                 case 7: return method_7();
                 default: return method_d();
     } 
}
우리는 pc레지스터의 값을 기준으로 x의 값을 인덱스로 실현할 수 있다. 최적화된 어셈블리 코드는 다음과 같다.
           ; int switch_relative(int x)
switch_relative
         MP     x, #8
         ADDLT   pc, pc, x, LSL#2
         B       method_d
         B       method_0
         B       method_1
         B       method_2
         B       method_3
         B       method_4
         B       method_5
         B       method_6
         B       method_7

2.x는 일반적인 값이다


만약 x가 0<=x예를 들어 x = 2^k일 때method 를 호출한다고 가정하십시오k 함수, 즉 x의 값은 1, 2, 4, 8, 16, 32, 64128이고 기타 값은 기본 함수method 를 호출합니다.d.우리는 해시 함수가 2의 몇몇 차방감일 곱셈으로 구성된 것을 찾아야 한다. (이런 방식은 ARM에서 효율이 비교적 높고 직접 위치를 바꾸면 실현할 수 있다.)실험을 통해 상기 8개의 값 x*15*31에서 얻은 수의 9-11위가 다르다는 것을 발견했고 우리는 이 특징을 이용하여 위치 운산을 통해 지점의 이동을 실현할 수 있다.
다음은 최적화된 어셈블리 코드입니다.
x RN0
hash RN 1
                     ; int switch_hash(int x)
switch_hash
                     RSB     hash, x, x, LSL#4             ; hash=x*15
                     RSB     hash, hash, hash, LSL#5   ; hash=x*15*31
                     AND hash, hash, #7 << 9           ; mask out the hash value
                     ADD pc, pc, hash, LSR#6 
                     NOP
                     TEQ x, #0x01
                     BEQ     method_0
                     TEQ     x, #0x02
                     BEQ     method_1
                     TEQ     x, #0x40
                     BEQ     method_6
                     TEQ     x, #0x04
                     BEQ     method_2
                     TEQ     x, #0x80
                     BEQ     method_7
                     TEQ     x, #0x20
                     BEQ     method_5
                     TEQ     x, #0x10
                     BEQ     method_4
                     TEQ     x, #0x08
                     BEQ     method_3
                     B       method_d

위의 방법은 우리가 제시한 특례일 뿐이다. x가 2가 아닌 멱인 상황에서 우리는 여전히 비슷한 방법을 사용하여 실현할 수 있다.여기에는 단지 하나의 사고방식을 제공할 뿐이다.

3. 정렬되지 않은 데이터 액세스


주소가 맞지 않는 데이터 접근은 가능한 한 피해야 한다. 그렇지 않으면 이식 가능성과 효율에 불리하다.
4
  • 가장 간단한 접근 방법은 한 바이트나 반 글자 단위로 읽기와 쓰기를 하는 것이다. 이런 방법은 비교적 추천하지만 효율이 비교적 낮다

  • 다음 코드는 주소가 맞지 않는 32비트 데이터를 읽습니다. 우리는 t0, t1, t2 세 개의 레지스터를 사용하여 유수선이 서로 잠기지 않도록 읽습니다.ARM9TDMI에서 주소가 아닌 각 데이터를 읽으려면 7 개의 클럭 주기가 필요합니다.다음 예에서littleendian 및 bigendian에 대응하는 버전입니다.
    p RN0 x RN1
    t0 RN 2
    t1 RN 3
    t2 RN 12
                         ; int load_32_little(char *p)
    load_32_little
                         LDRB    x,  [p]
                         LDRB    t0, [p, #1]
                         LDRB    t1, [p, #2]
                         LDRB    t2, [p, #3]
                         ORR     x, x, t0, LSL#8
                         ORR     x, x, t1, LSL#16
                         ORR     r0, x, t2, LSL#24
                         MOV     pc, lr
                         ; int load_32_big(char *p)
    load_32_big
                         LDRB    x,  [p]
                         LDRB    t0, [p, #1]
                         LDRB    t1, [p, #2]
                         LDRB    t2, [p, #3]
                         ORR     x, t0, x, LSL#8
                         ORR     x, t1, x, LSL#8
                         ORR     r0, t2, x, LSL#8
                         MOV     pc, lr
                       ; void store_32_little(char *p, int x)
    store_32_little
                       STRB    x,  [p]
                       MOV     t0, x, LSR#8
                       STRB    t0, [p, #1]
                       MOV     t0, x, LSR#16
                       STRB    t0, [p, #2]
                       MOV     t0, x, LSR#24
                       STRB    t0, [p, #3]
                       MOV     pc, lr
                       ; void store_32_big(char *p, int x)
    store_32_big
                       MOV t0, x, LSR#24
                       STRB t0, [p]
                       MOV t0, x, LSR#16
                       STRB t0, [p, #1]
                       MOV t0, x, LSR#8
                       STRB t0, [p, #2]
                       STRB x, [p, #3]
                       MOV pc,lr

    좋은 웹페이지 즐겨찾기