Skip to content

Commit 018c54c

Browse files
committed
Started testing building binary ops, build_switch,
and odds and ends for function values
1 parent d909250 commit 018c54c

File tree

4 files changed

+174
-5
lines changed

4 files changed

+174
-5
lines changed

src/builder.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ impl Builder {
118118
PointerValue::new(value)
119119
}
120120

121+
// REVIEW: Shouldn't this take a StructValue? Or does it still need to be PointerValue<StructValue>?
121122
pub fn build_struct_gep(&self, ptr: &PointerValue, index: u32, name: &str) -> PointerValue {
122123
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
123124

@@ -138,7 +139,7 @@ impl Builder {
138139
IntValue::new(value)
139140
}
140141

141-
pub fn build_phi(&self, type_: &AnyType, name: &str) -> PhiValue {
142+
pub fn build_phi(&self, type_: &BasicType, name: &str) -> PhiValue {
142143
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
143144

144145
let value = unsafe {

src/values/traits.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use llvm_sys::prelude::LLVMValueRef;
22

3-
use values::{ArrayValue, AggregateValueEnum, StructValue, BasicValueEnum, AnyValueEnum, IntValue, FloatValue, PointerValue, PhiValue, VectorValue, FunctionValue};
3+
use values::{ArrayValue, AggregateValueEnum, StructValue, BasicValueEnum, AnyValueEnum, IntValue, FloatValue, PointerValue, PhiValue, VectorValue, FunctionValue, InstructionValue};
44

55
// This is an ugly privacy hack so that Type can stay private to this module
66
// and so that super traits using this trait will be not be implementable
@@ -23,5 +23,5 @@ macro_rules! trait_value_set {
2323
}
2424

2525
trait_value_set! {AggregateValue: ArrayValue, AggregateValueEnum, StructValue}
26-
trait_value_set! {AnyValue: AnyValueEnum, BasicValueEnum, AggregateValueEnum, ArrayValue, IntValue, FloatValue, PhiValue, PointerValue, FunctionValue, StructValue, VectorValue}
26+
trait_value_set! {AnyValue: AnyValueEnum, BasicValueEnum, AggregateValueEnum, ArrayValue, IntValue, FloatValue, PhiValue, PointerValue, FunctionValue, StructValue, VectorValue, InstructionValue}
2727
trait_value_set! {BasicValue: ArrayValue, BasicValueEnum, AggregateValueEnum, IntValue, FloatValue, StructValue, PointerValue, VectorValue}

tests/test_builder.rs

Lines changed: 150 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ fn test_null_checked_ptr_ops() {
4747
// Here we're going to create a function that looks roughly like:
4848
// fn check_null_index1(ptr: *const i8) -> i8 {
4949
// if ptr.is_null() {
50-
// return -1;
50+
// -1
5151
// } else {
52-
// return ptr[1];
52+
// ptr[1]
5353
// }
5454
// }
5555

@@ -98,3 +98,151 @@ fn test_null_checked_ptr_ops() {
9898

9999
assert_eq!(check_null_index1(array.as_ptr()), 42i8);
100100
}
101+
102+
#[test]
103+
fn test_binary_ops() {
104+
Target::initialize_native(&InitializationConfig::default()).expect("Failed to initialize native target");
105+
106+
let context = Context::create();
107+
let module = context.create_module("unsafe");
108+
let builder = context.create_builder();
109+
let execution_engine = module.create_jit_execution_engine(0).unwrap();
110+
let module = execution_engine.get_module_at(0);
111+
112+
// Here we're going to create an and function which looks roughly like:
113+
// fn and(left: bool, right: bool) -> bool {
114+
// left && right
115+
// }
116+
117+
let bool_type = context.bool_type();
118+
let fn_type = bool_type.fn_type(&[&bool_type, &bool_type], false);
119+
let fn_value = module.add_function("and", &fn_type, None);
120+
let entry = fn_value.append_basic_block("entry");
121+
122+
builder.position_at_end(&entry);
123+
124+
let left = fn_value.get_first_param().unwrap().into_int_value();
125+
let right = fn_value.get_last_param().unwrap().into_int_value();
126+
127+
let and = builder.build_and(&left, &right, "and_op");
128+
129+
builder.build_return(Some(&and));
130+
131+
// Here we're going to create an or function which looks roughly like:
132+
// fn or(left: bool, right: bool) -> bool {
133+
// left || right
134+
// }
135+
136+
let fn_value = module.add_function("or", &fn_type, None);
137+
let entry = fn_value.append_basic_block("entry");
138+
139+
builder.position_at_end(&entry);
140+
141+
let left = fn_value.get_first_param().unwrap().into_int_value();
142+
let right = fn_value.get_last_param().unwrap().into_int_value();
143+
144+
let or = builder.build_or(&left, &right, "or_op");
145+
146+
builder.build_return(Some(&or));
147+
148+
// Here we're going to create a xor function which looks roughly like:
149+
// fn xor(left: bool, right: bool) -> bool {
150+
// left || right
151+
// }
152+
153+
let fn_value = module.add_function("xor", &fn_type, None);
154+
let entry = fn_value.append_basic_block("entry");
155+
156+
builder.position_at_end(&entry);
157+
158+
let left = fn_value.get_first_param().unwrap().into_int_value();
159+
let right = fn_value.get_last_param().unwrap().into_int_value();
160+
161+
let xor = builder.build_xor(&left, &right, "xor_op");
162+
163+
builder.build_return(Some(&xor));
164+
165+
let addr = execution_engine.get_function_address("and").unwrap();
166+
let and: extern "C" fn(bool, bool) -> bool = unsafe { transmute(addr) };
167+
let addr = execution_engine.get_function_address("or").unwrap();
168+
let or: extern "C" fn(bool, bool) -> bool = unsafe { transmute(addr) };
169+
let addr = execution_engine.get_function_address("xor").unwrap();
170+
let xor: extern "C" fn(bool, bool) -> bool = unsafe { transmute(addr) };
171+
172+
assert!(!and(false, false));
173+
assert!(!and(true, false));
174+
assert!(!and(false, true));
175+
assert!(and(true, true));
176+
177+
assert!(!or(false, false));
178+
assert!(or(true, false));
179+
assert!(or(false, true));
180+
assert!(or(true, true));
181+
182+
assert!(!xor(false, false));
183+
assert!(xor(true, false));
184+
assert!(xor(false, true));
185+
assert!(!xor(true, true));
186+
}
187+
188+
#[test]
189+
fn test_switch() {
190+
Target::initialize_native(&InitializationConfig::default()).expect("Failed to initialize native target");
191+
192+
let context = Context::create();
193+
let module = context.create_module("unsafe");
194+
let builder = context.create_builder();
195+
let execution_engine = module.create_jit_execution_engine(0).unwrap();
196+
let module = execution_engine.get_module_at(0);
197+
198+
// Here we're going to create a function which looks roughly like:
199+
// fn switch(val: u8) -> u8 {
200+
// if val == 0 {
201+
// 1
202+
// }
203+
// else if val == 42 {
204+
// 255
205+
// }
206+
// else {
207+
// val * 2
208+
// }
209+
// }
210+
211+
let i8_type = context.i8_type();
212+
let fn_type = i8_type.fn_type(&[&i8_type], false);
213+
let fn_value = module.add_function("switch", &fn_type, None);
214+
let i8_zero = i8_type.const_int(0, false);
215+
let i8_one = i8_type.const_int(1, false);
216+
let i8_two = i8_type.const_int(2, false);
217+
let i8_42 = i8_type.const_int(42, false);
218+
let i8_255 = i8_type.const_int(255, false);
219+
let entry = fn_value.append_basic_block("entry");
220+
let check = fn_value.append_basic_block("check");
221+
let elif = fn_value.append_basic_block("elif");
222+
let else_ = fn_value.append_basic_block("else");
223+
let value = fn_value.get_first_param().unwrap().into_int_value();
224+
225+
builder.position_at_end(&entry);
226+
builder.build_switch(&value, &else_, &[(&i8_zero, &check), (&i8_42, &elif)]);
227+
228+
builder.position_at_end(&check);
229+
builder.build_return(Some(&i8_one));
230+
231+
builder.position_at_end(&elif);
232+
builder.build_return(Some(&i8_255));
233+
234+
builder.position_at_end(&else_);
235+
236+
let double = builder.build_int_mul(&value, &i8_two, "double");
237+
238+
builder.build_return(Some(&double));
239+
240+
let addr = execution_engine.get_function_address("switch").unwrap();
241+
let switch: extern "C" fn(u8) -> u8 = unsafe { transmute(addr) };
242+
243+
assert_eq!(switch(0), 1);
244+
assert_eq!(switch(1), 2);
245+
assert_eq!(switch(3), 6);
246+
assert_eq!(switch(10), 20);
247+
assert_eq!(switch(42), 255);
248+
}

tests/test_values.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,3 +640,23 @@ fn test_floats() {
640640
assert!(u64_pi.as_instruction().is_none());
641641
assert!(f128_pi_cast.as_instruction().is_none());
642642
}
643+
644+
#[test]
645+
fn test_function_value_no_params() {
646+
let context = Context::create();
647+
let module = context.create_module("my_mod");
648+
let void_type = context.void_type();
649+
let fn_type = void_type.fn_type(&[], false);
650+
let fn_value = module.add_function("no_params", &fn_type, None);
651+
652+
// REVIEW: According to this, fn_value.get_type() is a void ptr??
653+
// assert_eq!(fn_value.get_type(), fn_type);
654+
assert_eq!(fn_value.count_params(), 0);
655+
assert_eq!(fn_value.params().collect::<Vec<_>>().len(), 0);
656+
assert!(fn_value.get_first_param().is_none());
657+
assert!(fn_value.get_last_param().is_none());
658+
assert!(fn_value.get_nth_param(0).is_none());
659+
assert!(fn_value.get_personality_function().is_none());
660+
assert!(!fn_value.is_null());
661+
assert!(!fn_value.is_undef());
662+
}

0 commit comments

Comments
 (0)