diff --git a/simpler_setup/toolchain.py b/simpler_setup/toolchain.py index e887b4ce7f..9d2eb25cbb 100644 --- a/simpler_setup/toolchain.py +++ b/simpler_setup/toolchain.py @@ -167,7 +167,7 @@ def get_compile_flags(self, core_type: str = "aiv", **kwargs) -> list[str]: else: raise ValueError(f"Unknown platform: {self.platform}. Supported: a2a3, a2a3sim, a5, a5sim") - return [ + flags = [ "-c", "-O3", "-g", @@ -189,6 +189,17 @@ def get_compile_flags(self, core_type: str = "aiv", **kwargs) -> list[str]: "-cce-aicore-dcci-insert-for-scalar=false", "-DMEMORY_BASE", ] + # A5: VF fusion can reorder same-V ops across expand/abs/sinkhorn and + # break DeepSeek-V4 correctness; keep it off by default for a5/a5sim. + # + # Scope: per-kernel incore compilation only. Do NOT mirror this into the + # platform AICore build (src/a5/platform/onboard/aicore/CMakeLists.txt) -- + # its only VF construct is the __simd_vf__ meta anchor in simt_anchor.h, + # whose fusion behaviour is what makes bisheng tag the entry + # SIMD_SIMT_MIX_VF(4); disabling fusion there breaks that classification. + if self.platform in ("a5", "a5sim"): + flags.append("--cce-simd-vf-fusion=false") + return flags def get_cmake_args(self) -> list[str]: return [ diff --git a/tests/ut/py/test_toolchain.py b/tests/ut/py/test_toolchain.py index 1bd9a432b1..b79af7bbd5 100644 --- a/tests/ut/py/test_toolchain.py +++ b/tests/ut/py/test_toolchain.py @@ -185,3 +185,41 @@ def test_path_with_spaces_is_quoted(self, monkeypatch): flags_arg = next(a for a in args if a.startswith("-DCMAKE_C_FLAGS=")) # shlex.join must re-quote the path so CMake re-parses it as one token. assert "'/opt/my compilers/compat'" in flags_arg + + +class TestCCECToolchainCompileFlags: + """A5 must disable SIMD VF fusion; A2/A3 must be left untouched. + + VF fusion can reorder same-V vector ops (expand/abs/sinkhorn) and silently + break DeepSeek-V4 numerics on Ascend950. The failure mode is a wrong result + rather than a compile error, so guard the flag explicitly. + """ + + @pytest.fixture + def ccec(self, monkeypatch): + """Build a CCECToolchain without needing a real CANN install.""" + + def _make(platform): + # Constructor probes ASCEND_HOME_PATH and the ccec/ld.lld binaries. + monkeypatch.setattr( + "simpler_setup.toolchain.env_manager.get", lambda _k: "/nonexistent/ascend" + ) + monkeypatch.setattr("simpler_setup.toolchain.os.path.isfile", lambda _p: True) + from simpler_setup.toolchain import CCECToolchain # noqa: PLC0415 + + return CCECToolchain(platform) + + return _make + + @pytest.mark.parametrize("platform", ["a5", "a5sim"]) + def test_a5_disables_vf_fusion(self, ccec, platform): + assert "--cce-simd-vf-fusion=false" in ccec(platform).get_compile_flags() + + @pytest.mark.parametrize("platform", ["a2a3", "a2a3sim"]) + def test_a2a3_keeps_vf_fusion(self, ccec, platform): + assert "--cce-simd-vf-fusion=false" not in ccec(platform).get_compile_flags() + + def test_a5_flag_applies_to_both_core_types(self, ccec): + toolchain = ccec("a5") + for core_type in ("aiv", "aic"): + assert "--cce-simd-vf-fusion=false" in toolchain.get_compile_flags(core_type)