Skip to content
This repository was archived by the owner on Dec 7, 2024. It is now read-only.
This repository was archived by the owner on Dec 7, 2024. It is now read-only.

Clarify interactions with runtime vtable dispatch #12

@rcombs

Description

@rcombs

I'd like to provide some context on this proposal from the perspective of open-source multimedia software (ffmpeg, x264, libass…): Usually, rather than using gcc/clang-style function multiversioning, we have multiple implementations of a given function with separate names (e.g. my_function_c, my_function_sse2, my_function_avx2, etc). These symbols exist in all builds for the relevant architecture(s) (here, x86/x86_64), and a runtime check determines which one to insert into a vtable (e.g. a function pointer for my_function would be populated with &my_function_sse2 if the SSE2 check passes but the AVX2 check fails).

Having all variants available at runtime also means that we can override the dispatch if needed (e.g. disable the AVX2 version at runtime to benchmark the SSE2 version, and call the C version to have a baseline to compare to during unit tests). It's also higher-performance than using a per-function runtime dispatcher symbol, since we only have to do the check once, and can eliminate the extra indirection layer afterwards.

The upshot of all this is:

  • Our use-case doesn't require any variation in function signatures for the same symbol between extensions
  • We also don't need any variation in data symbols or data types (if we do need any per-extension data, we just create a separate data symbol for each variant)
  • We do need the ability to have a symbol that uses an extension, but can still be referenced from a (non-taken) branch in a function that isn't versioned
  • From a compiler/linker perspective, the plain-C version of the function and the extended versions are generally in separate source files (and often in separate languages; the functions using ISA extensions are often implemented directly in the relevant assembly dialect, rather than C[++]-with-intrinsics).

It's not entirely clear how this ends up working from a code perspective in this proposal:

  • Can we just expose the symbols within an appropriate feature block, and have the symbols just not exist at runtime (so the function pointer would point to e.g. NULL, but we'd never call it?)
  • Can we have the symbols always exist at runtime, with their contents within a feature block, otherwise being no-op stubs?
  • With the concept proposed in Alternative sections #10, could we have two versions of the function, one real and one no-op stub (with the stub potentially being generated automatically by tooling)?
  • How do any of these options interact with any language? If we write the extended versions of functions in directly the .wat text format, what does that look like in code? What if we instead use C or AssemblyScript? Some of these questions might ultimately be up to compiler vendors to answer, but hopefully we can at least have some general ideas.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions