왜 이 소문제를 따로 배우는가
함수 호출은 단순한 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 호출 뒤에도 유지됩니다.
- 세 argument를 ABI register에 배치합니다.
callee swap이 표준 위치에서 arr와 두 index를 읽습니다.
종이 산출물: `mv a0,s0 # 0x5000; mv a1,s3 # 4; addi a2,s3,1 # 5`
- jal로 swap을 호출하고 call 경계를 표시합니다.
ra에는 돌아올 주소가 기록되고 a/t 값은 이후 보장되지 않습니다.
종이 산출물: `jal ra,swap; a/t after call = unknown`
- 보존된 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가 증가하는지 복원하세요.
ble taken 경로와 swap call fall-through 경로를 그린 뒤 공통 label을 찾으세요.
제출 후 모델 답 보기
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 순서의 이유를 한 줄로 쓰세요.
frame address를 사용하는 load가 sp 해제보다 먼저입니다.
제출 후 모델 답 보기
`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)`를 수행합니다. 첫 순서 오류와 예상 결과를 설명하고 수정하세요.
각 load의 base가 어느 frame을 가리키는지 추적하세요.
제출 후 모델 답 보기
첫 오류는 saved register를 읽기 전에 sp를 caller frame으로 복원한 것입니다. 이후 load는 bubbleSort frame이 아니라 엉뚱한 caller 주소에서 ra와 s0를 읽어 잘못된 return이나 상태 손상을 일으킵니다. 모든 `lw`를 현재 sp에서 먼저 실행하고 마지막에 `addi sp,sp,32; ret`해야 합니다.
이 소문제를 끝냈다고 말할 수 있는 기준
이 소문제의 정확한 공식 페이지와 대조하기
왼쪽은 문제를 읽을 때, 오른쪽은 자신의 풀이를 끝낸 뒤에 확인하세요. 해설 이미지를 먼저 보면 중간 과정을 스스로 만드는 연습이 사라집니다.
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 범위.


