From ede15e27a62358c5552ecdc8826bdf8255f1e0fc Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 22 Aug 2019 13:10:33 -0700 Subject: [PATCH 1/4] Add set_alignment and get_alignment on InstructionValue. --- src/values/instruction_value.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/values/instruction_value.rs b/src/values/instruction_value.rs index 84e2367af30..52801dfcde3 100644 --- a/src/values/instruction_value.rs +++ b/src/values/instruction_value.rs @@ -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}; #[llvm_versions(3.9..=latest)] use llvm_sys::core::LLVMInstructionRemoveFromParent; use llvm_sys::LLVMOpcode; @@ -198,6 +198,22 @@ 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) -> u32 { + unsafe { + LLVMGetAlignment(self.as_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) { + unsafe { + LLVMSetAlignment(self.as_value_ref(), alignment) + } + } + /// Obtains the number of operands an `InstructionValue` has. /// An operand is a `BasicValue` used in an IR instruction. /// From 2ac42646e2544a4f47e6f27850671dda7a1b4d24 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 22 Aug 2019 13:31:39 -0700 Subject: [PATCH 2/4] Make set_alignment check for power of 2, and return Result with error message on failure. It's still not safe because we don't check whether the value is a memory instruction. Add tests for alignment and volatile getters/setters. --- src/values/instruction_value.rs | 7 ++-- tests/all/test_instruction_values.rs | 53 ++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/values/instruction_value.rs b/src/values/instruction_value.rs index 52801dfcde3..daa2a45c49b 100644 --- a/src/values/instruction_value.rs +++ b/src/values/instruction_value.rs @@ -208,9 +208,12 @@ impl InstructionValue { // 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) { + pub fn set_alignment(&self, alignment: u32) -> Result<(), &'static str> { + if !alignment.is_power_of_two() { + return Err("Alignment is not a power of 2!"); + } unsafe { - LLVMSetAlignment(self.as_value_ref(), alignment) + Ok(LLVMSetAlignment(self.as_value_ref(), alignment)) } } diff --git a/tests/all/test_instruction_values.rs b/tests/all/test_instruction_values.rs index 432e2371f70..ab58bd5137d 100644 --- a/tests/all/test_instruction_values.rs +++ b/tests/all/test_instruction_values.rs @@ -250,3 +250,56 @@ 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_instruction = builder.build_load(arg1, "").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(), 0); + assert_eq!(load_instruction.get_alignment(), 0); + assert!(store_instruction.set_alignment(16).is_ok()); + assert!(load_instruction.set_alignment(16).is_ok()); + assert_eq!(store_instruction.get_alignment(), 16); + assert_eq!(load_instruction.get_alignment(), 16); + assert!(store_instruction.set_alignment(0).is_ok()); + assert!(load_instruction.set_alignment(0).is_ok()); + assert_eq!(store_instruction.get_alignment(), 0); + assert_eq!(load_instruction.get_alignment(), 0); + + assert!(store_instruction.set_alignment(14).is_err()); + assert_eq!(store_instruction.get_alignment(), 0); +} From 95555f28fba5d383cdd68f329f0a543722cb75ec Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 26 Aug 2019 12:45:15 -0700 Subject: [PATCH 3/4] =?UTF-8?q?Zero=20is=20not=20a=20power=20of=20two=20in?= =?UTF-8?q?=20=E2=84=9D,=20but=20it's=20a=20way=20to=20clear=20the=20align?= =?UTF-8?q?ment.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/values/instruction_value.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/values/instruction_value.rs b/src/values/instruction_value.rs index daa2a45c49b..b9f640586d7 100644 --- a/src/values/instruction_value.rs +++ b/src/values/instruction_value.rs @@ -209,7 +209,7 @@ impl InstructionValue { // 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> { - if !alignment.is_power_of_two() { + if !alignment.is_power_of_two() && alignment != 0 { return Err("Alignment is not a power of 2!"); } unsafe { From 3464374af2c1be7bdf92c7a54e14aff1fb181993 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 28 Aug 2019 15:57:45 -0700 Subject: [PATCH 4/4] Check that the instruction has an alignment to be queried or set. --- src/values/instruction_value.rs | 20 ++++++++++++++++---- tests/all/test_instruction_values.rs | 21 +++++++++++++-------- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/values/instruction_value.rs b/src/values/instruction_value.rs index b9f640586d7..4360e2f5e7c 100644 --- a/src/values/instruction_value.rs +++ b/src/values/instruction_value.rs @@ -1,5 +1,5 @@ use either::{Either, Either::{Left, Right}}; -use llvm_sys::core::{LLVMGetAlignment, LLVMSetAlignment, 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; @@ -200,9 +200,15 @@ 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) -> u32 { + pub fn get_alignment(&self) -> Result { + let value_ref = self.as_value_ref(); unsafe { - LLVMGetAlignment(self.as_value_ref()) + 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)) } } @@ -212,8 +218,14 @@ impl InstructionValue { 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 { - Ok(LLVMSetAlignment(self.as_value_ref(), alignment)) + 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)) } } diff --git a/tests/all/test_instruction_values.rs b/tests/all/test_instruction_values.rs index ab58bd5137d..a538c4f5fe5 100644 --- a/tests/all/test_instruction_values.rs +++ b/tests/all/test_instruction_values.rs @@ -276,7 +276,8 @@ fn test_mem_instructions() { let f32_val = f32_type.const_float(::std::f64::consts::PI); let store_instruction = builder.build_store(arg1, f32_val); - let load_instruction = builder.build_load(arg1, "").as_instruction_value().unwrap(); + 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); @@ -289,17 +290,21 @@ fn test_mem_instructions() { assert_eq!(store_instruction.get_volatile(), false); assert_eq!(load_instruction.get_volatile(), false); - assert_eq!(store_instruction.get_alignment(), 0); - assert_eq!(load_instruction.get_alignment(), 0); + 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(), 16); - assert_eq!(load_instruction.get_alignment(), 16); + 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(), 0); - assert_eq!(load_instruction.get_alignment(), 0); + 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(), 0); + 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()); }