2010-04-09 4 views
8

IL에서 while 루프가 어떻게 보이는지 이해하려고합니다. 나는이 C#을 기능을 작성했습니다 :IL의 루프 - 왜 stloc.0과 ldloc.0입니까?

static void Brackets() 
    { 
     while (memory[pointer] > 0) 
     { 
      // Snipped body of the while loop, as it's not important 
     } 
    } 

일리노이는 다음과 같습니다 : 대부분의 경우

.method private hidebysig static void Brackets() cil managed 
{ 
    // Code size  37 (0x25) 
    .maxstack 2 
    .locals init ([0] bool CS$4$0000) 
    IL_0000: nop 
    IL_0001: br.s  IL_0012 
    IL_0003: nop 
    // Snipped body of the while loop, as it's not important 
    IL_0011: nop 
    IL_0012: ldsfld  uint8[] BFHelloWorldCSharp.Program::memory 
    IL_0017: ldsfld  int16 BFHelloWorldCSharp.Program::pointer 
    IL_001c: ldelem.u1 
    IL_001d: ldc.i4.0 
    IL_001e: cgt 
    IL_0020: stloc.0 
    IL_0021: ldloc.0 
    IL_0022: brtrue.s IL_0003 
    IL_0024: ret 
} // end of method Program::Brackets 

이 CGT 이후 부분을 제외하고, 정말 간단합니다.

로컬 {0}과 stloc.0/ldloc.0은 내가 모르는 부분입니다. 늘어나는만큼, cgt는 결과를 스택으로 푸시합니다. stloc.0은 스택에서 로컬 변수로 결과를 가져오고, ldloc.0은 스택에 결과를 다시 푸시하고 스택에서 brtrue.s를 읽습니다.

이 작업의 목적은 무엇입니까? 이것은 cgt와 brtrue.s에 이어 단축 될 수 없었습니까?

+1

"중요하지 않다"와 트위터 피드를 기반으로 한 너겟은 'br * _s'와'br *'의 차이점을 기록합니다. '_s' 변종은 작은 * 상대 * 오프셋을 사용하고, ** 위치가 서로 가까이 있지 않으면 ** 작동하지 않습니다 ('_s '변형은 "작은"제한없이 * 절대 * 오프셋을 사용합니다). 따라서 컴파일러가 (미리) 몸체의 크기를 예측할 수 없다면'br * _s'보다'br *'을 사용하십시오. –

+0

@Marc 고맙습니다. 정확히 그 문제에 직면했습니다. D 내 데모 애플리케이션에 단일 명령이있어서 컴파일러에서 _s 변형을 생성했지만 실제 컴파일러는 훨씬 긴 루프 본문을 가졌습니다. 긍정적 인 부작용 : 나는 "Illegal one-byte branch"예외로부터 뭔가를 배웠습니다. 예외 : –

+0

IIRC, ILGenerator는 올바른 방법을 사용하면 상황에 맞는 올바른 opcode를 낼만큼 똑똑합니다. –

답변

6

최적화를 사용하여 컴파일 해보십시오.

+0

그게 실제로 "수정"- 그래서 거기에만 디버그/중단 점 목적을 위해 무엇입니까? 왜 처음부터 생성되었는지 궁금합니다. –

+0

나는 서로를 취소하는 두 가지 명령어가 컴파일러의 다른 부분에서 온 것 같아요. 필자는 모든 while 회 돌이가 처음에는 nop (점프 대상)로 전환되는 것을 상상할 수 있습니다 .... ldloc. brtrue.s (nop의 addr). 최적화 도구가 불필요한 nop 등을 제거 할 것이라는 것을 안다면 충분합니다. –

4

디버그 빌드 (nop)입니다. 모든 베팅은 떨어져 있지만, 단순히 편의상 부울 변수를 도입 것 같습니다 : 같은 변수를 제거해야 활성화 최적화와 릴리스의

goto testforexit; 
body: 
    .. 
testforexit: 
    bool tmp = memory[pointer] > 0; 
    if(tmp) goto body; 

빌드.

관련 문제