UNIT-SPECIFIC ACTIVE LESSON · 3-6

swap 호출과 Epilog

argument를 놓고 swap을 호출한 뒤 loop와 function을 끝내세요.

학습 목표: ABI argument register에 `swap(arr,j,j+1)`을 배치하고 call 뒤 s-register의 loop state로 반복을 진행한 뒤 Prolog의 역순으로 Epilog를 수행한다.
공식 근거 범위: SoSe26 Probeklausur 시험 p7–8 Aufgabe 3의 swap call·loop 종료·function 반환과 공식 해설 p11의 argument setup, 증가 label, Epilog 범위.

왜 이 소문제를 따로 배우는가

함수 호출은 단순한 jump가 아니라 register ownership 경계입니다. argument 준비, caller-saved invalidation, loop state 유지, stack 복원의 순서를 하나의 lifecycle로 묶어야 sort가 여러 swap 뒤에도 올바르게 계속되고 원래 caller로 돌아갑니다.

이 페이지는 Aufgabe 3의 공통 템플릿이 아니라 3-6 swap 호출과 Epilog에 필요한 내용만 담습니다. 챕터 전체 배경이 필요하면 Aufgabe 3 개념 수업을 먼저 읽으세요.

이 소문제에서 실제로 쓰는 용어

정의뿐 아니라 이 문제의 어느 판단에 쓰이는지까지 연결합니다.

argument registers
RISC-V ABI에서 첫 함수 인자를 전달하는 a0, a1, a2 등의 caller-saved register입니다.이 소문제에서: swap의 arr, j, j+1을 각각 a0, a1, a2에 둡니다.
jal
target 함수로 이동하면서 return address `PC+4`를 ra에 기록하는 call instruction입니다.이 소문제에서: `jal ra,swap`으로 swap을 호출합니다.
caller-saved
callee가 보존할 의무가 없어 call 뒤 값이 바뀔 수 있는 a/t register 분류입니다.이 소문제에서: swap 뒤 temporary를 신뢰하지 않고 s0–s3의 arr,n,i,j를 계속 사용합니다.
Epilog
저장한 register를 복원하고 stack frame을 해제한 뒤 반환하는 함수 끝 instruction 묶음입니다.이 소문제에서: ra와 s0–s3를 현재 sp 기준으로 load한 후 `sp+=32; ret`합니다.

이 소문제 전용 규칙과 종이 작업

ABI argument 순서 규칙

C call `swap(arr,j,j+1)`의 첫 세 인자는 차례대로 a0, a1, a2에 놓습니다.

종이에: call 직전 register 표에 `a0=arr, a1=j, a2=j+1`을 씁니다.

call 경계 kill 규칙

jal 이후 a/t register는 callee가 바꿀 수 있으므로 loop 지속에 필요한 arr,n,i,j는 s0–s3에서 다시 읽습니다.

종이에: call 선을 긋고 a/t 값에 `unknown after call` 표시를 합니다.

loop 증가 위치 규칙

swap 여부와 상관없이 inner iteration 끝에서는 j++, inner loop 종료 뒤에는 i++가 정확한 label에서 실행되어야 합니다.

종이에: `inner_inc: s3++`, `outer_inc: s2++`를 서로 다른 label 아래 둡니다.

Epilog 역순 규칙

saved register는 아직 frame을 가리키는 현재 sp로 load한 뒤에만 sp를 원래 값으로 되돌릴 수 있습니다.

종이에: `loads → addi sp,sp,32 → ret` 순서를 상자로 묶습니다.

Aufgabe 전체 흐름은 챕터 흐름도에서 확인할 수 있습니다. 여기서는 현재 판단에 직접 필요한 규칙만 적용합니다.

이 소문제 전용 작은 예제

s0에 arr base `0x5000`, s3에 j=4가 있다. `swap(arr,4,5)` call 준비와 call 뒤 inner index 증가를 쓰세요.

주어진 것

  • swap의 argument 순서는 arr, i, j입니다.
  • s0와 s3는 callee-saved라 swap 호출 뒤에도 유지됩니다.
  1. 세 argument를 ABI register에 배치합니다.

    callee swap이 표준 위치에서 arr와 두 index를 읽습니다.

    종이 산출물: `mv a0,s0 # 0x5000; mv a1,s3 # 4; addi a2,s3,1 # 5`

  2. jal로 swap을 호출하고 call 경계를 표시합니다.

    ra에는 돌아올 주소가 기록되고 a/t 값은 이후 보장되지 않습니다.

    종이 산출물: `jal ra,swap; a/t after call = unknown`

  3. 보존된 s3를 사용해 j를 증가합니다.

    argument a1이 보존된다고 가정하지 않고 장기 loop state를 이어갑니다.

    종이 산출물: `addi s3,s3,1 # j=5; j inner_loop`

