문제

32 비트 단어로 2 개의 서명 된 16 비트 값이 있으며, 일정한 값 (1에서 6까지)으로 올바른 (나누기)를 바꾸고 바이트 (0..0xff)로 포화해야합니다.

예를 들어,

  • 0x FFE1 00AA ~와 함께 시프트 = 5 해야합니다 0x 0000 0005;
  • 0x 2345 1234 해야합니다 0x 00ff 0091

이 의사 코드와 같은 값을 동시에 포화하려고합니다.

AND RT, R0, 0x80008000; - mask high bits to get negatives
ORR RT, RT, LSR #1
ORR RT, RT, LSR #2
ORR RT, RT, LSR #4
ORR RT, RT, LSR #8; - now its expanded signs in each halfword
MVN RT, RT
AND R0, RT; now negative values are zero
; here something to saturate high overflow and shift after

그러나 내가 얻는 코드는 매우 추악하고 느립니다. :) 내가 지금 가지고있는 가장 좋은 (가장 빠른) 것은 다음과 같이 각 절반의 별도의 채도입니다.

MOV RT, R0, LSL #16
MOVS RT, RT, ASR #16+5
MOVMI RT, #0
CMP RT, RT, #256
MOVCS RT, #255
MOVS R0, R0, ASR #16+5
MOVMI R0, #0
CMP R0, R0, #256
MOVCS R0, #255
ORR R0, RT, R0, LSL #16

그러나 그것은 10 사이클입니다. :( 더 빠를 수 있습니까?

추신 : 나중에 나는 이것에 대한 USAT16 명령을 발견했지만 ARMV6에만 해당됩니다. ARMV5TE 및 ARMV4에서 작업하려면 코드가 필요합니다.


편집하다: 이제 첫 번째 코드를 다시 작성합니다.

ANDS RT, 0x10000, R0 << 1;      // 0x10000 is in register. Sign (HI) moves to C flag, Sign (LO) is masked
SUBNE RT, RT, 1;            // Mask LO with 0xFFFF if it's negative
SUBCS RT, RT, 0x10000;      // Mask HI with 0xFFFF if it's negative
BIC R0, R0, RT;         // Negatives are 0 now. The mask can be used as XOR too
TST R0, 0xE0000000;         // check HI overflow             
ORRNE R0, R0, 0x1FE00000        // set HI to 0xFF (shifted) if so
TST R0, 0x0000E000          // check LO overflow             
ORRNE R0, R0, 0x00001FE0        // set LO to 0xFF if so          
AND R0, 0x00FF00FF, R0 >> 5;    // 0x00FF00FF is in register     

그러나 그것은 아름답 지 않습니다.

도움이 되었습니까?

해결책 2

하나의 수표를 사용하여 두 개의 작업에 플래그를 설정하는 것이 좋습니다. 그러나 나는 두 번째 부분을 위해 그것을 할 수 없습니다. 나는 다른 일을 할 수 있습니다 :) 여기에 1에서 6까지의 전환으로 사용할 보편적 변형이 있습니다.

;prepare:
MOV RMask, ((0xFF00 << shift) & 0xFF00) << 16;  Mask overflow bits
MOV R_0xFF00FF, 0xFF;
ORR R_0xFF00FF, 0xFF000000;
;...
; innerloop:
;....
TST R0, RMask, R0 << 16;            Set flags for LO half
ORRNE R0, R0, 0xFF << shift;        It is overflow. First try positive
BICMI R0, R0, 0xFF << shift;        Fix it if negative. LO half is ready
TST R0, RMask, R0;              Set flags for HI half. Can TST R0, R0, #Mask also
ORRNE R0, R0, 0xFF << (shift+16)
BICNE R0, R0, 0xFF << (shift+16)
AND R0, R_0xFF00FF, R0 >> shift;        Shift and mask

이제 7주기입니다. :)

더 나을 수 있습니까?


편집하다: 오버 플로우가 충분히 드물기 때문에 다음과 같은 것을 추가하는 것이 좋습니다.

TST R0, 0xE000E000
BEQ no_saturation_needed
... ; saturation ops here

다른 팁

당신이 가진 것은 당신이 언급 한대로 문제를 위해 할 수있는 것만 큼 좋은 것입니다. 단단한 루프로 많은 데이터를 위해이 작업을 수행하고 마스크를 보유 할 몇 가지 레지스터를 감당할 수 있다면, 사이클을 저장할 수 있지만 크게 개선되지는 않을 것입니다. V6 아키텍처 전에 ARM의 이러한 유형의 "소규모 벡터"포화 작업에 대한 지원은 없습니다.

기본적으로 이것이 프로그램에서 유일한 병목 현상이 아니라면, 이것을 버리고 다음 핫스팟으로 넘어갈 때입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top