Add initial support for simple IR functions in QIR#3344
Conversation
7135d28 to
0f8556f
Compare
4045608 to
a3f04f1
Compare
| /// capability that gates IR-function emission. | ||
| #[must_use] | ||
| pub fn get_rir_program_with_adaptive_profile(source: &str) -> Program { | ||
| get_rir_program_with_capabilities(source, Profile::Adaptive.into()) |
There was a problem hiding this comment.
we have other tests (mostly in loops.rs, but a few others too) that just call get_rir_program_with_capabilities passing adaptive. I think we should either update those to use this helper or just remove the helper and call the function with the parameter directly, for consistency. Same with the below.
| args.iter() | ||
| .map(|arg| { | ||
| let value = match arg { | ||
| Arg::Discard(value) => value, |
There was a problem hiding this comment.
This isn't really specific to your changes, but looking at how Arg::Discard is used, I don't think it needs to be handled here. We would never be emitting a call to an ir function with a discard, as that concept doesn't exist in LLVM. And even for existing usage, I feel like the right thing to do would be to transform away discards at an earlier step, but such a transform doesn't exist today. Perhaps we can consider something like that in the future with an FIR transform (especially post tuple decomposition), but for now leaving this is in is fine. Perhaps worth a follow up investigation issue or something?
| pub(crate) fn assert_panics_with(expected_substring: &str, operation: impl FnOnce()) { | ||
| let _hook_guard = PANIC_HOOK_LOCK | ||
| .lock() | ||
| .unwrap_or_else(std::sync::PoisonError::into_inner); | ||
|
|
||
| let previous_hook = std::panic::take_hook(); | ||
| std::panic::set_hook(Box::new(|_| {})); | ||
| let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(operation)); | ||
| std::panic::set_hook(previous_hook); | ||
|
|
||
| let payload = | ||
| result.expect_err("expected the operation to panic, but it completed without panicking"); | ||
| let message = match payload.downcast::<String>() { | ||
| Ok(message) => *message, | ||
| Err(payload) => match payload.downcast::<&str>() { | ||
| Ok(message) => (*message).to_string(), | ||
| Err(_) => "(non-string panic payload)".to_string(), | ||
| }, | ||
| }; | ||
| assert!( | ||
| message.contains(expected_substring), | ||
| "panic message did not contain the expected substring.\n expected substring: {expected_substring}\n actual message: {message}" | ||
| ); | ||
| } |
There was a problem hiding this comment.
this is text-identical to the assert_panics_with in the qsc_fir_transforms crate. I wonder if there is a reasonable place to put this so that both can depend on it? Maybe qsc_data_structures?
|
|
||
| declare void @__quantum__rt__tuple_record_output(i64, ptr) | ||
|
|
||
| attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="0" "required_num_results"="0" } |
There was a problem hiding this comment.
it occurs to me looking at this one that the required_num_qubits is 0 by design, but I wonder if might make more sense to make that whole part of the attributes somethign that gets filled in so we can skip it when dynamic qubit allocation is used. Double checking the spec, it says the attribute is "not required" when using the dynamic qubits extension. Likewise, the dynamic_qubit_management flag below should get set to true. Not critical right now as this feature is not yet exposed, so it can get included now or have a follow up issue filed.
There was a problem hiding this comment.
alternatively, we can wait until it gets incorporated into Adaptive by default and then just hard-code true and drop the required_num_qubits entirely.
Add support for simple IR functions in QIR
What
Adds support for emitting eligible user-package Q# callables as IR functions instead of inlining them in QIR codegen. This lays the groundwork for extending IR function support to non-use packages in follow-up PRs.
Why
Currently, all Q# callables are inlined into the entry point. By emitting simple eligible callables as IR functions, we:
How
Partial Evaluator Changes (
qsc_partial_eval)Unitor scalars (Int/Double/Bool)RegularRIR callables with bodies instead of inliningir_functions.rstest moduleRIR Builder & Codegen (
qsc_rir,qsc_codegen)qsc_rir::builderto support RIR function definitions with proper block managementqir::namemodule for correct LLVM global symbol name formatting (handling special characters and quoting)Supporting Changes
qsc_rca) to handle IR function bodiesNotes