From 26c66906a9714dc00f316965898ef79a9511872b Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Tue, 15 Oct 2024 17:39:06 +0000 Subject: [PATCH 1/5] Add ability to set name on values --- Cargo.toml | 2 +- pyqir/NOTICE-WHEEL.txt | 4 +- pyqir/pyproject.toml | 2 +- pyqir/pyqir/_native.pyi | 5 +++ pyqir/src/values.rs | 8 ++++ pyqir/tests/test_value_name.py | 73 ++++++++++++++++++++++++++++++++++ 6 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 pyqir/tests/test_value_name.py diff --git a/Cargo.toml b/Cargo.toml index 4b293ae4..3e6f9904 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ resolver = "2" [workspace.package] authors = ["Microsoft"] -version = "0.10.5" +version = "0.10.6" edition = "2021" license = "MIT" homepage = "https://github.com/qir-alliance/pyqir" diff --git a/pyqir/NOTICE-WHEEL.txt b/pyqir/NOTICE-WHEEL.txt index 5c6cd936..2059c050 100644 --- a/pyqir/NOTICE-WHEEL.txt +++ b/pyqir/NOTICE-WHEEL.txt @@ -5595,7 +5595,7 @@ limitations under the License. -qirlib 0.10.5 - SPDX: MIT - MIT License +qirlib 0.10.6 - SPDX: MIT - MIT License https://github.com/qir-alliance/pyqir /* @@ -5970,7 +5970,7 @@ SOFTWARE. -pyqir 0.10.5 - SPDX: MIT - MIT License +pyqir 0.10.6 - SPDX: MIT - MIT License https://github.com/qir-alliance/pyqir MIT License diff --git a/pyqir/pyproject.toml b/pyqir/pyproject.toml index f0ed8d95..5166df51 100644 --- a/pyqir/pyproject.toml +++ b/pyqir/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "pyqir" -version = "0.10.5" +version = "0.10.6" requires-python = ">= 3.8" classifiers = [ "License :: OSI Approved :: MIT License", diff --git a/pyqir/pyqir/_native.pyi b/pyqir/pyqir/_native.pyi index 4b151057..6c93fa9d 100644 --- a/pyqir/pyqir/_native.pyi +++ b/pyqir/pyqir/_native.pyi @@ -925,6 +925,11 @@ class Value: """The name of this value or the empty string if this value is anonymous.""" ... + @name.setter + def name(self, value: str) -> None: + """Sets the name of the value.""" + ... + def __richcmp__(self, other: Value, op: int) -> bool: """ Compares this value to another value. diff --git a/pyqir/src/values.rs b/pyqir/src/values.rs index c9de753f..b561fb52 100644 --- a/pyqir/src/values.rs +++ b/pyqir/src/values.rs @@ -93,6 +93,14 @@ impl Value { } } + #[setter] + fn set_name(&self, value: &str) { + unsafe { + let c_name = &CString::new(value).unwrap(); + LLVMSetValueName2(self.as_ptr(), value.as_ptr().cast(), c_name.as_bytes().len()); + } + } + fn __str__(&self) -> String { unsafe { Message::from_raw(LLVMPrintValueToString(self.as_ptr())) diff --git a/pyqir/tests/test_value_name.py b/pyqir/tests/test_value_name.py new file mode 100644 index 00000000..dce80593 --- /dev/null +++ b/pyqir/tests/test_value_name.py @@ -0,0 +1,73 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +from pathlib import Path + +import pyqir + + +current_file_path = Path(__file__) +# Get the directory of the current file +current_dir = current_file_path.parent + +from pyqir import ( + Context, + is_entry_point, +) + + +def read_file(file_name: str) -> str: + return Path(current_dir / file_name).read_text(encoding="utf-8") + +def test_setting_function_name_changes_name() -> None: + context = Context() + ir = read_file("random_bit.ll") + mod = pyqir.Module.from_ir(context, ir) + entry_point = next(filter(is_entry_point, mod.functions)) + assert entry_point.name == "random_bit" + expected = "new_name" + entry_point.name = expected + entry_point = next(filter(is_entry_point, mod.functions)) + assert entry_point.name == expected + + +def test_setting_constant_name_does_not_do_anything() -> None: + context = pyqir.Context() + const0 = pyqir.const(pyqir.IntType(context, 64), 42) + const0.name = "my_value" + assert const0.name == "" + + +def test_setting_block_name_changes_name() -> None: + mod = pyqir.SimpleModule("test_type_mismatch", 0, 0) + mod.entry_block.name = "my_block" + ir = mod.ir() + assert "my_block:" in ir + + +def test_int_variable() -> None: + mod = pyqir.SimpleModule("test", 0, 0) + i64 = pyqir.IntType(mod.context, 64) + + source = mod.add_external_function("source", pyqir.FunctionType(i64, [])) + sink = mod.add_external_function("sink", pyqir.FunctionType(i64, [i64])) + + source_res = mod.builder.call(source, []) + source_res.name = "my_var" + + sink_res = mod.builder.call(sink, [source_res]) + sink_res.name = "my_res" + ir = mod.ir() + assert "%my_var = call i64 @source()" in ir + assert "%my_res = call i64 @sink(i64 %my_var)" in ir + + +def test_function_name_can_contain_spaces_and_chars() -> None: + mod = pyqir.SimpleModule("test", 0, 0) + expected = "Some - ; name fin" + mod.entry_point.name = expected + + assert f"@\"{expected}\"() #0" in mod.ir() + # verify we can find it by name + func = next(filter(lambda f: f.name == expected, mod._module.functions)) + assert func == mod.entry_point From eb11c72afd101cf207a71b9f696d862e58d7b971 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Tue, 15 Oct 2024 18:38:18 +0000 Subject: [PATCH 2/5] Couple sanity checks and docs in tests --- pyqir/tests/test_value_name.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pyqir/tests/test_value_name.py b/pyqir/tests/test_value_name.py index dce80593..0b2e5773 100644 --- a/pyqir/tests/test_value_name.py +++ b/pyqir/tests/test_value_name.py @@ -67,7 +67,13 @@ def test_function_name_can_contain_spaces_and_chars() -> None: expected = "Some - ; name fin" mod.entry_point.name = expected + # verify the name is use and wrapped in quotes assert f"@\"{expected}\"() #0" in mod.ir() - # verify we can find it by name + + # verify we can find it by name without having to use quotes func = next(filter(lambda f: f.name == expected, mod._module.functions)) assert func == mod.entry_point + + # Double check that the module is valid with this kind of name + mod = pyqir.Module.from_ir(Context(), mod.ir()) + assert mod.verify() is None From 8286b64fb1ea52a92e89c381a509e709c3aec7f5 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Tue, 15 Oct 2024 19:54:13 +0000 Subject: [PATCH 3/5] fmt --- pyqir/src/values.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pyqir/src/values.rs b/pyqir/src/values.rs index b561fb52..e9e6c52f 100644 --- a/pyqir/src/values.rs +++ b/pyqir/src/values.rs @@ -97,7 +97,11 @@ impl Value { fn set_name(&self, value: &str) { unsafe { let c_name = &CString::new(value).unwrap(); - LLVMSetValueName2(self.as_ptr(), value.as_ptr().cast(), c_name.as_bytes().len()); + LLVMSetValueName2( + self.as_ptr(), + value.as_ptr().cast(), + c_name.as_bytes().len(), + ); } } From 27e83595a4967749a0b78d828a7d667f62538427 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Tue, 15 Oct 2024 20:41:42 +0000 Subject: [PATCH 4/5] fmt --- pyqir/tests/test_value_name.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pyqir/tests/test_value_name.py b/pyqir/tests/test_value_name.py index 0b2e5773..a61f69e2 100644 --- a/pyqir/tests/test_value_name.py +++ b/pyqir/tests/test_value_name.py @@ -19,6 +19,7 @@ def read_file(file_name: str) -> str: return Path(current_dir / file_name).read_text(encoding="utf-8") + def test_setting_function_name_changes_name() -> None: context = Context() ir = read_file("random_bit.ll") @@ -48,10 +49,10 @@ def test_setting_block_name_changes_name() -> None: def test_int_variable() -> None: mod = pyqir.SimpleModule("test", 0, 0) i64 = pyqir.IntType(mod.context, 64) - + source = mod.add_external_function("source", pyqir.FunctionType(i64, [])) sink = mod.add_external_function("sink", pyqir.FunctionType(i64, [i64])) - + source_res = mod.builder.call(source, []) source_res.name = "my_var" @@ -68,7 +69,7 @@ def test_function_name_can_contain_spaces_and_chars() -> None: mod.entry_point.name = expected # verify the name is use and wrapped in quotes - assert f"@\"{expected}\"() #0" in mod.ir() + assert f'@"{expected}"() #0' in mod.ir() # verify we can find it by name without having to use quotes func = next(filter(lambda f: f.name == expected, mod._module.functions)) From 275da2601c9ace6fd84db75881fc5bfc7043b632 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Tue, 15 Oct 2024 21:32:05 +0000 Subject: [PATCH 5/5] checks updates --- Cargo.lock | 4 ++-- pyqir/tests/test_value_name.py | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bea172b0..2332be33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -317,7 +317,7 @@ dependencies = [ [[package]] name = "pyqir" -version = "0.10.5" +version = "0.10.6" dependencies = [ "const-str", "llvm-sys 110.0.4", @@ -331,7 +331,7 @@ dependencies = [ [[package]] name = "qirlib" -version = "0.10.5" +version = "0.10.6" dependencies = [ "bitvec", "cc", diff --git a/pyqir/tests/test_value_name.py b/pyqir/tests/test_value_name.py index a61f69e2..b7a51d4d 100644 --- a/pyqir/tests/test_value_name.py +++ b/pyqir/tests/test_value_name.py @@ -64,17 +64,18 @@ def test_int_variable() -> None: def test_function_name_can_contain_spaces_and_chars() -> None: - mod = pyqir.SimpleModule("test", 0, 0) + simple_mod = pyqir.SimpleModule("test", 0, 0) expected = "Some - ; name fin" - mod.entry_point.name = expected + simple_mod.entry_point.name = expected # verify the name is use and wrapped in quotes - assert f'@"{expected}"() #0' in mod.ir() + ir = simple_mod.ir() + assert f'@"{expected}"() #0' in ir # verify we can find it by name without having to use quotes - func = next(filter(lambda f: f.name == expected, mod._module.functions)) - assert func == mod.entry_point + func = next(filter(lambda f: f.name == expected, simple_mod._module.functions)) + assert func == simple_mod.entry_point # Double check that the module is valid with this kind of name - mod = pyqir.Module.from_ir(Context(), mod.ir()) + mod = pyqir.Module.from_ir(Context(), ir) assert mod.verify() is None