Skip to content

Commit

Permalink
Add requiredQubits and requiredResults attributes (#166)
Browse files Browse the repository at this point in the history
  • Loading branch information
bamarsha authored and Sarah Marshall committed Oct 4, 2022
1 parent 516a10b commit ca5d3e6
Show file tree
Hide file tree
Showing 21 changed files with 136 additions and 14 deletions.
2 changes: 2 additions & 0 deletions pyqir-generator/src/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,8 @@ impl SimpleModule {
fn new(py: Python, name: String, num_qubits: u64, num_results: u64) -> PyResult<SimpleModule> {
let model = SemanticModel {
name,
required_num_qubits: num_qubits,
required_num_results: num_results,
external_functions: vec![],
instructions: vec![],
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ declare void @__quantum__qis__x__body(%Qubit*)

declare void @__quantum__qis__h__body(%Qubit*)

attributes #0 = { "EntryPoint" }
attributes #0 = { "EntryPoint" "requiredQubits"="1" "requiredResults"="1" }
2 changes: 1 addition & 1 deletion qirlib/resources/tests/test_call_variable.ll
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ entry:
ret void
}

attributes #0 = { "EntryPoint" }
attributes #0 = { "EntryPoint" "requiredQubits"="0" "requiredResults"="0" }
2 changes: 1 addition & 1 deletion qirlib/resources/tests/test_empty_if.ll
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ declare void @__quantum__qis__mz__body(%Qubit*, %Result*)

declare i1 @__quantum__qis__read_result__body(%Result*)

attributes #0 = { "EntryPoint" }
attributes #0 = { "EntryPoint" "requiredQubits"="1" "requiredResults"="1" }
2 changes: 1 addition & 1 deletion qirlib/resources/tests/test_if_else.ll
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ declare i1 @__quantum__qis__read_result__body(%Result*)

declare void @__quantum__qis__x__body(%Qubit*)

attributes #0 = { "EntryPoint" }
attributes #0 = { "EntryPoint" "requiredQubits"="1" "requiredResults"="1" }
2 changes: 1 addition & 1 deletion qirlib/resources/tests/test_if_else_continue.ll
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ declare void @__quantum__qis__x__body(%Qubit*)

declare void @__quantum__qis__h__body(%Qubit*)

attributes #0 = { "EntryPoint" }
attributes #0 = { "EntryPoint" "requiredQubits"="1" "requiredResults"="1" }
2 changes: 1 addition & 1 deletion qirlib/resources/tests/test_if_else_else.ll
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ declare i1 @__quantum__qis__read_result__body(%Result*)

declare void @__quantum__qis__x__body(%Qubit*)

attributes #0 = { "EntryPoint" }
attributes #0 = { "EntryPoint" "requiredQubits"="1" "requiredResults"="2" }
2 changes: 1 addition & 1 deletion qirlib/resources/tests/test_if_else_then.ll
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ declare i1 @__quantum__qis__read_result__body(%Result*)

declare void @__quantum__qis__x__body(%Qubit*)

attributes #0 = { "EntryPoint" }
attributes #0 = { "EntryPoint" "requiredQubits"="1" "requiredResults"="2" }
2 changes: 1 addition & 1 deletion qirlib/resources/tests/test_if_then.ll
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ declare i1 @__quantum__qis__read_result__body(%Result*)

declare void @__quantum__qis__x__body(%Qubit*)

attributes #0 = { "EntryPoint" }
attributes #0 = { "EntryPoint" "requiredQubits"="1" "requiredResults"="1" }
2 changes: 1 addition & 1 deletion qirlib/resources/tests/test_if_then_continue.ll
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ declare void @__quantum__qis__x__body(%Qubit*)

declare void @__quantum__qis__h__body(%Qubit*)

attributes #0 = { "EntryPoint" }
attributes #0 = { "EntryPoint" "requiredQubits"="1" "requiredResults"="1" }
2 changes: 1 addition & 1 deletion qirlib/resources/tests/test_if_then_else.ll
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ declare i1 @__quantum__qis__read_result__body(%Result*)

declare void @__quantum__qis__x__body(%Qubit*)

attributes #0 = { "EntryPoint" }
attributes #0 = { "EntryPoint" "requiredQubits"="1" "requiredResults"="2" }
2 changes: 1 addition & 1 deletion qirlib/resources/tests/test_if_then_else_continue.ll
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ declare void @__quantum__qis__y__body(%Qubit*)

declare void @__quantum__qis__h__body(%Qubit*)

attributes #0 = { "EntryPoint" }
attributes #0 = { "EntryPoint" "requiredQubits"="1" "requiredResults"="1" }
2 changes: 1 addition & 1 deletion qirlib/resources/tests/test_if_then_then.ll
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ declare i1 @__quantum__qis__read_result__body(%Result*)

declare void @__quantum__qis__x__body(%Qubit*)

attributes #0 = { "EntryPoint" }
attributes #0 = { "EntryPoint" "requiredQubits"="1" "requiredResults"="2" }
2 changes: 1 addition & 1 deletion qirlib/resources/tests/test_int_binary_operators.ll
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,4 @@ entry:
ret void
}

attributes #0 = { "EntryPoint" }
attributes #0 = { "EntryPoint" "requiredQubits"="0" "requiredResults"="0" }
9 changes: 9 additions & 0 deletions qirlib/resources/tests/test_many_required_qubits_results.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
; ModuleID = 'test_many_required_qubits_results'
source_filename = "test_many_required_qubits_results"

define void @main() #0 {
entry:
ret void
}

attributes #0 = { "EntryPoint" "requiredQubits"="5" "requiredResults"="7" }
9 changes: 9 additions & 0 deletions qirlib/resources/tests/test_one_required_qubit.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
; ModuleID = 'test_one_required_qubit'
source_filename = "test_one_required_qubit"

define void @main() #0 {
entry:
ret void
}

