Skip to content

⚡ Extend QCO DD construction and deallocation - #2079

Draft
simon1hofmann wants to merge 10 commits into
codex/qco-dd-classical-interpreterfrom
codex/qco-dd-construction-deallocation
Draft

⚡ Extend QCO DD construction and deallocation#2079
simon1hofmann wants to merge 10 commits into
codex/qco-dd-classical-interpreterfrom
codex/qco-dd-construction-deallocation

Conversation

@simon1hofmann

@simon1hofmann simon1hofmann commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

🤖 AI text below 🤖

Summary

Completes the pure-state interpreter and improves DD construction and deallocation on top of #2078.

  • Interpret multi-block function CFGs and concrete cf.switch branches.
  • Carry classical memrefs across func.call boundaries.
  • Add common integer, floating-point, and math operations.
  • Embed local QCO matrices directly into the surrounding DD.
  • Preserve wire semantics during deallocation and factor separable qubits natively without expanding the full state vector.
  • Expose complete symbolic bindings, dynamic QTensor extents, and supplied initial states in Python.

This is layer 4 of the QCO DD functionality stack. Part of #1915.

Validation

  • The layer builds independently.
  • All 147 QCO utility tests pass.
  • All 7 focused Python QCO DD tests pass.

GPT-5.6 via Codex materially assisted with implementation, testing, review remediation, and restructuring this work into a stacked pull request under maintainer direction.

@simon1hofmann simon1hofmann changed the title codex/qco dd construction deallocation ⚡ Extend QCO DD construction and deallocation Aug 13, 2026
@simon1hofmann simon1hofmann added enhancement Improvement of existing feature DD Anything related to the DD package c++ Anything related to C++ code MLIR Anything related to MLIR python Anything related to Python code labels Aug 13, 2026
@simon1hofmann simon1hofmann self-assigned this Aug 13, 2026
@simon1hofmann simon1hofmann added this to the MLIR Support milestone Aug 13, 2026
@simon1hofmann
simon1hofmann force-pushed the codex/qco-dd-construction-deallocation branch from b464f02 to 6a5d936 Compare August 13, 2026 10:51
@simon1hofmann
simon1hofmann force-pushed the codex/qco-dd-construction-deallocation branch from 6a5d936 to d721d90 Compare August 13, 2026 11:14
@simon1hofmann
simon1hofmann force-pushed the codex/qco-dd-construction-deallocation branch 2 times, most recently from f018bc5 to ee78dbd Compare August 13, 2026 12:21
@simon1hofmann
simon1hofmann force-pushed the codex/qco-dd-construction-deallocation branch 2 times, most recently from 878256e to 19d2a47 Compare August 13, 2026 12:26
@simon1hofmann
simon1hofmann force-pushed the codex/qco-dd-construction-deallocation branch from 500a038 to 3ac809d Compare August 13, 2026 12:51
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Cpp-Linter Report ⚠️

Some files did not pass the configured checks!

