생각해 볼 질문
두 명령열 사이에서 컴파일러는 언제 레지스터를 보존해야 할까요?
- 레지스터 needs와 modifies를 명령열 계약으로 읽기
- 앞선 명령열이 덮어쓴 뒤에도 필요한 값 감지하기
- 해당 충돌 주변에만 save와 restore 삽입하기
- 보존 후 합성된 명령열 계약 갱신하기
두 번째 명령열이 레지스터의 들어오는 값을 필요로 하고 첫 번째 명령열이 그 레지스터를 수정할 때 충돌이 일어납니다. preserving은 첫 번째 statements를 save와 restore로 감싸 두 번째 명령열이 원래 값을 볼 수 있게 합니다.
감싸진 첫 번째 명령열은 이제 레지스터를 저장하기 위해 그 레지스터를 필요로 하며, restore 이후에는 해당 레지스터가 수정되었다고 더 이상 드러내지 않습니다. 충돌의 어느 한쪽 조건이라도 없으면 합성은 스택 명령을 전혀 내보내지 않습니다.
SICP 코드UTF-8 1,789 / 1,048,576바이트
(begin
(define (contains? item items)
(cond ((null? items) #f)
((eq? item (car items)) #t)
(else (contains? item (cdr items)))))
(define (adjoin item items)
(if (contains? item items) items (append items (list item))))
(define (union left right)
(if (null? right) left
(union (adjoin (car right) left) (cdr right))))
(define (difference left right)
(cond ((null? left) '())
((contains? (car left) right)
(difference (cdr left) right))
(else
(cons (car left) (difference (cdr left) right)))))
(define (make-sequence needs modifies statements)
(list needs modifies statements))
(define (needs sequence) (car sequence))
(define (modifies sequence) (cadr sequence))
(define (statements sequence) (caddr sequence))
(define (append-sequences first second)
(make-sequence
(union (needs first)
(difference (needs second) (modifies first)))
(union (modifies first) (modifies second))
(append (statements first) (statements second))))
(define (preserving register first second)
(if (and (contains? register (needs second))
(contains? register (modifies first)))
(append-sequences
(make-sequence
(adjoin register (needs first))
(difference (modifies first) (list register))
(append (list (list 'save register))
(append (statements first)
(list (list 'restore register)))))
second)
(append-sequences first second)))
(preserving
'env
(make-sequence '(env) '(env val)
'((assign env extended) (assign val operand)))
(make-sequence '(env val) '(val)
'((perform apply)))))
예제
예상 결과첫 번째 프로그램은 (env)를 필요로 하고 (val)을 수정하며 첫 번째 statements를 (save env)와 (restore env)로 둘러싼 명령열을 반환합니다. 두 번째 프로그램은 (#t #f)를 반환합니다.
실행 추적에서 볼 점명령열이 감싸지기 전에 두 포함 여부 검사를 모두 따라가세요. 그런 다음 내보낸 statement 리스트에 save와 restore가 추가되는 동안 difference가 드러난 수정 집합에서 env를 어떻게 제거하는지 살펴보세요.
직접 해보기프로그램을 수정하고 결과를 비교해 보세요.
두 번째 명령열이 val만 필요로 하도록 바꾸세요. 합성된 need와 modify 집합 및 save나 restore가 남아 있는지 예측하세요.
힌트 보기
두 번째 need 집합에 env가 없으면 preserving은 일반적인 append-sequences 분기를 따릅니다.