attributes #0 = { "EntryPoint" "requiredQubits"="1" "requiredResults"="0" }
9 changes: 9 additions & 0 deletions qirlib/resources/tests/test_one_required_result.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
; ModuleID = 'test_one_required_result'
source_filename = "test_one_required_result"

define void @main() #0 {
entry:
ret void
}

attributes #0 = { "EntryPoint" "requiredQubits"="0" "requiredResults"="1" }
9 changes: 9 additions & 0 deletions qirlib/resources/tests/test_zero_required_qubits_results.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
; ModuleID = 'test_zero_required_qubits_results'
source_filename = "test_zero_required_qubits_results"

define void @main() #0 {
entry:
ret void
}

attributes #0 = { "EntryPoint" "requiredQubits"="0" "requiredResults"="0" }
82 changes: 81 additions & 1 deletion qirlib/src/generation/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::{
passes::run_basic_passes_on,
};
use inkwell::{
attributes::AttributeLoc,
context::Context,
module::Linkage,
types::{AnyTypeEnum, BasicType, BasicTypeEnum},
Expand Down Expand Up @@ -50,20 +51,29 @@ pub fn populate_context<'a>(
) -> Result<CodeGenerator<'a>, String> {
let module = ctx.create_module(&model.name);
let generator = CodeGenerator::new(ctx, module)?;
add_external_functions(&generator, model.external_functions.iter());
build_entry_function(&generator, model)?;
Ok(generator)
}

fn build_entry_function(generator: &CodeGenerator, model: &SemanticModel) -> Result<(), String> {
add_external_functions(generator, model.external_functions.iter());
let entry_point = qir::create_entry_point(generator.context, &generator.module);
add_num_attribute(entry_point, "requiredQubits", model.required_num_qubits);
add_num_attribute(entry_point, "requiredResults", model.required_num_results);

let entry = generator.context.append_basic_block(entry_point, "entry");
generator.builder.position_at_end(entry);
write_instructions(model, generator, entry_point);
generator.builder.build_return(None);
generator.module.verify().map_err(|e| e.to_string())
}

fn add_num_attribute(function: FunctionValue, key: &str, value: u64) {
let context = function.get_type().get_context();
let attribute = context.create_string_attribute(key, &value.to_string());
function.add_attribute(AttributeLoc::Function, attribute);
}

