Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add set_alignment and get_alignment on InstructionValue. #114

Merged
merged 4 commits into from
Sep 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 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, LLVMGetICmpPredicate, LLVMGetFCmpPredicate};
use llvm_sys::core::{LLVMGetAlignment, LLVMSetAlignment, LLVMGetInstructionOpcode, LLVMIsTailCall, LLVMGetPreviousInstruction, LLVMGetNextInstruction, LLVMGetInstructionParent, LLVMInstructionEraseFromParent, LLVMInstructionClone, LLVMSetVolatile, LLVMGetVolatile, LLVMGetNumOperands, LLVMGetOperand, LLVMGetOperandUse, LLVMSetOperand, LLVMValueAsBasicBlock, LLVMIsABasicBlock, LLVMGetICmpPredicate, LLVMGetFCmpPredicate, LLVMIsAAllocaInst, LLVMIsALoadInst, LLVMIsAStoreInst};
#[llvm_versions(3.9..=latest)]
use llvm_sys::core::LLVMInstructionRemoveFromParent;
use llvm_sys::LLVMOpcode;
Expand Down Expand Up @@ -198,6 +198,37 @@ impl InstructionValue {
}
}

// SubTypes: Only apply to memory access and alloca instructions
/// Returns alignment on a memory access instruction or alloca.
pub fn get_alignment(&self) -> Result<u32, &'static str> {
let value_ref = self.as_value_ref();
unsafe {
if LLVMIsAAllocaInst(value_ref).is_null() &&
LLVMIsALoadInst(value_ref).is_null() &&
LLVMIsAStoreInst(value_ref).is_null() {
return Err("Value is not an alloca, load or store.");
}
Ok(LLVMGetAlignment(value_ref))
}
}

// SubTypes: Only apply to memory access and alloca instructions
/// Sets alignment on a memory access instruction or alloca.
pub fn set_alignment(&self, alignment: u32) -> Result<(), &'static str> {
nlewycky marked this conversation as resolved.
Show resolved Hide resolved
if !alignment.is_power_of_two() && alignment != 0 {
return Err("Alignment is not a power of 2!");
}
let value_ref = self.as_value_ref();
unsafe {
if LLVMIsAAllocaInst(value_ref).is_null() &&
LLVMIsALoadInst(value_ref).is_null() &&
LLVMIsAStoreInst(value_ref).is_null() {
return Err("Value is not an alloca, load or store.");
}
Ok(LLVMSetAlignment(value_ref, alignment))
}
}

/// Obtains the number of operands an `InstructionValue` has.
/// An operand is a `BasicValue` used in an IR instruction.
///
Expand Down
58 changes: 58 additions & 0 deletions tests/all/test_instruction_values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,61 @@ fn test_instructions() {

assert_eq!(instruction_clone, instruction_clone_copy);
}

#[test]
fn test_mem_instructions() {
let context = Context::create();
let module = context.create_module("testing");
let builder = context.create_builder();

let void_type = context.void_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(), f32_type.into()], false);

let function = module.add_function("mem_inst", 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 load = builder.build_load(arg1, "");
let load_instruction = load.as_instruction_value().unwrap();

assert_eq!(store_instruction.get_volatile(), false);
assert_eq!(load_instruction.get_volatile(), false);
store_instruction.set_volatile(true);
load_instruction.set_volatile(true);
assert_eq!(store_instruction.get_volatile(), true);
assert_eq!(load_instruction.get_volatile(), true);
store_instruction.set_volatile(false);
load_instruction.set_volatile(false);
assert_eq!(store_instruction.get_volatile(), false);
assert_eq!(load_instruction.get_volatile(), false);

assert_eq!(store_instruction.get_alignment().unwrap(), 0);
assert_eq!(load_instruction.get_alignment().unwrap(), 0);
assert!(store_instruction.set_alignment(16).is_ok());
assert!(load_instruction.set_alignment(16).is_ok());
assert_eq!(store_instruction.get_alignment().unwrap(), 16);
assert_eq!(load_instruction.get_alignment().unwrap(), 16);
assert!(store_instruction.set_alignment(0).is_ok());
assert!(load_instruction.set_alignment(0).is_ok());
assert_eq!(store_instruction.get_alignment().unwrap(), 0);
assert_eq!(load_instruction.get_alignment().unwrap(), 0);

assert!(store_instruction.set_alignment(14).is_err());
assert_eq!(store_instruction.get_alignment().unwrap(), 0);

let fadd_instruction = builder.build_float_add(load.into_float_value(), f32_val, "").as_instruction_value().unwrap();
assert!(fadd_instruction.get_alignment().is_err());
assert!(fadd_instruction.set_alignment(16).is_err());
}