@@ -217,6 +217,120 @@ parse_lines()
217217 finalize_preempt ();
218218}
219219
220+ void
221+ asm_parser::
222+ handle_preempt_opcode (std::string& arg_str, std::string& line)
223+ {
224+ if (get_target_type () == " aie2ps" )
225+ throw error (error::error_code::internal_error, " PREEMPT opcode is not supported for aie2ps target" );
226+
227+ int current_group = current_col ();
228+ record_preempt_label (current_group);
229+
230+ std::vector<std::string> args;
231+ if (!arg_str.empty ()) {
232+ std::stringstream ss (arg_str);
233+ std::string arg;
234+ while (std::getline (ss, arg, ' ,' ))
235+ args.push_back (trim (arg));
236+ }
237+
238+ if (args.empty ())
239+ throw error (error::error_code::internal_error, " PREEMPT opcode has no arguments" );
240+
241+ std::string first_arg = args[0 ];
242+ if (first_arg.empty ())
243+ throw error (error::error_code::internal_error, " PREEMPT opcode has empty first argument" );
244+
245+ std::string hintmap_label;
246+ if (args.size () >= 4 ) {
247+ hintmap_label = args[3 ];
248+ if (!hintmap_label.empty () && hintmap_label[0 ] == ' @' )
249+ hintmap_label = hintmap_label.substr (1 );
250+ if (!hintmap_label.empty ()) {
251+ std::transform (hintmap_label.begin (), hintmap_label.end (), hintmap_label.begin (),
252+ [](unsigned char c) { return static_cast <char >(std::tolower (c)); });
253+ }
254+ }
255+
256+ std::pair<std::string, std::string> labels;
257+ if (!hintmap_label.empty ()) {
258+ // Qualify the hintmap key with its label scope so that the same label
259+ // name in different scopes (e.g. "default" vs "default:pdi") is treated
260+ // as a distinct hintmap.
261+ std::string qualified_key = m_current_label + " :" + hintmap_label;
262+ // Get unique save/restore labels for this hintmap BEFORE adding to vector
263+ // (so the index calculation is correct)
264+ labels = get_hintmap_save_restore_labels (hintmap_label, current_group);
265+ // Store qualified key for later processing (after getting labels)
266+ m_preempt_hintmaps[current_group].push_back (qualified_key);
267+ } else {
268+ // No hintmap, use group-level labels
269+ // Track that this group has PREEMPT opcodes without hintmaps
270+ m_preempt_without_hintmap.insert (current_group);
271+ labels = m_preempt_labels[current_group];
272+ }
273+
274+ if (!hintmap_label.empty ())
275+ arg_str = first_arg + " , @" + labels.first + " , @" + labels.second + " , @" + hintmap_label;
276+ else
277+ arg_str = first_arg + " , @" + labels.first + " , @" + labels.second ;
278+
279+ log_info () << " PREEMPT opcode: updated arg_str to '" << arg_str
280+ << " ' (hintmap: '" << hintmap_label << " ', labels: @" << labels.first
281+ << " / @" << labels.second << " )" << std::endl;
282+
283+ line = " preempt\t " + arg_str;
284+ }
285+
286+ void
287+ asm_parser::
288+ handle_load_or_preempt_cond (const std::string& op_name, const std::string& arg_str, const smatch& sm)
289+ {
290+ // col is common to all four opcodes; compute once.
291+ int col = current_col ();
292+
293+ if (sm[1 ].matched || sm[3 ].matched ) { // load_pdi or load_cores
294+ // operator[] default-constructs col_data if the key is absent (single lookup).
295+ auto & cdata = m_col[col];
296+ bool is_load_pdi = sm[1 ].matched ;
297+
298+ // Extract the @label at argument index 1 (<id>, @<label>).
299+ // Compiled once (static); regex_search finds the first ", @<label>" token.
300+ static const regex LOAD_LABEL_RE (" ,\\ s*(@[a-zA-Z0-9_]+)" );
301+ std::string label_arg;
302+ smatch lm;
303+ if (regex_search (arg_str, lm, LOAD_LABEL_RE))
304+ label_arg = lm[1 ].str ();
305+ // Enforce uniqueness of the PDI / core-elf address within this column.
306+ // label_arg will never be empty
307+ bool inserted = is_load_pdi
308+ ? cdata.try_add_load_pdi_label (label_arg)
309+ : cdata.try_add_load_cores_label (label_arg);
310+ if (!inserted)
311+ throw error (error::error_code::invalid_asm,
312+ op_name + " location '" + label_arg + " ' is not unique in column " +
313+ std::to_string (col) + " ; each " + op_name +
314+ " in a control code elf must use a distinct address\n " );
315+
316+ if (is_load_pdi)
317+ cdata.increment_load_pdi_count ();
318+ else
319+ cdata.increment_load_cores_count ();
320+ } else if (sm[2 ].matched ) { // load_cores_cp
321+ m_col[col].increment_load_cores_cp_count ();
322+ } else {
323+ // start_cond_job_preempt must only appear after at least one preempt in
324+ // the same column (cert uses the preceding preempt point for recovery).
325+ auto col_it = m_col.find (col);
326+ if (col_it == m_col.end () || col_it->second .get_preempt_count () == 0 )
327+ throw error (error::error_code::invalid_asm,
328+ " start_cond_job_preempt found in column " + std::to_string (col) +
329+ " before any preempt opcode; it must follow a preempt opcode\n " );
330+ col_it->second .increment_start_cond_job_preempt_count ();
331+ }
332+ }
333+
220334void
221335asm_parser::
222336parse_lines (const std::vector<char >& data, std::string& file)
@@ -317,125 +431,13 @@ parse_lines(const std::vector<char>& data, std::string& file)
317431
318432 // Handle PREEMPT opcode - record label for current group
319433 if (!op_name.compare (" preempt" )) {
320- if (get_target_type () == " aie2ps" )
321- throw error (error::error_code::internal_error, " PREEMPT opcode is not supported for aie2ps target" );
322-
323- // Get current group (default to 0 if no attach_to_group yet)
324- int current_group = current_col ();
325-
326- // Record preempt label for this group (save_N/restore_N) - for backward compatibility
327- record_preempt_label (current_group);
328-
329- // Parse arguments: id, @save, @restore, [@hintmap]
330- std::vector<std::string> args;
331- if (!arg_str.empty ()) {
332- std::stringstream ss (arg_str);
333- std::string arg;
334- while (std::getline (ss, arg, ' ,' )) {
335- args.push_back (trim (arg));
336- }
337- }
338-
339- // Extract first argument (id)
340- std::string first_arg;
341- if (args.empty ())
342- throw error (error::error_code::internal_error, " PREEMPT opcode has no arguments" );
343-
344- first_arg = args[0 ];
345- if (first_arg.empty ())
346- throw error (error::error_code::internal_error, " PREEMPT opcode has empty first argument" );
347-
348- // Extract hintmap label if present (4th argument, optional)
349- std::string hintmap_label;
350- if (args.size () >= 4 ) {
351- hintmap_label = args[3 ];
352- // Remove @ prefix if present
353- if (!hintmap_label.empty () && hintmap_label[0 ] == ' @' ) {
354- hintmap_label = hintmap_label.substr (1 );
355- }
356- if (!hintmap_label.empty ()) {
357- std::transform (hintmap_label.begin (), hintmap_label.end (), hintmap_label.begin (),
358- [](unsigned char c) { return static_cast <char >(std::tolower (c)); });
359- }
360- }
361-
362- // Get save/restore labels - specific to hintmap if present, otherwise use group labels
363- std::pair<std::string, std::string> labels;
364- if (!hintmap_label.empty ()) {
365- // Qualify the hintmap key with its label scope so that the same label
366- // name in different scopes (e.g. "default" vs "default:pdi") is treated
367- // as a distinct hintmap.
368- std::string qualified_key = m_current_label + " :" + hintmap_label;
369- // Get unique save/restore labels for this hintmap BEFORE adding to vector
370- // (so the index calculation is correct)
371- labels = get_hintmap_save_restore_labels (hintmap_label, current_group);
372- // Store qualified key for later processing (after getting labels)
373- m_preempt_hintmaps[current_group].push_back (qualified_key);
374- } else {
375- // No hintmap, use group-level labels
376- // Track that this group has PREEMPT opcodes without hintmaps
377- m_preempt_without_hintmap.insert (current_group);
378- labels = m_preempt_labels[current_group];
379- }
380-
381- // Build new arg_str: <first_arg>, @<save_label>, @<restore_label>[, @<hintmap_label>]
382- if (!hintmap_label.empty ())
383- arg_str = first_arg + " , @" + labels.first + " , @" + labels.second + " , @" + hintmap_label;
384- else
385- arg_str = first_arg + " , @" + labels.first + " , @" + labels.second ;
386-
387- log_info () << " PREEMPT opcode: updated arg_str to '" << arg_str
388- << " ' (hintmap: '" << hintmap_label << " ', labels: @" << labels.first
389- << " / @" << labels.second << " )" << std::endl;
390-
391- line = op_name + " \t " + arg_str;
434+ handle_preempt_opcode (arg_str, line);
392435 }
393436 // Per-opcode parse-time checks and counter updates.
394437 // These run after the preempt block so that m_preempt_count is already
395438 // incremented when we reach start_cond_job_preempt.
396439 else if (regex_match (op_name, sm, LOAD_OR_PREEMPT_COND_RE)) {
397- // col is common to all four opcodes; compute once.
398- int col = current_col ();
399-
400- if (sm[1 ].matched || sm[3 ].matched ) { // load_pdi or load_cores
401- // operator[] default-constructs col_data if the key is absent (single lookup).
402- auto & cdata = m_col[col];
403- bool is_load_pdi = sm[1 ].matched ; // if load_pdi
404-
405- // Extract the @label at argument index 1 (<id>, @<label>).
406- // Compiled once (static); regex_search finds the first ", @<label>" token.
407- static const regex LOAD_LABEL_RE (" ,\\ s*(@[a-zA-Z0-9_]+)" );
408- std::string label_arg;
409- smatch lm;
410- if (regex_search (arg_str, lm, LOAD_LABEL_RE))
411- label_arg = lm[1 ].str ();
412- // Enforce uniqueness of the PDI / core-elf address within this column.
413- if (!label_arg.empty ()) {
414- bool inserted = is_load_pdi
415- ? cdata.try_add_load_pdi_label (label_arg)
416- : cdata.try_add_load_cores_label (label_arg);
417- if (!inserted)
418- throw error (error::error_code::invalid_asm,
419- op_name + " location '" + label_arg + " ' is not unique in column " +
420- std::to_string (col) + " ; each " + op_name +
421- " in a control code elf must use a distinct address\n " );
422- }
423- if (is_load_pdi)
424- cdata.increment_load_pdi_count ();
425- else
426- cdata.increment_load_cores_count ();
427- } else if (sm[2 ].matched ) { // load_cores_cp
428- m_col[col].increment_load_cores_cp_count ();
429- } else {
430- // start_cond_job_preempt must only appear after at least one preempt in
431- // the same column (cert uses the preceding preempt point for recovery).
432- auto col_it = m_col.find (col);
433- if (col_it == m_col.end () || col_it->second .get_preempt_count () == 0 )
434- throw error (error::error_code::invalid_asm,
435- " start_cond_job_preempt found in column " + std::to_string (col) +
436- " before any preempt opcode; it must follow a preempt opcode\n " );
437- col_it->second .increment_start_cond_job_preempt_count ();
438- }
440+ handle_load_or_preempt_cond (op_name, arg_str, sm);
439441 }
440442 insert_col_asmdata (std::make_shared<asm_data>(operation (op_name, arg_str), operation_type::op,
441443 code_section::unknown, 0 , (uint32_t )-1 , linenumber,
0 commit comments