재귀 함수는 MIPS에서 어떻게 작동합니까?

PieceOfPizza

저는 MIPS의 초보자이고 (대학에서 MIPS 어셈블리를 배우기 시작하면서) MIPS에서 재귀 함수가 작동하는 방식을 이해하는 데 문제가 있습니다.

예를 들어, MIPS로 작성하기위한이 프로그램 (C)이 있습니다.

int fact (int n)
{
   if (n < 1) return 0;
   else return n * fact(n - 1);
}

누군가가 재귀 함수의이 또는 다른 예를 통해 나를 도와주고 어떻게 작동하는지 설명해 줄 수 있습니까?

에릭 아이 트

내가 공유하고 싶은 첫 번째 것은 이것을 MIPS로 변환fact 하는 복잡성이 재귀가 관련되어 있기 때문이 아니라 단순한 함수 호출의 존재에서 비롯된다는 것 입니다. 재귀적인 것은 IMHO a red herring 입니다. 이를 위해 여러분이 언급 한 재귀 함수의 모든 복잡성을 가진 비 재귀 함수를 설명하겠습니다.

int fact (int n)
{
   if (n < 1) return 0;
   else return n * other(n - 1);    // I've changed the call to "fact" to function "other"
}

내 변경은 더 이상 재귀 적이 지 않습니다! 그러나이 버전의 MIPS 코드는 귀하의 MIPS 코드와 동일하게 보입니다 fact(물론 jal fact변경 되는 경우는 예외입니다 jal other). 이것은 번역의 복잡성이 함수 내의 호출로 인한 것이며 호출되는 사람과는 아무 관련이 없음을 설명하기위한 것입니다. (최적화 기술이있는 YMMV이지만)


함수 호출을 이해하려면 다음을 이해해야합니다.

  • 프로그램 카운터 : 프로그램이 프로그램 카운터와 상호 작용하는 방법, 특히 함수 호출의 맥락에서 ..
  • 매개 변수 전달
  • 일반적으로 등록 규칙

C에는 명시 적 매개 변수가 있습니다. 물론 이러한 명시 적 매개 변수는 어셈블리 / 기계 언어로도 나타납니다. 그러나 C 코드에서는 볼 수없는 기계 코드로 전달되는 매개 변수도 있습니다. 이것의 예로는 반환 주소 값과 스택 포인터가 있습니다.


여기에 필요한 것은 (재귀와 무관 한) 함수 분석입니다.

매개 변수 n$a0기능 입력에 있습니다. 의 값은 n함수 호출 (to other) 뒤에 필요합니다. 그 함수 호출이의 오른손 피연산자를 반환 할 때까지 곱할 수 없기 때문입니다 *.

따라서, n(왼쪽 피연산자에가 *)에 대한 함수 호출을 반드시 살아남 아야한다 other, 그리고 $a0그것은하지 않습니다 - 우리 자신의 코드의 용도를 변경하기 때문에 $a0호출 순서 other(n-1)n-1로 이동해야 $a0그것에 대해.

또한 (C에서 암시 적) 매개 변수 $ra는 호출자에게 반환하는 데 필요한 반환 주소 값을 보유합니다. other마찬가지로에 대한 호출 $ra레지스터의 용도를 변경하여 이전 값을 삭제합니다.

따라서이 함수 (사용자 또는 내)는 본문 내에있는 함수 호출 (예 :에 대한 호출 other) 에서 살아 남기 위해 두 개의 값이 필요합니다 .

해결책은 간단합니다. 필요한 값 (우리가하는 일에 의해 용도가 변경되거나 지워지거나 피 호출자가 잠재적으로 할 수있는 레지스터에 있음)을 다른 곳으로 이동하거나 복사해야합니다.

이를 위해 메모리를 사용할 수 있으며 스택을 사용하여 이러한 목적을위한 메모리를 얻을 수 있습니다.