clang-tidy (v22.1.8) reports: 23 concern(s)
  • bindings/mlir/register_mlir.cpp:17:1: warning: [misc-include-cleaner]

    included header QCOOps.h is not used directly

       17 | #include "mlir/Dialect/QCO/IR/QCOOps.h"
          | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       18 | #include "mlir/Dialect/QCO/Utils/DDFunctionality.h"
  • bindings/mlir/register_mlir.cpp:154:5: warning: [misc-const-correctness]

    variable 'argument' of type 'mlir::Value' can be declared 'const'

      154 |     mlir::Value argument = func.getArgument(static_cast<unsigned>(index));
          |     ^
          |                 const 
  • bindings/mlir/register_mlir.cpp:156:11: warning: [misc-include-cleaner]

    no header providing "mlir::Attribute" is directly included

       24 |     mlir::Attribute attribute;
          |           ^
  • bindings/mlir/register_mlir.cpp:161:22: warning: [misc-include-cleaner]

    no header providing "mlir::isa" is directly included

       28 |     } else if (mlir::isa<mlir::IndexType, mlir::IntegerType>(type)) {
          |                      ^
  • bindings/mlir/register_mlir.cpp:165:45: warning: [misc-include-cleaner]

    no header providing "mlir::dyn_cast" is directly included

      165 |     } else if (const auto floatType = mlir::dyn_cast<mlir::FloatType>(type)) {
          |                                             ^
  • bindings/mlir/register_mlir.cpp:165:60: warning: [misc-include-cleaner]

    no header providing "mlir::FloatType" is directly included

       25 |     } else if (const auto floatType = mlir::dyn_cast<mlir::FloatType>(type)) {
          |                                                            ^
  • bindings/mlir/register_mlir.cpp:173:37: warning: [misc-include-cleaner]

    no header providing "mlir::qco::QubitType" is directly included

       17 |                mlir::isa<mlir::qco::QubitType>(tensorType.getElementType())) {
          |                                     ^
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:30:1: warning: [misc-include-cleaner]

    included header APSInt.h is not used directly

       30 | #include <llvm/ADT/APSInt.h>
          | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
       31 | #include <llvm/ADT/DenseMap.h>
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:32:1: warning: [misc-include-cleaner]

    included header DenseSet.h is not used directly

       32 | #include <llvm/ADT/DenseSet.h>
          | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       33 | #include <llvm/ADT/STLExtras.h>
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:164:27: warning: [readability-static-definition-in-anonymous-namespace]

    'isQTensorType' is a static definition in anonymous namespace; static is redundant here

      164 | [[nodiscard]] static bool isQTensorType(Type type) {
          |               ~~~~~~      ^
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:164:27: warning: [llvm-prefer-static-over-anonymous-namespace]

    place static function 'isQTensorType' outside of an anonymous namespace

  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:164:41: warning: [misc-include-cleaner]

    no header providing "mlir::Type" is directly included

       45 | [[nodiscard]] static bool isQTensorType(Type type) {
          |                                         ^
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:176:10: warning: [bugprone-exception-escape]

    an exception may be thrown in function 'MemRefStorage' which should not throw exceptions

      176 |   struct MemRefStorage {
          |          ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:1349:5: note: frame #0: unhandled exception of type 'bad_variant_access' may be thrown in function '__throw_bad_variant_access' here
     1349 |   { _GLIBCXX_THROW_OR_ABORT(bad_variant_access(__what)); }
          |     ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14/bits/c++config.h:234:42: note: expanded from macro '_GLIBCXX_THROW_OR_ABORT'
      234 | #  define _GLIBCXX_THROW_OR_ABORT(_EXC) (throw (_EXC))
          |                                          ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:1355:7: note: frame #1: function '__throw_bad_variant_access' calls function '__throw_bad_variant_access' here
     1355 |       __throw_bad_variant_access("std::get: variant is valueless");
          |       ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:1720:2: note: frame #2: function 'get<2UL, bool, long, llvm::APInt, double>' calls function '__throw_bad_variant_access' here
     1720 |         __throw_bad_variant_access(__v.valueless_by_exception());
          |         ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:1576:11: note: frame #3: function 'emplace<2UL, llvm::APInt>' calls function 'get<2UL, bool, long, llvm::APInt, double>' here
     1576 |           return std::get<_Np>(*this);
          |                  ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:735:4: note: frame #4: function 'operator()<llvm::APInt &, std::integral_constant<unsigned long, 2>>' calls function 'emplace<2UL, llvm::APInt>' here
      735 |                         __self.template emplace<__j>(std::move(__rhs_mem));
          |                         ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/invoke.h:61:14: note: frame #5: function '__invoke_impl<void, (lambda at /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:719:4), llvm::APInt &, std::integral_constant<unsigned long, 2>>' calls function 'operator()<llvm::APInt &, std::integral_constant<unsigned long, 2>>' here
       61 |     { return std::forward<_Fn>(__f)(std::forward<_Args>(__args)...); }
          |              ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/invoke.h:96:14: note: frame #6: function '__invoke<(lambda at /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:719:4), llvm::APInt &, std::integral_constant<unsigned long, 2>>' calls function '__invoke_impl<void, (lambda at /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:719:4), llvm::APInt &, std::integral_constant<unsigned long, 2>>' here
       96 |       return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn),
          |              ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:1049:4: note: frame #7: function '__visit_invoke' calls function '__invoke<(lambda at /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:719:4), llvm::APInt &, std::integral_constant<unsigned long, 2>>' here
     1049 |           std::__invoke(std::forward<_Visitor>(__visitor),
          |           ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:1821:5: note: frame #8: function '__do_visit<std::__detail::__variant::__variant_idx_cookie, (lambda at /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:719:4), std::variant<bool, long, llvm::APInt, double> &>' calls function '__visit_invoke' here
     1821 |                   _GLIBCXX_VISIT_CASE(2)
          |                   ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:1810:9: note: expanded from macro '_GLIBCXX_VISIT_CASE'
     1810 |         return __gen_vtable_impl<_Ma, index_sequence<N>>::              \
          |                ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:184:7: note: frame #9: function '__raw_idx_visit<(lambda at /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:719:4), std::variant<bool, long, llvm::APInt, double> &>' calls function '__do_visit<std::__detail::__variant::__variant_idx_cookie, (lambda at /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:719:4), std::variant<bool, long, llvm::APInt, double> &>' here
      184 |       std::__do_visit<__variant_idx_cookie>(std::forward<_Visitor>(__visitor),
          |       ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:718:2: note: frame #10: function 'operator=' calls function '__raw_idx_visit<(lambda at /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:719:4), std::variant<bool, long, llvm::APInt, double> &>' here
      718 |         __variant::__raw_idx_visit(
          |         ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:779:57: note: frame #11: function 'operator=' calls function 'operator=' here
      779 |       _Variant_base& operator=(_Variant_base&&) = default;
          |                                                         ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/variant:1437:45: note: frame #12: function 'operator=' calls function 'operator=' here
     1437 |       variant& operator=(variant&&) = default;
          |                                             ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/stl_algobase.h:428:18: note: frame #13: function '__copy_m<std::variant<bool, long, llvm::APInt, double> *, std::variant<bool, long, llvm::APInt, double> *>' calls function 'operator=' here
      428 |               *__result = std::move(*__first);
          |                         ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/stl_algobase.h:517:9: note: frame #14: function '__copy_move_a2<true, std::variant<bool, long, llvm::APInt, double> *, std::variant<bool, long, llvm::APInt, double> *>' calls function '__copy_m<std::variant<bool, long, llvm::APInt, double> *, std::variant<bool, long, llvm::APInt, double> *>' here
      517 |         return std::__copy_move<_IsMove, false, _Category>::
          |                ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/stl_algobase.h:548:14: note: frame #15: function '__copy_move_a1<true, std::variant<bool, long, llvm::APInt, double> *, std::variant<bool, long, llvm::APInt, double> *>' calls function '__copy_move_a2<true, std::variant<bool, long, llvm::APInt, double> *, std::variant<bool, long, llvm::APInt, double> *>' here
      548 |     { return std::__copy_move_a2<_IsMove>(__first, __last, __result); }
          |              ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/stl_algobase.h:556:3: note: frame #16: function '__copy_move_a<true, std::variant<bool, long, llvm::APInt, double> *, std::variant<bool, long, llvm::APInt, double> *>' calls function '__copy_move_a1<true, std::variant<bool, long, llvm::APInt, double> *, std::variant<bool, long, llvm::APInt, double> *>' here
      556 |                 std::__copy_move_a1<_IsMove>(std::__niter_base(__first),
          |                 ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/stl_algobase.h:683:14: note: frame #17: function 'move<std::variant<bool, long, llvm::APInt, double> *, std::variant<bool, long, llvm::APInt, double> *>' calls function '__copy_move_a<true, std::variant<bool, long, llvm::APInt, double> *, std::variant<bool, long, llvm::APInt, double> *>' here
      683 |       return std::__copy_move_a<true>(std::__miter_base(__first),
          |              ^
    /opt/hostedtoolcache/mlir-toolchain/22.1.7/x64/include/llvm/ADT/SmallVector.h:1079:16: note: frame #18: function 'operator=' calls function 'move<std::variant<bool, long, llvm::APInt, double> *, std::variant<bool, long, llvm::APInt, double> *>' here
     1079 |       NewEnd = std::move(RHS.begin(), RHS.end(), NewEnd);
          |                ^
    /opt/hostedtoolcache/mlir-toolchain/22.1.7/x64/include/llvm/ADT/SmallVector.h:1257:7: note: frame #19: function 'SmallVector' calls function 'operator=' here
     1257 |       SmallVectorImpl<T>::operator=(::std::move(RHS));
          |       ^
    /home/runner/work/core/core/mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:176:10: note: frame #20: function 'MemRefStorage' calls function 'SmallVector' here
      176 |   struct MemRefStorage {
          |          ^
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:212:13: warning: [misc-include-cleaner]

    no header providing "mlir::FloatType" is directly included

       43 |     if (isa<FloatType>(dest.getType())) {
          |             ^
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:335:12: warning: [misc-include-cleaner]

    no header providing "dd::mCachedEdge" is directly included

       15 | static dd::mCachedEdge
          |            ^
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:349:41: warning: [misc-include-cleaner]

    no header providing "dd::CachedEdge" is directly included

       13 |     return dd.makeDDNode<dd::mNode, dd::CachedEdge>(
          |                                         ^
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:721:12: warning: [misc-include-cleaner]

    no header providing "std::array" is directly included

       53 |       std::array<dd::VectorDD, dd::RADIX> edges{self(self, edge.p->e[0]),
          |            ^
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:723:48: warning: [misc-include-cleaner]

    no header providing "dd::Edge" is directly included

       14 |       projected = dd.makeDDNode<dd::vNode, dd::Edge>(
          |                                                ^
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:750:43: warning: [misc-include-cleaner]

    no header providing "dd::ComplexValue" is directly included

       13 |   const auto zeroWeight = static_cast<dd::ComplexValue>(zero.w);
          |                                           ^
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:770:21: warning: [readability-implicit-bool-conversion]

    implicit conversion 'bool' -> 'uint64_t' (aka 'unsigned long')

      770 |     return APInt(1, *bit);
          |                     ^   
          |                     static_cast<uint64_t>( )
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:887:55: warning: [performance-move-const-arg]

    passing result of std::move() as a const reference argument; no move will actually happen

      887 |                                                       std::move(zero))});
          |                                                       ^~~~~~~~~~    ~
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:1955:52: warning: [bugprone-optional-value-conversion]

    conversion from 'std::optional' into 'unsigned int' and back into 'std::optional', remove potentially error-prone optional dereference

     1955 |         outputSlots[static_cast<size_t>(*index)] = *wire;
          |                                                    ^
    /home/runner/work/core/core/mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:1955:52: note: remove '*' to silence this warning
     1955 |         outputSlots[static_cast<size_t>(*index)] = *wire;
          |                                                    ^
  • mlir/lib/Dialect/QCO/Utils/DDFunctionality.cpp:2417:8: warning: [misc-use-internal-linkage]

    struct 'PreparedState' can be moved into an anonymous namespace to enforce internal linkage

     2417 | struct PreparedState {
          |        ^

Have any feedback or feature suggestions? Share it here.

@simon1hofmann
simon1hofmann force-pushed the codex/qco-dd-construction-deallocation branch from 3ac809d to 69621de Compare August 13, 2026 14:27
@simon1hofmann
simon1hofmann force-pushed the codex/qco-dd-construction-deallocation branch 2 times, most recently from 2a0aad6 to 9a3981a Compare August 13, 2026 16:36
@simon1hofmann
simon1hofmann force-pushed the codex/qco-dd-construction-deallocation branch 2 times, most recently from c06206d to bb29c44 Compare August 13, 2026 16:50
@simon1hofmann
simon1hofmann force-pushed the codex/qco-dd-construction-deallocation branch from bb29c44 to 06674b8 Compare August 14, 2026 07:34
@simon1hofmann
simon1hofmann force-pushed the codex/qco-dd-construction-deallocation branch from 06674b8 to 3979117 Compare August 14, 2026 07:47
@simon1hofmann
simon1hofmann force-pushed the codex/qco-dd-construction-deallocation branch from 3979117 to 1aa5a50 Compare August 14, 2026 07:52
@simon1hofmann
simon1hofmann force-pushed the codex/qco-dd-construction-deallocation branch from 1aa5a50 to ed045d7 Compare August 14, 2026 07:53
@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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

Labels

c++ Anything related to C++ code conflict DD Anything related to the DD package enhancement Improvement of existing feature MLIR Anything related to MLIR python Anything related to Python code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant