Line data Source code
1 : /**
2 : * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "extract_operands.h"
12 :
13 : #include "config/barrier_config.h"
14 :
15 : namespace hcomm {
16 : namespace CcuOpt {
17 :
18 : namespace {
19 :
20 : // reduce.count 字段以 "实际 ms 数 - 2" 编码, 且仅占低 3 位:
21 : // 实际 ms 数 = (count_field & 0x7) + 2.
22 : constexpr uint16_t CCU_REDUCE_COUNT_MASK = 0x7;
23 : constexpr uint16_t CCU_REDUCE_COUNT_BIAS = 2;
24 : // operate.parMode == 1: 第二操作数为寄存器 (Xd = Xn @ Xm); == 0 时为 imm16.
25 : constexpr uint16_t PARMODE_REGISTER_PAIR = 1;
26 : // set/clearCKE.clearType == 1: 命中后自动清零 waitCKEId, 该 CKE 位既读又写.
27 : constexpr uint16_t CLEARTYPE_AUTO = 1;
28 :
29 558 : inline void AddRead(std::vector<RegOperand>& out, RegType type, uint16_t regId)
30 : {
31 558 : if (regId == 0 && type == RegType::CKE) {
32 25 : return;
33 : }
34 533 : out.push_back(RegOperand{type, regId, /*isDef=*/false});
35 : }
36 :
37 495 : inline void AddWrite(std::vector<RegOperand>& out, RegType type, uint16_t regId)
38 : {
39 495 : if (regId == 0 && type == RegType::CKE) {
40 25 : return;
41 : }
42 470 : out.push_back(RegOperand{type, regId, /*isDef=*/true});
43 : }
44 :
45 : // Load 类中的访存 / 清零指令 (非算子). 返回 true 表示已处理该 code.
46 645 : bool ExtractLoadMemOps(std::vector<RegOperand>& out, const CcuRep::CcuInstr& instr)
47 : {
48 : using namespace InstrCodeV2;
49 645 : switch (instr.header.code) {
50 15 : case LOADSQEARGSTOX_CODE:
51 15 : AddWrite(out, RegType::XN, instr.v2.loadSqeArgsToX.xnId);
52 15 : return true;
53 269 : case LOADIMDTOX_CODE:
54 269 : AddWrite(out, RegType::XN, instr.v2.loadImdToX.xnId);
55 269 : return true;
56 0 : case LOADSTOREX_CODE:
57 : // Xd = *Xs, *Xdo = Xso (读改写形式), 保守全部当作读写.
58 0 : AddRead(out, RegType::XN, instr.v2.loadStoreX.xsId);
59 0 : AddRead(out, RegType::XN, instr.v2.loadStoreX.xsoId);
60 0 : AddRead(out, RegType::XN, instr.v2.loadStoreX.xdoId);
61 0 : AddWrite(out, RegType::XN, instr.v2.loadStoreX.xdId);
62 0 : return true;
63 0 : case CLEARX_CODE:
64 : // ClearX 语义为把指定 Xn / Xm 清零, 两者都是 def.
65 0 : AddWrite(out, RegType::XN, instr.v2.clearX.xnId);
66 0 : AddWrite(out, RegType::XN, instr.v2.clearX.xmId);
67 0 : return true;
68 202 : case NOP_CODE:
69 : // 无寄存器操作数.
70 202 : return true;
71 0 : case LOAD_CODE:
72 0 : AddRead(out, RegType::XN, instr.v2.load.xsId);
73 0 : AddRead(out, RegType::XN, instr.v2.load.xstId);
74 0 : AddRead(out, RegType::XN, instr.v2.load.xlId);
75 0 : AddWrite(out, RegType::XN, instr.v2.load.xdId);
76 0 : return true;
77 0 : case STORE_CODE:
78 0 : AddRead(out, RegType::XN, instr.v2.store.xdId);
79 0 : AddRead(out, RegType::XN, instr.v2.store.xdtId);
80 0 : AddRead(out, RegType::XN, instr.v2.store.xsId);
81 0 : AddRead(out, RegType::XN, instr.v2.store.xlId);
82 0 : AddRead(out, RegType::XN, instr.v2.store.xhId);
83 0 : return true;
84 159 : default:
85 159 : return false;
86 : }
87 : }
88 :
89 : // Load 类中的算子指令 (Add / Sub / Mul / And / Or / Xor / Shl / Shr / Popcnt / Not).
90 : // Xd = Xn @ Xm (parMode == 1) 或 Xd = Xn @ imm16 (parMode == 0); Not / Popcnt 仅使用 Xn.
91 159 : void ExtractLoadOperator(std::vector<RegOperand>& out, const CcuRep::CcuInstr& instr)
92 : {
93 : using namespace InstrCodeV2;
94 159 : switch (instr.header.code) {
95 158 : case ADD_CODE:
96 : case SUB_CODE:
97 : case MUL_CODE:
98 : case AND_CODE:
99 : case OR_CODE:
100 : case XOR_CODE:
101 : case SHL_CODE:
102 : case SHR_CODE:
103 : case POPCNT_CODE:
104 158 : AddWrite(out, RegType::XN, instr.v2.operate.xdId);
105 158 : AddRead(out, RegType::XN, instr.v2.operate.xnId);
106 158 : if (instr.v2.operate.parMode == PARMODE_REGISTER_PAIR) {
107 80 : AddRead(out, RegType::XN, instr.v2.operate.xmId);
108 : }
109 158 : break;
110 1 : case NOT_CODE:
111 1 : AddWrite(out, RegType::XN, instr.v2.operate.xdId);
112 1 : AddRead(out, RegType::XN, instr.v2.operate.xnId);
113 1 : break;
114 0 : default:
115 0 : break;
116 : }
117 159 : }
118 :
119 645 : void ExtractLoadType(std::vector<RegOperand>& out, const CcuRep::CcuInstr& instr)
120 : {
121 645 : if (!ExtractLoadMemOps(out, instr)) {
122 159 : ExtractLoadOperator(out, instr);
123 : }
124 : // setCKEId 不作为 CKE def, 不提取 (见文件顶部 set 语义说明).
125 645 : }
126 :
127 117 : void ExtractCtrlType(std::vector<RegOperand>& out, const CcuRep::CcuInstr& instr)
128 : {
129 : using namespace InstrCodeV2;
130 117 : switch (instr.header.code) {
131 20 : case LOOP_CODE:
132 : // xmId = IterNum, xnId = Offset, xpId = ContextId; 三者都是 Xn 寄存器.
133 20 : AddRead(out, RegType::XN, instr.v2.loop.xmId);
134 20 : AddRead(out, RegType::XN, instr.v2.loop.xnId);
135 20 : AddRead(out, RegType::XN, instr.v2.loop.xpId);
136 20 : break;
137 10 : case LOOPGROUP_CODE:
138 10 : AddRead(out, RegType::XN, instr.v2.loopGroup.xnId);
139 10 : AddRead(out, RegType::XN, instr.v2.loopGroup.xmId);
140 10 : AddRead(out, RegType::XN, instr.v2.loopGroup.xpId);
141 10 : break;
142 32 : case SETCKBIT_CODE:
143 32 : AddRead(out, RegType::CKE, instr.v2.setCKE.waitCKEId);
144 32 : if (instr.v2.setCKE.clearType == CLEARTYPE_AUTO) {
145 32 : AddWrite(out, RegType::CKE, instr.v2.setCKE.waitCKEId);
146 : }
147 32 : break;
148 15 : case CLEARCKBIT_CODE:
149 : // 与 setcke 对称: 只有 clearType=1 自动清零的 waitCKEId 才是 CKE 写者 (read + def);
150 : // clearCKEId 只是主动清某位, 同样不作为触发写后读的 def.
151 15 : AddRead(out, RegType::CKE, instr.v2.clearCKE.waitCKEId);
152 15 : if (instr.v2.clearCKE.clearType == CLEARTYPE_AUTO) {
153 14 : AddWrite(out, RegType::CKE, instr.v2.clearCKE.waitCKEId);
154 : }
155 15 : break;
156 40 : case JMP_CODE:
157 40 : AddRead(out, RegType::XN, instr.v2.jmp.relTarInstrXnId);
158 40 : AddRead(out, RegType::XN, instr.v2.jmp.conditionXnId);
159 40 : AddRead(out, RegType::XN, instr.v2.jmp.expectedXnId);
160 40 : break;
161 0 : case WAIT_CODE:
162 0 : AddRead(out, RegType::XN, instr.v2.wait.conditionXnId);
163 0 : AddRead(out, RegType::XN, instr.v2.wait.expectedXnId);
164 0 : break;
165 0 : case FENCE_CODE:
166 0 : break;
167 0 : default:
168 0 : break;
169 : }
170 117 : }
171 :
172 : // Trans 类中的纯搬运指令 (Mem<->MS / Mem<->Mem / TransMem). 返回 true 表示已处理该 code.
173 11 : bool ExtractTransMoveOps(std::vector<RegOperand>& out, const CcuRep::CcuInstr& instr)
174 : {
175 : using namespace InstrCodeV2;
176 11 : switch (instr.header.code) {
177 4 : case TRANSLOCMEMTOLOCMS_CODE:
178 4 : AddRead(out, RegType::XN, instr.v2.transLocMemToLocMS.xsId);
179 4 : AddRead(out, RegType::XN, instr.v2.transLocMemToLocMS.xstId);
180 4 : AddRead(out, RegType::XN, instr.v2.transLocMemToLocMS.xlId);
181 4 : AddRead(out, RegType::XN, instr.v2.transLocMemToLocMS.xoId);
182 4 : AddWrite(out, RegType::MS, instr.v2.transLocMemToLocMS.msId);
183 4 : return true;
184 2 : case TRANSLOCMSTOLOCMEM_CODE:
185 2 : AddRead(out, RegType::MS, instr.v2.transLocMSToLocMem.msId);
186 2 : AddRead(out, RegType::XN, instr.v2.transLocMSToLocMem.xdId);
187 2 : AddRead(out, RegType::XN, instr.v2.transLocMSToLocMem.xdtId);
188 2 : AddRead(out, RegType::XN, instr.v2.transLocMSToLocMem.xlId);
189 2 : AddRead(out, RegType::XN, instr.v2.transLocMSToLocMem.xoId);
190 2 : return true;
191 0 : case TRANSLOCMSTOLOCMS_CODE:
192 0 : AddRead(out, RegType::MS, instr.v2.transLocMSToLocMS.mssId);
193 0 : AddRead(out, RegType::XN, instr.v2.transLocMSToLocMS.xlId);
194 0 : AddRead(out, RegType::XN, instr.v2.transLocMSToLocMS.xoId);
195 0 : AddWrite(out, RegType::MS, instr.v2.transLocMSToLocMS.msdId);
196 0 : return true;
197 0 : case TRANSLOCMEMTOLOCMEM_CODE:
198 0 : AddRead(out, RegType::XN, instr.v2.transLocMemToLocMem.xdId);
199 0 : AddRead(out, RegType::XN, instr.v2.transLocMemToLocMem.xdtId);
200 0 : AddRead(out, RegType::XN, instr.v2.transLocMemToLocMem.xsId);
201 0 : AddRead(out, RegType::XN, instr.v2.transLocMemToLocMem.xstId);
202 0 : AddRead(out, RegType::XN, instr.v2.transLocMemToLocMem.xlId);
203 : // usedMSId / msNum 描述临时 MS 区段, 保守视作 read.
204 0 : AddRead(out, RegType::MS, instr.v2.transLocMemToLocMem.usedMSId);
205 0 : return true;
206 1 : case TRANSMEM_CODE:
207 1 : AddRead(out, RegType::XN, instr.v2.transMem.xdId);
208 1 : AddRead(out, RegType::XN, instr.v2.transMem.xdtId);
209 1 : AddRead(out, RegType::XN, instr.v2.transMem.xsId);
210 1 : AddRead(out, RegType::XN, instr.v2.transMem.xstId);
211 1 : AddRead(out, RegType::XN, instr.v2.transMem.xlId);
212 1 : AddRead(out, RegType::XN, instr.v2.transMem.xcId);
213 1 : AddRead(out, RegType::XN, instr.v2.transMem.xnId);
214 1 : AddRead(out, RegType::XN, instr.v2.transMem.xntId);
215 1 : return true;
216 4 : default:
217 4 : return false;
218 : }
219 : }
220 :
221 : // Trans 类中的同步指令 (SyncWtX / SyncAtX).
222 4 : void ExtractTransSyncOps(std::vector<RegOperand>& out, const CcuRep::CcuInstr& instr)
223 : {
224 : using namespace InstrCodeV2;
225 4 : switch (instr.header.code) {
226 4 : case SYNCWTX_CODE:
227 4 : AddRead(out, RegType::XN, instr.v2.syncWtX.xdId);
228 4 : AddRead(out, RegType::XN, instr.v2.syncWtX.xdtId);
229 4 : AddRead(out, RegType::XN, instr.v2.syncWtX.xsId);
230 4 : AddRead(out, RegType::XN, instr.v2.syncWtX.xcId);
231 4 : if (instr.v2.syncWtX.notifyValid != 0) {
232 3 : AddRead(out, RegType::XN, instr.v2.syncWtX.xnId);
233 3 : AddRead(out, RegType::XN, instr.v2.syncWtX.xntId);
234 : }
235 4 : break;
236 0 : case SYNCATX_CODE:
237 0 : AddRead(out, RegType::XN, instr.v2.syncAtX.xdId);
238 0 : AddRead(out, RegType::XN, instr.v2.syncAtX.xdtId);
239 0 : AddRead(out, RegType::XN, instr.v2.syncAtX.xsId);
240 0 : AddRead(out, RegType::XN, instr.v2.syncAtX.xcId);
241 0 : break;
242 0 : default:
243 0 : break;
244 : }
245 4 : }
246 :
247 11 : void ExtractTransType(std::vector<RegOperand>& out, const CcuRep::CcuInstr& instr)
248 : {
249 11 : if (!ExtractTransMoveOps(out, instr)) {
250 4 : ExtractTransSyncOps(out, instr);
251 : }
252 : // setCKEId 不作为 CKE def, 不提取 (见文件顶部 set 语义说明).
253 11 : }
254 :
255 2 : void ExtractReduceType(std::vector<RegOperand>& out, const CcuRep::CcuInstr& instr)
256 : {
257 : // ReduceAdd / ReduceMax / ReduceMin: MSA~MSH reduce to MSA, msId[0] 既读又写.
258 2 : uint16_t countInInstr = instr.v2.reduce.count;
259 : // countInInstr 是 "count - 2" 后存进去的, 实际 ms 数 = count_field + 2.
260 2 : uint16_t realCount = (countInInstr & CCU_REDUCE_COUNT_MASK) + CCU_REDUCE_COUNT_BIAS;
261 2 : if (realCount > CcuRep::CCU_REDUCE_MAX_MS) {
262 0 : realCount = CcuRep::CCU_REDUCE_MAX_MS;
263 : }
264 :
265 2 : AddRead(out, RegType::MS, instr.v2.reduce.msId[0]);
266 2 : AddWrite(out, RegType::MS, instr.v2.reduce.msId[0]);
267 4 : for (uint16_t i = 1; i < realCount; ++i) {
268 2 : AddRead(out, RegType::MS, instr.v2.reduce.msId[i]);
269 : }
270 2 : AddRead(out, RegType::XN, instr.v2.reduce.XnIdLength);
271 : // setCKEId 不作为 CKE def, 不提取 (见文件顶部 set 语义说明).
272 2 : }
273 :
274 : } // namespace
275 :
276 775 : std::vector<RegOperand> ExtractOperandsV2(const CcuRep::CcuInstr& instr)
277 : {
278 : using namespace InstrCodeV2;
279 775 : std::vector<RegOperand> out;
280 775 : out.reserve(8);
281 775 : switch (instr.header.type) {
282 645 : case LOAD_TYPE:
283 645 : ExtractLoadType(out, instr);
284 645 : break;
285 117 : case CTRL_TYPE:
286 117 : ExtractCtrlType(out, instr);
287 117 : break;
288 11 : case TRANS_TYPE:
289 11 : ExtractTransType(out, instr);
290 11 : break;
291 2 : case REDUCE_TYPE:
292 2 : ExtractReduceType(out, instr);
293 2 : break;
294 0 : default:
295 0 : break;
296 : }
297 775 : return out;
298 0 : }
299 :
300 : } // namespace CcuOpt
301 : } // namespace hcomm
|