Repository: qir-alliance/pyqir (language: python)

Issue:
Support generating multiple entry points
Closes #194.


Discussion / hints:

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index a0fa9ede..a5737da0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -483,6 +483,7 @@ dependencies = [
  "cmake",
  "inkwell",
  "lazy_static",
+ "libc",
  "llvm-sys 110.0.4",
  "llvm-sys 120.2.5",
  "llvm-sys 130.0.5",
diff --git a/pyqir/src/builder.rs b/pyqir/src/builder.rs
index f77351a6..d454a2fc 100644
--- a/pyqir/src/builder.rs
+++ b/pyqir/src/builder.rs
@@ -4,7 +4,6 @@
 use crate::{
     context::{self, Context},
     instructions::IntPredicate,
-    module::Module,
     values::{self, AnyValue, Value},
 };
 use inkwell::{
@@ -12,6 +11,7 @@ use inkwell::{
     values::{AnyValueEnum, CallableValue, IntValue},
 };
 use pyo3::{exceptions::PyValueError, prelude::*, types::PySequence};
+use qirlib::builder::Ext;
 use std::{
     convert::{Into, TryFrom, TryInto},
     mem::transmute,
@@ -23,9 +23,6 @@ use std::{
 pub(crate) struct Builder {
     builder: inkwell::builder::Builder<'static>,
     context: Py<Context>,
-    // TODO: In principle, the module could be extracted from the builder.
-    // See https://github.com/TheDan64/inkwell/issues/347.
-    module: Py<Module>,
 }
 
 #[pymethods]
@@ -248,19 +245,16 @@ impl Builder {
         r#false: Option<&PyAny>,
     ) -> PyResult<()> {
         context::require_same(py, [&self.context, cond.context()])?;
-        let module = self.module.borrow(py);
-        let builder = qirlib::Builder::from(&self.builder, unsafe { module.get() });
-        builder.try_build_if(
+        self.builder.try_build_if(
             unsafe { cond.get() }.try_into()?,
-            |_| r#true.iter().try_for_each(|f| f.call0().map(|_| ())),
-            |_| r#false.iter().try_for_each(|f| f.call0().map(|_| ())),
+            || r#true.iter().try_for_each(|f| f.call0().map(|_| ())),
+            || r#false.iter().try_for_each(|f| f.call0().map(|_| ())),
         )
     }
 }
 
 impl Builder {
-    pub(crate) fn new(py: Python, module: Py<Module>) -> Self {
-        let context = module.borrow(py).context().clone();
+    pub(crate) fn new(py: Python, context: Py<Context>) -> Self {
         let builder = {
             let context = context.borrow(py);
             let builder = context.create_builder();
@@ -271,11 +265,7 @@ impl Builder {
             }
         };
 
-        Self {
-            builder,
-            context,
-            module,
-        }
+        Self { builder, context }
     }
 
     pub(crate) unsafe fn get(&self) -> &inkwell::builder::Builder<'static> {
@@ -285,10 +275,6 @@ impl Builder {
     pub(crate) fn context(&self) -> &Py<Context> {
         &self.context
     }
-
-    pub(crate) fn module(&self) -> &Py<Module> {
-        &self.module
-    }
 }
 
 struct Callable<'ctx> {
diff --git a/pyqir/src/qis.rs b/pyqir/src/qis.rs
index 5e8452e5..35bc2c1f 100644
--- a/pyqir/src/qis.rs
+++ b/pyqir/src/qis.rs
@@ -7,7 +7,7 @@ use crate::{
     values::{self, Value},
 };
 use pyo3::prelude::*;
-use qirlib::BuilderBasicQisExt;
+use qirlib::qis::BuilderExt;
 use std::convert::TryInto;
 
 /// An instruction builder that generates instructions from the basic quantum instruction set.
@@ -35,9 +35,7 @@ impl BasicQisBuilder {
     fn cx(&self, py: Python, control: &Value, target: &Value) -> PyResult<()> {
         let builder = self.builder.borrow(py);
         context::require_same(py, [builder.context(), control.context(), target.context()])?;
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
-        builder.build_cx(
+        unsafe { builder.get() }.build_cx(
             unsafe { control.get() }.try_into()?,
             unsafe { target.get() }.try_into()?,
         );
@@ -53,9 +51,7 @@ impl BasicQisBuilder {
     fn cz(&self, py: Python, control: &Value, target: &Value) -> PyResult<()> {
         let builder = self.builder.borrow(py);
         context::require_same(py, [builder.context(), control.context(), target.context()])?;
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
-        builder.build_cz(
+        unsafe { builder.get() }.build_cz(
             unsafe { control.get() }.try_into()?,
             unsafe { target.get() }.try_into()?,
         );
@@ -70,9 +66,7 @@ impl BasicQisBuilder {
     fn h(&self, py: Python, qubit: &Value) -> PyResult<()> {
         let builder = self.builder.borrow(py);
         context::require_same(py, [builder.context(), qubit.context()])?;
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
-        builder.build_h(unsafe { qubit.get() }.try_into()?);
+        unsafe { builder.get() }.build_h(unsafe { qubit.get() }.try_into()?);
         Ok(())
     }
 
@@ -85,9 +79,7 @@ impl BasicQisBuilder {
     fn mz(&self, py: Python, qubit: &Value, result: &Value) -> PyResult<()> {
         let builder = self.builder.borrow(py);
         context::require_same(py, [builder.context(), qubit.context(), result.context()])?;
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
-        builder.build_mz(
+        unsafe { builder.get() }.build_mz(
             unsafe { qubit.get() }.try_into()?,
             unsafe { result.get() }.try_into()?,
         );
@@ -102,9 +94,7 @@ impl BasicQisBuilder {
     fn reset(&self, py: Python, qubit: &Value) -> PyResult<()> {
         let builder = self.builder.borrow(py);
         context::require_same(py, [builder.context(), qubit.context()])?;
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
-        builder.build_reset(unsafe { qubit.get() }.try_into()?);
+        unsafe { builder.get() }.build_reset(unsafe { qubit.get() }.try_into()?);
         Ok(())
     }
 
@@ -123,10 +113,8 @@ impl BasicQisBuilder {
         )?;
 
         let context = builder.context().borrow(py);
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
         let theta = unsafe { values::extract_any(&context.f64_type(), theta)? };
-        builder.build_rx(theta.try_into()?, unsafe { qubit.get() }.try_into()?);
+        unsafe { builder.get() }.build_rx(theta.try_into()?, unsafe { qubit.get() }.try_into()?);
         Ok(())
     }
 
@@ -145,10 +133,8 @@ impl BasicQisBuilder {
         )?;
 
         let context = builder.context().borrow(py);
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
         let theta = unsafe { values::extract_any(&context.f64_type(), theta)? };
-        builder.build_ry(theta.try_into()?, unsafe { qubit.get() }.try_into()?);
+        unsafe { builder.get() }.build_ry(theta.try_into()?, unsafe { qubit.get() }.try_into()?);
         Ok(())
     }
 
@@ -167,10 +153,8 @@ impl BasicQisBuilder {
         )?;
 
         let context = builder.context().borrow(py);
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
         let theta = unsafe { values::extract_any(&context.f64_type(), theta)? };
-        builder.build_rz(theta.try_into()?, unsafe { qubit.get() }.try_into()?);
+        unsafe { builder.get() }.build_rz(theta.try_into()?, unsafe { qubit.get() }.try_into()?);
         Ok(())
     }
 
@@ -182,9 +166,7 @@ impl BasicQisBuilder {
     fn s(&self, py: Python, qubit: &Value) -> PyResult<()> {
         let builder = self.builder.borrow(py);
         context::require_same(py, [builder.context(), qubit.context()])?;
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
-        builder.build_s(unsafe { qubit.get() }.try_into()?);
+        unsafe { builder.get() }.build_s(unsafe { qubit.get() }.try_into()?);
         Ok(())
     }
 
@@ -196,9 +178,7 @@ impl BasicQisBuilder {
     fn s_adj(&self, py: Python, qubit: &Value) -> PyResult<()> {
         let builder = self.builder.borrow(py);
         context::require_same(py, [builder.context(), qubit.context()])?;
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
-        builder.build_s_adj(unsafe { qubit.get() }.try_into()?);
+        unsafe { builder.get() }.build_s_adj(unsafe { qubit.get() }.try_into()?);
         Ok(())
     }
 
@@ -210,9 +190,7 @@ impl BasicQisBuilder {
     fn t(&self, py: Python, qubit: &Value) -> PyResult<()> {
         let builder = self.builder.borrow(py);
         context::require_same(py, [builder.context(), qubit.context()])?;
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
-        builder.build_t(unsafe { qubit.get() }.try_into()?);
+        unsafe { builder.get() }.build_t(unsafe { qubit.get() }.try_into()?);
         Ok(())
     }
 
@@ -224,9 +202,7 @@ impl BasicQisBuilder {
     fn t_adj(&self, py: Python, qubit: &Value) -> PyResult<()> {
         let builder = self.builder.borrow(py);
         context::require_same(py, [builder.context(), qubit.context()])?;
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
-        builder.build_t_adj(unsafe { qubit.get() }.try_into()?);
+        unsafe { builder.get() }.build_t_adj(unsafe { qubit.get() }.try_into()?);
         Ok(())
     }
 
@@ -238,9 +214,7 @@ impl BasicQisBuilder {
     fn x(&self, py: Python, qubit: &Value) -> PyResult<()> {
         let builder = self.builder.borrow(py);
         context::require_same(py, [builder.context(), qubit.context()])?;
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
-        builder.build_x(unsafe { qubit.get() }.try_into()?);
+        unsafe { builder.get() }.build_x(unsafe { qubit.get() }.try_into()?);
         Ok(())
     }
 
@@ -252,9 +226,7 @@ impl BasicQisBuilder {
     fn y(&self, py: Python, qubit: &Value) -> PyResult<()> {
         let builder = self.builder.borrow(py);
         context::require_same(py, [builder.context(), qubit.context()])?;
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
-        builder.build_y(unsafe { qubit.get() }.try_into()?);
+        unsafe { builder.get() }.build_y(unsafe { qubit.get() }.try_into()?);
         Ok(())
     }
 
@@ -266,9 +238,7 @@ impl BasicQisBuilder {
     fn z(&self, py: Python, qubit: &Value) -> PyResult<()> {
         let builder = self.builder.borrow(py);
         context::require_same(py, [builder.context(), qubit.context()])?;
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
-        builder.build_z(unsafe { qubit.get() }.try_into()?);
+        unsafe { builder.get() }.build_z(unsafe { qubit.get() }.try_into()?);
         Ok(())
     }
 
@@ -294,12 +264,10 @@ impl BasicQisBuilder {
     ) -> PyResult<()> {
         let builder = self.builder.borrow(py);
         context::require_same(py, [builder.context(), cond.context()])?;
-        let module = builder.module().borrow(py);
-        let builder = unsafe { qirlib::Builder::from(builder.get(), module.get()) };
-        builder.try_build_if_result(
+        unsafe { builder.get() }.try_build_if_result(
             unsafe { cond.get() }.try_into()?,
-            |_| one.iter().try_for_each(|f| f.call0().map(|_| ())),
-            |_| zero.iter().try_for_each(|f| f.call0().map(|_| ())),
+            || one.iter().try_for_each(|f| f.call0().map(|_| ())),
+            || zero.iter().try_for_each(|f| f.call0().map(|_| ())),
         )
     }
 }
diff --git a/pyqir/src/simple.rs b/pyqir/src/simple.rs
index eccbe4b6..77ca3674 100644
--- a/pyqir/src/simple.rs
+++ b/pyqir/src/simple.rs
@@ -53,7 +53,7 @@ impl SimpleModule {
     fn new(py: Python, name: &str, num_qubits: u64, num_results: u64) -> PyResult<SimpleModule> {
         let context = Py::new(py, Context::new())?;
         let module = Py::new(py, Module::new(py, context.clone(), name))?;
-        let builder = Py::new(py, Builder::new(py, module.clone()))?;
+        let builder = Py::new(py, Builder::new(py, context.clone()))?;
 
         {
             let builder = builder.borrow(py);
diff --git a/qirlib/Cargo.toml b/qirlib/Cargo.toml
index e9ff7cce..f00a0980 100644
--- a/qirlib/Cargo.toml
+++ b/qirlib/Cargo.toml
@@ -14,6 +14,7 @@ rust-version = "1.59"
 bitvec = "1.0"
 inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", default-features = false, features = ["internal-getters", "target-x86"] }
 lazy_static = "1.4"
+libc = "0.2"
 llvm-sys-110 = { package = "llvm-sys", version = "110.0", optional = true }
 llvm-sys-120 = { package = "llvm-sys", version = "120.2", optional = true }
 llvm-sys-130 = { package = "llvm-sys", version = "130.0", optional = true }
diff --git a/qirlib/src/builder.rs b/qirlib/src/builder.rs
index e4535641..a5caaf72 100644
--- a/qirlib/src/builder.rs
+++ b/qirlib/src/builder.rs
@@ -1,100 +1,89 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-use inkwell::{builder::Builder as BuilderBase, module::Module, values::IntValue};
-use std::{borrow::Borrow, convert::Infallible, ops::Deref};
+use inkwell::{basic_block::BasicBlock, builder::Builder, values::IntValue, LLVMReference};
+use llvm_sys::{core::LLVMBuildCondBr, prelude::*};
+use std::convert::Infallible;
 
-// TODO: With LLVM, it's possible to get the module that a builder is positioned in using only the
-// builder itself. But it's not possible with Inkwell, so we have to bundle the references together.
-// See https://github.com/TheDan64/inkwell/issues/347
-pub struct Builder<'ctx, 'a> {
-    builder: OwnOrBorrow<'a, BuilderBase<'ctx>>,
-    module: &'a Module<'ctx>,
-}
-
-impl<'ctx, 'a> Deref for Builder<'ctx, 'a> {
-    type Target = BuilderBase<'ctx>;
+pub trait Ext {
+    fn build_if(&self, cond: IntValue, build_true: impl FnOnce(), build_false: impl FnOnce());
 
-    fn deref(&self) -> &Self::Target {
-        match &self.builder {
-            OwnOrBorrow::Owned(b) => b,
-            OwnOrBorrow::Borrowed(b) => b,
-        }
-    }
+    #[allow(clippy::missing_errors_doc)]
+    fn try_build_if<E>(
+        &self,
+        cond: IntValue,
+        build_true: impl FnOnce() -> Result<(), E>,
+        build_false: impl FnOnce() -> Result<(), E>,
+    ) -> Result<(), E>;
 }
 
-impl<'ctx, 'a> Builder<'ctx, 'a> {
-    pub fn new(module: &'a Module<'ctx>) -> Self {
-        Self {
-            builder: OwnOrBorrow::Owned(module.get_context().create_builder()),
-            module,
-        }
-    }
-
-    pub fn from(builder: &'a BuilderBase<'ctx>, module: &'a Module<'ctx>) -> Self {
-        Self {
-            builder: OwnOrBorrow::Borrowed(builder),
-            module,
-        }
-    }
-
-    #[must_use]
-    pub fn module(&self) -> &Module<'ctx> {
-        self.module.borrow()
+impl Ext for Builder<'_> {
+    fn build_if(&self, cond: IntValue, build_true: impl FnOnce(), build_false: impl FnOnce()) {
+        unsafe { build_if_unchecked(self, cond.get_ref(), build_true, build_false) }
     }
 
-    #[allow(clippy::missing_panics_doc)]
-    pub fn build_if(
+    fn try_build_if<E>(
         &self,
         cond: IntValue,
-        build_true: impl FnOnce(&Self),
-        build_false: impl FnOnce(&Self),
-    ) {
-        let always_ok: Result<(), Infallible> = Ok(());
-        self.try_build_if(
-            cond,
-            |builder| {
-                build_true(builder);
-                always_ok
-            },
-            |builder| {
-                build_false(builder);
-                always_ok
-            },
-        )
-        .unwrap();
+        build_true: impl FnOnce() -> Result<(), E>,
+        build_false: impl FnOnce() -> Result<(), E>,
+    ) -> Result<(), E> {
+        unsafe { try_build_if_unchecked(self, cond.get_ref(), build_true, build_false) }
     }
+}
 
-    #[allow(clippy::missing_errors_doc)]
-    #[allow(clippy::missing_panics_doc)]
-    pub fn try_build_if<E>(
-        &self,
-        cond: IntValue,
-        build_true: impl FnOnce(&Self) -> Result<(), E>,
-        build_false: impl FnOnce(&Self) -> Result<(), E>,
-    ) -> Result<(), E> {
-        let insert_block = self.get_insert_block().unwrap();
-        let context = insert_block.get_context();
-        let function = insert_block.get_parent().unwrap();
-        let then_block = context.append_basic_block(function, "then");
-        let else_block = context.append_basic_block(function, "else");
-        self.build_conditional_branch(cond, then_block, else_block);
-        let continue_block = context.append_basic_block(function, "continue");
+pub(crate) unsafe fn build_if_unchecked(
+    builder: &Builder,
+    cond: LLVMValueRef,
+    build_true: impl FnOnce(),
+    build_false: impl FnOnce(),
+) {
+    let always_ok: Result<(), Infallible> = Ok(());
+    try_build_if_unchecked(
+        builder,
+        cond,
+        || {
+            build_true();
+            always_ok
+        },
+        || {
+            build_false();
+            always_ok
+        },
+    )
+    .unwrap();
+}
 
-        self.position_at_end(then_block);
-        build_true(self)?;
-        self.build_unconditional_branch(continue_block);
+pub(crate) unsafe fn try_build_if_unchecked<E>(
+    builder: &Builder,
+    cond: LLVMValueRef,
+    build_true: impl FnOnce() -> Result<(), E>,
+    build_false: impl FnOnce() -> Result<(), E>,
+) -> Result<(), E> {
+    let function = builder
+        .get_insert_block()
+        .and_then(BasicBlock::get_parent)
+        .expect("The builder's position has not been set.");
 
-        self.position_at_end(else_block);
-        build_false(self)?;
-        self.build_unconditional_branch(continue_block);
+    let context = function.get_type().get_context();
+    let then_block = context.append_basic_block(function, "then");
+    let else_block = context.append_basic_block(function, "else");
+    LLVMBuildCondBr(
+        builder.get_ref(),
+        cond,
+        then_block.get_ref(),
+        else_block.get_ref(),
+    );
+    let continue_block = context.append_basic_block(function, "continue");
 
-        self.position_at_end(continue_block);
-        Ok(())
-    }
-}
+    builder.position_at_end(then_block);
+    build_true()?;
+    builder.build_unconditional_branch(continue_block);
+
+    builder.position_at_end(else_block);
+    build_false()?;
+    builder.build_unconditional_branch(continue_block);
 
-enum OwnOrBorrow<'a, T> {
-    Owned(T),
-    Borrowed(&'a T),
+    builder.position_at_end(continue_block);
+    Ok(())
 }
diff --git a/qirlib/src/lib.rs b/qirlib/src/lib.rs
index 013da4ed..f6b49efc 100644
--- a/qirlib/src/lib.rs
+++ b/qirlib/src/lib.rs
@@ -13,18 +13,13 @@ extern crate llvm_sys_130 as llvm_sys;
 extern crate llvm_sys_140 as llvm_sys;
 
 #[cfg(not(feature = "no-llvm-linking"))]
-pub use builder::Builder;
-#[cfg(not(feature = "no-llvm-linking"))]
-pub use qis::BuilderBasicQisExt;
-
-#[cfg(not(feature = "no-llvm-linking"))]
-mod builder;
+pub mod builder;
 #[cfg(not(feature = "no-llvm-linking"))]
 pub mod evaluation;
 #[cfg(not(feature = "no-llvm-linking"))]
 pub mod module;
 #[cfg(not(feature = "no-llvm-linking"))]
-mod qis;
+pub mod qis;
 #[cfg(all(test, not(feature = "no-llvm-linking")))]
 mod tests;
 #[cfg(not(feature = "no-llvm-linking"))]
diff --git a/qirlib/src/qis.rs b/qirlib/src/qis.rs
index c0f22639..f0b1f736 100644
--- a/qirlib/src/qis.rs
+++ b/qirlib/src/qis.rs
@@ -1,14 +1,28 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-use super::{builder::Builder, types};
+use crate::{
+    builder::{build_if_unchecked, try_build_if_unchecked},
+    types,
+};
 use inkwell::{
-    module::{Linkage, Module},
-    types::{BasicMetadataTypeEnum, BasicType, BasicTypeEnum},
-    values::{FloatValue, FunctionValue, IntValue, PointerValue},
+    builder::Builder,
+    values::{FloatValue, PointerValue},
+    LLVMReference,
+};
+use libc::c_uint;
+use llvm_sys::{
+    core::{
+        LLVMAddFunction, LLVMBuildCall, LLVMDoubleTypeInContext, LLVMFunctionType,
+        LLVMGetBasicBlockParent, LLVMGetGlobalParent, LLVMGetInsertBlock, LLVMGetModuleContext,
+        LLVMGetNamedFunction, LLVMInt1TypeInContext, LLVMSetLinkage, LLVMVoidTypeInContext,
+    },
+    prelude::*,
+    LLVMLinkage,
 };
+use std::{ffi::CString, ptr::NonNull};
 
-pub trait BuilderBasicQisExt<'ctx> {
+pub trait BuilderExt<'ctx> {
     fn build_cx(&self, control: PointerValue, qubit: PointerValue);
 
     fn build_cz(&self, control: PointerValue, qubit: PointerValue);
@@ -42,112 +56,192 @@ pub trait BuilderBasicQisExt<'ctx> {
     fn build_if_result(
         &self,
         cond: PointerValue<'ctx>,
-        build_one: impl FnOnce(&Self),
-        build_zero: impl FnOnce(&Self),
+        build_one: impl FnOnce(),
+        build_zero: impl FnOnce(),
     );
 
     #[allow(clippy::missing_errors_doc)]
     fn try_build_if_result<E>(
         &self,
         cond: PointerValue<'ctx>,
-        build_one: impl FnOnce(&Self) -> Result<(), E>,
-        build_zero: impl FnOnce(&Self) -> Result<(), E>,
+        build_one: impl FnOnce() -> Result<(), E>,
+        build_zero: impl FnOnce() -> Result<(), E>,
     ) -> Result<(), E>;
 }
 
-impl<'ctx, 'a> BuilderBasicQisExt<'ctx> for Builder<'ctx, 'a> {
+impl<'ctx> BuilderExt<'ctx> for Builder<'ctx> {
     fn build_cx(&self, control: PointerValue, qubit: PointerValue) {
-        let function = controlled_gate(self.module(), "cnot");
-        self.build_call(function, &[control.into(), qubit.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                controlled_gate(builder_module(self.get_ref()), "cnot"),
+                &mut [control.get_ref(), qubit.get_ref()],
+            );
+        }
     }
 
     fn build_cz(&self, control: PointerValue, qubit: PointerValue) {
-        let function = controlled_gate(self.module(), "cz");
-        self.build_call(function, &[control.into(), qubit.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                controlled_gate(builder_module(self.get_ref()), "cz"),
+                &mut [control.get_ref(), qubit.get_ref()],
+            );
+        }
     }
 
     fn build_h(&self, qubit: PointerValue) {
-        let function = simple_gate(self.module(), "h", Functor::Body);
-        self.build_call(function, &[qubit.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                simple_gate(builder_module(self.get_ref()), "h", Functor::Body),
+                &mut [qubit.get_ref()],
+            );
+        }
     }
 
     fn build_s(&self, qubit: PointerValue) {
-        let function = simple_gate(self.module(), "s", Functor::Body);
-        self.build_call(function, &[qubit.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                simple_gate(builder_module(self.get_ref()), "s", Functor::Body),
+                &mut [qubit.get_ref()],
+            );
+        }
     }
 
     fn build_s_adj(&self, qubit: PointerValue) {
-        let function = simple_gate(self.module(), "s", Functor::Adjoint);
-        self.build_call(function, &[qubit.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                simple_gate(builder_module(self.get_ref()), "s", Functor::Adjoint),
+                &mut [qubit.get_ref()],
+            );
+        }
     }
 
     fn build_t(&self, qubit: PointerValue) {
-        let function = simple_gate(self.module(), "t", Functor::Body);
-        self.build_call(function, &[qubit.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                simple_gate(builder_module(self.get_ref()), "t", Functor::Body),
+                &mut [qubit.get_ref()],
+            );
+        }
     }
 
     fn build_t_adj(&self, qubit: PointerValue) {
-        let function = simple_gate(self.module(), "t", Functor::Adjoint);
-        self.build_call(function, &[qubit.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                simple_gate(builder_module(self.get_ref()), "t", Functor::Adjoint),
+                &mut [qubit.get_ref()],
+            );
+        }
     }
 
     fn build_x(&self, qubit: PointerValue) {
-        let function = simple_gate(self.module(), "x", Functor::Body);
-        self.build_call(function, &[qubit.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                simple_gate(builder_module(self.get_ref()), "x", Functor::Body),
+                &mut [qubit.get_ref()],
+            );
+        }
     }
 
     fn build_y(&self, qubit: PointerValue) {
-        let function = simple_gate(self.module(), "y", Functor::Body);
-        self.build_call(function, &[qubit.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                simple_gate(builder_module(self.get_ref()), "y", Functor::Body),
+                &mut [qubit.get_ref()],
+            );
+        }
     }
 
     fn build_z(&self, qubit: PointerValue) {
-        let function = simple_gate(self.module(), "z", Functor::Body);
-        self.build_call(function, &[qubit.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                simple_gate(builder_module(self.get_ref()), "z", Functor::Body),
+                &mut [qubit.get_ref()],
+            );
+        }
     }
 
     fn build_rx(&self, theta: FloatValue, qubit: PointerValue) {
-        let function = rotation_gate(self.module(), "rx");
-        self.build_call(function, &[theta.into(), qubit.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                rotation_gate(builder_module(self.get_ref()), "rx"),
+                &mut [theta.get_ref(), qubit.get_ref()],
+            );
+        }
     }
 
     fn build_ry(&self, theta: FloatValue, qubit: PointerValue) {
-        let function = rotation_gate(self.module(), "ry");
-        self.build_call(function, &[theta.into(), qubit.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                rotation_gate(builder_module(self.get_ref()), "ry"),
+                &mut [theta.get_ref(), qubit.get_ref()],
+            );
+        }
     }
 
     fn build_rz(&self, theta: FloatValue, qubit: PointerValue) {
-        let function = rotation_gate(self.module(), "rz");
-        self.build_call(function, &[theta.into(), qubit.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                rotation_gate(builder_module(self.get_ref()), "rz"),
+                &mut [theta.get_ref(), qubit.get_ref()],
+            );
+        }
     }
 
     fn build_reset(&self, qubit: PointerValue) {
-        let function = simple_gate(self.module(), "reset", Functor::Body);
-        self.build_call(function, &[qubit.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                simple_gate(builder_module(self.get_ref()), "reset", Functor::Body),
+                &mut [qubit.get_ref()],
+            );
+        }
     }
 
     fn build_mz(&self, qubit: PointerValue, result: PointerValue) {
-        self.build_call(mz(self.module()), &[qubit.into(), result.into()], "");
+        unsafe {
+            build_call(
+                self.get_ref(),
+                mz(builder_module(self.get_ref())),
+                &mut [qubit.get_ref(), result.get_ref()],
+            );
+        }
     }
 
     fn build_if_result(
         &self,
         cond: PointerValue<'ctx>,
-        build_one: impl FnOnce(&Self),
-        build_zero: impl FnOnce(&Self),
+        build_one: impl FnOnce(),
+        build_zero: impl FnOnce(),
     ) {
-        let bool_cond = build_read_result(self, cond);
-        self.build_if(bool_cond, build_one, build_zero);
+        unsafe {
+            let bool_cond = build_read_result(self.get_ref(), cond.get_ref());
+            build_if_unchecked(self, bool_cond, build_one, build_zero);
+        }
     }
 
     fn try_build_if_result<E>(
         &self,
         cond: PointerValue<'ctx>,
-        build_one: impl FnOnce(&Self) -> Result<(), E>,
-        build_zero: impl FnOnce(&Self) -> Result<(), E>,
+        build_one: impl FnOnce() -> Result<(), E>,
+        build_zero: impl FnOnce() -> Result<(), E>,
     ) -> Result<(), E> {
-        let bool_cond = build_read_result(self, cond);
-        self.try_build_if(bool_cond, build_one, build_zero)
+        unsafe {
+            let bool_cond = build_read_result(self.get_ref(), cond.get_ref());
+            try_build_if_unchecked(self, bool_cond, build_one, build_zero)
+        }
     }
 }
 
@@ -157,89 +251,109 @@ enum Functor {
     Adjoint,
 }
 
-fn build_read_result<'ctx>(
-    builder: &Builder<'ctx, '_>,
-    result: PointerValue<'ctx>,
-) -> IntValue<'ctx> {
-    builder
-        .build_call(read_result(builder.module()), &[result.into()], "")
-        .try_as_basic_value()
-        .left()
-        .unwrap()
-        .into_int_value()
+unsafe fn build_read_result(builder: LLVMBuilderRef, result: LLVMValueRef) -> LLVMValueRef {
+    build_call(builder, read_result(builder_module(builder)), &mut [result])
+}
+
+unsafe fn build_call(
+    builder: LLVMBuilderRef,
+    function: LLVMValueRef,
+    args: &mut [LLVMValueRef],
+) -> LLVMValueRef {
+    LLVMBuildCall(
+        builder,
+        function,
+        args.as_mut_ptr(),
+        c_uint::try_from(args.len()).unwrap(),
+        [0].as_ptr(),
+    )
 }
 
-fn simple_gate<'ctx>(module: &Module<'ctx>, name: &str, functor: Functor) -> FunctionValue<'ctx> {
-    let qubit_type = types::qubit(&module.get_context()).into();
-    declare(module, name, functor, None, &[qubit_type])
+unsafe fn builder_module(builder: LLVMBuilderRef) -> LLVMModuleRef {
+    NonNull::new(LLVMGetInsertBlock(builder))
+        .and_then(|b| NonNull::new(LLVMGetBasicBlockParent(b.as_ptr())))
+        .and_then(|v| NonNull::new(LLVMGetGlobalParent(v.as_ptr())))
+        .expect("The builder's position has not been set.")
+        .as_ptr()
 }
 
-fn controlled_gate<'ctx>(module: &Module<'ctx>, name: &str) -> FunctionValue<'ctx> {
-    let qubit_type = types::qubit(&module.get_context()).into();
-    declare(module, name, Functor::Body, None, &[qubit_type, qubit_type])
+unsafe fn simple_gate(module: LLVMModuleRef, name: &str, functor: Functor) -> LLVMValueRef {
+    let context = LLVMGetModuleContext(module);
+    let ty = function_type(
+        LLVMVoidTypeInContext(context),
+        &mut [types::qubit_unchecked(context)],
+    );
+    declare(module, name, functor, ty)
 }
 
-fn rotation_gate<'ctx>(module: &Module<'ctx>, name: &str) -> FunctionValue<'ctx> {
-    let double_type = module.get_context().f64_type().into();
-    let qubit_type = types::qubit(&module.get_context()).into();
-    declare(
-        module,
-        name,
-        Functor::Body,
-        None,
-        &[double_type, qubit_type],
-    )
+unsafe fn controlled_gate(module: LLVMModuleRef, name: &str) -> LLVMValueRef {
+    let context = LLVMGetModuleContext(module);
+    let qubit = types::qubit_unchecked(context);
+    let ty = function_type(LLVMVoidTypeInContext(context), &mut [qubit, qubit]);
+    declare(module, name, Functor::Body, ty)
 }
 
-fn mz<'ctx>(module: &Module<'ctx>) -> FunctionValue<'ctx> {
-    let context = module.get_context();
-    let qubit_type = types::qubit(&context).into();
-    let result_type = types::result(&context).into();
-    declare(
-        module,
-        "mz",
-        Functor::Body,
-        None,
-        &[qubit_type, result_type],
-    )
+unsafe fn rotation_gate(module: LLVMModuleRef, name: &str) -> LLVMValueRef {
+    let context = LLVMGetModuleContext(module);
+    let ty = function_type(
+        LLVMVoidTypeInContext(context),
+        &mut [
+            LLVMDoubleTypeInContext(context),
+            types::qubit_unchecked(context),
+        ],
+    );
+    declare(module, name, Functor::Body, ty)
 }
 
-fn read_result<'ctx>(module: &Module<'ctx>) -> FunctionValue<'ctx> {
-    let bool_type = module.get_context().bool_type().into();
-    let result_type = types::result(&module.get_context()).into();
-    declare(
-        module,
-        "read_result",
-        Functor::Body,
-        Some(bool_type),
-        &[result_type],
-    )
+unsafe fn mz(module: LLVMModuleRef) -> LLVMValueRef {
+    let context = LLVMGetModuleContext(module);
+    let ty = function_type(
+        LLVMVoidTypeInContext(context),
+        &mut [
+            types::qubit_unchecked(context),
+            types::result_unchecked(context),
+        ],
+    );
+    declare(module, "mz", Functor::Body, ty)
+}
+
+unsafe fn read_result(module: LLVMModuleRef) -> LLVMValueRef {
+    let context = LLVMGetModuleContext(module);
+    let ty = function_type(
+        LLVMInt1TypeInContext(context),
+        &mut [types::result_unchecked(context)],
+    );
+    declare(module, "read_result", Functor::Body, ty)
 }
 
-fn declare<'ctx>(
-    module: &Module<'ctx>,
+unsafe fn declare(
+    module: LLVMModuleRef,
     name: &str,
     functor: Functor,
-    return_type: Option<BasicTypeEnum<'ctx>>,
-    param_types: &[BasicMetadataTypeEnum<'ctx>],
-) -> FunctionValue<'ctx> {
-    let name = format!(
-        "__quantum__qis__{}__{}",
-        name,
-        match functor {
-            Functor::Body => "body",
-            Functor::Adjoint => "adj",
-        }
-    );
+    ty: LLVMTypeRef,
+) -> LLVMValueRef {
+    let suffix = match functor {
+        Functor::Body => "body",
+        Functor::Adjoint => "adj",
+    };
+    let name = CString::new(format!("__quantum__qis__{}__{}", name, suffix)).unwrap();
+    let function = LLVMGetNamedFunction(module, name.as_ptr().cast());
+    if function.is_null() {
+        let function = LLVMAddFunction(module, name.as_ptr().cast(), ty);
+        LLVMSetLinkage(function, LLVMLinkage::LLVMExternalLinkage);
+        function
+    } else {
+        function
+    }
+}
 
-    module.get_function(&name).unwrap_or_else(|| {
-        log::debug!("{} global function was not defined in the module", name);
-        let ty = match return_type {
-            Some(ty) => ty.fn_type(param_types, false),
-            None => module.get_context().void_type().fn_type(param_types, false),
-        };
-        module.add_function(&name, ty, Some(Linkage::External))
-    })
+unsafe fn function_type(ret: LLVMTypeRef, params: &mut [LLVMTypeRef]) -> LLVMTypeRef {
+    LLVMFunctionType(
+        ret,
+        params.as_mut_ptr(),
+        c_uint::try_from(params.len()).unwrap(),
+        0,
+    )
 }
 
 #[cfg(test)]
@@ -249,11 +363,21 @@ mod tests {
         tests::assert_reference_ir,
         values::{qubit, result},
     };
+    use inkwell::context::Context;
+
+    #[test]
+    #[should_panic(expected = "The builder's position has not been set.")]
+    fn builder_not_positioned() {
+        let context = Context::create();
+        let builder = context.create_builder();
+        let context = context.void_type().get_context();
+        builder.build_x(qubit(&context, 0));
+    }
 
     #[test]
     fn cx() -> Result<(), String> {
         assert_reference_ir("qis/cx", 2, 0, |builder| {
-            let context = builder.module().get_context();
+            let context = builder.get_insert_block().unwrap().get_context();
             builder.build_cx(qubit(&context, 0), qubit(&context, 1));
         })
     }
@@ -261,7 +385,7 @@ mod tests {
     #[test]
     fn cz() -> Result<(), String> {
         assert_reference_ir("qis/cz", 2, 0, |builder| {
-            let context = builder.module().get_context();
+            let context = builder.get_insert_block().unwrap().get_context();
             builder.build_cz(qubit(&context, 0), qubit(&context, 1));
         })
     }
@@ -269,126 +393,136 @@ mod tests {
     #[test]
     fn h() -> Result<(), String> {
         assert_reference_ir("qis/h", 1, 0, |builder| {
-            builder.build_h(qubit(&builder.module().get_context(), 0));
+            let context = builder.get_insert_block().unwrap().get_context();
+            builder.build_h(qubit(&context, 0));
         })
     }
 
     #[test]
     fn s() -> Result<(), String> {
         assert_reference_ir("qis/s", 1, 0, |builder| {
-            builder.build_s(qubit(&builder.module().get_context(), 0));
+            let context = builder.get_insert_block().unwrap().get_context();
+            builder.build_s(qubit(&context, 0));
         })
     }
 
     #[test]
     fn s_adj() -> Result<(), String> {
         assert_reference_ir("qis/s_adj", 1, 0, |builder| {
-            builder.build_s_adj(qubit(&builder.module().get_context(), 0));
+            let context = builder.get_insert_block().unwrap().get_context();
+            builder.build_s_adj(qubit(&context, 0));
         })
     }
 
     #[test]
     fn t() -> Result<(), String> {
         assert_reference_ir("qis/t", 1, 0, |builder| {
-            builder.build_t(qubit(&builder.module().get_context(), 0));
+            let context = builder.get_insert_block().unwrap().get_context();
+            builder.build_t(qubit(&context, 0));
         })
     }
 
     #[test]
     fn t_adj() -> Result<(), String> {
         assert_reference_ir("qis/t_adj", 1, 0, |builder| {
-            builder.build_t_adj(qubit(&builder.module().get_context(), 0));
+            let context = builder.get_insert_block().unwrap().get_context();
+            builder.build_t_adj(qubit(&context, 0));
         })
     }
 
     #[test]
     fn x() -> Result<(), String> {
         assert_reference_ir("qis/x", 1, 0, |builder| {
-            builder.build_x(qubit(&builder.module().get_context(), 0));
+            let context = builder.get_insert_block().unwrap().get_context();
+            builder.build_x(qubit(&context, 0));
         })
     }
 
     #[test]
     fn y() -> Result<(), String> {
         assert_reference_ir("qis/y", 1, 0, |builder| {
-            builder.build_y(qubit(&builder.module().get_context(), 0));
+            let context = builder.get_insert_block().unwrap().get_context();
+            builder.build_y(qubit(&context, 0));
         })
     }
 
     #[test]
     fn z() -> Result<(), String> {
         assert_reference_ir("qis/z", 1, 0, |builder| {
-            builder.build_z(qubit(&builder.module().get_context(), 0));
+            let context = builder.get_insert_block().unwrap().get_context();
+            builder.build_z(qubit(&context, 0));
         })
     }
 
     #[test]
     fn rx() -> Result<(), String> {
         assert_reference_ir("qis/rx", 1, 0, |builder| {
-            let context = builder.module().get_context();
-            let double_type = context.f64_type();
-            builder.build_rx(double_type.const_float(0.0), qubit(&context, 0));
+            let context = builder.get_insert_block().unwrap().get_context();
+            let double = context.f64_type();
+            builder.build_rx(double.const_float(0.0), qubit(&context, 0));
         })
     }
 
     #[test]
     fn ry() -> Result<(), String> {
         assert_reference_ir("qis/ry", 1, 0, |builder| {
-            let context = builder.module().get_context();
-            let double_type = context.f64_type();
-            builder.build_ry(double_type.const_float(0.0), qubit(&context, 0));
+            let context = builder.get_insert_block().unwrap().get_context();
+            let double = context.f64_type();
+            builder.build_ry(double.const_float(0.0), qubit(&context, 0));
         })
     }
 
     #[test]
     fn rz() -> Result<(), String> {
         assert_reference_ir("qis/rz", 1, 0, |builder| {
-            let context = builder.module().get_context();
-            let double_type = context.f64_type();
-            builder.build_rz(double_type.const_float(0.0), qubit(&context, 0));
+            let context = builder.get_insert_block().unwrap().get_context();
+            let double = context.f64_type();
+            builder.build_rz(double.const_float(0.0), qubit(&context, 0));
         })
     }
 
     #[test]
     fn reset() -> Result<(), String> {
         assert_reference_ir("qis/reset", 1, 0, |builder| {
-            builder.build_reset(qubit(&builder.module().get_context(), 0));
+            let context = builder.get_insert_block().unwrap().get_context();
+            builder.build_reset(qubit(&context, 0));
         })
     }
 
     #[test]
     fn mz() -> Result<(), String> {
         assert_reference_ir("qis/mz", 1, 1, |builder| {
-            let context = builder.module().get_context();
+            let context = builder.get_insert_block().unwrap().get_context();
             builder.build_mz(qubit(&context, 0), result(&context, 0));
         })
     }
 
     #[test]
     fn read_result() -> Result<(), String> {
-        assert_reference_ir("qis/read_result", 1, 1, |builder| {
-            build_read_result(builder, result(&builder.module().get_context(), 0));
+        assert_reference_ir("qis/read_result", 1, 1, |builder| unsafe {
+            let context = builder.get_insert_block().unwrap().get_context();
+            build_read_result(builder.get_ref(), result(&context, 0).get_ref());
         })
     }
 
     #[test]
     fn empty_if() -> Result<(), String> {
         assert_reference_ir("qis/empty_if", 1, 1, |builder| {
-            let context = builder.module().get_context();
+            let context = builder.get_insert_block().unwrap().get_context();
             builder.build_mz(qubit(&context, 0), result(&context, 0));
-            builder.build_if_result(result(&context, 0), |_| (), |_| ());
+            builder.build_if_result(result(&context, 0), || (), || ());
         })
     }
 
     #[test]
     fn if_then() -> Result<(), String> {
         assert_reference_ir("qis/if_then", 1, 1, |builder| {
-            let context = builder.module().get_context();
+            let context = builder.get_insert_block().unwrap().get_context();
             builder.build_mz(qubit(&context, 0), result(&context, 0));
             builder.build_if_result(
                 result(&context, 0),
-                |builder| builder.build_x(qubit(&context, 0)),
-                |_| (),
+                || builder.build_x(qubit(&context, 0)),
+                || (),
             );
         })
     }
@@ -396,12 +530,12 @@ mod tests {
     #[test]
     fn if_else() -> Result<(), String> {
         assert_reference_ir("qis/if_else", 1, 1, |builder| {
-            let context = builder.module().get_context();
+            let context = builder.get_insert_block().unwrap().get_context();
             builder.build_mz(qubit(&context, 0), result(&context, 0));
             builder.build_if_result(
                 result(&context, 0),
-                |_| (),
-                |builder| builder.build_x(qubit(&context, 0)),
+                || (),
+                || builder.build_x(qubit(&context, 0)),
             );
         })
     }
@@ -409,12 +543,12 @@ mod tests {
     #[test]
     fn if_then_continue() -> Result<(), String> {
         assert_reference_ir("qis/if_then_continue", 1, 1, |builder| {
-            let context = builder.module().get_context();
+            let context = builder.get_insert_block().unwrap().get_context();
             builder.build_mz(qubit(&context, 0), result(&context, 0));
             builder.build_if_result(
                 result(&context, 0),
-                |builder| builder.build_x(qubit(&context, 0)),
-                |_| (),
+                || builder.build_x(qubit(&context, 0)),
+                || (),
             );
             builder.build_h(qubit(&context, 0));
         })
@@ -423,12 +557,12 @@ mod tests {
     #[test]
     fn if_else_continue() -> Result<(), String> {
         assert_reference_ir("qis/if_else_continue", 1, 1, |builder| {
-            let context = builder.module().get_context();
+            let context = builder.get_insert_block().unwrap().get_context();
             builder.build_mz(qubit(&context, 0), result(&context, 0));
             builder.build_if_result(
                 result(&context, 0),
-                |_| (),
-                |builder| builder.build_x(qubit(&context, 0)),
+                || (),
+                || builder.build_x(qubit(&context, 0)),
             );
             builder.build_h(qubit(&context, 0));
         })
@@ -437,12 +571,12 @@ mod tests {
     #[test]
     fn if_then_else_continue() -> Result<(), String> {
         assert_reference_ir("qis/if_then_else_continue", 1, 1, |builder| {
-            let context = builder.module().get_context();
+            let context = builder.get_insert_block().unwrap().get_context();
             builder.build_mz(qubit(&context, 0), result(&context, 0));
             builder.build_if_result(
                 result(&context, 0),
-                |builder| builder.build_x(qubit(&context, 0)),
-                |builder| builder.build_y(qubit(&context, 0)),
+                || builder.build_x(qubit(&context, 0)),
+                || builder.build_y(qubit(&context, 0)),
             );
             builder.build_h(qubit(&context, 0));
         })
@@ -451,19 +585,19 @@ mod tests {
     #[test]
     fn if_then_then() -> Result<(), String> {
         assert_reference_ir("qis/if_then_then", 1, 2, |builder| {
-            let context = builder.module().get_context();
+            let context = builder.get_insert_block().unwrap().get_context();
             builder.build_mz(qubit(&context, 0), result(&context, 0));
             builder.build_mz(qubit(&context, 0), result(&context, 1));
             builder.build_if_result(
                 result(&context, 0),
-                |builder| {
+                || {
                     builder.build_if_result(
                         result(&context, 1),
-                        |builder| builder.build_x(qubit(&context, 0)),
-                        |_| (),
+                        || builder.build_x(qubit(&context, 0)),
+                        || (),
                     );
                 },
-                |_| (),
+                || (),
             );
         })
     }
@@ -471,17 +605,17 @@ mod tests {
     #[test]
     fn if_else_else() -> Result<(), String> {
         assert_reference_ir("qis/if_else_else", 1, 2, |builder| {
-            let context = builder.module().get_context();
+            let context = builder.get_insert_block().unwrap().get_context();
             builder.build_mz(qubit(&context, 0), result(&context, 0));
             builder.build_mz(qubit(&context, 0), result(&context, 1));
             builder.build_if_result(
                 result(&context, 0),
-                |_| (),
-                |builder| {
+                || (),
+                || {
                     builder.build_if_result(
                         result(&context, 1),
-                        |_| (),
-                        |builder| builder.build_x(qubit(&context, 0)),
+                        || (),
+                        || builder.build_x(qubit(&context, 0)),
                     );
                 },
             );
@@ -491,19 +625,19 @@ mod tests {
     #[test]
     fn if_then_else() -> Result<(), String> {
         assert_reference_ir("qis/if_then_else", 1, 2, |builder| {
-            let context = builder.module().get_context();
+            let context = builder.get_insert_block().unwrap().get_context();
             builder.build_mz(qubit(&context, 0), result(&context, 0));
             builder.build_mz(qubit(&context, 0), result(&context, 1));
             builder.build_if_result(
                 result(&context, 0),
-                |builder| {
+                || {
                     builder.build_if_result(
                         result(&context, 1),
-                        |_| (),
-                        |builder| builder.build_x(qubit(&context, 0)),
+                        || (),
+                        || builder.build_x(qubit(&context, 0)),
                     );
                 },
-                |_| (),
+                || (),
             );
         })
     }
@@ -511,17 +645,17 @@ mod tests {
     #[test]
     fn if_else_then() -> Result<(), String> {
         assert_reference_ir("qis/if_else_then", 1, 2, |builder| {
-            let context = builder.module().get_context();
+            let context = builder.get_insert_block().unwrap().get_context();
             builder.build_mz(qubit(&context, 0), result(&context, 0));
             builder.build_mz(qubit(&context, 0), result(&context, 1));
             builder.build_if_result(
                 result(&context, 0),
-                |_| (),
-                |builder| {
+                || (),
+                || {
                     builder.build_if_result(
                         result(&context, 1),
-                        |builder| builder.build_x(qubit(&context, 0)),
-                        |_| (),
+                        || builder.build_x(qubit(&context, 0)),
+                        || (),
                     );
                 },
             );
@@ -531,11 +665,11 @@ mod tests {
     #[test]
     fn if_unmeasured_result() -> Result<(), String> {
         assert_reference_ir("qis/if_unmeasured_result", 1, 1, |builder| {
-            let context = builder.module().get_context();
+            let context = builder.get_insert_block().unwrap().get_context();
             builder.build_if_result(
                 result(&context, 0),
-                |builder| builder.build_x(qubit(&context, 0)),
-                |builder| builder.build_h(qubit(&context, 0)),
+                || builder.build_x(qubit(&context, 0)),
+                || builder.build_h(qubit(&context, 0)),
             );
         })
     }
diff --git a/qirlib/src/types.rs b/qirlib/src/types.rs
index 5765c0d8..be90fa24 100644
--- a/qirlib/src/types.rs
+++ b/qirlib/src/types.rs
@@ -3,10 +3,13 @@
 
 use inkwell::{
     context::ContextRef,
-    types::{AnyTypeEnum, PointerType, StructType},
-    AddressSpace, LLVMReference,
+    types::{AnyTypeEnum, PointerType},
+    LLVMReference,
+};
+use llvm_sys::{
+    core::{LLVMGetTypeByName2, LLVMPointerType, LLVMStructCreateNamed},
+    prelude::*,
 };
-use llvm_sys::core::{LLVMGetTypeByName2, LLVMStructCreateNamed};
 use std::ffi::CStr;
 
 const QUBIT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Qubit\0") };
@@ -14,7 +17,11 @@ const RESULT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Result\0")
 
 #[must_use]
 pub fn qubit<'ctx>(context: &ContextRef<'ctx>) -> PointerType<'ctx> {
-    get_or_create_struct(context, QUBIT).ptr_type(AddressSpace::Generic)
+    unsafe { PointerType::new(qubit_unchecked(context.get_ref())) }
+}
+
+pub(crate) unsafe fn qubit_unchecked(context: LLVMContextRef) -> LLVMTypeRef {
+    LLVMPointerType(get_or_create_struct(context, QUBIT), 0)
 }
 
 #[must_use]
@@ -24,7 +31,11 @@ pub fn is_qubit(ty: AnyTypeEnum) -> bool {
 
 #[must_use]
 pub fn result<'ctx>(context: &ContextRef<'ctx>) -> PointerType<'ctx> {
-    get_or_create_struct(context, RESULT).ptr_type(AddressSpace::Generic)
+    unsafe { PointerType::new(result_unchecked(context.get_ref())) }
+}
+
+pub(crate) unsafe fn result_unchecked(context: LLVMContextRef) -> LLVMTypeRef {
+    LLVMPointerType(get_or_create_struct(context, RESULT), 0)
 }
 
 #[must_use]
@@ -32,14 +43,13 @@ pub fn is_result(ty: AnyTypeEnum) -> bool {
     is_opaque_pointer_to(ty, RESULT)
 }
 
-fn get_or_create_struct<'ctx>(context: &ContextRef<'ctx>, name: &CStr) -> StructType<'ctx> {
-    let context = unsafe { context.get_ref() };
+unsafe fn get_or_create_struct(context: LLVMContextRef, name: &CStr) -> LLVMTypeRef {
     let name = name.as_ptr().cast();
-    let ty = unsafe { LLVMGetTypeByName2(context, name) };
+    let ty = LLVMGetTypeByName2(context, name);
     if ty.is_null() {
-        unsafe { StructType::new(LLVMStructCreateNamed(context, name)) }
+        LLVMStructCreateNamed(context, name)
     } else {
-        unsafe { StructType::new(ty) }
+        ty
     }
 }
 


Test patch:
diff --git a/qirlib/src/tests.rs b/qirlib/src/tests.rs
index 188f1123..98fb533e 100644
--- a/qirlib/src/tests.rs
+++ b/qirlib/src/tests.rs
@@ -1,8 +1,8 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-use crate::{module, Builder};
-use inkwell::context::Context;
+use crate::module;
+use inkwell::{builder::Builder, context::Context};
 use normalize_line_endings::normalized;
 use std::{env, fs, path::PathBuf};
 
@@ -17,7 +17,7 @@ pub(crate) fn assert_reference_ir(
     id: &str,
     required_num_qubits: u64,
     required_num_results: u64,
-    build: impl for<'ctx> Fn(&Builder<'ctx, '_>),
+    build: impl for<'ctx> Fn(&Builder<'ctx>),
 ) -> Result<(), String> {
     const PYQIR_TEST_SAVE_REFERENCES: &str = "PYQIR_TEST_SAVE_REFERENCES";
     let (prefix, name) = split_id(id);
@@ -50,11 +50,11 @@ fn build_ir(
     name: &str,
     required_num_qubits: u64,
     required_num_results: u64,
-    build: impl for<'ctx> Fn(&Builder<'ctx, '_>),
+    build: impl for<'ctx> Fn(&Builder<'ctx>),
 ) -> Result<String, String> {
     let context = Context::create();
     let module = context.create_module(name);
-    let builder = Builder::new(&module);
+    let builder = context.create_builder();
     module::simple_init(&module, &builder, required_num_qubits, required_num_results);
     build(&builder);
     builder.build_return(None);