|
12 | 12 | from testgen.data.test_chunk import TestChunk |
13 | 13 | from testgen.formatters import format_instruction |
14 | 14 | from testgen.formatters.params import generate_random_params |
| 15 | +from testgen.formatters.registry import get_instr_type_config |
15 | 16 |
|
16 | 17 |
|
17 | | -@add_coverpoint_generator("cp_gpr_hazard", "cp_fpr_hazard") |
| 18 | +@add_coverpoint_generator("cp_gpr_hazard") |
18 | 19 | def make_cp_gpr_hazard(instr_name: str, instr_type: str, coverpoint: str, test_data: TestData) -> list[TestChunk]: |
19 | 20 | """Generate tests for register hazards (RAW, WAW, WAR).""" |
20 | 21 | tc = test_data.begin_test_chunk() |
@@ -85,3 +86,80 @@ def make_cp_gpr_hazard(instr_name: str, instr_type: str, coverpoint: str, test_d |
85 | 86 |
|
86 | 87 | tc.code = "\n".join(test_lines) |
87 | 88 | return [test_data.end_test_chunk()] |
| 89 | + |
| 90 | + |
| 91 | +def _fp_producer_for(instr_name: str) -> tuple[str, str]: |
| 92 | + """Pick an FP producer instruction whose precision matches the instruction under test.""" |
| 93 | + if instr_name.endswith(".d"): |
| 94 | + return "fadd.d", "FR" |
| 95 | + if instr_name.endswith(".h"): |
| 96 | + return "fadd.h", "FR" |
| 97 | + if instr_name.endswith(".q"): |
| 98 | + return "fadd.q", "FR" |
| 99 | + return "fadd.s", "FR" |
| 100 | + |
| 101 | + |
| 102 | +@add_coverpoint_generator("cp_fpr_hazard") |
| 103 | +def make_cp_fpr_hazard(instr_name: str, instr_type: str, coverpoint: str, test_data: TestData) -> list[TestChunk]: |
| 104 | + """Generate tests for FP register hazards (RAW, WAW, WAR).""" |
| 105 | + tc = test_data.begin_test_chunk() |
| 106 | + parts = coverpoint.split("_") |
| 107 | + haz_class = parts[-1] if len(parts) > 3 and parts[-1] in ["r", "w", "rw"] else "rw" |
| 108 | + |
| 109 | + test_lines: list[str] = [] |
| 110 | + hazard_types: list[str] = ["nohaz"] |
| 111 | + if "r" in haz_class: |
| 112 | + hazard_types.append("raw") |
| 113 | + if "w" in haz_class: |
| 114 | + hazard_types.extend(["waw", "war"]) |
| 115 | + |
| 116 | + producer_instr, producer_type = _fp_producer_for(instr_name) |
| 117 | + consumer_required = get_instr_type_config(instr_type).required_params or set() |
| 118 | + consumer_fp_srcs = [f for f in ("fs1", "fs2", "fs3") if f in consumer_required] |
| 119 | + consumer_has_fd = "fd" in consumer_required |
| 120 | + |
| 121 | + for haz_type in hazard_types: |
| 122 | + for i in range(2): |
| 123 | + params_a = generate_random_params(test_data, producer_type) |
| 124 | + assert params_a.fs1 is not None and params_a.fs2 is not None and params_a.fd is not None |
| 125 | + |
| 126 | + if haz_type == "raw": |
| 127 | + if consumer_fp_srcs: |
| 128 | + src_field = consumer_fp_srcs[i % len(consumer_fp_srcs)] |
| 129 | + params_b = generate_random_params(test_data, instr_type, **{src_field: params_a.fd}) |
| 130 | + else: |
| 131 | + # Consumer reads no FP source register — skip this iteration's hazard |
| 132 | + # rather than emit a no-op test that pretends to cover RAW. |
| 133 | + continue |
| 134 | + elif haz_type == "waw": |
| 135 | + if not consumer_has_fd: |
| 136 | + continue |
| 137 | + params_b = generate_random_params(test_data, instr_type, fd=params_a.fd) |
| 138 | + elif haz_type == "war": |
| 139 | + if not consumer_has_fd: |
| 140 | + continue |
| 141 | + src_of_a = params_a.fs1 if i % 2 == 0 else params_a.fs2 |
| 142 | + params_b = generate_random_params(test_data, instr_type, fd=src_of_a) |
| 143 | + elif haz_type == "nohaz": |
| 144 | + params_b = generate_random_params(test_data, instr_type) |
| 145 | + else: |
| 146 | + raise ValueError(f"Unknown hazard type: {haz_type}") |
| 147 | + |
| 148 | + test_lines.append(f"\n# Testcase cp_fpr_hazard {haz_type} test") |
| 149 | + setup1, test1, check1 = format_instruction(producer_instr, producer_type, test_data, params_a) |
| 150 | + setup2, test2, check2 = format_instruction(instr_name, instr_type, test_data, params_b) |
| 151 | + |
| 152 | + test_lines.extend([setup1, setup2]) |
| 153 | + test_lines.extend([test1, test2]) |
| 154 | + if haz_type == "waw": |
| 155 | + test_lines.append(check2) |
| 156 | + else: |
| 157 | + test_lines.extend([check1, check2]) |
| 158 | + |
| 159 | + test_data.float_regs.return_registers(params_a.used_float_regs) |
| 160 | + test_data.float_regs.return_registers(params_b.used_float_regs) |
| 161 | + test_data.int_regs.return_registers(params_a.used_int_regs) |
| 162 | + test_data.int_regs.return_registers(params_b.used_int_regs) |
| 163 | + |
| 164 | + tc.code = "\n".join(test_lines) |
| 165 | + return [test_data.end_test_chunk()] |
0 commit comments