Skip to content

Derive intrinsic PTX floors through the existing target vocabulary owner #1213

Closed

Description

@almightychang

What problem does this solve?

minimum_ptx is written in both the intrinsic overlay and Rust recipe. Validation only compares the copies (validation). Nothing downstream checks it. ptx_isa_requirement_for_floor returns Default for every encoded floor <= 60 (codegen), so a wrong floor through PTX 6.0 changes only the generated reference.

The #1138 review named this shape:

The recorded libNVVM evidence was a hand-built fixture rather than real lowering output, which is why nothing caught it.

Where minimum_sm is a hardware requirement, the effective floor can be derived instead of copied.

Proposed API / behavior

AS-IS                              TO-BE

recipe  "1.0" --.                  minimum_sm
overlay "1.0" --+ ensure!(equal)       |
                |                      v
                | no external      TargetPtxFloor   (in-tree)
                | floor input          |
                v                      v
          catalog.json            max(target default,
             /      \                 instruction requirement)
    encoded<=60   verbatim             |
        |            |                 v
     Default     "1.0" in         catalog.json
 1.0 = ... = 6.0  reference

TargetPtxFloor / RECORDED_PTX_FLOORS already store the per-target floor (cuda-target-spec). #1105 introduced them, and #1184 routed target parsing and PTX spelling through them. Intrinsic minimum_ptx still does not use them.

# before
minimum_ptx = "1.0"
minimum_sm  = "sm_20"

# after — floor derived as PTX 2.0
minimum_sm  = "sm_20"

This rule applies only when minimum_sm is a hardware requirement. Legacy rows such as sm_20 -> 2.0 would be recorded as pinned ISA history. Instructions needing more than their target floor would keep a written value.

Alternatives considered

Correcting each floor separately leaves the self-check unchanged. #519 fixed trap/breakpoint/pmevent; the 1.0 / 3.2 / sm_20 shape remains in counted bar.arrive (overlay), from merged #721.

Additional context

Of 130 explicit overlay routes, 104 meet or exceed the target floor. The 26 below are lib_nvvm at sm_75: 16 at PTX 6.0, 7 at 4.2, 2 at 1.0, and 1 at 6.2. Here sm_75 records evidence collection, not instruction hardware. The #519 thread explains:

backend-codegen evidence must sit exactly at the hardware floor and CUDA 13 cannot probe older targets; the PTX floor alone was the blocker.

minimum_sm has two route meanings. That distinction must be resolved before or with floor derivation; no fix is proposed here.

Does anything depend on the per-entry declaration that I have not seen? Should this cover merged declarations or new entries only? #1189 records a second consumer left outside the same owner.

#1212 opened this as a PR before any discussion and was closed for that; this issue is that discussion.

Activity

  1. nihalpasham commented on Sep 3, 2026

    @nihalpasham
    Collaborator

    Where I stand: the defect is real but small, and it is catalog hygiene, not a codegen gap. Every target cuda-oxide emits for is sm_70+ and llc prints that target's default .version (7.0 at sm_80); a floor only reaches the PTX when it is above that default. A wrong floor at or below 6.0 changes the reference and the generated tables, not any kernel.

    Deriving from RECORDED_PTX_FLOORS is out. Its doc says the entries are LLVM 23 defaults, "not backend-independent CUDA facts", and the ISA keeps adding instructions to an existing SM later:

    sm_80 first named in PTX 7.0      sm_90 first named in PTX 7.8
      cvt.f32.bf16       7.1            cp.async.bulk.tensor  8.0
      cvt.bf16.*         7.8            fence.acquire         8.6
    derived = lower bound only; the written floor stays
    

    The llvm_nvptx route already holds what derivation would give: its floor must equal the .version LLVM emitted at the evidence target (3.2 at sm_20), checked in resolve/evidence.rs.

    Your two questions:

    • Yes, the per-entry value is load-bearing. validate_selected_target_predicates requires it to equal LLVM's getPTXVersion() >= N gate when the imported record has one (the counted barrier records have none, which is why 1.0 passed), evidence validation compares against it, and codegen falls back to it when a backend has no route.
    • A lower-bound check (floor >= the PTX version that first named minimum_sm) can cover every entry, but know its yield. Today it flags 39 places, none a hardware floor: 32 libNVVM routes at sm_75 (the target the CUDA 13 proof was compiled for; the route field is documented as the backend-profile floor, leave it) and 7 packed f16x2 ops at sm_70 (my oldest supported GPU; native_minimum_sm = 53 holds the hardware fact, compare against that). It would not have caught bar.arrive either: targets = "all" and no minimum_sm, so only the ISA text catches that one.

    What I would take as one PR:

    Bar for reference: https://discord.com/channels/1515530041767759993/1515561621156663487/1540970771323551775

    Sequencing: this one comes after #1211 and #1189 (one series at a time; all three touch the target vocabulary or the catalog artifacts). Does that scope work for you?

  2. nihalpasham commented on Sep 23, 2026

    @nihalpasham
    Collaborator

    Merged #1261 after #1256. This completes the scope we agreed here: counted barrier floors are corrected to PTX 2.0 / sm_20, authored hardware floors are checked against the separate SM-introduction table, and the negative/control tests and regenerated catalog artifacts are in place. Closing this as completed.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions