Map an assign operation in the AST to an equivalent variable value assignment in the MLIR. This method handles assignments, item updates, as well as deconstruction. For all assignments, the variable name will be used as a key for the symbol table, mapping to the corr
(self, node)
| 1982 | self.pushValue(lambdaFct) |
| 1983 | |
| 1984 | def visit_Assign(self, node): |
| 1985 | """Map an assign operation in the AST to an equivalent variable value |
| 1986 | assignment in the MLIR. This method handles assignments, item updates, |
| 1987 | as well as deconstruction. |
| 1988 | |
| 1989 | For all assignments, the variable name will be used as a key for the |
| 1990 | symbol table, mapping to the corresponding MLIR Value. Quantum values, |
| 1991 | measurements results, `cc.callable`, and `cc.stdvec` will be stored as |
| 1992 | values in the symbol table. For all other values, the variable will be |
| 1993 | allocated with a `cc.alloca` op, and the pointer will be stored in |
| 1994 | the symbol table. |
| 1995 | """ |
| 1996 | |
| 1997 | def storedAsValue(val): |
| 1998 | varTy = val.type |
| 1999 | if cc.PointerType.isinstance(varTy): |
| 2000 | varTy = cc.PointerType.getElementType(varTy) |
| 2001 | # If `buildingFunctionBody` is not set we are processing function |
| 2002 | # arguments. Function arguments are always passed by value, |
| 2003 | # except states. We can treat non-container function arguments |
| 2004 | # like any local variable and create a stack slot for them. |
| 2005 | # For container types, on the the other hand, we need to preserve |
| 2006 | # them as values in the symbol table to make sure we can detect |
| 2007 | # any access to reference types that are function arguments, or |
| 2008 | # function argument items. |
| 2009 | containerFuncArg = (not self.buildingFunctionBody and |
| 2010 | (cc.StructType.isinstance(varTy) or |
| 2011 | cc.StdvecType.isinstance(varTy))) |
| 2012 | # FIXME: Consider storing vectors and callables as pointers like |
| 2013 | # other variables. |
| 2014 | # A local `!cc.stdvec<!cc.measure_handle>` is backed by a stack slot |
| 2015 | # (like a scalar `!cc.measure_handle`) so it can be reassigned from a |
| 2016 | # child block. Function-argument handle vectors stay value-backed via |
| 2017 | # `containerFuncArg`; every other vector stays value-backed so |
| 2018 | # reassigning a general list across scopes is still rejected. |
| 2019 | # See https://github.com/NVIDIA/cuda-quantum/issues/4601. |
| 2020 | # Discriminated measurement results (`i1` / `stdvec<i1>` produced by |
| 2021 | # `quake.discriminate`) are stored like any other value: the |
| 2022 | # `!cc.measure_handle` type now carries the "is a measurement" |
| 2023 | # distinction, so they no longer need a value-storage carve-out to |
| 2024 | # preserve their discriminate origin. |
| 2025 | isLocalHandleVec = (cc.StdvecType.isinstance(varTy) and |
| 2026 | cc.MeasureHandleType.isinstance( |
| 2027 | cc.StdvecType.getElementType(varTy))) |
| 2028 | storeAsVal = (containerFuncArg or self.isQuantumType(varTy) or |
| 2029 | cc.CallableType.isinstance(varTy) or |
| 2030 | (cc.StdvecType.isinstance(varTy) and |
| 2031 | not isLocalHandleVec)) |
| 2032 | # Nothing should ever produce a pointer to a type we store as value |
| 2033 | # in the symbol table. |
| 2034 | assert (not storeAsVal or not cc.PointerType.isinstance(val.type)) |
| 2035 | return storeAsVal |
| 2036 | |
| 2037 | def process_assignment(target, value): |
| 2038 | |
| 2039 | if isinstance(target, ast.Tuple): |
| 2040 | |
| 2041 | if (isinstance(value, ast.Tuple) or |
no test coverage detected