fn add_external_functions<'a>(
generator: &CodeGenerator,
functions: impl Iterator<Item = &'a (String, interop::Type)>,
Expand Down Expand Up @@ -133,10 +143,56 @@ mod tests {
use normalize_line_endings::normalized;
use std::{env, fs, path::PathBuf};

#[test]
fn test_zero_required_qubits_results() -> Result<(), String> {
check_or_save_reference_ir(&SemanticModel {
name: "test_zero_required_qubits_results".to_string(),
required_num_qubits: 0,
required_num_results: 0,
external_functions: vec![],
instructions: vec![],
})
}

#[test]
fn test_one_required_qubit() -> Result<(), String> {
check_or_save_reference_ir(&SemanticModel {
name: "test_one_required_qubit".to_string(),
required_num_qubits: 1,
required_num_results: 0,
external_functions: vec![],
instructions: vec![],
})
}

#[test]
fn test_one_required_result() -> Result<(), String> {
check_or_save_reference_ir(&SemanticModel {
name: "test_one_required_result".to_string(),
required_num_qubits: 0,
required_num_results: 1,
external_functions: vec![],
instructions: vec![],
})
}

#[test]
fn test_many_required_qubits_results() -> Result<(), String> {
check_or_save_reference_ir(&SemanticModel {
name: "test_many_required_qubits_results".to_string(),
required_num_qubits: 5,
required_num_results: 7,
external_functions: vec![],
instructions: vec![],
})
}

#[test]
fn test_empty_if() -> Result<(), String> {
let model = SemanticModel {
name: "test_empty_if".to_string(),
required_num_qubits: 1,
required_num_results: 1,
external_functions: vec![],
instructions: vec![
Instruction::M(Measured::new(Value::Qubit(0), Value::Result(0))),
Expand All @@ -155,6 +211,8 @@ mod tests {
fn test_if_then() -> Result<(), String> {
let model = SemanticModel {
name: "test_if_then".to_string(),
required_num_qubits: 1,
required_num_results: 1,
external_functions: vec![],
instructions: vec![
Instruction::M(Measured::new(Value::Qubit(0), Value::Result(0))),
Expand All @@ -173,6 +231,8 @@ mod tests {
fn test_if_else() -> Result<(), String> {
let model = SemanticModel {
name: "test_if_else".to_string(),
required_num_qubits: 1,
required_num_results: 1,
external_functions: vec![],
instructions: vec![
Instruction::M(Measured::new(Value::Qubit(0), Value::Result(0))),
Expand All @@ -191,6 +251,8 @@ mod tests {
fn test_if_then_continue() -> Result<(), String> {
let model = SemanticModel {
name: "test_if_then_continue".to_string(),
required_num_qubits: 1,
required_num_results: 1,
external_functions: vec![],
instructions: vec![
Instruction::M(Measured::new(Value::Qubit(0), Value::Result(0))),
Expand All @@ -210,6 +272,8 @@ mod tests {
fn test_if_else_continue() -> Result<(), String> {
let model = SemanticModel {
name: "test_if_else_continue".to_string(),
required_num_qubits: 1,
required_num_results: 1,
external_functions: vec![],
instructions: vec![
Instruction::M(Measured::new(Value::Qubit(0), Value::Result(0))),
Expand All @@ -229,6 +293,8 @@ mod tests {
fn test_if_then_else_continue() -> Result<(), String> {
let model = SemanticModel {
name: "test_if_then_else_continue".to_string(),
required_num_qubits: 1,
required_num_results: 1,
external_functions: vec![],
instructions: vec![
Instruction::M(Measured::new(Value::Qubit(0), Value::Result(0))),
Expand All @@ -248,6 +314,8 @@ mod tests {
fn test_if_then_then() -> Result<(), String> {
let model = SemanticModel {
name: "test_if_then_then".to_string(),
required_num_qubits: 1,
required_num_results: 2,
external_functions: vec![],
instructions: vec![
Instruction::M(Measured::new(Value::Qubit(0), Value::Result(0))),
Expand All @@ -271,6 +339,8 @@ mod tests {
fn test_if_else_else() -> Result<(), String> {
let model = SemanticModel {
name: "test_if_else_else".to_string(),
required_num_qubits: 1,
required_num_results: 2,
external_functions: vec![],
instructions: vec![
Instruction::M(Measured::new(Value::Qubit(0), Value::Result(0))),
Expand All @@ -294,6 +364,8 @@ mod tests {
fn test_if_then_else() -> Result<(), String> {
let model = SemanticModel {
name: "test_if_then_else".to_string(),
required_num_qubits: 1,
required_num_results: 2,
external_functions: vec![],
instructions: vec![
Instruction::M(Measured::new(Value::Qubit(0), Value::Result(0))),
Expand All @@ -317,6 +389,8 @@ mod tests {
fn test_if_else_then() -> Result<(), String> {
let model = SemanticModel {
name: "test_if_else_then".to_string(),
required_num_qubits: 1,
required_num_results: 2,
external_functions: vec![],
instructions: vec![
Instruction::M(Measured::new(Value::Qubit(0), Value::Result(0))),
Expand All @@ -340,6 +414,8 @@ mod tests {
fn test_allows_unmeasured_result_condition() -> Result<(), String> {
let model = SemanticModel {
name: "test_allows_unmeasured_result_condition".to_string(),
required_num_qubits: 1,
required_num_results: 1,
external_functions: vec![],
instructions: vec![Instruction::IfResult(IfResult {
cond: Value::Result(0),
Expand All @@ -358,6 +434,8 @@ mod tests {

check_or_save_reference_ir(&SemanticModel {
name: "test_call_variable".to_string(),
required_num_qubits: 0,
required_num_results: 0,
external_functions: vec![
(
"foo".to_string(),
Expand Down Expand Up @@ -450,6 +528,8 @@ mod tests {

check_or_save_reference_ir(&SemanticModel {
name: "test_int_binary_operators".to_string(),
required_num_qubits: 0,
required_num_results: 0,
external_functions: vec![
(
"source".to_string(),
Expand Down
2 changes: 2 additions & 0 deletions qirlib/src/generation/interop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ impl Int {
#[derive(Clone)]
pub struct SemanticModel {
pub name: String,
pub required_num_qubits: u64,
pub required_num_results: u64,
pub external_functions: Vec<(String, Type)>,
pub instructions: Vec<Instruction>,
}
2 changes: 2 additions & 0 deletions qirlib/src/generation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ mod module_conversion_tests {
fn get_model(name: String) -> SemanticModel {
SemanticModel {
name,
required_num_qubits: 1,
required_num_results: 1,
external_functions: vec![],
instructions: vec![Instruction::M(Measured::new(
Value::Qubit(0),
Expand Down

0 comments on commit ca5d3e6

Please sign in to comment.