Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

test: Add integration tests lowering guppy programs #35

Merged
merged 5 commits into from
Jun 20, 2024
Merged
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
40 changes: 31 additions & 9 deletions .github/workflows/ci-rs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,19 @@ jobs:
toolchain: 'stable'
- name: Configure default rust toolchain
run: rustup override set ${{steps.toolchain.outputs.name}}
- name: Install poetry
run: pipx install poetry
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "poetry"
- name: Install python libraries
run: poetry install
- name: Build with all features
run: cargo test --verbose --workspace --no-run
- name: Tests with all features
run: cargo test --verbose --workspace
run: poetry run -- cargo test --verbose --workspace

# Run tests on other toolchains
tests-other:
Expand All @@ -146,14 +155,19 @@ jobs:
toolchain: ${{ matrix.rust }}
- name: Configure default rust toolchain
run: rustup override set ${{steps.toolchain.outputs.name}}
# - name: Build with no features
# run: cargo test --verbose --workspace --no-default-features --no-run
# - name: Tests with no features
# run: cargo test --verbose --workspace --no-default-features
- name: Install poetry
run: pipx install poetry
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "poetry"
- name: Install python libraries
run: poetry install
- name: Build with all features
run: cargo test --verbose --workspace --no-run
- name: Tests with all features
run: cargo test --verbose --workspace
run: poetry run -- cargo test --verbose --workspace

# This is a meta job to mark successful completion of the required checks,
# even if they are skipped due to no changes in the relevant files.
Expand Down Expand Up @@ -202,13 +216,21 @@ jobs:
# https://github.com/rust-lang/rust/issues/125474
toolchain: 'nightly-2024-05-22'
components: llvm-tools-preview
- name: Install poetry
run: pipx install poetry
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "poetry"
- name: Install python libraries
run: poetry install
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Run tests with coverage instrumentation
run: |
cargo llvm-cov clean --workspace
# cargo llvm-cov --no-report --workspace --no-default-features --doctests
cargo llvm-cov --no-report --workspace --doctests
poetry run -- cargo llvm-cov clean --workspace
poetry run -- cargo llvm-cov --no-report --workspace --doctests
- name: Generate coverage report
run: cargo llvm-cov report --codecov --output-path coverage.json
- name: Upload coverage to codecov.io
Expand Down
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ downcast-rs= "1.2.1"
insta = "1.39.0"
rstest = "0.19.0"
portgraph = "0.12.1"
pathsearch = "0.2.0"
serde_json = "1.0.117"

[profile.dev.package]
insta.opt-level = 3
Expand Down
8 changes: 8 additions & 0 deletions devenv.nix
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,13 @@ in {
enable = true;
channel = "stable";
};

languages.python = {
enable = true;
poetry = {
enable = true;
activate.enable = true;
};
};
};
}
204 changes: 204 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[tool.poetry]
name = "hugr-llvm"
version = "0.1.0"
description = ""
authors = ["Douglas Wilson"]
readme = "README.md"
package-mode = false

[tool.poetry.dependencies]
python = "^3.11"
guppylang= "^0.5.2"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
2 changes: 1 addition & 1 deletion src/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ impl<'c, H: HugrView> CodegenExtsMap<'c, H> {
let b = self
.extensions
.get(extension)
.ok_or(anyhow!("Unknown extension: {}", extension))?;
.ok_or(anyhow!("CodegenExtsMap: Unknown extension: {}", extension))?;
Ok(b.as_ref())
}

Expand Down
6 changes: 4 additions & 2 deletions src/custom/int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ fn emit_icmp<'c, H: HugrView>(

impl<'c, H: HugrView> EmitOp<'c, CustomOp, H> for IntOpEmitter<'c, '_, H> {
fn emit(&mut self, args: EmitOpArgs<'c, CustomOp, H>) -> Result<()> {
let iot = ConcreteIntOp::from_optype(&args.node().generalise())
.ok_or(anyhow!("IntOpEmitter from_optype_failed"))?;
let iot = ConcreteIntOp::from_optype(&args.node().generalise()).ok_or(anyhow!(
"IntOpEmitter from_optype_failed: {:?}",
args.node().as_ref()
))?;
match iot.name().as_str() {
"iadd" => emit_custom_binary_op(self.0, args, |builder, lhs, rhs| {
Ok(vec![builder
Expand Down
33 changes: 32 additions & 1 deletion src/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ use hugr::{
HugrView, Node,
};
use inkwell::{
builder::Builder,
context::Context,
module::{Linkage, Module},
types::{AnyType, BasicType, BasicTypeEnum, FunctionType},
values::{FunctionValue, GlobalValue},
values::{BasicValueEnum, CallSiteValue, FunctionValue, GlobalValue},
};
use std::{collections::HashSet, hash::Hash, rc::Rc};

Expand Down Expand Up @@ -411,5 +412,35 @@ impl<'c, H: HugrView> EmitHugr<'c, H> {
}
}

/// Extract all return values from the result of a `call`.
///
/// LLVM only supports functions with exactly zero or one return value.
/// For functions with multiple return values, we return a struct containing
/// all the return values.
///
/// `inkwell` provides a helper [Builder::build_aggregate_return] to construct
/// the return value, see `EmitHugr::emit_func_impl`. This function performs the
/// inverse.
pub fn deaggregate_call_result<'c>(
builder: &Builder<'c>,
call_result: CallSiteValue<'c>,
num_results: usize,
) -> Result<Vec<BasicValueEnum<'c>>> {
let call_result = call_result.try_as_basic_value();
Ok(match num_results as u32 {
0 => {
call_result.expect_right("void");
vec![]
}
1 => vec![call_result.expect_left("non-void")],
n => {
let return_struct = call_result.expect_left("non-void").into_struct_value();
(0..n)
.map(|i| builder.build_extract_value(return_struct, i, ""))
.collect::<Result<Vec<_>, _>>()?
}
})
}

#[cfg(test)]
pub mod test;
21 changes: 4 additions & 17 deletions src/emit/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::fat::FatExt as _;
use crate::{fat::FatNode, types::LLVMSumType};

use super::{
deaggregate_call_result,
func::{EmitFuncContext, RowPromise},
EmitOp, EmitOpArgs,
};
Expand Down Expand Up @@ -353,23 +354,9 @@ fn emit_call<'c, H: HugrView>(
};
let inputs = args.inputs.into_iter().map_into().collect_vec();
let builder = context.builder();
let call = builder
.build_call(func?, inputs.as_slice(), "")?
.try_as_basic_value();
let rets = match args.outputs.len() as u32 {
0 => {
call.expect_right("void");
vec![]
}
1 => vec![call.expect_left("non-void")],
n => {
let return_struct = call.expect_left("non-void").into_struct_value();
(0..n)
.map(|i| builder.build_extract_value(return_struct, i, ""))
.collect::<Result<Vec<_>, _>>()?
}
};
args.outputs.finish(builder, rets)
let call = builder.build_call(func?, inputs.as_slice(), "")?;
let call_results = deaggregate_call_result(builder, call, args.outputs.len())?;
args.outputs.finish(builder, call_results)
}

fn emit_cfg<'c, H: HugrView>(
Expand Down
Loading