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에 이어 단축 될 수 없었습니까?
"중요하지 않다"와 트위터 피드를 기반으로 한 너겟은 'br * _s'와'br *'의 차이점을 기록합니다. '_s' 변종은 작은 * 상대 * 오프셋을 사용하고, ** 위치가 서로 가까이 있지 않으면 ** 작동하지 않습니다 ('_s '변형은 "작은"제한없이 * 절대 * 오프셋을 사용합니다). 따라서 컴파일러가 (미리) 몸체의 크기를 예측할 수 없다면'br * _s'보다'br *'을 사용하십시오. –
@Marc 고맙습니다. 정확히 그 문제에 직면했습니다. D 내 데모 애플리케이션에 단일 명령이있어서 컴파일러에서 _s 변형을 생성했지만 실제 컴파일러는 훨씬 긴 루프 본문을 가졌습니다. 긍정적 인 부작용 : 나는 "Illegal one-byte branch"예외로부터 뭔가를 배웠습니다. 예외 : –
IIRC, ILGenerator는 올바른 방법을 사용하면 상황에 맞는 올바른 opcode를 낼만큼 똑똑합니다. –