2011-01-22 9 views
4

다음은 어셈블러에서 내 컴파일러의 일부 출력입니다. GCC v3.23을 기반으로하는 MPLAB C30 C 컴파일러는 dsPIC33FJ128GP802 (16 비트 중간 정도의 고속 DSP/MCU 용)입니다.최적화 버그입니까?

212:    inline uint16_t ror_16(uint16_t word, int num) 
213:    { 
078C4 608270  and.w w1,#16,w4 
078C6 DE0204  lsr w0,w4,w4 
078C8 780101  mov.w w1,w2 
078CA EA8102  com.w w2,w2 
078CC EA8183  com.w w3,w3 
078CE 610170  and.w w2,#16,w2 
078D0 DD0002  sl w0,w2,w0 
078D2 700004  ior.w w0,w4,w0 
214:    num &= 16; // limit to 16 shifts 
215:    return (word >> num) | (word << (16 - num)); 
216:    } 
078D4 060000  return 

특히 I는 다음의 관심 :

and.w w1,#16,w4   AND W1 with 16, storing result in W4 
lsr w0,w4,w4   Logical shift right W0 by W4 times storing result in W4 
mov.w w1,w2    Move W1 to W2 
com.w w2,w2    Logical complement of W2 stored in W2 
com.w w3,w3    Logical complement of W3 stored in W3 <-- This line is confusing me 
and.w w2,#16,w2   AND W2 with 16, storing result in W2 
sl w0,w2,w0    (Logical) shift left W0 left by W2 times storing result in W0 
ior.w w0,w4,w0   Inclusive OR of W0 and W4 stored in W0 
return     Return from function 

W0..W15 칩 16 비트 레지스터에 여섯 배열이다.

효과적으로이 (원시적 RTL에서)로 단순화

W4 := W1 & 16 
W4 := W0 LSR W4 
W1 := W2 
W2 := COM W2 
W3 := COM W3 
W2 := W2 & 16 
W0 := W0 SL W2 
W0 := W0 | W4 
return 

가 지금은 두 전달 된 인수 (W0 및 W1있을 때 왜 W3의 보수를 계산되어에서 혼란 스러워요 -이 사용 더 작은 인수를 갖는 함수에 인수를 함수에 전달하기위한 W 배열.) W3은 계산에 사용되지 않으며 반환되지 않습니다. 실제로 함수에 데이터가 저장되지는 ​​않습니다. 함수에 의해 저장되는 데이터는 없습니다. 함수가 W0..W7을 유지해야 할 필요는 없지만 호출 수신자 만 데이터를 가질 것입니다. 그것에 의존하고 있어야합니다.) 왜 코드에 포함되어 있습니까? 그냥 컴파일러 결함이나 오류, 아니면 내가 뭔가를 놓친거야?

그리고이 코드 만이 아닙니다. 코드의 다른 부분에서 매우 똑같은 이상함을보고 있습니다. 16 비트 변수의 보수와 같은 것을 계산하도록 고안된 코드조차도 항상 두 개의 레지스터를 사용하는 것처럼 보입니다. 그것은 내가 잃어버린있다!

+0

이로이 코드 수 있습니다. 아마도 파이프 라인은 이전 COM의 결과를 사용하기 전에 항상 다른 COM 명령을 실행해야하는 방식으로 작동합니다. –

+0

@Pascal Cuoq이 프로세서에는 이러한 파이프 라인이 없습니다. 어쩌면 2 단계 파이프 라인을 가지고 있기 때문에 (fetch-decode-execute-write RISC주기를 작동시킬 수는 있지만) 이전 지침에 의존하지는 않습니다. 유일한 지연 시간은 분기와 명령어 건너 뛰기에서 비롯됩니다. –

+0

함수의 원래 C 코드를 게시 할 수 있습니까? 16 비트 레지스터 중 16 개가 시프트되면 정말 이상하게 보입니다. – ruslik

답변

2
기능은 (난 당신이 0 ~ 16을 의미 의심) 16 수를 제한하는 코딩하지만 당신은 아마도

을 원하는
num &= 16 

0 또는 16

대신

에 제한되지

num > 16 ? (num & 15) : num 

Re : 질문은 기능이 인라인되어 있기 때문에 사용 된 곳을보고 만 대답 할 수 있습니다. 아마도 W3은 주변 코드에서 무언가에 사용됩니다. 아니면 "버그"일 수도 있지만 성능, 정확성, 영향력 만있는 것은 아닙니다.

num이 코드에서와 같이 단지 0 또는 16 일 수있는 경우 (16 - num) 또한 16 또는 0 일 수 있습니다. 따라서 C30은 보완 및 마스크로 "빼기"를 수행 할 수 있습니다. 내가 인라인하지 않는 경우 참고

는 C30에서 내가 얻을 :

34:    uint16_t ror_16(uint16_t word, int num) 
35:    { 
05AF4 608170  and.w 0x0002,#16,0x0004 
05AF6 DE0102  lsr 0x0000,0x0004,0x0004 
05AF8 EA8081  com.w 0x0002,0x0002 
05AFA 6080F0  and.w 0x0002,#16,0x0002 
05AFC DD0001  sl 0x0000,0x0002,0x0000 
05AFE 700002  ior.w 0x0000,0x0004,0x0000 
36:     num &= 16; // limit to 16 shifts 
37:     return (word >> num) | (word << (16 - num)); 
38:    } 
05B00 060000  return 

나는 명령어 세트의 디자인 특질이 될 수

34:    uint16_t ror_16(uint16_t word, int num) 
35:    { 
05AF4 780100  mov.w 0x0000,0x0004 
36:     num &= 15; // mod 16 
05AF6 60806F  and.w 0x0002,#15,0x0000 
37:     return (num == 0) ? word : ((word >> num) | (word << (16 - num))); 
05AF8 320004  bra z, 0x005b02 
05AFA DE1080  lsr 0x0004,0x0000,0x0002 
05AFC 100070  subr.w 0x0000,#16,0x0000 
05AFE DD1000  sl 0x0004,0x0000,0x0000 
05B00 708100  ior.w 0x0002,0x0000,0x0004 
38:    } 
05B02 780002  mov.w 0x0004,0x0000 
05B04 060000  return 
+0

아니요, 모듈러스를 계산하는 빠른 방법입니다. 숫자가 16보다 큰 경우 프로세서가 재설정 될 것이라고 생각합니다. 그리고 이것은 잘못된 데이터를 유발할 수 있지만 프로세서를 리셋/크래시하지는 않습니다.W3은 주변 코드에서 사용되지만 고정 된 목적이 없습니다. 자세한 내용은 내 질문을 참조하십시오. 그리고 컴파일러가 인라인 명령을 무시할까 봐 걱정됩니다. 코드는 사용 여부에 관계없이 동일합니다. –

+0

당신은 & = 15로 모듈로 16을 빠르게 얻을 수 있지만, 모듈로 17을 원한다. &로 할 수 없다. 그러나 16으로 회전하는 것은 0으로 회전하는 것과 같기 때문에 & = 15가 실제로 원하는 것입니다. –

+0

@Doug Currie, 좋은 지적입니다! –