역할과 입력
- FP/SIMD: x0=상태 구조체
- SVE: x0=매크로용 상태 기준, x1=FPSR 위치, x2=FFR 처리 여부
- SME: x0=ZA 버퍼, x1=ZT 저장·복원 여부
원본 .S · 빌드 조건: Makefile · 명령·주소 표기 읽는 법
134줄 · SHA-256: 6c856dfeffd897cab180000319b196cddf24f2e0778c3f554ade9dc6fbaa666d
구조와 흐름
고정 크기 FP/SIMD 상태의 저장 배치
고정 크기 FP/SIMD 상태
fpsimd_save는 q0–q31의 512바이트를 저장하고 이어 FPSR·FPCR을 각각 4바이트로 저장합니다. 두 번째 인자 8은 임시 x8/w8의 번호입니다. 마지막 q30/q31 접근은 writeback이 있어 x0가 원래 값에서 480바이트 증가합니다. 복원 매크로는 x0를 임시값으로도 사용하므로 호출 후 입력 포인터가 유지되지 않습니다.
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * FP/SIMD state saving and restoring
4 *
5 * Copyright (C) 2012 ARM Ltd.
6 * Author: Catalin Marinas <catalin.marinas@arm.com>
7 */
8
9#include <linux/linkage.h>
10
11#include <asm/assembler.h>
12#include <asm/fpsimdmacros.h>
13
14/*
15 * Save the FP registers.
16 *
17 * x0 - pointer to struct fpsimd_state
18 */
19SYM_FUNC_START(fpsimd_save_state)
20 fpsimd_save x0, 8
21 ret
22SYM_FUNC_END(fpsimd_save_state)
23
24/*
25 * Load the FP registers.
26 *
27 * x0 - pointer to struct fpsimd_state
28 */
29SYM_FUNC_START(fpsimd_load_state)
30 fpsimd_restore x0, 8
31 ret
32SYM_FUNC_END(fpsimd_load_state)
33
- L9
- SYM_FUNC_START·SYM_CODE_START·SYM_INNER_LABEL 등의 심볼 선언 규칙을 가져옵니다. 함수인지 코드 내부 라벨인지, 다른 오브젝트에 보일 이름인지와 정렬·크기 정보를 빌드 도구에 전달하는 데 필요합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
- L11
- ARM64의 큰 주소 구성, CPU별 값 조회, 시스템 레지스터 처리, 동기화 등에 쓰는 어셈블리 매크로를 가져옵니다. 각 사용 위치에서 일반 명령 여러 개로 펼쳐지는 작업입니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
- L12
- FP/SIMD·SVE·SME 레지스터 저장 형식과 명령 인코딩 매크로를 가져옵니다. 어떤 상태를 어느 offset에 저장하는지, 임시 레지스터 인수가 무엇인지가 여기에 정의됩니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
- L19
- (fpsimd_save_state)의 시작 심볼을 정의합니다. 외부에서 참조할 수 있습니다. 정의에 따른 정렬을 적용합니다. ARM64 함수 시작에는 BTI C가 들어갑니다.
- L20
- x0가 가리키는 저장 영역에 q0~q31의 SIMD/FP 값과 FPSR·FPCR을 보존합니다. 8은 주소나 벡터 수가 아니라 임시 x8/w8을 고르는 매크로 인수입니다. task 전환·시그널 등에서 계산 상태를 잃지 않으려는 저장이며 매크로 내부에서 x0도 이동합니다.
- L21
- x30(LR)에 든 주소로 이동합니다. SPSR/PSTATE를 복원하는 ERET와는 다릅니다.
- L22
- (fpsimd_save_state)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
- L29
- (fpsimd_load_state)의 시작 심볼을 정의합니다. 외부에서 참조할 수 있습니다. 정의에 따른 정렬을 적용합니다. ARM64 함수 시작에는 BTI C가 들어갑니다.
- L30
- x0의 메모리 사본에서 q0~q31과 FPSR·FPCR을 CPU에 복원합니다. 임시 레지스터는 x8/w8이며 FPCR은 기존 값과 같으면 불필요한 쓰기를 피합니다. 저장 때와 같은 레이아웃의 버퍼가 필요합니다.
- L31
- x30(LR)에 든 주소로 이동합니다. SPSR/PSTATE를 복원하는 ERET와는 다릅니다.
- L32
- (fpsimd_load_state)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
SVE 저장과 벡터 길이
매크로의 첫 인자 0은 x0의 번호입니다. Z 저장 오프셋은 -34부터, P 저장 오프셋은 -16부터 시작하므로 x0를 단순히 첫 Z 레지스터 저장 주소로 읽으면 안 됩니다. 헤더의 실제 주소식을 함께 봅니다. x2가 0이면 FFR 읽기를 생략하고 저장 슬롯을 0으로 채웁니다. sve_set_vq의 x0는 VQ가 아닌 VQ−1이며, LEN 필드가 바뀔 때만 레지스터에 씁니다.
34#ifdef CONFIG_ARM64_SVE
35
36/*
37 * Save the SVE state
38 *
39 * x0 - pointer to buffer for state
40 * x1 - pointer to storage for FPSR
41 * x2 - Save FFR if non-zero
42 */
43SYM_FUNC_START(sve_save_state)
44 sve_save 0, x1, x2, 3
45 ret
46SYM_FUNC_END(sve_save_state)
47
48/*
49 * Load the SVE state
50 *
51 * x0 - pointer to buffer for state
52 * x1 - pointer to storage for FPSR
53 * x2 - Restore FFR if non-zero
54 */
55SYM_FUNC_START(sve_load_state)
56 sve_load 0, x1, x2, 4
57 ret
58SYM_FUNC_END(sve_load_state)
59
60SYM_FUNC_START(sve_get_vl)
61 _sve_rdvl 0, 1
62 ret
63SYM_FUNC_END(sve_get_vl)
64
65SYM_FUNC_START(sve_set_vq)
66 sve_load_vq x0, x1, x2
67 ret
68SYM_FUNC_END(sve_set_vq)
- L34
- SVE는 기본 128비트 SIMD보다 긴 Z 벡터, P predicate와 FFR 상태를 추가하는 확장입니다. 이 설정을 켜야 아래 저장·복원·길이 조정 코드를 커널에 포함하여 지원 CPU의 task 상태를 관리할 수 있습니다. 꺼지면 아래 SVE 함수들은 빌드되지 않습니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
- L43
- (sve_save_state)의 시작 심볼을 정의합니다. 외부에서 참조할 수 있습니다. 정의에 따른 정렬을 적용합니다. ARM64 함수 시작에는 BTI C가 들어갑니다.
- L44
- x0를 SVE 저장 레이아웃의 FFR 기준 위치로 사용해 Z0~Z31과 P0~P15를 정해진 음수 offset에 저장합니다. 첫 인수 0은 주소 0이 아니라 x0 레지스터 번호입니다. x1은 FPSR/FPCR 저장 위치, x2는 FFR 보존 여부, 3은 임시 x3 번호입니다. x2=0이면 저장 이미지의 FFR은 0으로 만듭니다. 저장 공간의 크기와 Z·P·FFR 사이 오프셋은 현재 SVE 벡터 길이에 따라 달라집니다. 고정 크기인 FPSIMD 저장 형식과 구분해야 합니다.
- L45
- x30(LR)에 든 주소로 이동합니다. SPSR/PSTATE를 복원하는 ERET와는 다릅니다.
- L46
- (sve_save_state)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
- L55
- (sve_load_state)의 시작 심볼을 정의합니다. 외부에서 참조할 수 있습니다. 정의에 따른 정렬을 적용합니다. ARM64 함수 시작에는 BTI C가 들어갑니다.
- L56
- x0 기준의 Z·P 상태와 x1 위치의 FPSR/FPCR을 복원합니다. x2가 0이 아니면 FFR도 복원하고 0이면 FFR 로드를 생략합니다. 첫 인수 0과 마지막 4는 각각 x0 기준 주소와 임시 x4를 뜻하는 레지스터 번호입니다. 저장할 때와 같은 SVE 벡터 길이와 레이아웃을 사용해야 각 레지스터의 데이터를 올바른 위치에서 읽을 수 있습니다.
- L57
- x30(LR)에 든 주소로 이동합니다. SPSR/PSTATE를 복원하는 ERET와는 다릅니다.
- L58
- (sve_load_state)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
- L60
- (sve_get_vl)의 시작 심볼을 정의합니다. 외부에서 참조할 수 있습니다. 정의에 따른 정렬을 적용합니다. ARM64 함수 시작에는 BTI C가 들어갑니다.
- L61
- RDVL 명령을 인코딩해 현재 SVE 벡터 길이의 1배를 바이트 단위로 x0에 반환합니다. 인수 0은 결과 레지스터 x0, 1은 길이 배수이며 bit 수나 저장 버퍼 주소가 아닙니다.
- L62
- x30(LR)에 든 주소로 이동합니다. SPSR/PSTATE를 복원하는 ERET와는 다릅니다.
- L63
- (sve_get_vl)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
- L65
- (sve_set_vq)의 시작 심볼을 정의합니다. 외부에서 참조할 수 있습니다. 정의에 따른 정렬을 적용합니다. ARM64 함수 시작에는 BTI C가 들어갑니다.
- L66
- x0의 VQ-1 값을 ZCR_EL1.LEN 필드에 반영하여 SVE 벡터 길이를 선택합니다. VQ는 16바이트 단위이며 0 인코딩은 128비트 길이입니다. x1·x2는 기존 제어값과 수정값을 계산할 임시 레지스터이고 같은 설정이면 레지스터 쓰기를 생략합니다.
- L67
- x30(LR)에 든 주소로 이동합니다. SPSR/PSTATE를 복원하는 ERET와는 다릅니다.
- L68
- (sve_set_vq)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
SVE 상위 영역 지우기
VQ−1이 0이면 Z의 추가 영역이 없어 sve_flush_z를 생략합니다. 그 외에는 각 V 레지스터의 128비트를 자기 자신에게 써서 Z의 상위 영역을 0으로 만듭니다. P 레지스터는 항상 0으로 만들고 x0의 비트 0이 설정된 경우에만 FFR도 지웁니다.
69
70/*
71 * Zero all SVE registers but the first 128-bits of each vector
72 *
73 * VQ must already be configured by caller, any further updates of VQ
74 * will need to ensure that the register state remains valid.
75 *
76 * x0 = include FFR?
77 * x1 = VQ - 1
78 */
79SYM_FUNC_START(sve_flush_live)
80 cbz x1, 1f // A VQ-1 of 0 is 128 bits so no extra Z state
81 sve_flush_z
821: sve_flush_p
83 tbz x0, #0, 2f
84 sve_flush_ffr
852: ret
86SYM_FUNC_END(sve_flush_live)
87
88#endif /* CONFIG_ARM64_SVE */
89
- L79
- (sve_flush_live)의 시작 심볼을 정의합니다. 외부에서 참조할 수 있습니다. 정의에 따른 정렬을 적용합니다. ARM64 함수 시작에는 BTI C가 들어갑니다.
- L80
- x1은 VQ-1입니다. 값 0이면 Z 레지스터가 기본 128비트뿐이므로 지울 상위 SVE 부분이 없어 sve_flush_z를 건너뜁니다. 이 분기는 지정 레지스터의 값이나 비트를 직접 검사하며 CMP가 남긴 NZCV를 읽거나 바꾸지 않습니다. 조건이 맞지 않으면 바로 다음 명령으로 진행합니다.
- L81
- 모든 Z 레지스터의 하위 128비트 FP/SIMD 값은 유지하고 그 위의 SVE 부분만 0으로 만듭니다. 전체 계산 상태를 버리는 것이 아니라 기본 FPSIMD에서 확장 SVE 상태로 넘어갈 때의 잔여값을 정리합니다.
- L82
- P0~P15를 모두 false로 만듭니다. predicate는 각 벡터 원소가 연산에 참여할지 정하는 마스크이므로, 이전 사용자의 predicate 상태가 확장 상태에 남지 않게 합니다. 각 predicate 레지스터에 PFALSE 명령을 적용합니다.
- L83
- x0의 bit 0은 FFR도 정리할지 나타내는 인수입니다. 0이면 해당 작업을 생략하고, 1이면 다음 sve_flush_ffr를 실행합니다. 이 분기는 지정 레지스터의 값이나 비트를 직접 검사하며 CMP가 남긴 NZCV를 읽거나 바꾸지 않습니다. 조건이 맞지 않으면 바로 다음 명령으로 진행합니다.
- L84
- 이미 false로 만든 P0를 FFR에 써서 first-fault 상태를 0으로 정리합니다. FFR은 fault-first load에서 어느 원소까지 유효했는지 나타내는 상태이며 일반 condition flags가 아닙니다.
- L85
- 2 라벨: 다음 코드나 데이터의 위치에 이름을 붙입니다. x30(LR)에 든 주소로 이동합니다. SPSR/PSTATE를 복원하는 ERET와는 다릅니다.
- L86
- (sve_flush_live)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
- L88
- — 전처리 조건 구간을 끝냅니다.
SME의 ZA와 ZT
RDSVL은 스트리밍 벡터 길이를 바이트 단위로 x2에 돌려줍니다. sme_save_za/sme_load_za는 행 인덱스 w12를 증가시키며 행마다 x0를 x2만큼 이동합니다. 완료 후 x0는 ZA 끝을 가리키며, x1이 0이 아니면 이 위치에서 ZT0을 처리합니다. SVE와 SME 경로는 각각의 CONFIG에 따라 포함됩니다.
90#ifdef CONFIG_ARM64_SME
91
92SYM_FUNC_START(sme_get_vl)
93 _sme_rdsvl 0, 1
94 ret
95SYM_FUNC_END(sme_get_vl)
96
97SYM_FUNC_START(sme_set_vq)
98 sme_load_vq x0, x1, x2
99 ret
100SYM_FUNC_END(sme_set_vq)
101
102/*
103 * Save the ZA and ZT state
104 *
105 * x0 - pointer to buffer for state
106 * x1 - number of ZT registers to save
107 */
108SYM_FUNC_START(sme_save_state)
109 _sme_rdsvl 2, 1 // x2 = VL/8
110 sme_save_za 0, x2, 12 // Leaves x0 pointing to the end of ZA
111
112 cbz x1, 1f
113 _str_zt 0
1141:
115 ret
116SYM_FUNC_END(sme_save_state)
117
118/*
119 * Load the ZA and ZT state
120 *
121 * x0 - pointer to buffer for state
122 * x1 - number of ZT registers to save
123 */
124SYM_FUNC_START(sme_load_state)
125 _sme_rdsvl 2, 1 // x2 = VL/8
126 sme_load_za 0, x2, 12 // Leaves x0 pointing to the end of ZA
127
128 cbz x1, 1f
129 _ldr_zt 0
1301:
131 ret
132SYM_FUNC_END(sme_load_state)
133
134#endif /* CONFIG_ARM64_SME */
- L90
- SME는 streaming vector 실행과 2차원 행렬 누산 상태 ZA 등을 추가합니다. 이 설정을 켜면 아래 streaming 길이·ZA·선택적 ZT 저장 복원 함수를 빌드하고, 꺼지면 포함하지 않습니다. 실제 SME/SME2 사용 가능 여부와 mode 활성화는 호출자도 확인해야 합니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
- L92
- (sme_get_vl)의 시작 심볼을 정의합니다. 외부에서 참조할 수 있습니다. 정의에 따른 정렬을 적용합니다. ARM64 함수 시작에는 BTI C가 들어갑니다.
- L93
- RDSVL로 streaming vector 길이의 1배를 바이트 단위로 x0에 읽습니다. 일반 SVE VL과 SME의 SVL은 별도로 선택될 수 있으므로 sve_get_vl 대신 이 함수를 사용합니다. 매크로 인수 0은 목적 레지스터 x0의 번호이고 1은 길이에 곱할 배수입니다. 어셈블러가 이 인수로 RDSVL 인코딩을 만듭니다.
- L94
- x30(LR)에 든 주소로 이동합니다. SPSR/PSTATE를 복원하는 ERET와는 다릅니다.
- L95
- (sme_get_vl)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
- L97
- (sme_set_vq)의 시작 심볼을 정의합니다. 외부에서 참조할 수 있습니다. 정의에 따른 정렬을 적용합니다. ARM64 함수 시작에는 BTI C가 들어갑니다.
- L98
- x0의 VQ-1 인코딩을 SMCR_EL1.LEN에 반영해 streaming vector 길이를 정합니다. x1·x2는 임시 값이며 ZCR_EL1을 쓰는 일반 SVE 길이 설정과 구분합니다.
- L99
- x30(LR)에 든 주소로 이동합니다. SPSR/PSTATE를 복원하는 ERET와는 다릅니다.
- L100
- (sme_set_vq)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
- L108
- (sme_save_state)의 시작 심볼을 정의합니다. 외부에서 참조할 수 있습니다. 정의에 따른 정렬을 적용합니다. ARM64 함수 시작에는 BTI C가 들어갑니다.
- L109
- streaming vector 길이를 바이트 수로 x2에 읽습니다. ZA 한 행의 크기이자 ZA 행 개수의 기준이므로 뒤의 반복 저장에 필요합니다. 매크로 인수 2은 목적 레지스터 x2의 번호이고 1은 길이에 곱할 배수입니다. 어셈블러가 이 인수로 RDSVL 인코딩을 만듭니다.
- L110
- ZA의 각 행을 x0가 가리키는 버퍼에 저장합니다. 0은 기준 x0 번호, x2는 행 크기, 12는 행 선택용 w12 번호입니다. 매 행 뒤 x0를 늘려 전체 SVL_bytes² 영역을 저장하고 끝 위치를 남깁니다.
- L112
- 호출자가 x1로 ZT 상태 저장 필요 여부를 전달합니다. 0이면 ZA만 저장한 뒤 반환하고, 0이 아니면 바로 뒤의 ZT 저장을 실행합니다. 이 분기는 지정 레지스터의 값이나 비트를 직접 검사하며 CMP가 남긴 NZCV를 읽거나 바꾸지 않습니다. 조건이 맞지 않으면 바로 다음 명령으로 진행합니다.
- L113
- 현재 x0, 즉 ZA 이미지 뒤의 위치에 ZT0 상태를 저장하는 인코딩을 출력합니다. ZT0는 지원 SME 확장의 추가 상태이며 이 줄이 모든 SME CPU에서 무조건 실행된다고 가정하지 않습니다.
- L114
- 1 라벨: 다음 코드나 데이터의 위치에 이름을 붙입니다.
- L115
- x30(LR)에 든 주소로 이동합니다. SPSR/PSTATE를 복원하는 ERET와는 다릅니다.
- L116
- (sme_save_state)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
- L124
- (sme_load_state)의 시작 심볼을 정의합니다. 외부에서 참조할 수 있습니다. 정의에 따른 정렬을 적용합니다. ARM64 함수 시작에는 BTI C가 들어갑니다.
- L125
- 현재 streaming vector 길이를 바이트 단위로 x2에 읽어 ZA 복원 행 크기를 정합니다. 저장 버퍼의 레이아웃과 복원 시 길이가 맞아야 합니다. 매크로 인수 2은 목적 레지스터 x2의 번호이고 1은 길이에 곱할 배수입니다. 어셈블러가 이 인수로 RDSVL 인코딩을 만듭니다.
- L126
- x0 기준 버퍼에서 ZA를 행 단위로 복원하고 x0를 ZA 이미지 끝으로 이동합니다. w12가 행 선택을 위한 임시 레지스터이며 x2가 각 행의 바이트 수입니다.
- L128
- x1=0이면 추가 ZT 상태 복원을 생략하고, 그 외에는 저장 이미지에서 ZA 뒤의 ZT0를 읽습니다. 하드웨어 지원에 맞는 인수를 주는 것은 호출자의 책임입니다. 이 분기는 지정 레지스터의 값이나 비트를 직접 검사하며 CMP가 남긴 NZCV를 읽거나 바꾸지 않습니다. 조건이 맞지 않으면 바로 다음 명령으로 진행합니다.
- L129
- ZA 복원 뒤의 x0 위치에서 ZT0를 읽습니다. 첫 인수 0은 주소 상수가 아니라 x0 레지스터를 고르는 매크로 인수입니다.
- L130
- 1 라벨: 다음 코드나 데이터의 위치에 이름을 붙입니다.
- L131
- x30(LR)에 든 주소로 이동합니다. SPSR/PSTATE를 복원하는 ERET와는 다릅니다.
- L132
- (sme_load_state)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
- L134
- — 전처리 조건 구간을 끝냅니다.
매크로 정의와 확장
각 정의는 v6.18.37 원문입니다. 역슬래시 인자는 사용 위치의 값으로 치환되며, 안쪽 매크로와 조건부 블록은 이후 단계에서 다시 처리됩니다.
SYM_FUNC_END
아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.
include/linux/linkage.h L248–L249
#define SYM_FUNC_END(name) \
SYM_END(name, SYM_T_FUNC)SYM_FUNC_START
아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.
arch/arm64/include/asm/linkage.h L18–L20
#define SYM_FUNC_START(name) \
SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN) \
bti c ;include/linux/linkage.h L209–L210
#define SYM_FUNC_START(name) \
SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN)_ldr_zt
레지스터 번호 인자가 가리키는 주소에서 ZT0을 복원합니다.
arch/arm64/include/asm/fpsimdmacros.h L228–L232
.macro _ldr_zt nx
_check_general_reg \nx
.inst 0xe11f8000 \
| (\nx << 5)
.endm인자 치환 예: _ldr_zt 0
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
_check_general_reg 0
.inst 0xe11f8000 \
| (0 << 5)_sme_rdsvl
첫 인자가 가리키는 X 레지스터에 스트리밍 벡터 길이×즉시값을 바이트 단위로 반환하는 RDSVL 인코딩을 생성합니다.
arch/arm64/include/asm/fpsimdmacros.h L187–L193
.macro _sme_rdsvl nx, imm
_check_general_reg \nx
_check_num (\imm), -0x20, 0x1f
.inst 0x04bf5800 \
| (\nx) \
| (((\imm) & 0x3f) << 5)
.endm인자 치환 예: _sme_rdsvl 0, 1
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
_check_general_reg 0
_check_num (1), -0x20, 0x1f
.inst 0x04bf5800 \
| (0) \
| (((1) & 0x3f) << 5)_str_zt
레지스터 번호 인자가 가리키는 주소에 ZT0을 저장합니다.
arch/arm64/include/asm/fpsimdmacros.h L239–L243
.macro _str_zt nx
_check_general_reg \nx
.inst 0xe13f8000 \
| (\nx << 5)
.endm인자 치환 예: _str_zt 0
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
_check_general_reg 0
.inst 0xe13f8000 \
| (0 << 5)_sve_rdvl
첫 인자가 가리키는 X 레지스터에 현재 SVE 벡터 길이×즉시값을 바이트 단위로 반환하는 RDVL 인코딩을 생성합니다.
arch/arm64/include/asm/fpsimdmacros.h L154–L160
.macro _sve_rdvl nx, imm
_check_general_reg \nx
_check_num (\imm), -0x20, 0x1f
.inst 0x04bf5000 \
| (\nx) \
| (((\imm) & 0x3f) << 5)
.endm인자 치환 예: _sve_rdvl 0, 1
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
_check_general_reg 0
_check_num (1), -0x20, 0x1f
.inst 0x04bf5000 \
| (0) \
| (((1) & 0x3f) << 5)fpsimd_restore
q0–q31·FPSR·FPCR을 복원합니다. FPCR이 기존 값과 같은 경우 쓰기를 생략합니다. 상태 포인터는 보존되지 않습니다.
arch/arm64/include/asm/fpsimdmacros.h L47–L68
.macro fpsimd_restore state, tmpnr
ldp q0, q1, [\state, #16 * 0]
ldp q2, q3, [\state, #16 * 2]
ldp q4, q5, [\state, #16 * 4]
ldp q6, q7, [\state, #16 * 6]
ldp q8, q9, [\state, #16 * 8]
ldp q10, q11, [\state, #16 * 10]
ldp q12, q13, [\state, #16 * 12]
ldp q14, q15, [\state, #16 * 14]
ldp q16, q17, [\state, #16 * 16]
ldp q18, q19, [\state, #16 * 18]
ldp q20, q21, [\state, #16 * 20]
ldp q22, q23, [\state, #16 * 22]
ldp q24, q25, [\state, #16 * 24]
ldp q26, q27, [\state, #16 * 26]
ldp q28, q29, [\state, #16 * 28]
ldp q30, q31, [\state, #16 * 30]!
ldr w\tmpnr, [\state, #16 * 2]
msr fpsr, x\tmpnr
ldr w\tmpnr, [\state, #16 * 2 + 4]
fpsimd_restore_fpcr x\tmpnr, \state
.endm인자 치환 예: fpsimd_restore x0, 8
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
ldp q0, q1, [x0, #16 * 0]
ldp q2, q3, [x0, #16 * 2]
ldp q4, q5, [x0, #16 * 4]
ldp q6, q7, [x0, #16 * 6]
ldp q8, q9, [x0, #16 * 8]
ldp q10, q11, [x0, #16 * 10]
ldp q12, q13, [x0, #16 * 12]
ldp q14, q15, [x0, #16 * 14]
ldp q16, q17, [x0, #16 * 16]
ldp q18, q19, [x0, #16 * 18]
ldp q20, q21, [x0, #16 * 20]
ldp q22, q23, [x0, #16 * 22]
ldp q24, q25, [x0, #16 * 24]
ldp q26, q27, [x0, #16 * 26]
ldp q28, q29, [x0, #16 * 28]
ldp q30, q31, [x0, #16 * 30]!
ldr w8, [x0, #16 * 2]
msr fpsr, x8
ldr w8, [x0, #16 * 2 + 4]
fpsimd_restore_fpcr x8, x0fpsimd_save
q0–q31과 FPSR·FPCR을 저장합니다. 두 번째 인자는 임시 레지스터 번호이며, 마지막 쌍 저장의 writeback으로 상태 포인터도 바뀝니다.
arch/arm64/include/asm/fpsimdmacros.h L11–L32
.macro fpsimd_save state, tmpnr
stp q0, q1, [\state, #16 * 0]
stp q2, q3, [\state, #16 * 2]
stp q4, q5, [\state, #16 * 4]
stp q6, q7, [\state, #16 * 6]
stp q8, q9, [\state, #16 * 8]
stp q10, q11, [\state, #16 * 10]
stp q12, q13, [\state, #16 * 12]
stp q14, q15, [\state, #16 * 14]
stp q16, q17, [\state, #16 * 16]
stp q18, q19, [\state, #16 * 18]
stp q20, q21, [\state, #16 * 20]
stp q22, q23, [\state, #16 * 22]
stp q24, q25, [\state, #16 * 24]
stp q26, q27, [\state, #16 * 26]
stp q28, q29, [\state, #16 * 28]
stp q30, q31, [\state, #16 * 30]!
mrs x\tmpnr, fpsr
str w\tmpnr, [\state, #16 * 2]
mrs x\tmpnr, fpcr
str w\tmpnr, [\state, #16 * 2 + 4]
.endm인자 치환 예: fpsimd_save x0, 8
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
stp q0, q1, [x0, #16 * 0]
stp q2, q3, [x0, #16 * 2]
stp q4, q5, [x0, #16 * 4]
stp q6, q7, [x0, #16 * 6]
stp q8, q9, [x0, #16 * 8]
stp q10, q11, [x0, #16 * 10]
stp q12, q13, [x0, #16 * 12]
stp q14, q15, [x0, #16 * 14]
stp q16, q17, [x0, #16 * 16]
stp q18, q19, [x0, #16 * 18]
stp q20, q21, [x0, #16 * 20]
stp q22, q23, [x0, #16 * 22]
stp q24, q25, [x0, #16 * 24]
stp q26, q27, [x0, #16 * 26]
stp q28, q29, [x0, #16 * 28]
stp q30, q31, [x0, #16 * 30]!
mrs x8, fpsr
str w8, [x0, #16 * 2]
mrs x8, fpcr
str w8, [x0, #16 * 2 + 4]sme_load_vq
VQ−1을 SMCR_EL1.LEN에 반영하여 스트리밍 벡터 길이를 설정합니다.
arch/arm64/include/asm/fpsimdmacros.h L280–L288
.macro sme_load_vq xvqminus1, xtmp, xtmp2
mrs_s \xtmp, SYS_SMCR_EL1
bic \xtmp2, \xtmp, SMCR_ELx_LEN_MASK
orr \xtmp2, \xtmp2, \xvqminus1
cmp \xtmp2, \xtmp
b.eq 921f
msr_s SYS_SMCR_EL1, \xtmp2 //self-synchronising
921:
.endm인자 치환 예: sme_load_vq x0, x1, x2
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
mrs_s x1, SYS_SMCR_EL1
bic x2, x1, SMCR_ELx_LEN_MASK
orr x2, x2, x0
cmp x2, x1
b.eq 921f
msr_s SYS_SMCR_EL1, x2 //self-synchronising
921:sme_load_za
ZA의 각 행을 버퍼에서 읽으며 포인터를 ZA 끝까지 증가시킵니다.
arch/arm64/include/asm/fpsimdmacros.h L348–L357
.macro sme_load_za nxbase, xvl, nw
mov w\nw, #0
423:
_sme_ldr_zav \nw, \nxbase
add x\nxbase, x\nxbase, \xvl
add x\nw, x\nw, #1
cmp \xvl, x\nw
bne 423b
.endm인자 치환 예: sme_load_za 0, x2, 12
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
mov w12, #0
423:
_sme_ldr_zav 12, 0
add x0, x0, x2
add x12, x12, #1
cmp x2, x12
bne 423bsme_save_za
ZA를 스트리밍 벡터 길이만큼의 행 단위로 저장하고 버퍼 포인터를 ZA 끝까지 증가시킵니다.
arch/arm64/include/asm/fpsimdmacros.h L337–L346
.macro sme_save_za nxbase, xvl, nw
mov w\nw, #0
423:
_sme_str_zav \nw, \nxbase
add x\nxbase, x\nxbase, \xvl
add x\nw, x\nw, #1
cmp \xvl, x\nw
bne 423b
.endm인자 치환 예: sme_save_za 0, x2, 12
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
mov w12, #0
423:
_sme_str_zav 12, 0
add x0, x0, x2
add x12, x12, #1
cmp x2, x12
bne 423bsve_flush_ffr
앞에서 0으로 만든 P0를 FFR에 씁니다.
인자 치환 예: sve_flush_ffr
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
_sve_wrffr 0sve_flush_p
P0–P15에 PFALSE를 적용합니다.
arch/arm64/include/asm/fpsimdmacros.h L299–L301
.macro sve_flush_p
_for n, 0, 15, _sve_pfalse \n
.endm인자 치환 예: sve_flush_p
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
_for n, 0, 15, _sve_pfalse \nsve_flush_z
각 Z 레지스터의 하위 128비트는 유지하고 나머지 비트를 0으로 만듭니다.
arch/arm64/include/asm/fpsimdmacros.h L296–L298
.macro sve_flush_z
_for n, 0, 31, _sve_flush_z \n
.endm인자 치환 예: sve_flush_z
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
_for n, 0, 31, _sve_flush_z \nsve_load
Z·P와 선택적 FFR을 복구하고 별도 포인터의 FPSR/FPCR을 읽습니다.
arch/arm64/include/asm/fpsimdmacros.h L323–L335
.macro sve_load nxbase, xpfpsr, restore_ffr, nxtmp
_for n, 0, 31, _sve_ldr_v \n, \nxbase, \n - 34
cbz \restore_ffr, 921f
_sve_ldr_p 0, \nxbase
_sve_wrffr 0
921:
_for n, 0, 15, _sve_ldr_p \n, \nxbase, \n - 16
ldr w\nxtmp, [\xpfpsr]
msr fpsr, x\nxtmp
ldr w\nxtmp, [\xpfpsr, #4]
msr fpcr, x\nxtmp
.endm인자 치환 예: sve_load 0, x1, x2, 4
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
_for n, 0, 31, _sve_ldr_v \n, 0, \n - 34
cbz x2, 921f
_sve_ldr_p 0, 0
_sve_wrffr 0
921:
_for n, 0, 15, _sve_ldr_p \n, 0, \n - 16
ldr w4, [x1]
msr fpsr, x4
ldr w4, [x1, #4]
msr fpcr, x4sve_load_vq
x0에 해당하는 VQ−1을 ZCR_EL1.LEN에 반영합니다. 현재 값과 다를 때만 MSR을 수행합니다.
arch/arm64/include/asm/fpsimdmacros.h L269–L277
.macro sve_load_vq xvqminus1, xtmp, xtmp2
mrs_s \xtmp, SYS_ZCR_EL1
bic \xtmp2, \xtmp, ZCR_ELx_LEN_MASK
orr \xtmp2, \xtmp2, \xvqminus1
cmp \xtmp2, \xtmp
b.eq 921f
msr_s SYS_ZCR_EL1, \xtmp2 //self-synchronising
921:
.endm인자 치환 예: sve_load_vq x0, x1, x2
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
mrs_s x1, SYS_ZCR_EL1
bic x2, x1, ZCR_ELx_LEN_MASK
orr x2, x2, x0
cmp x2, x1
b.eq 921f
msr_s SYS_ZCR_EL1, x2 //self-synchronising
921:sve_save
Z0–Z31, P0–P15와 FFR 슬롯을 저장합니다. FFR을 읽지 않는 경로에서는 슬롯을 0으로 저장합니다. FPSR/FPCR은 별도 포인터에 저장합니다.
arch/arm64/include/asm/fpsimdmacros.h L306–L321
.macro sve_save nxbase, xpfpsr, save_ffr, nxtmp
_for n, 0, 31, _sve_str_v \n, \nxbase, \n - 34
_for n, 0, 15, _sve_str_p \n, \nxbase, \n - 16
cbz \save_ffr, 921f
_sve_rdffr 0
b 922f
921:
_sve_pfalse 0 // Zero out FFR
922:
_sve_str_p 0, \nxbase
_sve_ldr_p 0, \nxbase, -16
mrs x\nxtmp, fpsr
str w\nxtmp, [\xpfpsr]
mrs x\nxtmp, fpcr
str w\nxtmp, [\xpfpsr, #4]
.endm인자 치환 예: sve_save 0, x1, x2, 3
1단계 치환 결과입니다. 내부 매크로·조건·고유 라벨 번호는 아직 펼치지 않았습니다.
_for n, 0, 31, _sve_str_v \n, 0, \n - 34
_for n, 0, 15, _sve_str_p \n, 0, \n - 16
cbz x2, 921f
_sve_rdffr 0
b 922f
921:
_sve_pfalse 0 // Zero out FFR
922:
_sve_str_p 0, 0
_sve_ldr_p 0, 0, -16
mrs x3, fpsr
str w3, [x1]
mrs x3, fpcr
str w3, [x1, #4]상수·구조체 오프셋
S_*·THREAD_*·FREGS_* 등의 구조체 오프셋은 빌드한 C 구조체 배치에서 생성됩니다. 숫자를 고정하지 않고 원래 기호를 사용했습니다.