Skip to content

Commit

Permalink
Merge pull request rust-lang#87 from cdisselkoen/icmp-fcmp-predicates
Browse files Browse the repository at this point in the history
add bindings for LLVMGet{I,F}CmpPredicate
TheDan64 authored Jun 24, 2019
2 parents 5650064 + 4bdee1c commit 67aed4c
Showing 2 changed files with 57 additions and 3 deletions.
43 changes: 42 additions & 1 deletion src/values/instruction_value.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use either::{Either, Either::{Left, Right}};
use llvm_sys::core::{LLVMGetInstructionOpcode, LLVMIsTailCall, LLVMGetPreviousInstruction, LLVMGetNextInstruction, LLVMGetInstructionParent, LLVMInstructionEraseFromParent, LLVMInstructionClone, LLVMSetVolatile, LLVMGetVolatile, LLVMGetNumOperands, LLVMGetOperand, LLVMGetOperandUse, LLVMSetOperand, LLVMValueAsBasicBlock, LLVMIsABasicBlock};
use llvm_sys::core::{LLVMGetInstructionOpcode, LLVMIsTailCall, LLVMGetPreviousInstruction, LLVMGetNextInstruction, LLVMGetInstructionParent, LLVMInstructionEraseFromParent, LLVMInstructionClone, LLVMSetVolatile, LLVMGetVolatile, LLVMGetNumOperands, LLVMGetOperand, LLVMGetOperandUse, LLVMSetOperand, LLVMValueAsBasicBlock, LLVMIsABasicBlock, LLVMGetICmpPredicate, LLVMGetFCmpPredicate};
#[llvm_versions(3.9 => latest)]
use llvm_sys::core::LLVMInstructionRemoveFromParent;
use llvm_sys::LLVMOpcode;
@@ -8,6 +8,7 @@ use llvm_sys::prelude::LLVMValueRef;
use crate::basic_block::BasicBlock;
use crate::values::traits::AsValueRef;
use crate::values::{BasicValue, BasicValueEnum, BasicValueUse, Value};
use crate::{IntPredicate, FloatPredicate};

// REVIEW: Split up into structs for SubTypes on InstructionValues?
// REVIEW: This should maybe be split up into InstructionOpcode and ConstOpcode?
@@ -619,6 +620,46 @@ impl InstructionValue {
pub fn get_first_use(&self) -> Option<BasicValueUse> {
self.instruction_value.get_first_use()
}

/// Gets the predicate of an `ICmp` `InstructionValue`.
/// For instance, in the LLVM instruction
/// `%3 = icmp slt i32 %0, %1`
/// this gives the `slt`.
///
/// If the instruction is not an `ICmp`, this returns None.
pub fn get_icmp_predicate(&self) -> Option<IntPredicate> {
// REVIEW: this call to get_opcode() can be inefficient;
// what happens if we don't perform this check, and just call
// LLVMGetICmpPredicate() regardless?
if self.get_opcode() == InstructionOpcode::ICmp {
let pred = unsafe {
LLVMGetICmpPredicate(self.as_value_ref())
};
Some(IntPredicate::new(pred))
} else {
None
}
}

/// Gets the predicate of an `FCmp` `InstructionValue`.
/// For instance, in the LLVM instruction
/// `%3 = fcmp olt float %0, %1`
/// this gives the `olt`.
///
/// If the instruction is not an `FCmp`, this returns None.
pub fn get_fcmp_predicate(&self) -> Option<FloatPredicate> {
// REVIEW: this call to get_opcode() can be inefficient;
// what happens if we don't perform this check, and just call
// LLVMGetFCmpPredicate() regardless?
if self.get_opcode() == InstructionOpcode::FCmp {
let pred = unsafe {
LLVMGetFCmpPredicate(self.as_value_ref())
};
Some(FloatPredicate::new(pred))
} else {
None
}
}
}

impl Clone for InstructionValue {
17 changes: 15 additions & 2 deletions tests/all/test_instruction_values.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extern crate inkwell;

use self::inkwell::AddressSpace;
use self::inkwell::{AddressSpace, IntPredicate, FloatPredicate};
use self::inkwell::context::Context;
use self::inkwell::values::{BasicValue, InstructionOpcode::*};

@@ -201,28 +201,41 @@ fn test_instructions() {
let i64_type = context.i64_type();
let f32_type = context.f32_type();
let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic);
let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
let fn_type = void_type.fn_type(&[f32_ptr_type.into(), f32_type.into()], false);

let function = module.add_function("free_f32", fn_type, None);
let basic_block = context.append_basic_block(&function, "entry");

builder.position_at_end(&basic_block);

let arg1 = function.get_first_param().unwrap().into_pointer_value();
let arg2 = function.get_nth_param(1).unwrap().into_float_value();

assert!(arg1.get_first_use().is_none());
assert!(arg2.get_first_use().is_none());

let f32_val = f32_type.const_float(::std::f64::consts::PI);

let store_instruction = builder.build_store(arg1, f32_val);
let ptr_val = builder.build_ptr_to_int(arg1, i64_type, "ptr_val");
let ptr = builder.build_int_to_ptr(ptr_val, f32_ptr_type, "ptr");
let icmp = builder.build_int_compare(IntPredicate::EQ, ptr_val, ptr_val, "icmp");
let f32_sum = builder.build_float_add(arg2, f32_val, "f32_sum");
let fcmp = builder.build_float_compare(FloatPredicate::OEQ, f32_sum, arg2, "fcmp");
let free_instruction = builder.build_free(arg1);
let return_instruction = builder.build_return(None);

assert_eq!(store_instruction.get_opcode(), Store);
assert_eq!(ptr_val.as_instruction().unwrap().get_opcode(), PtrToInt);
assert_eq!(ptr.as_instruction().unwrap().get_opcode(), IntToPtr);
assert_eq!(icmp.as_instruction().unwrap().get_opcode(), ICmp);
assert_eq!(ptr.as_instruction().unwrap().get_icmp_predicate(), None);
assert_eq!(icmp.as_instruction().unwrap().get_icmp_predicate().unwrap(), IntPredicate::EQ);
assert_eq!(f32_sum.as_instruction().unwrap().get_opcode(), FAdd);
assert_eq!(fcmp.as_instruction().unwrap().get_opcode(), FCmp);
assert_eq!(f32_sum.as_instruction().unwrap().get_fcmp_predicate(), None);
assert_eq!(icmp.as_instruction().unwrap().get_fcmp_predicate(), None);
assert_eq!(fcmp.as_instruction().unwrap().get_fcmp_predicate().unwrap(), FloatPredicate::OEQ);
assert_eq!(free_instruction.get_opcode(), Call);
assert_eq!(return_instruction.get_opcode(), Return);

0 comments on commit 67aed4c

Please sign in to comment.