예제 답과 독립 검산 보기

`mv a0,s0; mv a1,s3; addi a2,s3,1; jal ra,swap; addi s3,s3,1; j inner_loop`이며 call에는 (arr,4,5)가 전달됩니다.

독립 검산: call 뒤 j 증가 source가 a1이 아니라 s3인지 확인합니다.

이제 실제 시험 문제를 micro-work로 풀기

공식 시험이 요구하는 것

argument를 놓고 swap을 호출한 뒤 loop와 function을 끝내세요.

공식 답을 보기 전, 내 답 먼저 남기기

완성 문장이 아니어도 좋습니다. 중간값·register·cycle·cache state처럼 채점 가능한 흔적을 먼저 적으세요.

각 작업의 중간 산출물을 직접 적고 완료 조건을 만족한 뒤 체크하세요. 단계별 이유·산출물·오류가 현재 소문제에 맞게 따로 작성되어 있습니다.

a0=arr, a1=j, a2=j+1을 만듭니다.

왜 하는가
swap이 기대하는 첫 세 argument를 RISC-V ABI 순서로 전달해야 합니다.
종이 산출물
`mv a0,s0; mv a1,s3; addi a2,s3,1`
완료 조건
call 직전 a0, a1, a2의 의미가 각각 arr, j, j+1로 표시되어 있습니다.
막혔을 때 단계 힌트·대표 오류

힌트: arr와 j 원본은 보존된 s0와 s3에서 복사하세요.

이 단계의 대표 오류: a1=j+1, a2=j로 두 index 순서를 바꾸거나 a0에 `&arr[j]`를 전달하는 것입니다.

`jal ra,swap`을 실행하고 caller-saved 값을 더 이상 신뢰하지 않습니다.

왜 하는가
jal은 ra를 새 link로 덮고 swap은 a/t register를 자유롭게 사용할 수 있습니다.
종이 산출물
`jal ra,swap` 아래에 `a0–a2,t0–t6 may change`를 표시합니다.
완료 조건
call 뒤 이어지는 loop code가 a/t의 이전 값에 의존하지 않습니다.
막혔을 때 단계 힌트·대표 오류

힌트: loop state는 Prolog에서 s0–s3에 보존했습니다.

이 단계의 대표 오류: swap이 끝난 뒤 a1에 여전히 j가 있다고 가정해 a1을 증가시키는 것입니다.

inner_inc에서 s3의 j를 증가시키고 inner_loop로 돌아갑니다.

왜 하는가
swap을 했든 skip했든 현재 이웃 쌍 처리가 끝났으므로 다음 j를 검사해야 합니다.
종이 산출물
`inner_inc: addi s3,s3,1; j inner_loop`
완료 조건
swap path와 no-swap path가 모두 같은 inner_inc label로 합쳐집니다.
막혔을 때 단계 힌트·대표 오류

힌트: ble가 taken된 target도 이 label이어야 합니다.

이 단계의 대표 오류: swap한 경우에만 j를 증가시키거나 j++ 뒤 outer_loop로 직접 가는 것입니다.

outer_inc에서 s2의 i를 증가시키고 outer_loop로 돌아갑니다.

왜 하는가
inner bound에 도달한 뒤에만 다음 pass로 넘어가고 새 pass에서 j가 다시 0으로 reset됩니다.
종이 산출물
`outer_inc: addi s2,s2,1; j outer_loop`
완료 조건
inner 종료 branch가 outer_inc로 오고 outer_loop에서 guard와 j reset을 다시 실행합니다.
막혔을 때 단계 힌트·대표 오류

힌트: s3=j가 아니라 s2=i를 증가시킵니다.

이 단계의 대표 오류: inner loop의 매 iteration마다 i도 증가시키는 것입니다.

done에서 s0–s3와 ra를 load한 뒤 sp를 32만큼 복원하고 ret합니다.

왜 하는가
현재 sp가 frame base를 가리킬 때 saved 값을 읽어야 하며, 그 다음 caller의 stack와 return address로 돌아갈 수 있습니다.
종이 산출물
`lw ra,0(sp); lw s0,4(sp); lw s1,8(sp); lw s2,12(sp); lw s3,16(sp); addi sp,sp,32; ret`
완료 조건
Prolog에서 저장한 다섯 register가 같은 offset으로 복원되고 sp 증가가 load 뒤, ret 앞에 있습니다.
막혔을 때 단계 힌트·대표 오류

