aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/llvm/builder.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/llvm/builder.rs')
-rw-r--r--src/llvm/builder.rs189
1 files changed, 189 insertions, 0 deletions
diff --git a/src/llvm/builder.rs b/src/llvm/builder.rs
new file mode 100644
index 0000000..3d43b68
--- /dev/null
+++ b/src/llvm/builder.rs
@@ -0,0 +1,189 @@
+use llvm_sys::{
+ core::{
+ LLVMBuildFAdd, LLVMBuildFCmp, LLVMBuildFMul, LLVMBuildFSub, LLVMBuildRet, LLVMBuildUIToFP,
+ LLVMCreateBuilderInContext, LLVMDisposeBuilder, LLVMPositionBuilderAtEnd,
+ },
+ prelude::{LLVMBuilderRef, LLVMValueRef},
+ LLVMRealPredicate,
+};
+
+use std::marker::PhantomData;
+
+use super::{BasicBlock, FnValue, Module, Type, Value};
+
+// Definition of LLVM C API functions using our `repr(transparent)` types.
+extern "C" {
+ fn LLVMBuildCall2(
+ arg1: LLVMBuilderRef,
+ arg2: Type<'_>,
+ Fn: FnValue<'_>,
+ Args: *mut Value<'_>,
+ NumArgs: ::libc::c_uint,
+ Name: *const ::libc::c_char,
+ ) -> LLVMValueRef;
+}
+
+/// Wrapper for a LLVM IR Builder.
+pub struct IRBuilder<'llvm> {
+ builder: LLVMBuilderRef,
+ _ctx: PhantomData<&'llvm ()>,
+}
+
+impl<'llvm> IRBuilder<'llvm> {
+ /// Create a new LLVM IR Builder with the `module`s context.
+ ///
+ /// # Panics
+ ///
+ /// Panics if creating the IR Builder fails.
+ pub fn with_ctx(module: &'llvm Module) -> IRBuilder<'llvm> {
+ let builder = unsafe { LLVMCreateBuilderInContext(module.ctx()) };
+ assert!(!builder.is_null());
+
+ IRBuilder {
+ builder,
+ _ctx: PhantomData,
+ }
+ }
+
+ /// Position the IR Builder at the end of the given Basic Block.
+ pub fn pos_at_end(&self, bb: BasicBlock<'llvm>) {
+ unsafe {
+ LLVMPositionBuilderAtEnd(self.builder, bb.0);
+ }
+ }
+
+ /// Emit a [fadd](https://llvm.org/docs/LangRef.html#fadd-instruction) instruction.
+ ///
+ /// # Panics
+ ///
+ /// Panics if LLVM API returns a `null` pointer.
+ pub fn fadd(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
+ debug_assert!(lhs.is_f64(), "fadd: Expected f64 as lhs operand!");
+ debug_assert!(rhs.is_f64(), "fadd: Expected f64 as rhs operand!");
+
+ let value_ref = unsafe {
+ LLVMBuildFAdd(
+ self.builder,
+ lhs.value_ref(),
+ rhs.value_ref(),
+ b"fadd\0".as_ptr().cast(),
+ )
+ };
+ Value::new(value_ref)
+ }
+
+ /// Emit a [fsub](https://llvm.org/docs/LangRef.html#fsub-instruction) instruction.
+ ///
+ /// # Panics
+ ///
+ /// Panics if LLVM API returns a `null` pointer.
+ pub fn fsub(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
+ debug_assert!(lhs.is_f64(), "fsub: Expected f64 as lhs operand!");
+ debug_assert!(rhs.is_f64(), "fsub: Expected f64 as rhs operand!");
+
+ let value_ref = unsafe {
+ LLVMBuildFSub(
+ self.builder,
+ lhs.value_ref(),
+ rhs.value_ref(),
+ b"fsub\0".as_ptr().cast(),
+ )
+ };
+ Value::new(value_ref)
+ }
+
+ /// Emit a [fmul](https://llvm.org/docs/LangRef.html#fmul-instruction) instruction.
+ ///
+ /// # Panics
+ ///
+ /// Panics if LLVM API returns a `null` pointer.
+ pub fn fmul(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
+ debug_assert!(lhs.is_f64(), "fmul: Expected f64 as lhs operand!");
+ debug_assert!(rhs.is_f64(), "fmul: Expected f64 as rhs operand!");
+
+ let value_ref = unsafe {
+ LLVMBuildFMul(
+ self.builder,
+ lhs.value_ref(),
+ rhs.value_ref(),
+ b"fmul\0".as_ptr().cast(),
+ )
+ };
+ Value::new(value_ref)
+ }
+
+ /// Emit a [fcmult](https://llvm.org/docs/LangRef.html#fcmp-instruction) instruction.
+ ///
+ /// # Panics
+ ///
+ /// Panics if LLVM API returns a `null` pointer.
+ pub fn fcmpult(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
+ debug_assert!(lhs.is_f64(), "fcmplt: Expected f64 as lhs operand!");
+ debug_assert!(rhs.is_f64(), "fcmplt: Expected f64 as rhs operand!");
+
+ let value_ref = unsafe {
+ LLVMBuildFCmp(
+ self.builder,
+ LLVMRealPredicate::LLVMRealULT,
+ lhs.value_ref(),
+ rhs.value_ref(),
+ b"fcmplt\0".as_ptr().cast(),
+ )
+ };
+ Value::new(value_ref)
+ }
+
+ /// Emit a [uitofp](https://llvm.org/docs/LangRef.html#uitofp-to-instruction) instruction.
+ ///
+ /// # Panics
+ ///
+ /// Panics if LLVM API returns a `null` pointer.
+ pub fn uitofp(&self, val: Value<'llvm>, dest_type: Type<'llvm>) -> Value<'llvm> {
+ debug_assert!(val.is_int(), "uitofp: Expected integer operand!");
+
+ let value_ref = unsafe {
+ LLVMBuildUIToFP(
+ self.builder,
+ val.value_ref(),
+ dest_type.type_ref(),
+ b"uitofp\0".as_ptr().cast(),
+ )
+ };
+ Value::new(value_ref)
+ }
+
+ /// Emit a [call](https://llvm.org/docs/LangRef.html#call-instruction) instruction.
+ ///
+ /// # Panics
+ ///
+ /// Panics if LLVM API returns a `null` pointer.
+ pub fn call(&self, fn_value: FnValue<'llvm>, args: &mut [Value<'llvm>]) -> Value<'llvm> {
+ let value_ref = unsafe {
+ LLVMBuildCall2(
+ self.builder,
+ fn_value.ret_type(),
+ fn_value,
+ args.as_mut_ptr(),
+ args.len() as libc::c_uint,
+ b"call\0".as_ptr().cast(),
+ )
+ };
+ Value::new(value_ref)
+ }
+
+ /// Emit a [ret](https://llvm.org/docs/LangRef.html#ret-instruction) instruction.
+ ///
+ /// # Panics
+ ///
+ /// Panics if LLVM API returns a `null` pointer.
+ pub fn ret(&self, ret: Value<'llvm>) {
+ let ret = unsafe { LLVMBuildRet(self.builder, ret.value_ref()) };
+ assert!(!ret.is_null());
+ }
+}
+
+impl Drop for IRBuilder<'_> {
+ fn drop(&mut self) {
+ unsafe { LLVMDisposeBuilder(self.builder) }
+ }
+}