Skip to content

Commit 6c722df

Browse files
committed
Fix, test, and document build_extract_value
1 parent 395ce6a commit 6c722df

File tree

2 files changed

+60
-5
lines changed

2 files changed

+60
-5
lines changed

src/builder.rs

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -945,16 +945,61 @@ impl Builder {
945945
}
946946
}
947947

948-
// REVIEW: How does LLVM treat out of bound index? Maybe we should return an Option?
949-
// or is that only in bounds GEP
950-
pub fn build_extract_value<AV: AggregateValue>(&self, value: AV, index: u32, name: &str) -> BasicValueEnum {
948+
/// Builds an extract value instruction which extracts a `BasicValueEnum`
949+
/// from a struct or array.
950+
///
951+
/// # Example
952+
///
953+
/// ```no_run
954+
/// use inkwell::context::Context;
955+
///
956+
/// let context = Context::create();
957+
/// let module = context.create_module("av");
958+
/// let void_type = context.void_type();
959+
/// let f32_type = context.f32_type();
960+
/// let i32_type = context.i32_type();
961+
/// let struct_type = context.struct_type(&[i32_type.into(), f32_type.into()], false);
962+
/// let array_type = i32_type.array_type(3);
963+
/// let fn_type = void_type.fn_type(&[], false);
964+
/// let fn_value = module.add_function("av_fn", fn_type, None);
965+
/// let builder = context.create_builder();
966+
/// let entry = fn_value.append_basic_block("entry");
967+
///
968+
/// builder.position_at_end(&entry);
969+
///
970+
/// let array_alloca = builder.build_alloca(array_type, "array_alloca");
971+
/// let array = builder.build_load(array_alloca, "array_load").into_array_value();
972+
/// let const_int1 = i32_type.const_int(2, false);
973+
/// let const_int2 = i32_type.const_int(5, false);
974+
/// let const_int3 = i32_type.const_int(6, false);
975+
///
976+
/// assert!(builder.build_insert_value(array, const_int1, 0, "insert").is_some());
977+
/// assert!(builder.build_insert_value(array, const_int2, 1, "insert").is_some());
978+
/// assert!(builder.build_insert_value(array, const_int3, 2, "insert").is_some());
979+
/// assert!(builder.build_insert_value(array, const_int3, 3, "insert").is_none());
980+
///
981+
/// assert!(builder.build_extract_value(array, 0, "extract").unwrap().is_int_value());
982+
/// assert!(builder.build_extract_value(array, 1, "extract").unwrap().is_int_value());
983+
/// assert!(builder.build_extract_value(array, 2, "extract").unwrap().is_int_value());
984+
/// assert!(builder.build_extract_value(array, 3, "extract").is_none());
985+
/// ```
986+
pub fn build_extract_value<AV: AggregateValue>(&self, agg: AV, index: u32, name: &str) -> Option<BasicValueEnum> {
987+
let size = match agg.as_aggregate_value_enum() {
988+
AggregateValueEnum::ArrayValue(av) => av.get_type().len(),
989+
AggregateValueEnum::StructValue(sv) => sv.get_type().count_fields(),
990+
};
991+
992+
if index >= size {
993+
return None;
994+
}
995+
951996
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
952997

953998
let value = unsafe {
954-
LLVMBuildExtractValue(self.builder, value.as_value_ref(), index, c_string.as_ptr())
999+
LLVMBuildExtractValue(self.builder, agg.as_value_ref(), index, c_string.as_ptr())
9551000
};
9561001

957-
BasicValueEnum::new(value)
1002+
Some(BasicValueEnum::new(value))
9581003
}
9591004

9601005
/// Builds an insert value instruction which inserts a `BasicValue` into a struct

tests/all/test_builder.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,11 @@ fn test_insert_value() {
630630
assert!(builder.build_insert_value(array, const_int3, 3, "insert").is_none());
631631
assert!(builder.build_insert_value(array, const_int3, 4, "insert").is_none());
632632

633+
assert!(builder.build_extract_value(array, 0, "extract").unwrap().is_int_value());
634+
assert!(builder.build_extract_value(array, 1, "extract").unwrap().is_int_value());
635+
assert!(builder.build_extract_value(array, 2, "extract").unwrap().is_int_value());
636+
assert!(builder.build_extract_value(array, 3, "extract").is_none());
637+
633638
let struct_alloca = builder.build_alloca(struct_type, "struct_alloca");
634639
let struct_value = builder.build_load(struct_alloca, "struct_load").into_struct_value();
635640

@@ -638,6 +643,11 @@ fn test_insert_value() {
638643
assert!(builder.build_insert_value(struct_value, const_float, 2, "insert").is_none());
639644
assert!(builder.build_insert_value(struct_value, const_float, 3, "insert").is_none());
640645

646+
assert!(builder.build_extract_value(struct_value, 0, "extract").unwrap().is_int_value());
647+
assert!(builder.build_extract_value(struct_value, 1, "extract").unwrap().is_float_value());
648+
assert!(builder.build_extract_value(struct_value, 2, "extract").is_none());
649+
assert!(builder.build_extract_value(struct_value, 3, "extract").is_none());
650+
641651
builder.build_return(None);
642652

643653
assert!(module.verify().is_ok());

0 commit comments

Comments
 (0)