Skip to content

Commit fdf8957

Browse files
authored
Merge pull request rust-lang#190 from wasmerio/volatile-atomics
Get/set of volatile on atomicrmw and cmpxchg was added in LLVM 10.
2 parents fcf7742 + 13d2afb commit fdf8957

File tree

2 files changed

+91
-3
lines changed

2 files changed

+91
-3
lines changed

src/values/instruction_value.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use llvm_sys::core::{LLVMGetAlignment, LLVMSetAlignment, LLVMGetInstructionOpcod
44
use llvm_sys::core::{LLVMGetOrdering, LLVMSetOrdering};
55
#[llvm_versions(3.9..=latest)]
66
use llvm_sys::core::LLVMInstructionRemoveFromParent;
7+
#[llvm_versions(10.0..=latest)]
8+
use llvm_sys::core::{LLVMIsAAtomicRMWInst, LLVMIsAAtomicCmpXchgInst};
79
use llvm_sys::LLVMOpcode;
810
use llvm_sys::prelude::LLVMValueRef;
911

@@ -113,6 +115,14 @@ impl<'ctx> InstructionValue<'ctx> {
113115
fn is_a_alloca_inst(self) -> bool {
114116
!unsafe { LLVMIsAAllocaInst(self.as_value_ref()) }.is_null()
115117
}
118+
#[llvm_versions(10.0..=latest)]
119+
fn is_a_atomicrmw_inst(self) -> bool {
120+
!unsafe { LLVMIsAAtomicRMWInst(self.as_value_ref()) }.is_null()
121+
}
122+
#[llvm_versions(10.0..=latest)]
123+
fn is_a_cmpxchg_inst(self) -> bool {
124+
!unsafe { LLVMIsAAtomicCmpXchgInst(self.as_value_ref()) }.is_null()
125+
}
116126

117127
pub(crate) fn new(instruction_value: LLVMValueRef) -> Self {
118128
debug_assert!(!instruction_value.is_null());
@@ -203,25 +213,49 @@ impl<'ctx> InstructionValue<'ctx> {
203213

204214
// SubTypes: Only apply to memory access instructions
205215
/// Returns whether or not a memory access instruction is volatile.
216+
#[llvm_versions(3.6..=9.0)]
206217
pub fn get_volatile(self) -> Result<bool, &'static str> {
207218
// Although cmpxchg and atomicrmw can have volatile, LLVM's C API
208-
// does not export that functionality.
219+
// does not export that functionality until 10.0.
209220
if !self.is_a_load_inst() && !self.is_a_store_inst() {
210221
return Err("Value is not a load or store.");
211222
}
212223
Ok(unsafe { LLVMGetVolatile(self.as_value_ref()) } == 1)
213224
}
214225

226+
// SubTypes: Only apply to memory access instructions
227+
/// Returns whether or not a memory access instruction is volatile.
228+
#[llvm_versions(10.0..=latest)]
229+
pub fn get_volatile(self) -> Result<bool, &'static str> {
230+
if !self.is_a_load_inst() && !self.is_a_store_inst() &&
231+
!self.is_a_atomicrmw_inst() && !self.is_a_cmpxchg_inst() {
232+
return Err("Value is not a load, store, atomicrmw or cmpxchg.");
233+
}
234+
Ok(unsafe { LLVMGetVolatile(self.as_value_ref()) } == 1)
235+
}
236+
215237
// SubTypes: Only apply to memory access instructions
216238
/// Sets whether or not a memory access instruction is volatile.
239+
#[llvm_versions(3.6..=9.0)]
217240
pub fn set_volatile(self, volatile: bool) -> Result<(), &'static str> {
218241
// Although cmpxchg and atomicrmw can have volatile, LLVM's C API
219-
// does not export that functionality.
242+
// does not export that functionality until 10.0.
220243
if !self.is_a_load_inst() && !self.is_a_store_inst() {
221244
return Err("Value is not a load or store.");
222245
}
223246
Ok(unsafe { LLVMSetVolatile(self.as_value_ref(), volatile as i32) })
224247
}
248+
249+
// SubTypes: Only apply to memory access instructions
250+
/// Sets whether or not a memory access instruction is volatile.
251+
#[llvm_versions(10.0..=latest)]
252+
pub fn set_volatile(self, volatile: bool) -> Result<(), &'static str> {
253+
if !self.is_a_load_inst() && !self.is_a_store_inst() &&
254+
!self.is_a_atomicrmw_inst() && !self.is_a_cmpxchg_inst() {
255+
return Err("Value is not a load, store, atomicrmw or cmpxchg.");
256+
}
257+
Ok(unsafe { LLVMSetVolatile(self.as_value_ref(), volatile as i32) })
258+
}
225259

226260
// SubTypes: Only apply to memory access and alloca instructions
227261
/// Returns alignment on a memory access instruction or alloca.

tests/all/test_instruction_values.rs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use inkwell::{AddressSpace, AtomicOrdering, IntPredicate, FloatPredicate};
21
use inkwell::context::Context;
32
use inkwell::values::{BasicValue, InstructionOpcode::*};
3+
use inkwell::{AddressSpace, AtomicOrdering, AtomicRMWBinOp, FloatPredicate, IntPredicate};
44

55
#[test]
66
fn test_operands() {
@@ -249,6 +249,60 @@ fn test_instructions() {
249249
assert_eq!(instruction_clone, instruction_clone_copy);
250250
}
251251

252+
#[llvm_versions(10.0..=latest)]
253+
#[test]
254+
fn test_volatile_atomicrmw_cmpxchg() {
255+
let context = Context::create();
256+
let module = context.create_module("testing");
257+
let builder = context.create_builder();
258+
259+
let void_type = context.void_type();
260+
let i32_type = context.i32_type();
261+
let i32_ptr_type = i32_type.ptr_type(AddressSpace::Generic);
262+
let fn_type = void_type.fn_type(&[i32_ptr_type.into(), i32_type.into()], false);
263+
264+
let function = module.add_function("mem_inst", fn_type, None);
265+
let basic_block = context.append_basic_block(function, "entry");
266+
267+
builder.position_at_end(basic_block);
268+
269+
let arg1 = function.get_first_param().unwrap().into_pointer_value();
270+
let arg2 = function.get_nth_param(1).unwrap().into_int_value();
271+
272+
assert!(arg1.get_first_use().is_none());
273+
assert!(arg2.get_first_use().is_none());
274+
275+
let i32_val = i32_type.const_int(7, false);
276+
277+
let atomicrmw = builder
278+
.build_atomicrmw(AtomicRMWBinOp::Add, arg1, arg2, AtomicOrdering::Unordered)
279+
.unwrap()
280+
.as_instruction_value()
281+
.unwrap();
282+
let cmpxchg = builder
283+
.build_cmpxchg(
284+
arg1,
285+
arg2,
286+
i32_val,
287+
AtomicOrdering::Monotonic,
288+
AtomicOrdering::Monotonic,
289+
)
290+
.unwrap()
291+
.as_instruction_value()
292+
.unwrap();
293+
294+
assert_eq!(atomicrmw.get_volatile().unwrap(), false);
295+
assert_eq!(cmpxchg.get_volatile().unwrap(), false);
296+
atomicrmw.set_volatile(true).unwrap();
297+
cmpxchg.set_volatile(true).unwrap();
298+
assert_eq!(atomicrmw.get_volatile().unwrap(), true);
299+
assert_eq!(cmpxchg.get_volatile().unwrap(), true);
300+
atomicrmw.set_volatile(false).unwrap();
301+
cmpxchg.set_volatile(false).unwrap();
302+
assert_eq!(atomicrmw.get_volatile().unwrap(), false);
303+
assert_eq!(cmpxchg.get_volatile().unwrap(), false);
304+
}
305+
252306
#[test]
253307
fn test_mem_instructions() {
254308
let context = Context::create();

0 commit comments

Comments
 (0)