Skip to content

Commit 50c370b

Browse files
committed
Add {set,get}_atomic_ordering to instruction_value.
1 parent 3fcc594 commit 50c370b

File tree

2 files changed

+56
-3
lines changed

2 files changed

+56
-3
lines changed

Diff for: src/values/instruction_value.rs

+41-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use either::{Either, Either::{Left, Right}};
2-
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};
2+
use llvm_sys::core::{LLVMGetAlignment, LLVMSetAlignment, LLVMGetOrdering, LLVMSetOrdering, LLVMGetInstructionOpcode, LLVMIsTailCall, LLVMGetPreviousInstruction, LLVMGetNextInstruction, LLVMGetInstructionParent, LLVMInstructionEraseFromParent, LLVMInstructionClone, LLVMSetVolatile, LLVMGetVolatile, LLVMGetNumOperands, LLVMGetOperand, LLVMGetOperandUse, LLVMSetOperand, LLVMValueAsBasicBlock, LLVMIsABasicBlock, LLVMGetICmpPredicate, LLVMGetFCmpPredicate, LLVMIsAAllocaInst, LLVMIsALoadInst, LLVMIsAStoreInst};
33
#[llvm_versions(3.9..=latest)]
44
use llvm_sys::core::LLVMInstructionRemoveFromParent;
55
use llvm_sys::LLVMOpcode;
@@ -8,7 +8,7 @@ use llvm_sys::prelude::LLVMValueRef;
88
use crate::basic_block::BasicBlock;
99
use crate::values::traits::AsValueRef;
1010
use crate::values::{BasicValue, BasicValueEnum, BasicValueUse, Value};
11-
use crate::{IntPredicate, FloatPredicate};
11+
use crate::{AtomicOrdering, IntPredicate, FloatPredicate};
1212

1313
// REVIEW: Split up into structs for SubTypes on InstructionValues?
1414
// REVIEW: This should maybe be split up into InstructionOpcode and ConstOpcode?
@@ -243,6 +243,45 @@ impl InstructionValue {
243243
}
244244
}
245245

246+
// SubTypes: Only apply to memory access instructions
247+
/// Returns atomic ordering on a memory access instruction.
248+
pub fn get_atomic_ordering(&self) -> Result<AtomicOrdering, &'static str> {
249+
let value_ref = self.as_value_ref();
250+
if unsafe { LLVMIsALoadInst(value_ref) }.is_null() &&
251+
unsafe { LLVMIsAStoreInst(value_ref) }.is_null() {
252+
return Err("Value is not a load or store.");
253+
}
254+
Ok(unsafe { LLVMGetOrdering(value_ref) }.into())
255+
}
256+
257+
// SubTypes: Only apply to memory access instructions
258+
/// Sets atomic ordering on a memory access instruction.
259+
pub fn set_atomic_ordering(&self, ordering: AtomicOrdering) -> Result<(), &'static str> {
260+
let value_ref = self.as_value_ref();
261+
let is_load = !unsafe { LLVMIsALoadInst(value_ref) }.is_null();
262+
let is_store = !unsafe { LLVMIsAStoreInst(value_ref) }.is_null();
263+
264+
// Although fence and atomicrmw both have an ordering, the LLVM C API
265+
// does not support them. The cmpxchg instruction has two orderings and
266+
// does not work with this API.
267+
if !is_load && !is_store {
268+
return Err("Value is not a load or store instruction.");
269+
}
270+
match ordering {
271+
AtomicOrdering::Release => {
272+
if is_load { return Err("The release ordering is not valid on load instructions.") }
273+
}
274+
AtomicOrdering::AcquireRelease => {
275+
return Err("The acq_rel ordering is not valid on load or store instructions.")
276+
}
277+
AtomicOrdering::Acquire => {
278+
if is_store { return Err("The acquire ordering is not valid on store instructions.") }
279+
}
280+
_ => { }
281+
};
282+
Ok(unsafe { LLVMSetOrdering(value_ref, ordering.into()) })
283+
}
284+
246285
/// Obtains the number of operands an `InstructionValue` has.
247286
/// An operand is a `BasicValue` used in an IR instruction.
248287
///

Diff for: tests/all/test_instruction_values.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
extern crate inkwell;
22

3-
use self::inkwell::{AddressSpace, IntPredicate, FloatPredicate};
3+
use self::inkwell::{AddressSpace, AtomicOrdering, IntPredicate, FloatPredicate};
44
use self::inkwell::context::Context;
55
use self::inkwell::values::{BasicValue, InstructionOpcode::*};
66

@@ -304,9 +304,23 @@ fn test_mem_instructions() {
304304
assert!(store_instruction.set_alignment(14).is_err());
305305
assert_eq!(store_instruction.get_alignment().unwrap(), 0);
306306

307+
assert_eq!(store_instruction.get_atomic_ordering().unwrap(), AtomicOrdering::NotAtomic);
308+
assert_eq!(load_instruction.get_atomic_ordering().unwrap(), AtomicOrdering::NotAtomic);
309+
assert!(store_instruction.set_atomic_ordering(AtomicOrdering::Monotonic).is_ok());
310+
assert_eq!(store_instruction.get_atomic_ordering().unwrap(), AtomicOrdering::Monotonic);
311+
assert!(store_instruction.set_atomic_ordering(AtomicOrdering::Release).is_ok());
312+
assert!(load_instruction.set_atomic_ordering(AtomicOrdering::Acquire).is_ok());
313+
314+
assert!(store_instruction.set_atomic_ordering(AtomicOrdering::Acquire).is_err());
315+
assert!(store_instruction.set_atomic_ordering(AtomicOrdering::AcquireRelease).is_err());
316+
assert!(load_instruction.set_atomic_ordering(AtomicOrdering::AcquireRelease).is_err());
317+
assert!(load_instruction.set_atomic_ordering(AtomicOrdering::Release).is_err());
318+
307319
let fadd_instruction = builder.build_float_add(load.into_float_value(), f32_val, "").as_instruction_value().unwrap();
308320
assert!(fadd_instruction.get_volatile().is_err());
309321
assert!(fadd_instruction.set_volatile(false).is_err());
310322
assert!(fadd_instruction.get_alignment().is_err());
311323
assert!(fadd_instruction.set_alignment(16).is_err());
324+
assert!(fadd_instruction.get_atomic_ordering().is_err());
325+
assert!(fadd_instruction.set_atomic_ordering(AtomicOrdering::NotAtomic).is_err());
312326
}

0 commit comments

Comments
 (0)