RIFLA: Support emission of loops over constant arrays#3101
Open
RIFLA: Support emission of loops over constant arrays#3101
Conversation
This updates the `Adaptive_RIFLA` profile to support emission of loops over arrays with constant, compile-time known content. Where the prior looping support only handled loops with iteration-invariant internals, this updates RCA, Partial Eval, RIR, and QIR codegen to allow for arrays with constant content stored in the global section to be the source of iteration values within a loop. For now, only loops with variable types we already support work with this pattern, specifically loops over constant arrays of `Bool`, `Int`, and `Double`. Arrays of arrays are not supported, due to the lack of QIR compatible mechanism for dynamically querying the length of an array and Q# support for jagged arrays of arrays (ie: `[[1.0], [2.0, 3.0]]`). Follow up PRs will add support for iteration over constant arrays of new types like `Qubit` and `Pauli`. Arrays with dynamic contents will be handled later down the line.
|
Change in memory usage detected by benchmark. Memory Report for 76291c3
|
billti
reviewed
Apr 7, 2026
source/pip/tests-integration/resources/adaptive_rifla/output/LoopOverArrays.ll
Show resolved
Hide resolved
orpuente-MS
reviewed
Apr 8, 2026
orpuente-MS
reviewed
Apr 9, 2026
| while let Some(block_id) = blocks_to_visit.pop() { | ||
| visited_blocks.insert(block_id); | ||
| let mut used_vars_in_block = FxHashSet::default(); | ||
| let mut gep_vars_in_block = FxHashSet::default(); |
Contributor
There was a problem hiding this comment.
What does "gep" mean?
Contributor
There was a problem hiding this comment.
I am guessing "global element pointer"
orpuente-MS
reviewed
Apr 9, 2026
Comment on lines
+3974
to
+3989
| let array_literal = | ||
| convert_to_array_literal(array, array_package_span, index_package_span)?; | ||
| let array_elem_ty = array_literal.ty; | ||
|
|
||
| let const_array_id = if let Some(idx) = self | ||
| .program | ||
| .array_literals | ||
| .iter() | ||
| .position(|a| a == &array_literal) | ||
| { | ||
| idx | ||
| } else { | ||
| let idx = self.program.array_literals.len(); | ||
| self.program.array_literals.push(array_literal); | ||
| idx | ||
| }; |
Contributor
There was a problem hiding this comment.
Converting the same array every time we see it to an array-literal, and then iterating over all seen arrays and doing element-wise comparisons feels expensive. I think we could use the data-pointer of the Rc as a key in a hash table to build a cache to reduce the cost.
Will also need to add this field to the PartialEvaluator struct:
array_literal_cache: FxHashMap<*const Vec<Value>, (usize, rir::Prim)>,
Suggested change
| let array_literal = | |
| convert_to_array_literal(array, array_package_span, index_package_span)?; | |
| let array_elem_ty = array_literal.ty; | |
| let const_array_id = if let Some(idx) = self | |
| .program | |
| .array_literals | |
| .iter() | |
| .position(|a| a == &array_literal) | |
| { | |
| idx | |
| } else { | |
| let idx = self.program.array_literals.len(); | |
| self.program.array_literals.push(array_literal); | |
| idx | |
| }; | |
| let array_ptr = Rc::as_ptr(array); | |
| // Fast path: if we have already converted this exact Rc allocation, | |
| // reuse the cached array-literal index and element type. | |
| let (const_array_id, array_elem_ty) = | |
| if let Some(&(id, ty)) = self.array_literal_cache.get(&array_ptr) { | |
| (id, ty) | |
| } else { | |
| // Slow path: convert the array to a literal and deduplicate. | |
| let array_literal = | |
| convert_to_array_literal(array, array_package_span, index_package_span)?; | |
| let elem_ty = array_literal.ty; | |
| let id = if let Some(idx) = self | |
| .program | |
| .array_literals | |
| .iter() | |
| .position(|a| a == &array_literal) | |
| { | |
| idx | |
| } else { | |
| let idx = self.program.array_literals.len(); | |
| self.program.array_literals.push(array_literal); | |
| idx | |
| }; | |
| self.array_literal_cache.insert(array_ptr, (id, elem_ty)); | |
| (id, elem_ty) | |
| }; |
Contributor
There was a problem hiding this comment.
EDIT: just added the last two lines to the suggestion, was missing pushing to the cache and returning the tuple.
orpuente-MS
approved these changes
Apr 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This updates the
Adaptive_RIFLAprofile to support emission of loops over arrays with constant, compile-time known content. Where the prior looping support only handled loops with iteration-invariant internals, this updates RCA, Partial Eval, RIR, and QIR codegen to allow for arrays with constant content stored in the global section to be the source of iteration values within a loop.For now, only loops with variable types we already support work with this pattern, specifically loops over constant arrays of
Bool,Int, andDouble. Arrays of arrays are not supported, due to the lack of QIR compatible mechanism for dynamically querying the length of an array and Q# support for jagged arrays of arrays (ie:[[1.0], [2.0, 3.0]]). Follow up PRs will add support for iteration over constant arrays of new types likeQubitandPauli. Arrays with dynamic contents will be handled later down the line.