Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions source/compiler/qsc/src/codegen/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5388,3 +5388,51 @@ fn chemistry_like_iqpe_with_udt_capture_closure_generates_base_profile_qir() {
"expected threaded Controlled X capture in QIR:\n{qir}"
);
}

#[test]
fn foreign_table_lookup_callable_generates_qir() {
let source = indoc::indoc! {r#"
operation Invoke() : Unit {
use address = Qubit[1];
use output = Qubit[1];
Std.TableLookup.Select([[false], [true]], address, output);

// Adjoint of Select does not work until support for static sized, dynamic content arrays is added.
// See related issue: https://github.com/microsoft/qdk/issues/3388
// Adjoint Std.TableLookup.Select([[false], [true]], address, output);
}
"#};
for profile in [Profile::AdaptiveRI, Profile::AdaptiveRIF, Profile::Adaptive] {
let capabilities = profile.into();
let (mut store, package_id, items) =
compile_and_locate_items(source, &[("Invoke", true)], capabilities);
let root_sources =
source_map_from_source("namespace DriverEmpty { function Anchor() : Unit {} }");
let root_dependencies = vec![(package_id, Some(Arc::from("ReproLib")))];
let (root_unit, root_errors) = crate::compile::compile(
&store,
&root_dependencies,
root_sources,
PackageType::Lib,
capabilities,
LanguageFeatures::default(),
);
assert!(
root_errors.is_empty(),
"{profile:?} root compilation failed: {root_errors:?}"
);
store.insert(root_unit);

let qir = callable_args_to_qir(
&store,
package_id,
items["Invoke"],
&Value::unit(),
capabilities,
);
assert!(
qir.contains("define i64 @ENTRYPOINT__main()"),
"{profile:?} callable should emit an entry point, got:\n{qir}"
);
}
}
28 changes: 27 additions & 1 deletion source/compiler/qsc_rca/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1542,7 +1542,25 @@ impl<'a> Analyzer<'a> {
let mut args_compute_kinds = Vec::<ComputeKind>::with_capacity(args.len());
for arg_expr_id in args {
let arg_compute_kind = application_instance.get_expr_compute_kind(*arg_expr_id);
args_compute_kinds.push(*arg_compute_kind);
let arg_ty = &self.get_expr(*arg_expr_id).ty;
if matches!(
arg_compute_kind,
ComputeKind::Dynamic {
value_kind: ValueKind::Constant,
..
}
) && !is_any_result(arg_ty)
&& !is_any_array(arg_ty)
{
// If the argument is expected to have a constant value, we can consider it static across function boundaries.
// This matches the behavior in partial evaluation, captured in source/compiler/qsc_partial_eval/src/evaluation_context.rs
// `Scope` construction, where non-result runtime values are set as static when computing argument `ComputeKind`.
// We skip this for result types, which must remain dynamic constant as they are the source of later variables during
// comparison of result values, and for arrays, which during evaluation do not have investigatable contents.
args_compute_kinds.push(ComputeKind::Static);
} else {
args_compute_kinds.push(*arg_compute_kind);
}
}
args_compute_kinds
}
Expand Down Expand Up @@ -2803,6 +2821,14 @@ fn is_any_result(t: &Ty) -> bool {
}
}

fn is_any_array(t: &Ty) -> bool {
match t {
Ty::Array(_) => true,
Ty::Tuple(ts) => ts.iter().any(is_any_array),
_ => false,
}
}

struct ClearComputeKinds<'a, 'b> {
analyzer: &'a mut Analyzer<'b>,
}
Expand Down
Loading