Skip to content

-fp-mode precise does not disable FMA contraction on CUDA/NVRTC — PTX is byte-identical to default #12799

Description

@jvepsalainen-nv

Target: Slang, source/compiler-core/slang-nvrtc-compiler.cpp (the empty
case FloatingPointMode::Precise: at ~:1209).

Summary

-fp-mode precise is documented as "Disable optimization that could change the
output of floating-point computations". FMA contraction changes results — it keeps
the intermediate product at higher precision, so a*b+c does not round the same
way as a separate multiply and add. NVRTC contracts by default (--fmad=true),
and Slang's Precise case for NVRTC is empty, so nothing suppresses it.

This is the same defect, on a different target, that #11933 reported and #11935
fixed for SPIR-V by emitting NoContraction.

Reproducer

fma.slang:

RWStructuredBuffer<float> gOut;
[shader("compute")][numthreads(1,1,1)]
void computeMain(uint3 tid : SV_DispatchThreadID)
{
    float a = gOut[0], b = gOut[1], c = gOut[2];
    gOut[3] = a * b + c;
}
slangc fma.slang -target ptx -entry computeMain -stage compute -o default.ptx
slangc fma.slang -target ptx -entry computeMain -stage compute -fp-mode precise -o precise.ptx

Evidence

invocation emitted PTX for a * b + c
default fma.rn.f32 %f4, %f1, %f2, %f3;
-fp-mode precise fma.rn.f32 %f4, %f1, %f2, %f3;byte-identical to default
-fp-mode precise -Xnvrtc --fmad=false mul.rn.f32 + add.rn.f32

cmp reports the default and precise PTX files as identical, so precise
currently has no effect whatsoever on this path.

Suggested fix

Pass --fmad=false from the Precise case in slang-nvrtc-compiler.cpp:

case FloatingPointMode::Precise:
    {
        cmdLine.addArg("--fmad=false");
        break;
    }

--fmad=false alone is the complete fix — verified. NVRTC's other
precision-relevant defaults are already at their precise settings
(--prec-div=true, --prec-sqrt=true, --ftz=false), so passing all four
produces byte-identical PTX to passing only --fmad=false (checked on a shader
exercising multiply-add, divide, sqrt and transcendentals). No other flag needs to
be added.

Why this is the right layer

The contraction decision belongs to the downstream compiler, and Slang already owns
the translation from -fp-mode to downstream flags for every other backend
(-Gis for DXC, D3DCOMPILE_IEEE_STRICTNESS for FXC, /fp:precise for MSVC).
The NVRTC case is simply unimplemented rather than deliberately empty; there is no
IR- or emit-level work required, and no Slang-side representation question.

Limits of what was measured

  • PTX inspection only. No runtime numerics were compared, so the magnitude of the
    accuracy difference contraction causes on real shaders is not quantified here —
    only that the emitted instruction changes.
  • Performance impact of --fmad=false was not measured. Disabling contraction will
    cost some throughput; that is the expected and intended price of precise, but a
    reviewer may want a number before enabling it by default.
  • Only the CUDA/NVRTC path was checked. Metal, WGSL and GLSL emit identical source
    under both modes
    , so whatever their downstream compilers do about contraction is
    likewise uncontrolled by -fp-mode — worth a separate look, not covered here.
  • The reproducer is the six-line fma.slang quoted above.

Related

Found while establishing what -fp-mode actually switches on each target; the
verification that --fmad=false alone suffices was done by comparing PTX with all
four precision flags against PTX with only that one.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

reproducedProvided instructions confirmed to reproduce the issue

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions