Skip to content

Commit d2e9ee3

Browse files
authored
Merge pull request rust-lang#118 from wasmerio/atomic
Add {set,get}_atomic_ordering to instruction_value.
2 parents 3fcc594 + 5a34a76 commit d2e9ee3

File tree

2 files changed

+108
-36
lines changed

2 files changed

+108
-36
lines changed

Diff for: src/values/instruction_value.rs

+61-35
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use either::{Either, Either::{Left, Right}};
22
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};
3+
#[llvm_versions(3.8..=latest)]
4+
use llvm_sys::core::{LLVMGetOrdering, LLVMSetOrdering};
35
#[llvm_versions(3.9..=latest)]
46
use llvm_sys::core::LLVMInstructionRemoveFromParent;
57
use llvm_sys::LLVMOpcode;
@@ -8,7 +10,7 @@ use llvm_sys::prelude::LLVMValueRef;
810
use crate::basic_block::BasicBlock;
911
use crate::values::traits::AsValueRef;
1012
use crate::values::{BasicValue, BasicValueEnum, BasicValueUse, Value};
11-
use crate::{IntPredicate, FloatPredicate};
13+
use crate::{AtomicOrdering, IntPredicate, FloatPredicate};
1214

1315
// REVIEW: Split up into structs for SubTypes on InstructionValues?
1416
// REVIEW: This should maybe be split up into InstructionOpcode and ConstOpcode?
@@ -98,6 +100,16 @@ pub struct InstructionValue {
98100
}
99101

100102
impl InstructionValue {
103+
fn is_a_load_inst(&self) -> bool {
104+
!unsafe { LLVMIsALoadInst(self.as_value_ref()) }.is_null()
105+
}
106+
fn is_a_store_inst(&self) -> bool {
107+
!unsafe { LLVMIsAStoreInst(self.as_value_ref()) }.is_null()
108+
}
109+
fn is_a_alloca_inst(&self) -> bool {
110+
!unsafe { LLVMIsAAllocaInst(self.as_value_ref()) }.is_null()
111+
}
112+
101113
pub(crate) fn new(instruction_value: LLVMValueRef) -> Self {
102114
debug_assert!(!instruction_value.is_null());
103115

@@ -185,45 +197,32 @@ impl InstructionValue {
185197
// SubTypes: Only apply to memory access instructions
186198
/// Returns whether or not a memory access instruction is volatile.
187199
pub fn get_volatile(&self) -> Result<bool, &'static str> {
188-
let value_ref = self.as_value_ref();
189-
unsafe {
190-
// Although cmpxchg and atomicrmw can have volatile, LLVM's C API
191-
// does not export that functionality.
192-
if LLVMIsALoadInst(value_ref).is_null() &&
193-
LLVMIsAStoreInst(value_ref).is_null() {
194-
return Err("Value is not a load or store.");
195-
}
196-
Ok(LLVMGetVolatile(value_ref) == 1)
200+
// Although cmpxchg and atomicrmw can have volatile, LLVM's C API
201+
// does not export that functionality.
202+
if !self.is_a_load_inst() && !self.is_a_store_inst() {
203+
return Err("Value is not a load or store.");
197204
}
205+
Ok(unsafe { LLVMGetVolatile(self.as_value_ref()) } == 1)
198206
}
199207

200208
// SubTypes: Only apply to memory access instructions
201209
/// Sets whether or not a memory access instruction is volatile.
202210
pub fn set_volatile(&self, volatile: bool) -> Result<(), &'static str> {
203-
let value_ref = self.as_value_ref();
204-
unsafe {
205-
// Although cmpxchg and atomicrmw can have volatile, LLVM's C API
206-
// does not export that functionality.
207-
if LLVMIsALoadInst(value_ref).is_null() &&
208-
LLVMIsAStoreInst(value_ref).is_null() {
209-
return Err("Value is not a load or store.");
210-
}
211-
Ok(LLVMSetVolatile(value_ref, volatile as i32))
211+
// Although cmpxchg and atomicrmw can have volatile, LLVM's C API
212+
// does not export that functionality.
213+
if !self.is_a_load_inst() && !self.is_a_store_inst() {
214+
return Err("Value is not a load or store.");
212215
}
216+
Ok(unsafe { LLVMSetVolatile(self.as_value_ref(), volatile as i32) })
213217
}
214218

215219
// SubTypes: Only apply to memory access and alloca instructions
216220
/// Returns alignment on a memory access instruction or alloca.
217221
pub fn get_alignment(&self) -> Result<u32, &'static str> {
218-
let value_ref = self.as_value_ref();
219-
unsafe {
220-
if LLVMIsAAllocaInst(value_ref).is_null() &&
221-
LLVMIsALoadInst(value_ref).is_null() &&
222-
LLVMIsAStoreInst(value_ref).is_null() {
223-
return Err("Value is not an alloca, load or store.");
224-
}
225-
Ok(LLVMGetAlignment(value_ref))
222+
if !self.is_a_alloca_inst() && !self.is_a_load_inst() && !self.is_a_store_inst() {
223+
return Err("Value is not an alloca, load or store.");
226224
}
225+
Ok(unsafe { LLVMGetAlignment(self.as_value_ref()) })
227226
}
228227

229228
// SubTypes: Only apply to memory access and alloca instructions
@@ -232,15 +231,42 @@ impl InstructionValue {
232231
if !alignment.is_power_of_two() && alignment != 0 {
233232
return Err("Alignment is not a power of 2!");
234233
}
235-
let value_ref = self.as_value_ref();
236-
unsafe {
237-
if LLVMIsAAllocaInst(value_ref).is_null() &&
238-
LLVMIsALoadInst(value_ref).is_null() &&
239-
LLVMIsAStoreInst(value_ref).is_null() {
240-
return Err("Value is not an alloca, load or store.");
241-
}
242-
Ok(LLVMSetAlignment(value_ref, alignment))
234+
if !self.is_a_alloca_inst() && !self.is_a_load_inst() && !self.is_a_store_inst() {
235+
return Err("Value is not an alloca, load or store.");
243236
}
237+
Ok(unsafe { LLVMSetAlignment(self.as_value_ref(), alignment) })
238+
}
239+
240+
// SubTypes: Only apply to memory access instructions
241+
/// Returns atomic ordering on a memory access instruction.
242+
#[llvm_versions(3.8..=latest)]
243+
pub fn get_atomic_ordering(&self) -> Result<AtomicOrdering, &'static str> {
244+
if !self.is_a_load_inst() && !self.is_a_store_inst() {
245+
return Err("Value is not a load or store.");
246+
}
247+
Ok(unsafe { LLVMGetOrdering(self.as_value_ref()) }.into())
248+
}
249+
250+
// SubTypes: Only apply to memory access instructions
251+
/// Sets atomic ordering on a memory access instruction.
252+
#[llvm_versions(3.8..=latest)]
253+
pub fn set_atomic_ordering(&self, ordering: AtomicOrdering) -> Result<(), &'static str> {
254+
// Although fence and atomicrmw both have an ordering, the LLVM C API
255+
// does not support them. The cmpxchg instruction has two orderings and
256+
// does not work with this API.
257+
if !self.is_a_load_inst() && !self.is_a_store_inst() {
258+
return Err("Value is not a load or store instruction.");
259+
}
260+
match ordering {
261+
AtomicOrdering::Release if self.is_a_load_inst() =>
262+
return Err("The release ordering is not valid on load instructions."),
263+
AtomicOrdering::AcquireRelease =>
264+
return Err("The acq_rel ordering is not valid on load or store instructions."),
265+
AtomicOrdering::Acquire if self.is_a_store_inst() =>
266+
return Err("The acquire ordering is not valid on store instructions."),
267+
_ => { },
268+
};
269+
Ok(unsafe { LLVMSetOrdering(self.as_value_ref(), ordering.into()) })
244270
}
245271

246272
/// Obtains the number of operands an `InstructionValue` has.

Diff for: tests/all/test_instruction_values.rs

+47-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

@@ -310,3 +310,49 @@ fn test_mem_instructions() {
310310
assert!(fadd_instruction.get_alignment().is_err());
311311
assert!(fadd_instruction.set_alignment(16).is_err());
312312
}
313+
314+
#[llvm_versions(3.8..=latest)]
315+
#[test]
316+
fn test_atomic_ordering_mem_instructions() {
317+
let context = Context::create();
318+
let module = context.create_module("testing");
319+
let builder = context.create_builder();
320+
321+
let void_type = context.void_type();
322+
let f32_type = context.f32_type();
323+
let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic);
324+
let fn_type = void_type.fn_type(&[f32_ptr_type.into(), f32_type.into()], false);
325+
326+
let function = module.add_function("mem_inst", fn_type, None);
327+
let basic_block = context.append_basic_block(&function, "entry");
328+
329+
builder.position_at_end(&basic_block);
330+
331+
let arg1 = function.get_first_param().unwrap().into_pointer_value();
332+
let arg2 = function.get_nth_param(1).unwrap().into_float_value();
333+
334+
assert!(arg1.get_first_use().is_none());
335+
assert!(arg2.get_first_use().is_none());
336+
337+
let f32_val = f32_type.const_float(::std::f64::consts::PI);
338+
339+
let store_instruction = builder.build_store(arg1, f32_val);
340+
let load = builder.build_load(arg1, "");
341+
let load_instruction = load.as_instruction_value().unwrap();
342+
343+
assert_eq!(store_instruction.get_atomic_ordering().unwrap(), AtomicOrdering::NotAtomic);
344+
assert_eq!(load_instruction.get_atomic_ordering().unwrap(), AtomicOrdering::NotAtomic);
345+
assert!(store_instruction.set_atomic_ordering(AtomicOrdering::Monotonic).is_ok());
346+
assert_eq!(store_instruction.get_atomic_ordering().unwrap(), AtomicOrdering::Monotonic);
347+
assert!(store_instruction.set_atomic_ordering(AtomicOrdering::Release).is_ok());
348+
assert!(load_instruction.set_atomic_ordering(AtomicOrdering::Acquire).is_ok());
349+
350+
assert!(store_instruction.set_atomic_ordering(AtomicOrdering::Acquire).is_err());
351+
assert!(store_instruction.set_atomic_ordering(AtomicOrdering::AcquireRelease).is_err());
352+
assert!(load_instruction.set_atomic_ordering(AtomicOrdering::AcquireRelease).is_err());
353+
assert!(load_instruction.set_atomic_ordering(AtomicOrdering::Release).is_err());
354+
355+
let fadd_instruction = builder.build_float_add(load.into_float_value(), f32_val, "").as_instruction_value().unwrap();
356+
assert!(fadd_instruction.get_atomic_ordering().is_err());
357+
assert!(fadd_instruction.set_atomic_ordering(AtomicOrdering::NotAtomic).is_err());
358+
}

0 commit comments

Comments
 (0)