Skip to content

Commit

Permalink
Added get_field_at_index and count_fields to struct values
Browse files Browse the repository at this point in the history
  • Loading branch information
tfzee authored and TheDan64 committed Nov 27, 2023
1 parent 7a09ad8 commit 5268911
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 1 deletion.
55 changes: 54 additions & 1 deletion src/values/struct_value.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use llvm_sys::core::{LLVMGetNumOperands, LLVMGetOperand, LLVMIsConstant};

use llvm_sys::prelude::LLVMValueRef;

use std::ffi::CStr;
Expand All @@ -7,7 +9,7 @@ use crate::types::StructType;
use crate::values::traits::AsValueRef;
use crate::values::{InstructionValue, Value};

use super::AnyValue;
use super::{AnyValue, BasicValueEnum};

#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct StructValue<'ctx> {
Expand All @@ -23,6 +25,56 @@ impl<'ctx> StructValue<'ctx> {
}
}

/// Gets the value of a field belonging to this `StructType`.
///
/// ```no_run
/// use inkwell::context::Context;
///
/// let context = Context::create();
/// let i32_type = context.i32_type();
/// let i8_type = context.i8_type();
/// let i8_val = i8_type.const_all_ones();
/// let i32_val = i32_type.const_all_ones();
/// let struct_type = context.struct_type(&[i8_type.into(), i32_type.into()], false);
/// let struct_val = struct_type.const_named_struct(&[i8_val.into(), i32_val.into()]);
///
/// assert!(struct_val.get_field_at_index(0).is_some());
/// assert!(struct_val.get_field_at_index(1).is_some());
/// assert!(struct_val.get_field_at_index(3).is_none());
/// assert!(struct_val.get_field_at_index(0).unwrap().is_int_value());
/// ```
pub fn get_field_at_index(self, index: u32) -> Option<BasicValueEnum<'ctx>> {
if unsafe { LLVMIsConstant(self.as_value_ref()) } == 0 {
return None;
}
// OoB indexing seems to be unchecked and therefore is UB
if index >= self.count_fields() {
return None;
}

unsafe { Some(BasicValueEnum::new(LLVMGetOperand(self.as_value_ref(), index))) }
}

/// Counts the number of fields.
///
/// ```no_run
/// use inkwell::context::Context;
///
/// let context = Context::create();
/// let i32_type = context.i32_type();
/// let i8_type = context.i8_type();
/// let i8_val = i8_type.const_all_ones();
/// let i32_val = i32_type.const_all_ones();
/// let struct_type = context.struct_type(&[i8_type.into(), i32_type.into()], false);
/// let struct_val = struct_type.const_named_struct(&[i8_val.into(), i32_val.into()]);
///
/// assert_eq!(struct_val.count_fields(), 2);
/// assert_eq!(struct_val.count_fields(), struct_type.count_fields());
/// ```
pub fn count_fields(self) -> u32 {
unsafe { LLVMGetNumOperands(self.as_value_ref()) as u32 }
}

/// Gets the name of a `StructValue`. If the value is a constant, this will
/// return an empty string.
pub fn get_name(&self) -> &CStr {
Expand Down Expand Up @@ -70,3 +122,4 @@ impl Display for StructValue<'_> {
write!(f, "{}", self.print_to_string())
}
}

29 changes: 29 additions & 0 deletions tests/all/test_values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,34 @@ fn test_consts() {
assert_eq!(f128_val.get_constant(), Some((7.8, false)));
assert_eq!(ppc_f128_val.get_constant(), Some((9.0, false)));

//const struct member access
let struct_type = context.struct_type(&[i8_type.into(), i32_type.into()], false);
let struct_val = struct_type.const_named_struct(&[i8_val.into(), i32_val.into()]);

assert_eq!(struct_val.count_fields(), 2);
assert_eq!(struct_val.count_fields(), struct_type.count_fields());
assert!(struct_val.get_field_at_index(0).is_some());
assert!(struct_val.get_field_at_index(1).is_some());
assert!(struct_val.get_field_at_index(3).is_none());
assert!(struct_val.get_field_at_index(0).unwrap().is_int_value());
assert!(struct_val.get_field_at_index(1).unwrap().is_int_value());
assert_eq!(
struct_val
.get_field_at_index(0)
.unwrap()
.into_int_value()
.get_sign_extended_constant(),
Some(-1)
);
assert_eq!(
struct_val
.get_field_at_index(1)
.unwrap()
.into_int_value()
.get_sign_extended_constant(),
Some(-1)
);

// Non const test
let builder = context.create_builder();
let module = context.create_module("fns");
Expand Down Expand Up @@ -1365,3 +1393,4 @@ fn test_constant_expression() {
assert!(expr.is_const());
assert!(!expr.is_constant_int());
}

0 comments on commit 5268911

Please sign in to comment.