이를 기반으로을 호출 한 후 필요한 두 가지 (그렇지 않으면 지워질 수 있음)를위한 공간이있는 스택 프레임을 만들어야합니다 other. 항목 $ra을 저장하고 나중에 다시로드해야 반환 할 수 있습니다. 또한 초기 n값을 저장해야 곱하기 위해 사용할 수 있습니다. (스택 프레임은 일반적으로 함수 프롤로그에서 생성되고 함수 에필로그에서 제거됩니다.)


기계 코드 (또는 일반적으로 프로그래밍)의 경우와 마찬가지로 요점은 동일하지만 다른 방법으로도 처리 할 수 ​​있습니다. (이것은 좋은 일이며 최적화 컴파일러는 일반적으로 특정 상황에서 가장 좋은 방법을 찾습니다.)


재귀의 존재 또는 부재는이를 어셈블리 / 기계 언어로 변환하는 데 필요한 기본 분석을 변경하지 않습니다. 재귀는 스택 오버플로 가능성을 크게 증가 시키지만 그렇지 않으면이 분석을 변경하지 않습니다.


추가

명확하게 말하면 재귀는 동적으로 확장 가능한 호출 스택을 사용해야한다는 요구 사항을 부과합니다. 모든 최신 컴퓨터 시스템은 호출을 위해 이러한 스택을 제공하므로이 요구 사항은 오늘날의 시스템에서 쉽게 잊거나 무시할 수 있습니다.

재귀가없는 프로그램의 경우 호출 스택이 필요하지 않습니다. 로컬 변수는 함수 전용 전역 변수 (반환 주소 포함)에 할당 될 수 있으며 이는 특정 기능을 제공하지 않는 PDP-8과 같은 특정 구형 시스템에서 수행되었습니다. 호출 스택에 대한 하드웨어 지원.


매개 변수를 전달하기 위해 스택 메모리를 사용하거나 레지스터가 좋지 않은 시스템은 변수가 중첩 된 함수 호출을 견디는 메모리에 이미 저장되어 있기 때문에이 답변에 설명 된 분석이 필요하지 않을 수 있습니다.

위의 분석에 대한 요구 사항을 생성하는 것은 레지스터가 풍부한 최신 기계에서 레지스터를 분할하는 것입니다. 이러한 레지스터가 풍부한 머신은 CPU 레지스터에서 매개 변수와 반환 값 (대부분)을 전달하므로 효율적이지만 레지스터가 한 기능에서 다른 기능으로 용도가 변경 될 때 복사본을 만들어야하는 경우가 있습니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

다음 재귀 함수는 어떻게 작동합니까?

분류에서Dev

재귀 함수는 어떻게 작동합니까?

분류에서Dev

자바에서 숫자 합계의 재귀는 어떻게 작동합니까?

분류에서Dev

이 바이너리 트리 최장 경로 함수에서 재귀는 어떻게 작동합니까?

분류에서Dev

Haskell에서 (공) 재귀 적 정의는 어떻게 작동합니까?

분류에서Dev

호출 스택 뒤에서 재귀는 어떻게 작동합니까?

분류에서Dev

다음 코드에서 재귀는 어떻게 작동합니까?

분류에서Dev

피보나치 재귀는 C #에서 어떻게 작동합니까?

분류에서Dev

재귀 함수에서 행렬을 어떻게 작성합니까?

분류에서Dev

Quick Sort Python Recursion-재귀 함수는 어떻게 작동합니까?

분류에서Dev

이 인터리빙 재귀 함수는 어떻게 작동합니까?

분류에서Dev

재귀에서 스택은 어떻게 작동합니까?

분류에서Dev

이 코드에서 재귀가 어떻게 작동합니까?

분류에서Dev

이 재귀 코드는 어떻게 작동합니까?

분류에서Dev

이 코드는 어떻게 작동합니까? (자바 재귀)

분류에서Dev

파이썬은 재귀 함수에서 'and'를 어떻게 평가합니까?

분류에서Dev

F #에서 재귀를 사용하여이 함수를 작성하려면 어떻게해야합니까?

분류에서Dev

