Skip to content

Releases: halide/Halide

v22.0.0

Choose a tag to compare

@alexreinking alexreinking released this 27 Oct 20:55
4d97d89

Halide 22.0.0

Highlights

  • New scheduling directives: eager_inline(), change_type(), hoist_invariants(), split_storage, stream_loads/stream_stores, aligned_split, a GPU max-register cap, and Pipeline::sever().
  • New profiler with counters, recompute statistics and automatic performance warnings.
  • Halidoscope, a new interactive trace and profiling visualizer.
  • Struct types are now supported in the language.
  • MultiRamp, a better representation of affine vectors (nested ramps), with simplifier and codegen work built on it.
  • ARM: SVE2 and SME2 streaming-SVE support, plus new Neon patterns.
  • Docs and tutorials moved to Sphinx, and all C++ tutorials were ported to Python.
  • Contributor tooling: pre-commit checks, a fuzz-test framework, and Claude skills for scheduling and simplifier rules.

Breaking changes and deprecations

Build and platform

  • Dropped Python 3.9 (#8830). Python 3.12 is now required, and the bindings target the stable ABI via nanobind (#9618).
  • Dropped LLVM 20 (#8998). LLVM 21, 22 and 23 are supported.
  • Removed the Halide_BUNDLE_STATIC feature (#8801).
  • Removed FetchContent from the compiler, hannk and onnx (#8962, #9001, #9005). Dependencies now come from vcpkg or the system.
  • The autoschedulers now have their own CMake package (#9292).
  • Fixed the Halide/HalideHelpers CMake package dependency inversion (#9234).
  • Python packages are split, and there is a standalone AOT runtime (#9272).
  • CUDA: per-capability libdevice bitcode is replaced by a unified libdevice.10.bc (#9226).

C++ API and ABI

  • ABI: halide_type_t no longer has a lanes field. It is now {code, bits, reserved}, and halide_buffer_t keeps its size and layout. Halide::Type is a separate language-level type that must be explicitly converted with as_abi (#9205).
  • For loops now store an inclusive min/max instead of min/extent (#8858).
  • Removed the confusing lanes parameter from Handle. Use .with_lanes() for vectors of handles (#9198).
  • The IRMutator/IRVisitor entry point is now operator(). Custom lowering passes that call custom mutators or visitors may need updating (#9023).
  • Func::in() and Func::clone_in() are now transitive (#9117) and eager (#9277).
  • Removed the CompilerLogger (#9269).
  • Removed the ability to iterate over a Scope (#9594).
  • Renamed CodeGen_Posix to CodeGen_CPU (#9097).
  • Deprecated Target::OS::OSX in favor of MacOS (#9451). The "osx" target string is still accepted, with a warning.
  • Deprecated TailStrategy::Predicate in favor of GuardWithIf (#9446).

Python

  • The axis convention between hl.Buffer and the Python buffer protocol is now consistent across the bindings, PyCallable and the Python extension (#8953, #8931).

Tests

  • Removed test/error/. Its tests are now correctness tests (#9463).
  • Moved the internal self-tests out of libHalide into test/correctness (#9276).

New features

Scheduling

  • eager_inline() (#9256): g.eager_inline({f1, ..., fN}) immediately and destructively inlines the bodies of the listed Funcs into g, in order, so direct calls between them are inlined too.
  • change_type() (#9257): replaces a Func's computation type with another (e.g. float → int32) by computing in the new type and casting back. It uses value-bounds analysis to prove no values change, adds runtime asserts when a reduction might be long enough to overflow, and rewrites products into widening intrinsics where possible. Unsafe float product accumulation can also be fused into an fma (#9578).
  • hoist_invariants() (#9190): like rfactor, but pulls factors that are invariant over a reduction out of the accumulation when the operators obey a distributive (semiring) law. Multi-term reductions are split into one intermediate per term, returned as a FuncVec (#9419). This lets quantized kernels be written naively and scheduled into efficient ones.
  • split_storage (#9460): splits a storage dimension into inner and outer dimensions to express swizzled memory layouts. This helps feed dot-product instructions and matrix-multiply accelerators, and avoids shared-memory bank conflicts. It works on Halide-allocated intermediates only and doesn't compose with fold_storage.
  • stream_loads and stream_stores (#9207): request non-temporal accesses for a stage's loads (all of them, or from named Funcs) and stores, with a fence after streamed stores. On an Apple M3 this fully recovers memcpy performance.
  • Aligned splits (#9409, #9501): split takes an optional offset so the first inner-loop iteration can be aligned to a boundary other than the Func's min. Inner loops now always run from 0 to the factor, which helps constant-bounds analysis.
  • GPU register cap (#9389): a scheduling directive replaces the HL_CUDA_MAX_REGISTERS environment variable for limiting registers per thread. It only affects CUDA.
  • Pipeline::sever() (#9484): replaces a set of Funcs with ImageParam inputs and returns a second pipeline that computes them. Work that would otherwise be redone on every realize(), such as quantizing static weights, becomes ordinary input data computed once.
  • Merged bounds directives (#9410): repeated bound/align_bounds/align_extent calls on the same Var now combine into one entry, so call order no longer affects bounds inference. Overwriting a previously set field emits a warning.
  • Stricter checks: Stage::fuse rejects fusions that illegally reorder dimensions, such as swapping inner and outer RVars (#9186). An explicit fold_storage that the compiler can't apply is now an error instead of being silently ignored (#9201).
  • Name collisions (#9145, #9210): Generator Input<>s and named scalar Params now reserve their names so later Funcs get unique names. If a Func was declared first, you get a clear error instead of a crash in lowering.

Language and IR

  • Struct types (#9416): Type::Struct defines record types with named, optionally array-valued fields, e.g. Type::Struct({{"d", Float(16)}, {"qs", Int(8), 32}}). Inputs and outputs can use packed wire formats, such as blocks of quantized weights, directly, and you read fields with field(x(b), "d"). Records are not meant for efficient computation: you extract fields first.
  • fma intrinsic (#8900): the equivalent of std::fma, for when you need a real fused multiply-add inside a strict_float context, such as for bit-exact transcendentals.
  • round_half_away (#9573): rounds ties away from zero like C's round(), while round() keeps rounding ties to even. It maps to native instructions such as frinta and fcvtas on AArch64, and is exposed in Python as hl.round_half_away.
  • fixed_to_float intrinsic (#9572): float(x) * 2^-k is recognized as a fixed-point to float conversion, which becomes a single scvtf/ucvtf on ARM. It saves a multiply per vector when dequantizing fixed-point data, and is lowered back to cast-and-multiply elsewhere.
  • Better widening (#9195): FindIntrinsics now handles 8-bit integer to float32 widening multiplies, and concat_bits/extract_bits have lowerings for the C and Vulkan backends.
  • MultiRamp (#9113): represents a vector whose lanes are an affine function of a multi-dimensional index, i.e. sums of compatible nested ramps. Multidimensional SIMD targets (and matrix multiplies built from nested vectorized loops) used to scalarize easily. Related work includes the AMX fix (#9122), dense load/store canonicalization (#9535), alignment-aware div/mod (#9536), and load recognition (#9261).
  • Front-end helpers:
    • FuncRef::type() is available, which matters mostly for the Python bindings (#8895).
    • You can get the Vars that have splits applied, for writing generic schedules (#8889).
    • likely, strict_float, require, print and similar non-arithmetic helpers now accept Tuples (#9425).
  • Compiler-developer APIs:
    • mutate_with/visit_with let you write mutators and visitors from lambdas that can capture local state (#8877, #8893).
    • Load::make(type, name, index) and Store::make(name, value, index) short forms are available (#9247).
    • IR nodes have remake methods that copy a node with new children (#9245).
    • Block::to_vector unpacks a Stmt into its non-Block statements (#9384).

Profiling, tracing and debugging

  • New profiler (#9157, #9164, #9344, #9368): the report is organized by loop nesting, with allocations and device copies as their own entries. Cheap runtime counters feed recompute ratios and a set of performance warnings about likely schedule problems, which are especially useful to LLMs scheduling Halide code. Inlined Funcs are counted but can't be sampled.
  • Profiler control (#9423, #9492): JIT code can access profiler state programmatically. halide_profiler_set_json_output sets the JSON path from code, and ProfilerScope accepts a Callable so repeated calls accumulate statistics.
  • Halidoscope (#9356, #9413): an interactive tool for exploring traces and profiler output, with a trace view and a profile view. It complements HalideTraceViz, which shows how a schedule executes but not how much time it takes, and installs via pip.
  • Tracing:
    • Tasks that run in parallel now emit trace events, using a more compact packet format (#9192).
    • trace_bounds_required events report the region bounds inference requires of each Func, so tools can tell required values from ones computed outside that region (#9506).
    • Produce/consume events now sit inside the node body, so a skipped stage emits no unmatched begin event (#9505).
    • JITSharedRuntime::set_trace_file redirects JIT trace output between realizations (#9516).
  • HL_DEBUG_CODEGEN:
    • Tag-based filtering selects a specific debug() call witho...
Read more

v21.0.0

Choose a tag to compare

@alexreinking alexreinking released this 16 Sep 19:26
b629c80

Release highlights

We have deliberately skipped version 20.0.0 to align with the LLVM version we are now using. Note that LLVM 21.1.1 or higher is required as LLVM 21.1.0 has a major bug in the NVPTX backend.

Major changes

  • The rfactor scheduling directive was rewritten and enhanced. It is now compatible with autoschedulers.
  • The Mullapudi2016 autoscheduler now supports experimental GPU scheduling.
  • The Python bindings have been substantially improved, with many missing bindings filled in.
  • HL_DEBUG_CODEGEN gained a new filtering mode. Debug levels can now be set on a per-file/per-function basis.
  • Support was added for AMD Zen5 and the iOS Simulator.
  • The strict_float feature has been reimplemented and should be much more reliable.
  • Lots of bugfixes, performance improvements, and build system improvements. We spent a lot of time fixing issues with our testing infrastructure and are looking forward to implementing a more stable contribution experience going forward.

Deprecations

  • LLVM 19 and below are no longer supported, in keeping with our support policy.
  • Halide_BUNDLE_STATIC will be removed in the next release. If you are using it, please migrate to the shared library instead.
  • Support for Python 3.8 has been dropped.

Changelog

Scheduling

  • The rfactor scheduling directive was rewritten and enhanced.
  • The Mullapudi2016 autoscheduler now supports experimental GPU scheduling.
    • GPU autoscheduling with Mullapudi2016: the reference implementation by @antonysigma in #7787
    • Mullapudi2016-GPU: Reorder to avoid for-loops to be sandwiched between gpu_blocks. by @antonysigma in #8647
    • Enable experimental Mullapudi2016 GPU scheduler for test-bench by @antonysigma in #8650
    • Highlight Metal GPU code in stmt_html by @antonysigma in #8659
    • Always ensure gpu_threads count >= warp size of 32 by @antonysigma in #8656
  • Fix incorrect natural vector size on Zen4 by @abadams in #8570
  • Make it an error to use a device extern stage without target support by @abadams in #8794
  • Add support for adding tuple outputs in the configure() method by @abadams in #8649

Python

Debugging

CodeGen

  • Mark our PTX kernels as kernels, to stop them from being stripped by @abadams in #8571
  • Math functions renaming table for GPU backends to support vectorized evaluation of math functions. by @mcourteaux in #8595
  • Apply version constraints to iOS objects by @alexreinking in #8546
  • Redirect bitwise ops to logical ops in case the arguments are bool. by @mcourteaux in #8597
  • scalarize select condition for LLVM where possible by @abadams in #8575
  • Add missing addition simplifier rules by @abadams in #8630
  • Bounds and alignment analysis through bitwise ops by @abadams in #8574
  • Make the vld2 pattern more obviously profitable by @abadams in #8765
  • Fix vector shuffle for Vulkan CodeGen by @derek-gerstmann in #8621
  • Suppress warning on Windows for duplicate constant symbols. by @mcourteaux in #8555
  • Use lossless_cast for saturating casts from unsigned to signed on x86 by @abadams in #8527
  • AMD Zen5 support by @changhoon-sung in #8612

Compiler

  • Rework strict_float to use individual op intrinsics instead by @abadams in #8641
  • Don't cache mutations of Exprs that have only one reference to them by @abadams in #8518
  • Only use the nodes-visited set for nodes with multiple refs by @abadams in #8547
  • In graph_equal(), call the correct implementation for comparing equalities between statements and expressions by @BachiLi in #8611

Runtime

  • Support copying the overlapping region from one buffer to another. by @mcourteaux in #8463
  • Add (iOS) simulator target feature. by @alexreinking in #8623
  • Opt out of JIT exceptions by @abadams in #8615
  • Experimental: support removing unused runtime functions via
    HL_RUNTIME_DROP_FUNCS environment variable.

Apps

Documentation

Bugfixes

Testing / CI

Read more

v19.0.0

Choose a tag to compare

@alexreinking alexreinking released this 17 Dec 02:03

Major improvements

  • Halide is now available for both C++ and Python usage via Pip. Try pip install halide today!
  • The Vulkan backend has matured substantially.
  • The HTML "conceptual statement" output now supports dark mode viewing.
  • For developers, CMake 3.28 is now required and we no longer require an internet connection during the build.
  • Thread pool improvements mean that workloads that do a small number of small tasks in parallel (e.g. a cheap operation applied to a small image) are up to 3x faster. If you have schedules that do not use parallelism for small inputs because you found it didn't provide any speedup, you may want to re-benchmark.
  • You can now query properties of the compiled-for target as Exprs, simplifying helper code that wants to do different things depending on the target architecture. Example: f(x) = select(target_arch_is(Target::ARM), 3, 7). Helpers include target_arch_is, target_os_is, target_has_feature, target_bits, and target_natural_vector_size. These are resolved to constants at compile-time and simplified away. Use with care, as this (intentionally) results in different behavior on different platforms.

Breaking changes

  • We now distribute libGenGen.a rather than GenGen.cpp.
    • Downstream users should link to this library with /WHOLEARCHIVE: or -Wl,--whole-archive rather than build GenGen.cpp themselves.
    • Users of the CMake package should be unaffected.
  • In keeping with our LLVM support policy, support for LLVM 16 has been removed.
  • We no longer use the le64/le32 generic targets for compiling runtime modules to LLVM. These targets were removed in LLVM upstream.

What's Changed

Apps and tests

Autoschedulers

  • Consider all Exprs a func uses, not just the RHS, in Li2018 by @abadams in #8326

Build system

CodeGen

Debugging

Documentation

Frontend

Hardware backends

LLVM

Python

Runtime

  • Fix profiler to report time spent on GPU kernels again instead of on 'wait for parallel tasks'. by @mcourteaux in #8453
  • Don't spin on the main mutex while waiting for new work by @abadams in #8433

Minor bugfixes / other cleanup

Read more

Halide v18.0.0

Choose a tag to compare

@steven-johnson steven-johnson released this 17 Jul 20:31
8c651b4

Changes Of Note since Halide 17

  • Ring-buffering now supported in schedules (Func::ring_buffer()). This is distinct from fold_storage in that it folds across time (the loop variables) rather than folding across space (the pure vars of the Func).
  • Fixed a longstanding bug in lossless_cast()
  • Lots of fixes for Vulkan backend
  • OpenGLCompute is no longer supported
  • Added support for ARM SVE2
  • Added (basic) support for Intel APX and AVX10
  • Added support for Hexagon HVX v68
  • Added support for numpy's .npy format to .debug_to_file() and the code in halide_image_io.h
  • Python bindings now support bfloat and int64 properly
  • Hacky code that auto-named Funcs, Vars etc via DWARF introspection was removed
  • The profiler was revamped to behave better when multiple Halide pipelines are in flight at the same time.
  • Numerous lowering passes were sped up, resulting in faster compilation for large pipelines. However, time spent in LLVM is still the long pole for most pipelines.
  • Fixed-point instruction selection has been improved via tracking constant integer bounds of expressions.
  • Adds feature detection for ARM CPUs to the runtime library and to the host target feature computation. Supports Windows, macOS,
    Linux, iOS, and Android.

Deprecations / Removals

  • tuple_select() has been removed in favor of overloads to select().
  • Various fixed-point operators have been removed from the Halide::Internal namespace and are now in the public Halide namespace.

What's Changed

Read more

Halide v17.0.2

Choose a tag to compare

@steven-johnson steven-johnson released this 25 Jun 15:30
b2e6d2a

What's Changed

  • Backport a fix for the simpler bug in lossless_cast by @abadams in #8264
  • Fix Vulkan SIMT mappings for GPU loop vars; avoid formatting the GPU kernel to a string for Vulkan (since it's binary SPIR-V needs to remain intact). @derek-gerstmann in #8270

Full Changelog: v17.0.1...v17.0.2

Halide v17.0.1

Choose a tag to compare

@steven-johnson steven-johnson released this 20 Feb 19:50
5254117

What's Changed

  • Changes to make WebGPU code compliant with recent versions of Emscripten (#8106)
  • Fix rfactor adding too many pure loops (#8107)
  • Forward the partition methods from generator outputs (#8090)
  • Fix reduce_expr_modulo of vector in Solve.cpp (#8107)

Full Changelog: v17.0.0...v17.0.1

Halide v17.0.0

Choose a tag to compare

@steven-johnson steven-johnson released this 02 Feb 00:30

Changes Of Note

  • ParamMap has been removed entirely from the public API. All users of ParamMap should migrate to Callable instead.
  • Halide::Parameter has been moved to the public Halide API (it was formerly "internal" and not intended for public use).
  • New scheduling primitives:
    • Func::partition() and friends: Set the loop partition policy, which controls how/whether a loop is split into three loops (prologue/steady-state/epilogue). Loop partitioning can be useful to optimize boundary conditions (e.g. clamp_edge).
    • Func::hoist_storage() and friends: allows a functions's storage to be moved to a given loop level. Unlike Func::store_at(), no optimizations are triggered (e.g. sliding window).
  • New TailStrategy options for for existing scheduling directives:
    • ShiftInwardsAndBlend: Equivalent to ShiftInwards, but protects values that would be re-evaluated by loading the memory location that would be stored to, modifying only the elements not contained within the overlap, and then storing the blended result. Unlike ShiftInwards, this is valid to use in update definitions.
    • RoundUpAndBlend: Equivalent to RoundUp, but protects values that would be written beyond the end by loading the memory location that would be stored to, modifying only the elements within the region being computed, and then storing the blended result. Unlike RoundUp, this is valid to use on non-outermost splits in update definitions.
  • Substantially improved performance and display in the VizIR output.
  • Profiler improvements:
    • Substantially nicer text output
    • Injects timing into calls for copy_to_host and copy_to_device so you can measure host<->device copy overhead
    • Allows option sorting via HL_PROFILER_SORT env var
  • Substantially faster codegen for several GPU backends.
  • Experimental serialization/deserialization feature allows for saving of Halide IR code.
  • Various bug fixes and improvements in the Anderson2021 autoscheduler.
  • Improved ARM codegen, including: better patterns for sdot/udot; improved shift/mul codegen.
  • Support for Zen4 architecture in the x86 backend.
  • Updates to the ONNX app.
  • Various fixes and improvements to sliding-window and storage-folding.
  • Improvements to slow gather operations for some x86 variants.
  • Improvements to correctness for the .async() scheduling directive.
  • Improved codegen for float16 conversion, especially on x86.
  • Several compile-time warnings of dubious usefulness disabled.
  • WebAssembly codegen now defaults to assuming that saturating-float-to-int and sign-extension instructions sets are always available.
  • Target now does some reality-checking that it doesn't contain obviously nonsensical Feature combinations

What's Changed

Read more

Halide v16.0.0

Choose a tag to compare

@derek-gerstmann derek-gerstmann released this 24 Jun 01:10
027547f

What's Changed

General Notes

  • Support for the Vulkan API (w/SPIR-V codegen)
  • Support for WebGPU (experimental)
  • Improved Halide IR HTML Visualization
  • Fixed a regression in the Adams2019 auto-scheduler that disabled sub-tiling
  • Added GPU auto-scheduler (Anderson2021)

Efficient Automatic Scheduling of Imaging and Vision Pipelines for the GPU
Luke Anderson, Andrew Adams, Karima Ma, Tzu-Mao Li, Tian Jin, Jonathan Ragan-Kelley
Proceedings of the ACM on Programming Languages (OOPSLA 2021)

Deprecations / Removals

  • OpenGLCompute has been deprecated
  • ParamMap has been deprecated
  • Deprecated HVX_shared_object feature has been removed
  • References to deprecated fixed-point operators have been removed
  • Deprecated halide_target_feature_disable_llvm_loop_opt has been removed
  • Deprecated MIPS device support has been removed

Notable Fixes & Changes

New Contributors

Read more

Halide v15.0.1

Choose a tag to compare

@steven-johnson steven-johnson released this 07 Apr 23:21
4c63f1b

What's Changed

  • The Python binding of compile_to_callable() was not properly copying from device to host for output buffers, so output was typically black (or garbage) when used with a GPU target. (#7213)
  • The bin directory was missing from the installs.
  • Upgraded LLVM to 15.0.7
  • New in 15.0.0, but restated here for visibility: The target flag disable_llvm_loop_opt is deprecated, as it's now the default behavior. This means that we have turned off llvm's autovectorization and loop unrolling. This should not affect any schedules with manually-specified vectorization and unrolling, other than trimming code size a little. However, schedules that do not vectorize or unroll may slow down because they were (intentionally or not) relying on llvm to do it automatically. If you see a performance regression with Halide 15, try turning on the enable_llvm_loop_opt target flag.

Halide v15.0.0

Choose a tag to compare

@steven-johnson steven-johnson released this 06 Mar 23:38
d7651f4

What's Changed

General Notes

  • Support for RISC V Vector architectures.

  • Python-related:

    • Halide builds for Python are now being built and provided to PyPI, so it is now possible to use the Halide Python bindings simply by pip install halide
    • Major improvements were made to the Python bindings, with many missing or incomplete sections of the API added or filled in.
    • We now support the use of Generators from Python (for both JIT and AOT usage).
    • The standard CMake rules now support generating a Python extension directly.
    • Support for Python was removed from Halide's Makefiles; you must use CMake to build the Python bindings
  • Halide::Func now allows you to (optionally) constrain the type(s) of Exprs that the Func can contain, and/or the dimensionality of the Func.

  • Added a new way to use the JIT (compile_to_callable) that allows calling a jitted function with the same syntax as for AOT-compiled functions, allowing more control over JIT lifespan, as well as thread-safe arguments without requiring ParamMap

  • General improvements to SIMD codegen

  • Several rarely-used parts of the C++ Generator API were deprecated, and the way that autoschedulers are specified for AOT compilation is now completely different (but better for future expandability).

  • CMake builds now require >= v3.22

  • WABT usage requires >= v1.0.30

  • LLVM 12 is no longer supported

  • The target flag disable_llvm_loop_opt is deprecated, as it's now the default behavior. This means that we have turned off llvm's autovectorization and loop unrolling. This should not affect any schedules with manually-specified vectorization and unrolling, other than trimming code size a little. However, schedules that do not vectorize or unroll may slow down because they were (intentionally or not) relying on llvm to do it automatically. If you see a performance regression with Halide 15, try turning on the enable_llvm_loop_opt target flag.

Notable bug fixes

  • Make Halide::round behave as documented (#7012)
  • Incorrect folding of saturating_sub (#6883)
  • The check for race conditions didn't consider where clauses (#6808)
  • Performance regression for x86 for certain LLVM versions (#6783)
  • Fusing a specialization drops compute_withs from generated code (#6770)
  • Incorrect output when realize condition depends on tuple call (#6915)
  • Python extensions should default to throwing exceptions rather than calling abort() for errors (#6986)
  • Python bindings didn't support bool buffers (#7006)
  • Python bindings didn't support float16 buffers (#7060)
  • Python extensions that executed on GPU didn't copy back to host properly (#6869)
  • Fix bugs in div_round_to_zero and fast_integer_divide_round_to_zero (#7008)
  • Bugs in add_requirement() (#7045)

Major changes

Minor changes

Read more