힌트: Prolog의 store offset 목록과 한 줄씩 대조하세요.

이 단계의 대표 오류: sp를 먼저 +32해 load가 caller frame의 엉뚱한 주소를 읽게 만드는 것입니다.

공식 답을 열기 전 마지막 회상

Epilog에서 sp를 먼저 복원한 뒤 load하면 왜 잘못되나요?

내 풀이 후 공식 결론·이유·대표 함정 확인

공식 결론

공식안은 `mv a0,s0; mv a1,s3; addi a2,s3,1; jal ra,swap`, 이후 j++/i++, 마지막에 저장한 register를 역으로 load하고 `addi sp,sp,32; ret`.

왜 이 답이 되는가

ABI에서 첫 세 argument는 a0,a1,a2입니다. s0–s3는 호출 뒤에도 유지되어 loop 상태를 계속 쓸 수 있습니다.

대표 함정

swap 호출 뒤 t-register 값은 믿지 마세요. loop에서 계속 필요한 값은 s-register에 있습니다.

명령어와 식을 줄 단위로 읽기

본문 속 code를 한 줄씩 분리했습니다. 각 줄에서 source, operation, destination을 표시하세요.

mv a0,s0;
mv a1,s3;
addi a2,s3,1;
jal ra,swap;
addi sp,sp,32;
ret;

새 문제로 전이하기

세 문항은 앞 문장의 반복이 아닙니다. 직접 답을 입력하면 rubric의 필수 기준을 하나씩 검사하고, 첫 누락 기준을 알려 줍니다.

1. 개념 재구성

한 inner iteration의 control-flow를 ordered pair와 reversed pair 두 경로로 나눠, 두 경로가 어디서 합쳐지고 어떤 state가 증가하는지 복원하세요.

제출 후 모델 답 보기

ordered pair에서는 `ble left,right,inner_inc`가 taken되어 swap을 건너뜁니다. reversed pair에서는 ble가 not taken이라 argument를 놓고 `jal ra,swap`을 실행한 뒤 inner_inc로 옵니다. 두 경로는 `inner_inc`에서 합쳐져 `s3=j`를 1 증가시키고 inner_loop로 돌아갑니다.

2. 변형 문제

Prolog가 `ra, s0, s1`을 0,4,8(sp)에 저장하고 16-Byte frame을 만들었다. 정확한 Epilog를 작성하고 각 instruction 순서의 이유를 한 줄로 쓰세요.

제출 후 모델 답 보기

`lw ra,0(sp); lw s0,4(sp); lw s1,8(sp); addi sp,sp,16; ret`입니다. saved register는 현재 frame base인 sp로 먼저 load하고, 그 뒤 sp를 caller 값으로 복원한 후 복원된 ra로 ret합니다.

3. 오류 진단

학생 Epilog는 `addi sp,sp,32`를 먼저 실행한 뒤 `lw ra,0(sp); lw s0,4(sp)`를 수행합니다. 첫 순서 오류와 예상 결과를 설명하고 수정하세요.

제출 후 모델 답 보기

첫 오류는 saved register를 읽기 전에 sp를 caller frame으로 복원한 것입니다. 이후 load는 bubbleSort frame이 아니라 엉뚱한 caller 주소에서 ra와 s0를 읽어 잘못된 return이나 상태 손상을 일으킵니다. 모든 `lw`를 현재 sp에서 먼저 실행하고 마지막에 `addi sp,sp,32; ret`해야 합니다.

이 소문제를 끝냈다고 말할 수 있는 기준

이 소문제의 정확한 공식 페이지와 대조하기

왼쪽은 문제를 읽을 때, 오른쪽은 자신의 풀이를 끝낸 뒤에 확인하세요. 해설 이미지를 먼저 보면 중간 과정을 스스로 만드는 연습이 사라집니다.

3-6 관련 공식 시험 또는 해설 페이지
exam-p07.png · 클릭해 원본 크기로 확인
3-6 관련 공식 시험 또는 해설 페이지
solution-p08.png · 클릭해 원본 크기로 확인
3-6 관련 공식 시험 또는 해설 페이지
solution-p11.png · 클릭해 원본 크기로 확인

Source: Probeklausur.pdf / Probeklausur Musterlösung und Hinweise.pdf · 시험 p7–8 · 공식 해설 p8–11 · SoSe26 Probeklausur 시험 p7–8 Aufgabe 3의 swap call·loop 종료·function 반환과 공식 해설 p11의 argument setup, 증가 label, Epilog 범위.