재귀 함수는 어떻게 관리합니까?

분류에서Dev

C #의 재귀 함수에 액세스 할 수없는 매개 변수를 어떻게 추가합니까?

분류에서Dev

재귀 함수에서 벡터를 어떻게 인쇄 할 수 있습니까?

분류에서Dev

결과는 재귀에서 어떻게 생성됩니까?

분류에서Dev

배열의 최소 요소를 찾는 재귀 함수는 어떻게 작동합니까?

분류에서Dev

XSLT에서 document () 함수는 어떻게 작동합니까?

분류에서Dev

Gradient 함수는 Backpropagation에서 어떻게 작동합니까?

분류에서Dev

#defined 함수는 C에서 어떻게 작동합니까?

분류에서Dev

dist 함수는 MATLAB에서 어떻게 작동합니까?

분류에서Dev

ReactJS에서 "너무 많은 재귀"오류를 어떻게 수정합니까?

분류에서Dev

upheap 메서드에 대한 재귀 함수 (이 비 재귀 메서드를 재귀에 어떻게 쓸 수 있습니까?)

분류에서Dev

OPC / UA-.NETStandard의 재귀 적 GetEndpoints-Method는 어떻게 작동합니까?

Related 관련 기사

  1. 1

    다음 재귀 함수는 어떻게 작동합니까?

  2. 2

    재귀 함수는 어떻게 작동합니까?

  3. 3

    자바에서 숫자 합계의 재귀는 어떻게 작동합니까?

  4. 4

    이 바이너리 트리 최장 경로 함수에서 재귀는 어떻게 작동합니까?

  5. 5

    Haskell에서 (공) 재귀 적 정의는 어떻게 작동합니까?

  6. 6

    호출 스택 뒤에서 재귀는 어떻게 작동합니까?

  7. 7

    다음 코드에서 재귀는 어떻게 작동합니까?

  8. 8

    피보나치 재귀는 C #에서 어떻게 작동합니까?

  9. 9

    재귀 함수에서 행렬을 어떻게 작성합니까?

  10. 10

    Quick Sort Python Recursion-재귀 함수는 어떻게 작동합니까?

  11. 11

    이 인터리빙 재귀 함수는 어떻게 작동합니까?

  12. 12

    재귀에서 스택은 어떻게 작동합니까?

  13. 13

    이 코드에서 재귀가 어떻게 작동합니까?

  14. 14

    이 재귀 코드는 어떻게 작동합니까?

  15. 15

    이 코드는 어떻게 작동합니까? (자바 재귀)

  16. 16

    파이썬은 재귀 함수에서 'and'를 어떻게 평가합니까?

  17. 17

    F #에서 재귀를 사용하여이 함수를 작성하려면 어떻게해야합니까?

  18. 18

    재귀 함수는 어떻게 관리합니까?

  19. 19

    C #의 재귀 함수에 액세스 할 수없는 매개 변수를 어떻게 추가합니까?

  20. 20

    재귀 함수에서 벡터를 어떻게 인쇄 할 수 있습니까?

  21. 21

    결과는 재귀에서 어떻게 생성됩니까?

  22. 22

    배열의 최소 요소를 찾는 재귀 함수는 어떻게 작동합니까?

  23. 23

    XSLT에서 document () 함수는 어떻게 작동합니까?

  24. 24

    Gradient 함수는 Backpropagation에서 어떻게 작동합니까?

  25. 25

    #defined 함수는 C에서 어떻게 작동합니까?

  26. 26

    dist 함수는 MATLAB에서 어떻게 작동합니까?

  27. 27

    ReactJS에서 "너무 많은 재귀"오류를 어떻게 수정합니까?

  28. 28

    upheap 메서드에 대한 재귀 함수 (이 비 재귀 메서드를 재귀에 어떻게 쓸 수 있습니까?)

  29. 29

    OPC / UA-.NETStandard의 재귀 적 GetEndpoints-Method는 어떻게 작동합니까?

뜨겁다태그

보관